blob: 054f57db975b672a3d0d45e2afe7ec50eb8c4705 [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
11#include <base/string_number_conversions.h>
12#include <base/string_split.h>
13#include <base/string_util.h>
14
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
24namespace {
25
26const char kConnectionInfoFilePath[] = "/proc/net/ip_conntrack";
27const char kSourceIPAddressTag[] = "src=";
28const char kSourcePortTag[] = "sport=";
29const char kDestinationIPAddressTag[] = "dst=";
30const char kDestinationPortTag[] = "dport=";
31const char kUnrepliedTag[] = "[UNREPLIED]";
32
33} // namespace
34
35ConnectionInfoReader::ConnectionInfoReader() {}
36
37ConnectionInfoReader::~ConnectionInfoReader() {}
38
39FilePath ConnectionInfoReader::GetConnectionInfoFilePath() const {
40 return FilePath(kConnectionInfoFilePath);
41}
42
43bool ConnectionInfoReader::LoadConnectionInfo(
44 vector<ConnectionInfo> *info_list) {
45 info_list->clear();
46
47 FilePath info_file_path = GetConnectionInfoFilePath();
48 FileReader file_reader;
49 if (!file_reader.Open(info_file_path)) {
50 SLOG(Link, 2) << __func__ << ": Failed to open '"
51 << info_file_path.value() << "'.";
52 return false;
53 }
54
55 string line;
56 while (file_reader.ReadLine(&line)) {
57 ConnectionInfo info;
58 if (ParseConnectionInfo(line, &info))
59 info_list->push_back(info);
60 }
61 return true;
62}
63
64bool ConnectionInfoReader::ParseConnectionInfo(const string &input,
65 ConnectionInfo *info) {
66 vector<string> tokens;
67 base::SplitStringAlongWhitespace(input, &tokens);
68 if (tokens.size() < 10) {
69 return false;
70 }
71
72 int index = 0;
73
74 int protocol = 0;
75 if (!ParseProtocol(tokens[++index], &protocol)) {
76 return false;
77 }
78 info->set_protocol(protocol);
79
80 int64 time_to_expire_seconds = 0;
81 if (!ParseTimeToExpireSeconds(tokens[++index], &time_to_expire_seconds)) {
82 return false;
83 }
84 info->set_time_to_expire_seconds(time_to_expire_seconds);
85
86 if (protocol == IPPROTO_TCP)
87 ++index;
88
89 IPAddress ip_address(IPAddress::kFamilyUnknown);
90 uint16 port = 0;
91 bool is_source = false;
92
93 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || !is_source) {
94 return false;
95 }
96 info->set_original_source_ip_address(ip_address);
97 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || is_source) {
98 return false;
99 }
100 info->set_original_destination_ip_address(ip_address);
101
102 if (!ParsePort(tokens[++index], &port, &is_source) || !is_source) {
103 return false;
104 }
105 info->set_original_source_port(port);
106 if (!ParsePort(tokens[++index], &port, &is_source) || is_source) {
107 return false;
108 }
109 info->set_original_destination_port(port);
110
111 if (tokens[index + 1] == kUnrepliedTag) {
112 info->set_is_unreplied(true);
113 ++index;
114 } else {
115 info->set_is_unreplied(false);
116 }
117
118 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || !is_source) {
119 return false;
120 }
121 info->set_reply_source_ip_address(ip_address);
122 if (!ParseIPAddress(tokens[++index], &ip_address, &is_source) || is_source) {
123 return false;
124 }
125 info->set_reply_destination_ip_address(ip_address);
126
127 if (!ParsePort(tokens[++index], &port, &is_source) || !is_source) {
128 return false;
129 }
130 info->set_reply_source_port(port);
131 if (!ParsePort(tokens[++index], &port, &is_source) || is_source) {
132 return false;
133 }
134 info->set_reply_destination_port(port);
135
136 return true;
137}
138
139bool ConnectionInfoReader::ParseProtocol(const string &input, int *protocol) {
140 if (!base::StringToInt(input, protocol) ||
141 *protocol < 0 || *protocol >= IPPROTO_MAX) {
142 return false;
143 }
144 return true;
145}
146
147bool ConnectionInfoReader::ParseTimeToExpireSeconds(
148 const string &input, int64 *time_to_expire_seconds) {
149 if (!base::StringToInt64(input, time_to_expire_seconds) ||
150 *time_to_expire_seconds < 0) {
151 return false;
152 }
153 return true;
154}
155
156bool ConnectionInfoReader::ParseIPAddress(
157 const string &input, IPAddress *ip_address, bool *is_source) {
158 string ip_address_string;
159
160 if (StartsWithASCII(input, kSourceIPAddressTag, false)) {
161 *is_source = true;
162 ip_address_string = input.substr(strlen(kSourceIPAddressTag));
163 } else if (StartsWithASCII(input, kDestinationIPAddressTag, false)) {
164 *is_source = false;
165 ip_address_string = input.substr(strlen(kDestinationIPAddressTag));
166 } else {
167 return false;
168 }
169
170 IPAddress ipv4_address(IPAddress::kFamilyIPv4);
171 if (ipv4_address.SetAddressFromString(ip_address_string)) {
172 *ip_address = ipv4_address;
173 return true;
174 }
175
176 IPAddress ipv6_address(IPAddress::kFamilyIPv6);
177 if (ipv6_address.SetAddressFromString(ip_address_string)) {
178 *ip_address = ipv6_address;
179 return true;
180 }
181
182 return false;
183}
184
185bool ConnectionInfoReader::ParsePort(
186 const string &input, uint16 *port, bool *is_source) {
187 int result = 0;
188 string port_string;
189
190 if (StartsWithASCII(input, kSourcePortTag, false)) {
191 *is_source = true;
192 port_string = input.substr(strlen(kSourcePortTag));
193 } else if (StartsWithASCII(input, kDestinationPortTag, false)) {
194 *is_source = false;
195 port_string = input.substr(strlen(kDestinationPortTag));
196 } else {
197 return false;
198 }
199
200 if (!base::StringToInt(port_string, &result) ||
201 result < 0 || result > std::numeric_limits<uint16>::max()) {
202 return false;
203 }
204
205 *port = result;
206 return true;
207}
208
209} // namespace shill