1 // 2 // Copyright (C) 2013 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "shill/connection_info_reader.h" 18 19 #include <netinet/in.h> 20 21 #include <limits> 22 23 #include <base/strings/string_number_conversions.h> 24 #include <base/strings/string_split.h> 25 #include <base/strings/string_util.h> 26 27 #include "shill/file_reader.h" 28 #include "shill/logging.h" 29 30 using base::FilePath; 31 using std::string; 32 using std::vector; 33 34 namespace shill { 35 36 namespace Logging { 37 static auto kModuleLogScope = ScopeLogger::kLink; 38 static string ObjectID(ConnectionInfoReader* c) { 39 return "(connection_info_reader)"; 40 } 41 } 42 43 namespace { 44 45 const char kConnectionInfoFilePath[] = "/proc/net/ip_conntrack"; 46 const char kSourceIPAddressTag[] = "src="; 47 const char kSourcePortTag[] = "sport="; 48 const char kDestinationIPAddressTag[] = "dst="; 49 const char kDestinationPortTag[] = "dport="; 50 const char kUnrepliedTag[] = "[UNREPLIED]"; 51 52 } // namespace 53 54 ConnectionInfoReader::ConnectionInfoReader() {} 55 56 ConnectionInfoReader::~ConnectionInfoReader() {} 57 58 FilePath ConnectionInfoReader::GetConnectionInfoFilePath() const { 59 return FilePath(kConnectionInfoFilePath); 60 } 61 62 bool ConnectionInfoReader::LoadConnectionInfo( 63 vector<ConnectionInfo>* info_list) { 64 info_list->clear(); 65 66 FilePath info_file_path = GetConnectionInfoFilePath(); 67 FileReader file_reader; 68 if (!file_reader.Open(info_file_path)) { 69 SLOG(this, 2) << __func__ << ": Failed to open '" 70 << info_file_path.value() << "'."; 71 return false; 72 } 73 74 string line; 75 while (file_reader.ReadLine(&line)) { 76 ConnectionInfo info; 77 if (ParseConnectionInfo(line, &info)) 78 info_list->push_back(info); 79 } 80 return true; 81 } 82 83 bool ConnectionInfoReader::ParseConnectionInfo(const string& input, 84 ConnectionInfo* info) { 85 vector<string> tokens = base::SplitString(input, base::kWhitespaceASCII, 86 base::KEEP_WHITESPACE, 87 base::SPLIT_WANT_NONEMPTY); 88 if (tokens.size() < 10) { 89 return false; 90 } 91 92 int index = 0; 93 94 int protocol = 0; 95 if (!ParseProtocol(tokens[++index], &protocol)) { 96 return false; 97 } 98 info->set_protocol(protocol); 99 100 int64_t time_to_expire_seconds = 0; 101 if (!ParseTimeToExpireSeconds(tokens[++index], &time_to_expire_seconds)) { 102 return false; 103 } 104 info->set_time_to_expire_seconds(time_to_expire_seconds); 105 106 if (protocol == IPPROTO_TCP) 107 ++index; 108 109 IPAddress ip_address(IPAddress::kFamilyUnknown); 110 uint16_t port = 0; 111 bool is_source = false; 112 113 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || !is_source) { 114 return false; 115 } 116 info->set_original_source_ip_address(ip_address); 117 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || is_source) { 118 return false; 119 } 120 info->set_original_destination_ip_address(ip_address); 121 122 if (!ParsePort(tokens[++index], &port, &is_source) || !is_source) { 123 return false; 124 } 125 info->set_original_source_port(port); 126 if (!ParsePort(tokens[++index], &port, &is_source) || is_source) { 127 return false; 128 } 129 info->set_original_destination_port(port); 130 131 if (tokens[index + 1] == kUnrepliedTag) { 132 info->set_is_unreplied(true); 133 ++index; 134 } else { 135 info->set_is_unreplied(false); 136 } 137 138 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || !is_source) { 139 return false; 140 } 141 info->set_reply_source_ip_address(ip_address); 142 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || is_source) { 143 return false; 144 } 145 info->set_reply_destination_ip_address(ip_address); 146 147 if (!ParsePort(tokens[++index], &port, &is_source) || !is_source) { 148 return false; 149 } 150 info->set_reply_source_port(port); 151 if (!ParsePort(tokens[++index], &port, &is_source) || is_source) { 152 return false; 153 } 154 info->set_reply_destination_port(port); 155 156 return true; 157 } 158 159 bool ConnectionInfoReader::ParseProtocol(const string& input, int* protocol) { 160 if (!base::StringToInt(input, protocol) || 161 *protocol < 0 || *protocol >= IPPROTO_MAX) { 162 return false; 163 } 164 return true; 165 } 166 167 bool ConnectionInfoReader::ParseTimeToExpireSeconds( 168 const string& input, int64_t* time_to_expire_seconds) { 169 if (!base::StringToInt64(input, time_to_expire_seconds) || 170 *time_to_expire_seconds < 0) { 171 return false; 172 } 173 return true; 174 } 175 176 bool ConnectionInfoReader::ParseIPAddress( 177 const string& input, IPAddress* ip_address, bool* is_source) { 178 string ip_address_string; 179 180 if (base::StartsWith(input, kSourceIPAddressTag, 181 base::CompareCase::INSENSITIVE_ASCII)) { 182 *is_source = true; 183 ip_address_string = input.substr(strlen(kSourceIPAddressTag)); 184 } else if (base::StartsWith(input, kDestinationIPAddressTag, 185 base::CompareCase::INSENSITIVE_ASCII)) { 186 *is_source = false; 187 ip_address_string = input.substr(strlen(kDestinationIPAddressTag)); 188 } else { 189 return false; 190 } 191 192 IPAddress ipv4_address(IPAddress::kFamilyIPv4); 193 if (ipv4_address.SetAddressFromString(ip_address_string)) { 194 *ip_address = ipv4_address; 195 return true; 196 } 197 198 IPAddress ipv6_address(IPAddress::kFamilyIPv6); 199 if (ipv6_address.SetAddressFromString(ip_address_string)) { 200 *ip_address = ipv6_address; 201 return true; 202 } 203 204 return false; 205 } 206 207 bool ConnectionInfoReader::ParsePort( 208 const string& input, uint16_t* port, bool* is_source) { 209 int result = 0; 210 string port_string; 211 212 if (base::StartsWith(input, kSourcePortTag, 213 base::CompareCase::INSENSITIVE_ASCII)) { 214 *is_source = true; 215 port_string = input.substr(strlen(kSourcePortTag)); 216 } else if (base::StartsWith(input, kDestinationPortTag, 217 base::CompareCase::INSENSITIVE_ASCII)) { 218 *is_source = false; 219 port_string = input.substr(strlen(kDestinationPortTag)); 220 } else { 221 return false; 222 } 223 224 if (!base::StringToInt(port_string, &result) || 225 result < 0 || result > std::numeric_limits<uint16_t>::max()) { 226 return false; 227 } 228 229 *port = result; 230 return true; 231 } 232 233 } // namespace shill 234