OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/web_socket_proxy.h" | 5 #include "chrome/browser/chromeos/web_socket_proxy.h" |
6 | 6 |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 #include <string.h> | 9 #include <string.h> |
10 | 10 |
11 #include <algorithm> | 11 #include <algorithm> |
12 #include <limits> | 12 #include <limits> |
13 #include <list> | 13 #include <list> |
14 #include <map> | 14 #include <map> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include <arpa/inet.h> | 17 #include <arpa/inet.h> |
18 #include <errno.h> | 18 #include <errno.h> |
19 #include <fcntl.h> | 19 #include <fcntl.h> |
20 #include <netinet/in.h> | 20 #include <netinet/in.h> |
21 #include <signal.h> | 21 #include <signal.h> |
22 #include <sys/socket.h> | 22 #include <sys/socket.h> |
23 #include <sys/types.h> | 23 #include <sys/types.h> |
24 #include <sys/wait.h> | 24 #include <sys/wait.h> |
25 | 25 |
26 #include "base/base64.h" | 26 #include "base/base64.h" |
27 #include "base/basictypes.h" | 27 #include "base/basictypes.h" |
28 #include "base/bind.h" | 28 #include "base/bind.h" |
29 #include "base/logging.h" | 29 #include "base/logging.h" |
| 30 #include "base/string_split.h" |
30 #include "base/memory/ref_counted.h" | 31 #include "base/memory/ref_counted.h" |
31 #include "base/memory/scoped_ptr.h" | 32 #include "base/memory/scoped_ptr.h" |
32 #include "base/sha1.h" | 33 #include "base/sha1.h" |
33 #include "base/stl_util.h" | 34 #include "base/stl_util.h" |
34 #include "base/string_number_conversions.h" | 35 #include "base/string_number_conversions.h" |
35 #include "base/string_util.h" | 36 #include "base/string_util.h" |
36 #include "chrome/browser/internal_auth.h" | 37 #include "chrome/browser/internal_auth.h" |
37 #include "chrome/common/chrome_notification_types.h" | 38 #include "chrome/common/chrome_notification_types.h" |
38 #include "chrome/common/url_constants.h" | 39 #include "chrome/common/url_constants.h" |
39 #include "content/public/browser/browser_thread.h" | 40 #include "content/public/browser/browser_thread.h" |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 std::string FetchAsciiSnippet(uint8* begin, uint8* end, AsciiFilter filter) { | 141 std::string FetchAsciiSnippet(uint8* begin, uint8* end, AsciiFilter filter) { |
141 std::string rv; | 142 std::string rv; |
142 for (; begin < end; ++begin) { | 143 for (; begin < end; ++begin) { |
143 if (!isascii(*begin)) | 144 if (!isascii(*begin)) |
144 return rv; | 145 return rv; |
145 rv += filter(*begin); | 146 rv += filter(*begin); |
146 } | 147 } |
147 return rv; | 148 return rv; |
148 } | 149 } |
149 | 150 |
150 // Parses "passport:hostname:port:" string. Returns true on success. | 151 // Parses "passport:addr:hostname:port:" string. Returns true on success. |
151 bool FetchPassportNamePort( | 152 bool FetchPassportAddrNamePort( |
152 uint8* begin, uint8* end, | 153 uint8* begin, uint8* end, |
153 std::string* passport, std::string* name, int* port) { | 154 std::string* passport, std::string* addr, |
| 155 std::string* hostname, int* port) { |
| 156 |
154 std::string input(begin, end); | 157 std::string input(begin, end); |
155 if (input[input.size() - 1] != ':') | |
156 return false; | |
157 input.resize(input.size() - 1); | |
158 | 158 |
159 size_t pos = input.find_last_of(':'); | 159 std::vector<std::string> parts; |
160 if (pos == std::string::npos) | 160 base::SplitString(input, ':', &parts); |
161 return false; | 161 |
162 std::string port_str(input, pos + 1); | 162 if (parts.size() != 5 || !parts.back().empty()) { |
163 if (port_str.empty()) | 163 LOG(ERROR) << "Wrong format, input" << input; |
164 return false; | |
165 const char kAsciiDigits[] = "0123456789"; | |
166 COMPILE_ASSERT(sizeof(kAsciiDigits) == 10 + 1, mess_with_digits); | |
167 if (port_str.find_first_not_of(kAsciiDigits) != std::string::npos) | |
168 return false; | |
169 if (!base::StringToInt(port_str, port) || | |
170 *port < 0 || | |
171 *port >= (1 << 16)) { | |
172 return false; | 164 return false; |
173 } | 165 } |
174 input.resize(pos); | |
175 | 166 |
176 pos = input.find_first_of(':'); | 167 // Get passport |
177 if (pos == std::string::npos) | 168 *passport = parts[0]; |
| 169 // Get IP address. |
| 170 *addr = parts[1]; |
| 171 // Get hostname. |
| 172 *hostname = parts[2]; |
| 173 // Get port. |
| 174 if (!base::StringToInt(parts[3], port) || *port < 0 || *port >= (1<<16)) { |
| 175 LOG(ERROR) << "Not a port: " << port << ", input=" << input; |
178 return false; | 176 return false; |
179 passport->assign(input, 0, pos); | 177 } |
180 name->assign(input, pos + 1, std::string::npos); | 178 |
181 return !name->empty(); | 179 if (passport->empty() || hostname->empty()) { |
| 180 LOG(ERROR) << "Password or hostname is empty, input=" << input; |
| 181 return false; |
| 182 } |
| 183 return true; |
182 } | 184 } |
183 | 185 |
184 std::string FetchExtensionIdFromOrigin(const std::string &origin) { | 186 std::string FetchExtensionIdFromOrigin(const std::string &origin) { |
185 GURL url(origin); | 187 GURL url(origin); |
186 if (url.SchemeIs(chrome::kExtensionScheme)) | 188 if (url.SchemeIs(chrome::kExtensionScheme)) |
187 return url.host(); | 189 return url.host(); |
188 else | 190 else |
189 return std::string(); | 191 return std::string(); |
190 } | 192 } |
191 | 193 |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 std::map<std::string, std::string> header_fields_; | 445 std::map<std::string, std::string> header_fields_; |
444 | 446 |
445 // Parameters requested via query component of GET resource. | 447 // Parameters requested via query component of GET resource. |
446 std::map<std::string, std::string> requested_parameters_; | 448 std::map<std::string, std::string> requested_parameters_; |
447 | 449 |
448 // Hostname and port of destination socket. | 450 // Hostname and port of destination socket. |
449 // Websocket client supplies them in first data frame (destframe). | 451 // Websocket client supplies them in first data frame (destframe). |
450 std::string destname_; | 452 std::string destname_; |
451 int destport_; | 453 int destport_; |
452 | 454 |
| 455 // Preresolved |destname_| (empty if not pre-resolved). |
| 456 std::string destaddr_; |
| 457 |
453 // Whether TLS over TCP requested. | 458 // Whether TLS over TCP requested. |
454 bool do_tls_; | 459 bool do_tls_; |
455 | 460 |
456 // We try to DNS resolve hostname in both IPv4 and IPv6 domains. | 461 // We try to DNS resolve hostname in both IPv4 and IPv6 domains. |
457 // Track resolution failures here. | 462 // Track resolution failures here. |
458 bool destresolution_ipv4_failed_; | 463 bool destresolution_ipv4_failed_; |
459 bool destresolution_ipv6_failed_; | 464 bool destresolution_ipv6_failed_; |
460 | 465 |
461 // Used to schedule a timeout for initial phase of connection. | 466 // Used to schedule a timeout for initial phase of connection. |
462 scoped_ptr<struct event> destconnect_timeout_event_; | 467 scoped_ptr<struct event> destconnect_timeout_event_; |
(...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1295 return STATUS_ABORT; | 1300 return STATUS_ABORT; |
1296 | 1301 |
1297 if (!requested_parameters_.empty()) { | 1302 if (!requested_parameters_.empty()) { |
1298 destname_ = requested_parameters_["hostname"]; | 1303 destname_ = requested_parameters_["hostname"]; |
1299 int port; | 1304 int port; |
1300 if (!base::StringToInt(requested_parameters_["port"], &port) || | 1305 if (!base::StringToInt(requested_parameters_["port"], &port) || |
1301 port < 0 || port >= 1 << 16) { | 1306 port < 0 || port >= 1 << 16) { |
1302 return STATUS_ABORT; | 1307 return STATUS_ABORT; |
1303 } | 1308 } |
1304 destport_ = port; | 1309 destport_ = port; |
| 1310 destaddr_ = requested_parameters_["addr"]; |
1305 do_tls_ = (requested_parameters_["tls"] == "true"); | 1311 do_tls_ = (requested_parameters_["tls"] == "true"); |
1306 | 1312 |
1307 requested_parameters_["extension_id"] = | 1313 requested_parameters_["extension_id"] = |
1308 FetchExtensionIdFromOrigin(GetOrigin()); | 1314 FetchExtensionIdFromOrigin(GetOrigin()); |
1309 std::string passport(requested_parameters_["passport"]); | 1315 std::string passport(requested_parameters_["passport"]); |
1310 requested_parameters_.erase("passport"); | 1316 requested_parameters_.erase("passport"); |
1311 if (!browser::InternalAuthVerification::VerifyPassport( | 1317 if (!browser::InternalAuthVerification::VerifyPassport( |
1312 passport, "web_socket_proxy", requested_parameters_)) { | 1318 passport, "web_socket_proxy", requested_parameters_)) { |
1313 return STATUS_ABORT; | 1319 return STATUS_ABORT; |
1314 } | 1320 } |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 | 1388 |
1383 uint8* buf = EVBUFFER_DATA(evb); | 1389 uint8* buf = EVBUFFER_DATA(evb); |
1384 size_t buf_size = EVBUFFER_LENGTH(evb); | 1390 size_t buf_size = EVBUFFER_LENGTH(evb); |
1385 if (buf_size < frame_bytes_remaining_) | 1391 if (buf_size < frame_bytes_remaining_) |
1386 return STATUS_INCOMPLETE; | 1392 return STATUS_INCOMPLETE; |
1387 for (size_t i = 0; i < buf_size; ++i) { | 1393 for (size_t i = 0; i < buf_size; ++i) { |
1388 buf[i] ^= frame_mask_[frame_mask_index_]; | 1394 buf[i] ^= frame_mask_[frame_mask_index_]; |
1389 frame_mask_index_ = (frame_mask_index_ + 1) % 4; | 1395 frame_mask_index_ = (frame_mask_index_ + 1) % 4; |
1390 } | 1396 } |
1391 std::string passport; | 1397 std::string passport; |
1392 if (!FetchPassportNamePort(buf, buf + frame_bytes_remaining_, | 1398 if (!FetchPassportAddrNamePort(buf, buf + frame_bytes_remaining_, |
1393 &passport, &destname_, &destport_)) { | 1399 &passport, &destaddr_, &destname_, &destport_)) { |
1394 return STATUS_ABORT; | 1400 return STATUS_ABORT; |
1395 } | 1401 } |
1396 std::map<std::string, std::string> map; | 1402 std::map<std::string, std::string> map; |
1397 map["hostname"] = destname_; | 1403 map["hostname"] = destname_; |
1398 map["port"] = base::IntToString(destport_); | 1404 map["port"] = base::IntToString(destport_); |
1399 map["extension_id"] = FetchExtensionIdFromOrigin(GetOrigin()); | 1405 map["extension_id"] = FetchExtensionIdFromOrigin(GetOrigin()); |
| 1406 if (!destaddr_.empty()) |
| 1407 map["addr"] = destaddr_; |
1400 if (!browser::InternalAuthVerification::VerifyPassport( | 1408 if (!browser::InternalAuthVerification::VerifyPassport( |
1401 passport, "web_socket_proxy", map)) { | 1409 passport, "web_socket_proxy", map)) { |
1402 return STATUS_ABORT; | 1410 return STATUS_ABORT; |
1403 } | 1411 } |
1404 | 1412 |
1405 evbuffer_drain(evb, frame_bytes_remaining_); | 1413 evbuffer_drain(evb, frame_bytes_remaining_); |
1406 frame_bytes_remaining_ = 0; | 1414 frame_bytes_remaining_ = 0; |
1407 return STATUS_OK; | 1415 return STATUS_OK; |
1408 } | 1416 } |
1409 | 1417 |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1598 case PHASE_WAIT_DESTFRAME: { | 1606 case PHASE_WAIT_DESTFRAME: { |
1599 switch (cs->ConsumeDestframe(EVBUFFER_INPUT(bev))) { | 1607 switch (cs->ConsumeDestframe(EVBUFFER_INPUT(bev))) { |
1600 case STATUS_OK: { | 1608 case STATUS_OK: { |
1601 { | 1609 { |
1602 // Unfortunately libevent as of 1.4 does not look into /etc/hosts. | 1610 // Unfortunately libevent as of 1.4 does not look into /etc/hosts. |
1603 // There seems to be no easy API to perform only "local" part of | 1611 // There seems to be no easy API to perform only "local" part of |
1604 // getaddrinfo resolution. Hence this hack for "localhost". | 1612 // getaddrinfo resolution. Hence this hack for "localhost". |
1605 if (cs->destname_ == "localhost") | 1613 if (cs->destname_ == "localhost") |
1606 cs->destname_ = "127.0.0.1"; | 1614 cs->destname_ = "127.0.0.1"; |
1607 } | 1615 } |
| 1616 if (cs->destaddr_.empty()) |
| 1617 cs->destaddr_ = cs->destname_; |
1608 { | 1618 { |
1609 struct sockaddr_in sa; | 1619 struct sockaddr_in sa; |
1610 memset(&sa, 0, sizeof(sa)); | 1620 memset(&sa, 0, sizeof(sa)); |
1611 sa.sin_port = htons(cs->destport_); | 1621 sa.sin_port = htons(cs->destport_); |
1612 if (inet_pton(sa.sin_family = AF_INET, | 1622 if (inet_pton(sa.sin_family = AF_INET, |
1613 cs->destname_.c_str(), | 1623 cs->destaddr_.c_str(), |
1614 &sa.sin_addr) == 1) { | 1624 &sa.sin_addr) == 1) { |
1615 // valid IPv4 address supplied. | 1625 // valid IPv4 address supplied. |
1616 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa))) { | 1626 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa))) { |
1617 cs->phase_ = PHASE_WAIT_DESTCONNECT; | 1627 cs->phase_ = PHASE_WAIT_DESTCONNECT; |
1618 return; | 1628 return; |
1619 } | 1629 } |
1620 } | 1630 } |
1621 } | 1631 } |
1622 { | 1632 { |
1623 if (cs->destname_.size() >= 2 && | 1633 if (cs->destaddr_.size() >= 2 && |
1624 cs->destname_[0] == '[' && | 1634 cs->destaddr_[0] == '[' && |
1625 cs->destname_[cs->destname_.size() - 1] == ']') { | 1635 cs->destaddr_[cs->destaddr_.size() - 1] == ']') { |
1626 // Literal IPv6 address in brackets. | 1636 // Literal IPv6 address in brackets. |
1627 cs->destname_ = | 1637 cs->destaddr_ = |
1628 cs->destname_.substr(1, cs->destname_.size() - 2); | 1638 cs->destaddr_.substr(1, cs->destaddr_.size() - 2); |
1629 } | 1639 } |
1630 struct sockaddr_in6 sa; | 1640 struct sockaddr_in6 sa; |
1631 memset(&sa, 0, sizeof(sa)); | 1641 memset(&sa, 0, sizeof(sa)); |
1632 sa.sin6_port = htons(cs->destport_); | 1642 sa.sin6_port = htons(cs->destport_); |
1633 if (inet_pton(sa.sin6_family = AF_INET6, | 1643 if (inet_pton(sa.sin6_family = AF_INET6, |
1634 cs->destname_.c_str(), | 1644 cs->destaddr_.c_str(), |
1635 &sa.sin6_addr) == 1) { | 1645 &sa.sin6_addr) == 1) { |
1636 // valid IPv6 address supplied. | 1646 // valid IPv6 address supplied. |
1637 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa))) { | 1647 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa))) { |
1638 cs->phase_ = PHASE_WAIT_DESTCONNECT; | 1648 cs->phase_ = PHASE_WAIT_DESTCONNECT; |
1639 return; | 1649 return; |
1640 } | 1650 } |
1641 } | 1651 } |
1642 } | 1652 } |
1643 // Asynchronous DNS resolution. | 1653 // Asynchronous DNS resolution. |
1644 if (evdns_count_nameservers() < 1) { | 1654 if (evdns_count_nameservers() < 1) { |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1929 | 1939 |
1930 void WebSocketProxy::Shutdown() { | 1940 void WebSocketProxy::Shutdown() { |
1931 static_cast<Serv*>(impl_)->Shutdown(); | 1941 static_cast<Serv*>(impl_)->Shutdown(); |
1932 } | 1942 } |
1933 | 1943 |
1934 void WebSocketProxy::OnNetworkChange() { | 1944 void WebSocketProxy::OnNetworkChange() { |
1935 static_cast<Serv*>(impl_)->OnNetworkChange(); | 1945 static_cast<Serv*>(impl_)->OnNetworkChange(); |
1936 } | 1946 } |
1937 | 1947 |
1938 } // namespace chromeos | 1948 } // namespace chromeos |
OLD | NEW |