proxy_auto_config_library.cc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // Copyright 2018 The Chromium 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. #include "services/network/proxy_auto_config_library.h"
  5. #include <set>
  6. #include "base/memory/raw_ptr.h"
  7. #include "net/base/address_list.h"
  8. #include "net/base/ip_address.h"
  9. #include "net/base/network_interfaces.h"
  10. #include "net/dns/host_resolver_proc.h"
  11. #include "net/socket/client_socket_factory.h"
  12. #include "net/socket/udp_client_socket.h"
  13. namespace network {
  14. namespace {
  15. enum class Mode {
  16. kMyIpAddress,
  17. kMyIpAddressEx,
  18. };
  19. // Helper used to accumulate and select the best candidate IP addresses.
  20. //
  21. // myIpAddress() is a broken API available to PAC scripts.
  22. // It has the problematic definition of:
  23. // "Returns the IP address of the host machine."
  24. //
  25. // This has ambiguity on what should happen for multi-homed hosts which may have
  26. // multiple IP addresses to choose from. To be unambiguous we would need to
  27. // know which hosts is going to be connected to, in order to use the outgoing
  28. // IP for that request.
  29. //
  30. // However at this point that is not known, as the proxy still hasn't been
  31. // decided.
  32. //
  33. // The strategy used here is to prioritize the IP address that would be used
  34. // for connecting to the public internet by testing which interface is used for
  35. // connecting to 8.8.8.8 and 2001:4860:4860::8888 (public IPs).
  36. //
  37. // If that fails, we will try resolving the machine's hostname, and also probing
  38. // for routes in the private IP space.
  39. //
  40. // Link-local IP addresses are not generally returned, however may be if no
  41. // other IP was found by the probes.
  42. class MyIpAddressImpl {
  43. public:
  44. MyIpAddressImpl() = default;
  45. MyIpAddressImpl(const MyIpAddressImpl&) = delete;
  46. MyIpAddressImpl& operator=(const MyIpAddressImpl&) = delete;
  47. // Used for mocking the socket dependency.
  48. void SetSocketFactoryForTest(net::ClientSocketFactory* socket_factory) {
  49. override_socket_factory_ = socket_factory;
  50. }
  51. // Used for mocking the DNS dependency.
  52. void SetDNSResultForTest(const net::AddressList& addrs) {
  53. override_dns_result_ = std::make_unique<net::AddressList>(addrs);
  54. }
  55. net::IPAddressList Run(Mode mode) {
  56. DCHECK(candidate_ips_.empty());
  57. DCHECK(link_local_ips_.empty());
  58. DCHECK(!done_);
  59. mode_ = mode;
  60. // Try several different methods to obtain IP addresses.
  61. TestPublicInternetRoutes();
  62. TestResolvingHostname();
  63. TestPrivateIPRoutes();
  64. return mode_ == Mode::kMyIpAddress ? GetResultForMyIpAddress()
  65. : GetResultForMyIpAddressEx();
  66. }
  67. private:
  68. // Adds |address| to the result.
  69. void Add(const net::IPAddress& address) {
  70. if (done_)
  71. return;
  72. // Don't consider loopback addresses (ex: 127.0.0.1). These can notably be
  73. // returned when probing addresses associated with the hostname.
  74. if (address.IsLoopback())
  75. return;
  76. if (!seen_ips_.insert(address).second)
  77. return; // Duplicate IP address.
  78. // Link-local addresses are only used as a last-resort if there are no
  79. // better addresses.
  80. if (address.IsLinkLocal()) {
  81. link_local_ips_.push_back(address);
  82. return;
  83. }
  84. // For legacy reasons IPv4 addresses are favored over IPv6 for myIpAddress()
  85. // - https://crbug.com/905126 - so this only stops the search when a IPv4
  86. // address is found.
  87. if ((mode_ == Mode::kMyIpAddress) && address.IsIPv4())
  88. done_ = true;
  89. candidate_ips_.push_back(address);
  90. }
  91. net::IPAddressList GetResultForMyIpAddress() const {
  92. DCHECK_EQ(Mode::kMyIpAddress, mode_);
  93. if (!candidate_ips_.empty())
  94. return GetSingleResultFavoringIPv4(candidate_ips_);
  95. if (!link_local_ips_.empty())
  96. return GetSingleResultFavoringIPv4(link_local_ips_);
  97. return {};
  98. }
  99. net::IPAddressList GetResultForMyIpAddressEx() const {
  100. DCHECK_EQ(Mode::kMyIpAddressEx, mode_);
  101. if (!candidate_ips_.empty())
  102. return candidate_ips_;
  103. if (!link_local_ips_.empty()) {
  104. // Note that only a single link-local address is returned here, even
  105. // though multiple could be returned for this API. See
  106. // http://crbug.com/905366 before expanding this.
  107. return GetSingleResultFavoringIPv4(link_local_ips_);
  108. }
  109. return {};
  110. }
  111. // Tests what source IP address would be used for sending a UDP packet to the
  112. // given destination IP. This does not hit the network and should be fast.
  113. void TestRoute(const net::IPAddress& destination_ip) {
  114. if (done_)
  115. return;
  116. net::ClientSocketFactory* socket_factory =
  117. override_socket_factory_
  118. ? override_socket_factory_.get()
  119. : net::ClientSocketFactory::GetDefaultFactory();
  120. auto socket = socket_factory->CreateDatagramClientSocket(
  121. net::DatagramSocket::DEFAULT_BIND, nullptr, net::NetLogSource());
  122. net::IPEndPoint destination(destination_ip, /*port=*/80);
  123. if (socket->Connect(destination) != net::OK)
  124. return;
  125. net::IPEndPoint source;
  126. if (socket->GetLocalAddress(&source) != net::OK)
  127. return;
  128. Add(source.address());
  129. }
  130. void TestPublicInternetRoutes() {
  131. if (done_)
  132. return;
  133. // 8.8.8.8 and 2001:4860:4860::8888 are Google DNS.
  134. TestRoute(net::IPAddress(8, 8, 8, 8));
  135. TestRoute(net::IPAddress(0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0, 0, 0, 0, 0,
  136. 0, 0, 0, 0x88, 0x88));
  137. MarkAsDoneIfHaveCandidates();
  138. }
  139. // Marks the current search as done if candidate IPs have been found.
  140. //
  141. // This is used to stop exploring for IPs if any of the high-level tests find
  142. // a match (i.e. either the public internet route test, or hostname test, or
  143. // private route test found something).
  144. //
  145. // In the case of myIpAddressEx() this means it will be conservative in which
  146. // IPs it returns and not enumerate the full set. See http://crbug.com/905366
  147. // before expanding that policy.
  148. void MarkAsDoneIfHaveCandidates() {
  149. if (!candidate_ips_.empty())
  150. done_ = true;
  151. }
  152. void TestPrivateIPRoutes() {
  153. if (done_)
  154. return;
  155. // Representative IP from each range in RFC 1918.
  156. TestRoute(net::IPAddress(10, 0, 0, 0));
  157. TestRoute(net::IPAddress(172, 16, 0, 0));
  158. TestRoute(net::IPAddress(192, 168, 0, 0));
  159. // Representative IP for Unique Local Address (FC00::/7).
  160. TestRoute(
  161. net::IPAddress(0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
  162. MarkAsDoneIfHaveCandidates();
  163. }
  164. void TestResolvingHostname() {
  165. if (done_)
  166. return;
  167. net::AddressList addrlist;
  168. int resolver_error;
  169. if (override_dns_result_) {
  170. addrlist = *override_dns_result_;
  171. resolver_error = addrlist.empty() ? net::ERR_NAME_NOT_RESOLVED : net::OK;
  172. } else {
  173. resolver_error = SystemHostResolverCall(
  174. net::GetHostName(), net::AddressFamily::ADDRESS_FAMILY_UNSPECIFIED, 0,
  175. &addrlist,
  176. /*os_error=*/nullptr);
  177. }
  178. if (resolver_error != net::OK)
  179. return;
  180. for (const auto& e : addrlist.endpoints())
  181. Add(e.address());
  182. MarkAsDoneIfHaveCandidates();
  183. }
  184. static net::IPAddressList GetSingleResultFavoringIPv4(
  185. const net::IPAddressList& ips) {
  186. for (const auto& ip : ips) {
  187. if (ip.IsIPv4())
  188. return {ip};
  189. }
  190. if (!ips.empty())
  191. return {ips.front()};
  192. return {};
  193. }
  194. std::set<net::IPAddress> seen_ips_;
  195. // The preferred ordered candidate IPs so far.
  196. net::IPAddressList candidate_ips_;
  197. // The link-local IP addresses seen so far (not part of |candidate_ips_|).
  198. net::IPAddressList link_local_ips_;
  199. // The operation being carried out.
  200. Mode mode_;
  201. // Whether the search for results has completed.
  202. //
  203. // Once "done", calling Add() will not change the final result. This is used
  204. // to short-circuit early.
  205. bool done_ = false;
  206. raw_ptr<net::ClientSocketFactory> override_socket_factory_ = nullptr;
  207. std::unique_ptr<net::AddressList> override_dns_result_;
  208. };
  209. } // namespace
  210. net::IPAddressList PacMyIpAddress() {
  211. MyIpAddressImpl impl;
  212. return impl.Run(Mode::kMyIpAddress);
  213. }
  214. net::IPAddressList PacMyIpAddressEx() {
  215. MyIpAddressImpl impl;
  216. return impl.Run(Mode::kMyIpAddressEx);
  217. }
  218. net::IPAddressList PacMyIpAddressForTest(
  219. net::ClientSocketFactory* socket_factory,
  220. const net::AddressList& dns_result) {
  221. MyIpAddressImpl impl;
  222. impl.SetSocketFactoryForTest(socket_factory);
  223. impl.SetDNSResultForTest(dns_result);
  224. return impl.Run(Mode::kMyIpAddress);
  225. }
  226. net::IPAddressList PacMyIpAddressExForTest(
  227. net::ClientSocketFactory* socket_factory,
  228. const net::AddressList& dns_result) {
  229. MyIpAddressImpl impl;
  230. impl.SetSocketFactoryForTest(socket_factory);
  231. impl.SetDNSResultForTest(dns_result);
  232. return impl.Run(Mode::kMyIpAddressEx);
  233. }
  234. } // namespace network