proxy_bypass_rules.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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
  3. // found in the LICENSE file.
  4. #include "net/proxy_resolution/proxy_bypass_rules.h"
  5. #include "base/strings/string_tokenizer.h"
  6. #include "base/strings/string_util.h"
  7. #include "build/build_config.h"
  8. #include "net/base/url_util.h"
  9. namespace net {
  10. namespace {
  11. // The <-loopback> rule corresponds with "remove the implicitly added bypass
  12. // rules".
  13. //
  14. // The name <-loopback> is not a very precise name (as the implicit rules cover
  15. // more than strictly loopback addresses), however this is the name that is
  16. // used on Windows so re-used here.
  17. //
  18. // For platform-differences between implicit rules see
  19. // ProxyResolverRules::MatchesImplicitRules().
  20. const char kSubtractImplicitBypasses[] = "<-loopback>";
  21. // The <local> rule bypasses any hostname that has no dots (and is not
  22. // an IP literal). The name is misleading as it has nothing to do with
  23. // localhost/loopback addresses, and would have better been called
  24. // something like "simple hostnames". However this is the name used on
  25. // Windows so is matched here.
  26. const char kBypassSimpleHostnames[] = "<local>";
  27. bool IsLinkLocalIP(const GURL& url) {
  28. // Quick fail if definitely not link-local, to avoid doing unnecessary work in
  29. // common case.
  30. if (!(base::StartsWith(url.host_piece(), "169.254.") ||
  31. base::StartsWith(url.host_piece(), "["))) {
  32. return false;
  33. }
  34. IPAddress ip_address;
  35. if (!ip_address.AssignFromIPLiteral(url.HostNoBracketsPiece()))
  36. return false;
  37. return ip_address.IsLinkLocal();
  38. }
  39. // Returns true if the URL's host is an IPv6 literal in the range
  40. // [::ffff:127.0.0.1]/104.
  41. //
  42. // Note that net::IsLocalhost() does not currently return true for such
  43. // addresses. However for proxy resolving such URLs should bypass the use
  44. // of a PAC script, since the destination is local.
  45. bool IsIPv4MappedLoopback(const GURL& url) {
  46. if (!base::StartsWith(url.host_piece(), "[::ffff"))
  47. return false;
  48. IPAddress ip_address;
  49. if (!ip_address.AssignFromIPLiteral(url.HostNoBracketsPiece()))
  50. return false;
  51. if (!ip_address.IsIPv4MappedIPv6())
  52. return false;
  53. return ip_address.bytes()[12] == 127;
  54. }
  55. class BypassSimpleHostnamesRule : public SchemeHostPortMatcherRule {
  56. public:
  57. BypassSimpleHostnamesRule() = default;
  58. BypassSimpleHostnamesRule(const BypassSimpleHostnamesRule&) = delete;
  59. BypassSimpleHostnamesRule& operator=(const BypassSimpleHostnamesRule&) =
  60. delete;
  61. SchemeHostPortMatcherResult Evaluate(const GURL& url) const override {
  62. return ((url.host_piece().find('.') == std::string::npos) &&
  63. !url.HostIsIPAddress())
  64. ? SchemeHostPortMatcherResult::kInclude
  65. : SchemeHostPortMatcherResult::kNoMatch;
  66. }
  67. std::string ToString() const override { return kBypassSimpleHostnames; }
  68. };
  69. class SubtractImplicitBypassesRule : public SchemeHostPortMatcherRule {
  70. public:
  71. SubtractImplicitBypassesRule() = default;
  72. SubtractImplicitBypassesRule(const SubtractImplicitBypassesRule&) = delete;
  73. SubtractImplicitBypassesRule& operator=(const SubtractImplicitBypassesRule&) =
  74. delete;
  75. SchemeHostPortMatcherResult Evaluate(const GURL& url) const override {
  76. return ProxyBypassRules::MatchesImplicitRules(url)
  77. ? SchemeHostPortMatcherResult::kExclude
  78. : SchemeHostPortMatcherResult::kNoMatch;
  79. }
  80. std::string ToString() const override { return kSubtractImplicitBypasses; }
  81. };
  82. std::unique_ptr<SchemeHostPortMatcherRule> ParseRule(
  83. base::StringPiece raw_untrimmed) {
  84. base::StringPiece raw =
  85. base::TrimWhitespaceASCII(raw_untrimmed, base::TRIM_ALL);
  86. // <local> and <-loopback> are special syntax used by WinInet's bypass list
  87. // -- we allow it on all platforms and interpret it the same way.
  88. if (base::EqualsCaseInsensitiveASCII(raw, kBypassSimpleHostnames))
  89. return std::make_unique<BypassSimpleHostnamesRule>();
  90. if (base::EqualsCaseInsensitiveASCII(raw, kSubtractImplicitBypasses))
  91. return std::make_unique<SubtractImplicitBypassesRule>();
  92. return SchemeHostPortMatcherRule::FromUntrimmedRawString(raw_untrimmed);
  93. }
  94. } // namespace
  95. constexpr char net::ProxyBypassRules::kBypassListDelimeter[];
  96. ProxyBypassRules::ProxyBypassRules() = default;
  97. ProxyBypassRules::ProxyBypassRules(const ProxyBypassRules& rhs) {
  98. *this = rhs;
  99. }
  100. ProxyBypassRules::ProxyBypassRules(ProxyBypassRules&& rhs) {
  101. *this = std::move(rhs);
  102. }
  103. ProxyBypassRules::~ProxyBypassRules() = default;
  104. ProxyBypassRules& ProxyBypassRules::operator=(const ProxyBypassRules& rhs) {
  105. ParseFromString(rhs.ToString());
  106. return *this;
  107. }
  108. ProxyBypassRules& ProxyBypassRules::operator=(ProxyBypassRules&& rhs) {
  109. matcher_ = std::move(rhs.matcher_);
  110. return *this;
  111. }
  112. void ProxyBypassRules::ReplaceRule(
  113. size_t index,
  114. std::unique_ptr<SchemeHostPortMatcherRule> rule) {
  115. matcher_.ReplaceRule(index, std::move(rule));
  116. }
  117. bool ProxyBypassRules::Matches(const GURL& url, bool reverse) const {
  118. switch (matcher_.Evaluate(url)) {
  119. case SchemeHostPortMatcherResult::kInclude:
  120. return !reverse;
  121. case SchemeHostPortMatcherResult::kExclude:
  122. return reverse;
  123. case SchemeHostPortMatcherResult::kNoMatch:
  124. break;
  125. }
  126. // If none of the explicit rules matched, fall back to the implicit rules.
  127. bool matches_implicit = MatchesImplicitRules(url);
  128. if (matches_implicit)
  129. return matches_implicit;
  130. return reverse;
  131. }
  132. bool ProxyBypassRules::operator==(const ProxyBypassRules& other) const {
  133. if (rules().size() != other.rules().size())
  134. return false;
  135. for (size_t i = 0; i < rules().size(); ++i) {
  136. if (rules()[i]->ToString() != other.rules()[i]->ToString())
  137. return false;
  138. }
  139. return true;
  140. }
  141. void ProxyBypassRules::ParseFromString(const std::string& raw) {
  142. Clear();
  143. base::StringTokenizer entries(
  144. raw, SchemeHostPortMatcher::kParseRuleListDelimiterList);
  145. while (entries.GetNext()) {
  146. AddRuleFromString(entries.token_piece());
  147. }
  148. }
  149. void ProxyBypassRules::PrependRuleToBypassSimpleHostnames() {
  150. matcher_.AddAsFirstRule(std::make_unique<BypassSimpleHostnamesRule>());
  151. }
  152. bool ProxyBypassRules::AddRuleFromString(base::StringPiece raw_untrimmed) {
  153. auto rule = ParseRule(raw_untrimmed);
  154. if (rule) {
  155. matcher_.AddAsLastRule(std::move(rule));
  156. return true;
  157. }
  158. return false;
  159. }
  160. void ProxyBypassRules::AddRulesToSubtractImplicit() {
  161. matcher_.AddAsLastRule(std::make_unique<SubtractImplicitBypassesRule>());
  162. }
  163. std::string ProxyBypassRules::GetRulesToSubtractImplicit() {
  164. ProxyBypassRules rules;
  165. rules.AddRulesToSubtractImplicit();
  166. return rules.ToString();
  167. }
  168. std::string ProxyBypassRules::ToString() const {
  169. return matcher_.ToString();
  170. }
  171. void ProxyBypassRules::Clear() {
  172. matcher_.Clear();
  173. }
  174. bool ProxyBypassRules::MatchesImplicitRules(const GURL& url) {
  175. // On Windows the implict rules are:
  176. //
  177. // localhost
  178. // loopback
  179. // 127.0.0.1
  180. // [::1]
  181. // 169.254/16
  182. // [FE80::]/10
  183. //
  184. // And on macOS they are:
  185. //
  186. // localhost
  187. // 127.0.0.1/8
  188. // [::1]
  189. // 169.254/16
  190. //
  191. // Our implicit rules are approximately:
  192. //
  193. // localhost
  194. // localhost.
  195. // *.localhost
  196. // loopback [Windows only]
  197. // loopback. [Windows only]
  198. // [::1]
  199. // 127.0.0.1/8
  200. // 169.254/16
  201. // [FE80::]/10
  202. return IsLocalhost(url) || IsIPv4MappedLoopback(url) ||
  203. IsLinkLocalIP(url)
  204. #if BUILDFLAG(IS_WIN)
  205. // See http://crbug.com/904889
  206. || (url.host_piece() == "loopback") ||
  207. (url.host_piece() == "loopback.")
  208. #endif
  209. ;
  210. }
  211. } // namespace net