Home | History | Annotate | Download | only in shill
      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