blob: d39e5dd6f71d1cd036f95559193f2e319156fc2f [file] [log] [blame]
Ben Chanbac5bc82013-04-12 17:15:43 -07001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/connection_info_reader.h"
6
7#include <netinet/in.h>
8
9#include <limits>
10
Ben Chana0ddf462014-02-06 11:32:42 -080011#include <base/strings/string_number_conversions.h>
12#include <base/strings/string_split.h>
13#include <base/strings/string_util.h>
Ben Chanbac5bc82013-04-12 17:15:43 -070014
15#include "shill/file_reader.h"
16#include "shill/logging.h"
17
18using base::FilePath;
19using std::string;
20using std::vector;
21
22namespace shill {
23
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070024namespace Logging {
25static auto kModuleLogScope = ScopeLogger::kLink;
Paul Stewarta794cd62015-06-16 13:13:10 -070026static string ObjectID(ConnectionInfoReader* c) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070027 return "(connection_info_reader)";
28}
29}
30
Ben Chanbac5bc82013-04-12 17:15:43 -070031namespace {
32
33const char kConnectionInfoFilePath[] = "/proc/net/ip_conntrack";
34const char kSourceIPAddressTag[] = "src=";
35const char kSourcePortTag[] = "sport=";
36const char kDestinationIPAddressTag[] = "dst=";
37const char kDestinationPortTag[] = "dport=";
38const char kUnrepliedTag[] = "[UNREPLIED]";
39
40} // namespace
41
42ConnectionInfoReader::ConnectionInfoReader() {}
43
44ConnectionInfoReader::~ConnectionInfoReader() {}
45
46FilePath ConnectionInfoReader::GetConnectionInfoFilePath() const {
47 return FilePath(kConnectionInfoFilePath);
48}
49
50bool ConnectionInfoReader::LoadConnectionInfo(
Paul Stewarta794cd62015-06-16 13:13:10 -070051 vector<ConnectionInfo>* info_list) {
Ben Chanbac5bc82013-04-12 17:15:43 -070052 info_list->clear();
53
54 FilePath info_file_path = GetConnectionInfoFilePath();
55 FileReader file_reader;
56 if (!file_reader.Open(info_file_path)) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070057 SLOG(this, 2) << __func__ << ": Failed to open '"
Ben Chanbac5bc82013-04-12 17:15:43 -070058 << info_file_path.value() << "'.";
59 return false;
60 }
61
62 string line;
63 while (file_reader.ReadLine(&line)) {
64 ConnectionInfo info;
65 if (ParseConnectionInfo(line, &info))
66 info_list->push_back(info);
67 }
68 return true;
69}
70
Paul Stewarta794cd62015-06-16 13:13:10 -070071bool ConnectionInfoReader::ParseConnectionInfo(const string& input,
72 ConnectionInfo* info) {
Ben Chanbac5bc82013-04-12 17:15:43 -070073 vector<string> tokens;
74 base::SplitStringAlongWhitespace(input, &tokens);
75 if (tokens.size() < 10) {
76 return false;
77 }
78
79 int index = 0;
80
81 int protocol = 0;
82 if (!ParseProtocol(tokens[++index], &protocol)) {
83 return false;
84 }
85 info->set_protocol(protocol);
86
Ben Chan7fab8972014-08-10 17:14:46 -070087 int64_t time_to_expire_seconds = 0;
Ben Chanbac5bc82013-04-12 17:15:43 -070088 if (!ParseTimeToExpireSeconds(tokens[++index], &time_to_expire_seconds)) {
89 return false;
90 }
91 info->set_time_to_expire_seconds(time_to_expire_seconds);
92
93 if (protocol == IPPROTO_TCP)
94 ++index;
95
96 IPAddress ip_address(IPAddress::kFamilyUnknown);
Ben Chan7fab8972014-08-10 17:14:46 -070097 uint16_t port = 0;
Ben Chanbac5bc82013-04-12 17:15:43 -070098 bool is_source = false;
99
100 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || !is_source) {
101 return false;
102 }
103 info->set_original_source_ip_address(ip_address);
104 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || is_source) {
105 return false;
106 }
107 info->set_original_destination_ip_address(ip_address);
108
109 if (!ParsePort(tokens[++index], &port, &is_source) || !is_source) {
110 return false;
111 }
112 info->set_original_source_port(port);
113 if (!ParsePort(tokens[++index], &port, &is_source) || is_source) {
114 return false;
115 }
116 info->set_original_destination_port(port);
117
118 if (tokens[index + 1] == kUnrepliedTag) {
119 info->set_is_unreplied(true);
120 ++index;
121 } else {
122 info->set_is_unreplied(false);
123 }
124
125 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || !is_source) {
126 return false;
127 }
128 info->set_reply_source_ip_address(ip_address);
129 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || is_source) {
130 return false;
131 }
132 info->set_reply_destination_ip_address(ip_address);
133
134 if (!ParsePort(tokens[++index], &port, &is_source) || !is_source) {
135 return false;
136 }
137 info->set_reply_source_port(port);
138 if (!ParsePort(tokens[++index], &port, &is_source) || is_source) {
139 return false;
140 }
141 info->set_reply_destination_port(port);
142
143 return true;
144}
145
Paul Stewarta794cd62015-06-16 13:13:10 -0700146bool ConnectionInfoReader::ParseProtocol(const string& input, int* protocol) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700147 if (!base::StringToInt(input, protocol) ||
148 *protocol < 0 || *protocol >= IPPROTO_MAX) {
149 return false;
150 }
151 return true;
152}
153
154bool ConnectionInfoReader::ParseTimeToExpireSeconds(
Paul Stewarta794cd62015-06-16 13:13:10 -0700155 const string& input, int64_t* time_to_expire_seconds) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700156 if (!base::StringToInt64(input, time_to_expire_seconds) ||
157 *time_to_expire_seconds < 0) {
158 return false;
159 }
160 return true;
161}
162
163bool ConnectionInfoReader::ParseIPAddress(
Paul Stewarta794cd62015-06-16 13:13:10 -0700164 const string& input, IPAddress* ip_address, bool* is_source) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700165 string ip_address_string;
166
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700167 if (base::StartsWithASCII(input, kSourceIPAddressTag, false)) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700168 *is_source = true;
169 ip_address_string = input.substr(strlen(kSourceIPAddressTag));
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700170 } else if (base::StartsWithASCII(input, kDestinationIPAddressTag, false)) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700171 *is_source = false;
172 ip_address_string = input.substr(strlen(kDestinationIPAddressTag));
173 } else {
174 return false;
175 }
176
177 IPAddress ipv4_address(IPAddress::kFamilyIPv4);
178 if (ipv4_address.SetAddressFromString(ip_address_string)) {
179 *ip_address = ipv4_address;
180 return true;
181 }
182
183 IPAddress ipv6_address(IPAddress::kFamilyIPv6);
184 if (ipv6_address.SetAddressFromString(ip_address_string)) {
185 *ip_address = ipv6_address;
186 return true;
187 }
188
189 return false;
190}
191
192bool ConnectionInfoReader::ParsePort(
Paul Stewarta794cd62015-06-16 13:13:10 -0700193 const string& input, uint16_t* port, bool* is_source) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700194 int result = 0;
195 string port_string;
196
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700197 if (base::StartsWithASCII(input, kSourcePortTag, false)) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700198 *is_source = true;
199 port_string = input.substr(strlen(kSourcePortTag));
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700200 } else if (base::StartsWithASCII(input, kDestinationPortTag, false)) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700201 *is_source = false;
202 port_string = input.substr(strlen(kDestinationPortTag));
203 } else {
204 return false;
205 }
206
207 if (!base::StringToInt(port_string, &result) ||
Ben Chan7fab8972014-08-10 17:14:46 -0700208 result < 0 || result > std::numeric_limits<uint16_t>::max()) {
Ben Chanbac5bc82013-04-12 17:15:43 -0700209 return false;
210 }
211
212 *port = result;
213 return true;
214}
215
216} // namespace shill