1# Proxy support in Chrome 2 3This document establishes basic proxy terminology and describes Chrome-specific 4proxy behaviors. 5 6[TOC] 7 8## Proxy server identifiers 9 10A proxy server is an intermediary used for network requests. A proxy server can 11be described by its address, along with the proxy scheme that should be used to 12communicate with it. 13 14This can be written as a string using either the "PAC format" or the "URI 15format". 16 17The PAC format is how one names a proxy server in [Proxy 18auto-config](https://en.wikipedia.org/wiki/Proxy_auto-config) scripts. For 19example: 20* `PROXY foo:2138` 21* `SOCKS5 foo:1080` 22* `DIRECT` 23 24The "URI format" instead encodes the information as a URL. For example: 25* `foo:2138` 26* `http://foo:2138` 27* `socks5://foo:1080` 28* `direct://` 29 30The port number is optional in both formats. When omitted, a per-scheme default 31is used. 32 33See the [Proxy server schemes](#Proxy-server-schemes) section for details on 34what schemes Chrome supports, and how to write them in the PAC and URI formats. 35 36Most UI surfaces in Chrome (including command lines and policy) expect URI 37formatted proxy server identifiers. However outside of Chrome, proxy servers 38are generally identified less precisely by just an address -- the proxy 39scheme is assumed based on context. 40 41In Windows' proxy settings there are host and port fields for the 42"HTTP", "Secure", "FTP", and "SOCKS" proxy. With the exception of "SOCKS", 43those are all identifiers for insecure HTTP proxy servers (proxy scheme is 44assumed as HTTP). 45 46## Proxy resolution 47 48Proxying in Chrome is done at the URL level. 49 50When the browser is asked to fetch a URL, it needs to decide which IP endpoint 51to send the request to. This can be either a proxy server, or the target host. 52 53This is called proxy resolution. The input to proxy resolution is a URL, and 54the output is an ordered list of [proxy server 55identifiers](#Proxy-server-identifiers). 56 57What proxies to use can be described using either: 58 59* [Manual proxy settings](#Manual-proxy-settings) - proxy resolution is defined 60 using a declarative set of rules. These rules are expressed as a mapping from 61 URL scheme to proxy server identifier(s), and a list of proxy bypass rules for 62 when to go DIRECT instead of using the mapped proxy. 63 64* PAC script - proxy resolution is defined using a JavaScript program, that is 65 invoked whenever fetching a URL to get the list of proxy server identifiers 66 to use. 67 68* Auto-detect - the WPAD protocol is used to probe the network (using DHCP/DNS) 69 and possibly discover the URL of a PAC script. 70 71## Proxy server schemes 72 73When using an explicit proxy in the browser, multiple layers of the network 74request are impacted, depending on the scheme that is used. Some implications 75of the proxy scheme are: 76 77* Is communication to the proxy done over a secure channel? 78* Is name resolution (ex: DNS) done client side, or proxy side? 79* What authentication schemes to the proxy server are supported? 80* What network traffic can be sent through the proxy? 81 82Chrome supports these proxy server schemes: 83 84* [DIRECT](#DIRECT-proxy-scheme) 85* [HTTP](#HTTP-proxy-scheme) 86* [HTTPS](#HTTPS-proxy-scheme) 87* [SOCKSv4](#SOCKSv4-proxy-scheme) 88* [SOCKSv5](#SOCKSv5-proxy-scheme) 89 90### DIRECT proxy scheme 91 92* Default port: N/A (neither host nor port are applicable) 93* Example identifier (PAC): `DIRECT` 94* Example identifier (URI): `direct://` 95 96This is a pseudo proxy scheme that indicates instead of using a proxy we are 97sending the request directly to the target server. 98 99It is imprecise to call this a "proxy server", but it is a convenient abstraction. 100 101### HTTP proxy scheme 102 103* Default port: 80 104* Example identifier (PAC): `PROXY proxy:8080`, `proxy` (non-standard; don't use) 105* Example identifiers (URI): `http://proxy:8080`, `proxy:8080` (can omit scheme) 106 107Generally when one refers to a "proxy server" or "web proxy", they are talking 108about an HTTP proxy. 109 110When using an HTTP proxy in Chrome, name resolution is always deferred to the 111proxy. HTTP proxies can proxy `http://`, `https://`, `ws://` and `wss://` URLs. 112 113Communication to HTTP proxy servers is insecure, meaning proxied `http://` 114requests are sent in the clear. When proxying `https://` requests through an 115HTTP proxy, the TLS exchange is forwarded through the proxy using the `CONNECT` 116method, so end-to-end encryption is not broken. However when establishing the 117tunnel, the hostname of the target URL is sent to the proxy server in the 118clear. 119 120HTTP proxies in Chrome support the same HTTP authentiation schemes as for 121target servers: Basic, Digest, Negotiate, NTLM. 122 123### HTTPS proxy scheme 124 125* Default port: 443 126* Example identifier (PAC): `HTTPS proxy:8080` 127* Example identifier (URI): `https://proxy:8080` 128 129This works like an [HTTP proxy](#HTTP-proxy-scheme), except the 130communication to the proxy server is protected by TLS, and may negotiate 131HTTP/2 (but not QUIC). 132 133Because the connection to the proxy server is secure, https:// requests 134sent through the proxy are not sent in the clear as with an HTTP proxy. 135Similarly, since CONNECT requests are sent over a protected channel, the 136hostnames for proxied https:// URLs is also not revealed. 137 138In addition to the usual HTTP authentication methods, HTTPS proxies also 139support client certificates. 140 141HTTPS proxies using HTTP/2 can offer better performance in Chrome than a 142regular HTTP proxy due to higher connection limits (HTTP/1.1 proxies in Chrome 143are limited to 32 simultaneous connections across all domains). 144 145Chrome, Firefox, and Opera support HTTPS proxies; however, most older HTTP 146stacks do not. 147 148Specifying an HTTPS proxy is generally not possible through system proxy 149settings. Instead, one must use either a PAC script or a Chrome proxy setting 150(command line, extension, or policy). 151 152See the dev.chromium.org document on [secure web 153proxies](http://dev.chromium.org/developers/design-documents/secure-web-proxy) 154for tips on how to run and test against an HTTPS proxy. 155 156### SOCKSv4 proxy scheme 157 158* Default port: 1080 159* Example identifiers (PAC): `SOCKS4 proxy:8080`, `SOCKS proxy:8080` 160* Example identifier (URI): `socks4://proxy:8080` 161 162SOCKSv4 is a simple transport layer proxy that wraps a TCP socket. Its use 163is transparent to the rest of the protocol stack; after an initial 164handshake when connecting the TCP socket (to the proxy), the rest of the 165loading stack is unchanged. 166 167No proxy authentication methods are supported for SOCKSv4. 168 169When using a SOCKSv4 proxy, name resolution for target hosts is always done 170client side, and moreover must resolve to an IPv4 address (SOCKSv4 encodes 171target address as 4 octets, so IPv6 targets are not possible). 172 173There are extensions to SOCKSv4 that allow for proxy side name resolution, and 174IPv6, namely SOCKSv4a. However Chrome does not allow configuring, or falling 175back to v4a. 176 177A better alternative is to just use the newer version of the protocol, SOCKSv5 178(which is still 20+ years old). 179 180### SOCKSv5 proxy scheme 181 182* Default port: 1080 183* Example identifier (PAC): `SOCKS5 proxy:8080` 184* Example identifiers (URI): `socks://proxy:8080`, `socks5://proxy:8080` 185 186[SOCKSv5](https://tools.ietf.org/html/rfc1928) is a transport layer proxy that 187wraps a TCP socket, and allows for name resolution to be deferred to the proxy. 188 189In Chrome when a proxy's scheme is set to SOCKSv5, name resolution is always 190done proxy side (even though the protocol allows for client side as well). In 191Firefox client side vs proxy side name resolution can be configured with 192`network.proxy.socks_remote_dns`; Chrome has no equivalent option and will 193always use proxy side resolution. 194 195No authentication methods are supported for SOCKSv5 in Chrome (although some do 196exist for the protocol). 197 198A handy way to create a SOCKSv5 proxy is with `ssh -D`, which can be used to 199tunnel web traffic to a remote host over SSH. 200 201In Chrome SOCKSv5 is only used to proxy TCP-based URL requests. It cannot be 202used to relay UDP traffic. 203 204## Manual proxy settings 205 206The simplest way to configure proxy resolution is by providing a static list of 207rules comprised of: 208 2091. A mapping of URL schemes to [proxy server identifiers](#Proxy-server-identifiers). 2102. A list of [proxy bypass rules](#Proxy-bypass-rules) 211 212We refer to this mode of configuration as "manual proxy settings". 213 214Manual proxy settings can succinctly describe setups like: 215 216* Use proxy `http://foo:8080` for all requests 217* Use proxy `http://foo:8080` for all requests except those to a `google.com` 218 subdomain. 219* Use proxy `http://foo:8080` for all `https://` requests, and proxy 220 `socsk5://mysocks:90` for everything else 221 222Although manual proxy settings are a ubiquituous way to configure proxies 223across platforms, there is no standard representation or feature set. 224 225Chrome's manual proxy settings most closely resembles that of WinInet. But it 226also supports idioms from other platforms -- for instance KDE's notion of 227reversing the bypass list, or Gnome's interpretation of bypass patterns as 228suffix matches. 229 230When defining manual proxy settings in Chrome, we specify three (possibly 231empty) lists of [proxy server identifiers](#Proxy-server-identifiers). 232 233 * proxies for HTTP - A list of proxy server identifiers to use for `http://` 234 requests, if non-empty. 235 * proxies for HTTPS - A list of proxy server identifiers to use for 236 `https://` requests, if non-empty. 237 * other proxies - A list of proxy server identifiers to use for everything 238 else (whatever isn't matched by the other two lists) 239 240There are a lot of ways to end up with manual proxy settings in Chrome 241(discussed in other sections). 242 243The following examples will use the command line method. Launching Chrome with 244`--proxy-server=XXX` (and optionally `--proxy-bypass-list=YYY`) 245 246Example: To use proxy `http://foo:8080` for all requests we can launch 247Chrome with `--proxy-server="http://foo:8080"`. This translates to: 248 249 * proxies for HTTP - *empty* 250 * proxies for HTTPS - *empty* 251 * other proxies - `http://foo:8080` 252 253With the above configuration, if the proxy server was unreachable all requests 254would fail with `ERR_PROXY_CONNECTION_FAILED`. To address this we could add a 255fallback to `DIRECT` by launching using 256`--proxy-server="http://foo:8080,direct://"` (note the comma separated list). 257This command line means: 258 259 * proxies for HTTP - *empty* 260 * proxies for HTTPS - *empty* 261 * other proxies - `http://foo:8080`, `direct://` 262 263If instead we wanted to proxy only `http://` URLs through the 264HTTPS proxy `https://foo:443`, and have everything else use the SOCKSv5 proxy 265`socks5://mysocks:1080` we could launch Chrome with 266`--proxy-server="http=https://foo:443;socks=socks5://mysocks:1080"`. This now 267expands to: 268 269 * proxies for HTTP - `https://foo:443` 270 * proxies for HTTPS - *empty* 271 * other proxies - `socks5://mysocks:1080` 272 273The command line above uses WinInet's proxy map format, with some additional 274features: 275 276* Instead of naming proxy servers by just a hostname:port, you can use Chrome's 277 URI format for proxy server identifiers. In other words, you can prefix the 278 proxy scheme so it doesn't default to HTTP. 279* The `socks=` mapping is understood more broadly as "other proxies". The 280 subsequent proxy list can include proxies of any scheme, however if the 281 scheme is omitted it will be understood as SOCKSv4 rather than HTTP. 282 283### Mapping WebSockets URLs to a proxy 284 285[Manual proxy settings](#Manual-proxy-settings) don't have mappings for `ws://` 286or `wss://` URLs. 287 288Selecting a proxy for these URL schemes is a bit different from other URL 289schemes. The algorithm that Chrome uses is: 290 291* If "other proxies" is non-empty use it 292* If "proxies for HTTPS" is non-empty use it 293* Otherwise use "proxies for HTTP" 294 295This is per the recommendation in section 4.1.3 of [RFC 2966455](https://tools.ietf.org/html/rfc6455). 297 298It is possible to route `ws://` and `wss://` separately using a PAC script. 299 300### Proxy credentials in manual proxy settings 301 302Most platforms' [manual proxy settings](#Manual-proxy-settings) allow 303specifying a cleartext username/password for proxy sign in. Chrome does not 304implement this, and will not use any credentials embedded in the proxy 305settings. 306 307Proxy authentication will instead go through the ordinary flow to find 308credentials. 309 310## Proxy bypass rules 311 312In addition to specifying three lists of [proxy server 313identifiers](#proxy-server-identifiers), Chrome's [manual proxy 314settings](#Manual-proxy-settings) lets you specify a list of "proxy bypass 315rules". 316 317This ruleset determines whether a given URL should skip use of a proxy all 318together, even when a proxy is otherwise defined for it. 319 320This concept is also known by names like "exception list", "exclusion list" or 321"no proxy list". 322 323Proxy bypass rules can be written as an ordered list of strings. Ordering 324generally doesn't matter, but may when using subtractive rules. 325 326When manual proxy settings are specified from the command line, the 327`--proxy-bypass-list="RULES"` switch can be used, where `RULES` is a semicolon 328or comma separated list of bypass rules. 329 330Following are the string constructions for the bypass rules that Chrome 331supports. They can be used when defining a Chrome manual proxy settings from 332command line flags, extensions, or policy. 333 334When using system proxy settings, one should use the platform's rule format and 335not Chrome's. 336 337### Bypass rule: Hostname 338 339``` 340[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ] 341``` 342 343Matches a hostname using a wildcard pattern, and an optional scheme and port 344restriction. 345 346Examples: 347 348* `foobar.com` - Matches URL of any scheme and port, whose normalized host is 349 `foobar.com` 350* `*foobar.com` - Matches URL of any scheme and port, whose normalized host 351 ends with `foobar.com` (for instance `blahfoobar.com` and `foo.foobar.com`). 352* `*.org:443` - Matches URLs of any scheme, using port 443 and whose top level 353 domain is `.org` 354* `https://x.*.y.com:99` - Matches https:// URLs on port 99 whose normalized 355 hostname matches `x.*.y.com` 356 357### Bypass rule: Subdomain 358 359``` 360[ URL_SCHEME "://" ] "." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ] 361``` 362 363Hostname patterns that start with a dot are special cased to mean a subdomain 364matches. `.foo.com` is effectively another way of writing `*.foo.com`. 365 366Examples: 367 368* `.google.com` - Matches `calendar.google.com` and `foo.bar.google.com`, but 369 not `google.com`. 370* `http://.google.com` - Matches only http:// URLs that are a subdomain of `google.com`. 371 372### Bypass rule: IP literal 373 374``` 375[ SCHEME "://" ] IP_LITERAL [ ":" PORT ] 376``` 377 378Matches URLs that are IP address literals, and optional scheme and port 379restrictions. This is a special case of hostname matching that takes into 380account IP literal canonicalization. For example the rules `[0:0:0::1]` and 381`[::1]` are equivalent (both represent the same IPv6 address). 382 383Examples: 384 385* `127.0.0.1` 386* `http://127.0.0.1` 387* `[::1]` - Matches any URL to the IPv6 loopback address. 388* `[0:0::1]` - Same as above 389* `http://[::1]:99` - Matches any http:// URL to the IPv6 loopback on port 99 390 391### Bypass rule: IPv4 address range 392 393``` 394IPV4_LITERAL "/" PREFIX_LENGTH_IN_BITS 395``` 396 397Matches any URL whose hostname is an IPv4 literal, and falls between the given 398address range. 399 400Note this [only applies to URLs that are IP 401literals](#Meaning-of-IP-address-range-bypass-rules). 402 403Examples: 404 405* `192.168.1.1/16` 406 407### Bypass rule: IPv6 address range 408 409``` 410IPV6_LITERAL "/" PREFIX_LENGTH_IN_BITS 411``` 412 413Matches any URL that is an IPv6 literal that falls between the given range. 414Note that IPv6 literals must *not* be bracketed. 415 416Note this [only applies to URLs that are IP 417literals](#Meaning-of-IP-address-range-bypass-rules). 418 419Examples: 420 421* `fefe:13::abc/33` 422* `[fefe::]/40` -- WRONG! IPv6 literals must not be bracketed. 423 424### Bypass rule: Simple hostnames 425 426``` 427<local> 428``` 429 430Matches hostnames without a period in them, and that are not IP literals. This 431is a naive string search -- meaning that periods appearing *anywhere* count 432(including trailing dots!). 433 434This rule corresponds to the "Exclude simple hostnames" checkbox on macOS and 435the "Don't use proxy server for local (intranet) addresses" on Windows. 436 437The rule name comes from WinInet, and can easily be confused with the concept 438of localhost. However the two concepts are completely orthogonal. In practice 439one wouldn't add rules to bypass localhost, as it is [already done 440implicitly](#Implicit-bypass-rules). 441 442### Bypass rule: Subtract implicit rules 443 444``` 445<-loopback> 446``` 447 448*Subtracts* the [implicit proxy bypass rules](#Implicit-bypass-rules) 449(localhost and link local addresses). This is generally only needed for test 450setups. Beware of the security implications to proxying localhost. 451 452Whereas regular bypass rules instruct the browser about URLs that should *not* 453use the proxy, this rule has the opposite effect and tells the browser to 454instead *use* the proxy. 455 456Ordering may matter when using a subtractive rule, as rules will be evaluated 457in a left-to-right order. `<-loopback>;127.0.0.1` has a subtly different effect 458than `127.0.0.1;<-loopback>`. 459 460### Meaning of IP address range bypass rules 461 462The IP address range bypass rules in manual proxy settings applies only to URL 463literals. This is not what one would intuitively expect. 464 465Example: 466 467Say we have have configured a proxy for all requests, but added a bypass rule 468for `192.168.0.0.1/16`. If we now navigate to `http://foo` (which resolves 469to `192.168.1.5` in our setup) will the browser connect directly (bypass proxy) 470because we have indicated a bypass rule that includes this IP? 471 472It will go through the proxy. 473 474The bypass rule in this case is not applicable, since the browser never 475actually does a name resolution for `foo`. Proxy resolution happens before 476name resolution, and depending on what proxy scheme is subsequently chosen, 477client side name resolution may never be performed. 478 479The usefulness of IP range proxy bypass rules is rather limited, as they only 480apply to requests whose URL was explicitly an IP literal. 481 482If proxy decisions need to be made based on the resolved IP address(es) of a 483URL's hostname, one must use a PAC script. 484 485## Implicit bypass rules 486 487Requests to certain hosts will not be sent through a proxy, and will instead be 488sent directly. 489 490We call these the _implicit bypass rules_. The implicit bypass rules match URLs 491whose host portion is either a localhost name or a link-local IP literal. 492Essentially it matches: 493 494``` 495localhost 496*.localhost 497[::1] 498127.0.0.1/8 499169.254/16 500[FE80::]/10 501``` 502 503The complete rules are slightly more complicated. For instance on 504Windows we will also recognize `loopback`. 505 506This concept of implicit proxy bypass rules is consistent with the 507platform-level proxy support on Windows and macOS (albeit with some differences 508due to their implementation quirks - see compatibility notes in 509`net::ProxyBypassRules::MatchesImplicitRules`) 510 511Why apply implicit proxy bypass rules in the first place? Certainly there are 512considerations around ergonomics and user expectation, but the bigger problem 513is security. Since the web platform treats `localhost` as a secure origin, the 514ability to proxy it grants extra powers. This is [especially 515problematic](https://bugs.chromium.org/p/chromium/issues/detail?id=899126) when 516proxy settings are externally controllable, as when using PAC scripts. 517 518Historical support in Chrome: 519 520* Prior to M71 there were no implicit proxy bypass rules, except if using 521 [`--winhttp-proxy-resolver`](#winhttp_proxy_resolver-command-line-switch). 522* In M71 Chrome applied implicit proxy bypass rules to PAC scripts 523* In M72 Chrome generalized the implicit proxy bypass rules to manually 524 configured proxies 525 526### Overriding the implicit bypass rules 527 528If you want traffic to `localhost` to be sent through a proxy despite the 529security concerns, it can be done by adding the special proxy bypass rule 530`<-loopback>`. This has the effect of _subtracting_ the implicit rules. 531 532For instance, launch Chrome with the command line flag: 533 534``` 535--proxy-bypass-list="<-loopback>" 536``` 537 538Note that there currently is no mechanism to disable the implicit proxy bypass 539rules when using a PAC script. Proxy bypass lists only apply to manual 540settings, so the technique above cannot be used to let PAC scripts decide the 541proxy for localhost URLs. 542 543## Evaluating proxy lists (proxy fallback) 544 545Proxy resolution results in a _list_ of [proxy server 546identifiers](#Proxy-server-identifiers) to use for a 547given request, not just a single proxy server identifier. 548 549For instance, consider this PAC script: 550 551``` 552function FindProxyForURL(url, host) { 553 if (host == "www.example.com") { 554 return "PROXY proxy1; HTTPS proxy2; SOCKS5 proxy3"; 555 } 556 return "DIRECT"; 557} 558 559``` 560 561What proxy will Chrome use for connections to `www.example.com`, given that 562we have a choice of three separate proxy server identifiers to choose from 563{`http://proxy1:80`, `https://proxy2:443`, `socks5://proxy3:1080`}? 564 565Initially, Chrome will try the proxies in order. This means first attempting 566the request through `http://proxy1:80`. If that "fails", the request is 567next attempted through `https://proxy2:443`. Lastly if that fails, the 568request is attempted through `socks5://proxy3:1080`. 569 570This process is referred to as _proxy fallback_. What constitutes a 571"failure" is described later. 572 573Proxy fallback is stateful. The actual order of proxy attempts made be Chrome 574is influenced by the past responsiveness of proxy servers. 575 576Let's say we request `http://www.example.com/`. Per the PAC script this 577resolves to a list of three proxy server identifiers: 578 579{`http://proxy1:80`, `https://proxy2:443`, `socks5://proxy3:1080`} 580 581Chrome will first attempt to issue the request through these proxies in the 582left-to-right order. 583 584Let's say that the attempt through `http://proxy1:80` fails, but then the 585attempt through `https://proxy2:443` succeeds. Chrome will mark 586`http://proxy1:80` as _bad_ for the next 5 minutes. Being marked as _bad_ 587means that `http://proxy1:80` is de-prioritized with respect to 588other proxy server identifiers (including `direct://`) that are not marked as 589bad. 590 591That means the next time `http://www.example.com/` is requested, the effective 592order for proxies to attempt will be: 593 594{`https://proxy2:443`, `socks5://proxy3:1080`, `http://proxy1:80`} 595 596Conceptually, _bad_ proxies are moved to the end of the list, rather than being 597removed from consideration all together. 598 599What constitutes a "failure" when it comes to triggering proxy fallback depends 600on the proxy type. Generally speaking, only connection level failures 601are deemed eligible for proxy fallback. This includes: 602 603* Failure resolving the proxy server's DNS 604* Failure connecting a TCP socket to the proxy server 605 606(There are some caveats for how HTTPS and QUIC proxies count failures for 607fallback) 608 609Prior to M67, Chrome would consider failures establishing a 610CONNECT tunnel as an error eligible for proxy fallback. This policy [resulted 611in problems](https://bugs.chromium.org/p/chromium/issues/detail?id=680837) for 612deployments whose HTTP proxies intentionally failed certain https:// requests, 613since that necessitates inducing a failure during the CONNECT tunnel 614establishment. The problem would occur when a working proxy fallback option 615like DIRECT was given, since the failing proxy would then be marked as bad. 616 617Currently there are no options to configure proxy fallback (including disabling 618the caching of bad proxies). Future versions of Chrome may [remove caching 619of bad proxies](https://bugs.chromium.org/p/chromium/issues/detail?id=936130) 620to make fallback predictable. 621 622To investigate issues relating to proxy fallback, one can [collect a NetLog 623dump using 624chrome://net-export/](https://dev.chromium.org/for-testers/providing-network-details). 625These logs can then be loaded with the [NetLog 626viewer](https://netlog-viewer.appspot.com/). 627 628There are a few things of interest in the logs: 629 630* The "Proxy" tab will show which proxies (if any) were marked as bad at the 631 time the capture ended. 632* The "Events" tab notes what the resolved proxy list was, and what the 633 re-ordered proxy list was after taking into account bad proxies. 634* The "Events" tab notes when a proxy is marked as bad and why (provided the 635 event occurred while capturing was enabled). 636 637When debugging issues with bad proxies, it is also useful to reset Chrome's 638cache of bad proxies. This can be done by clicking the "Clear bad proxies" 639button on 640[chrome://net-internals/#proxy](chrome://net-internals/#proxy). Note the UI 641will not give feedback that the bad proxies were cleared, however capturing a 642new NetLog dump can confirm it was cleared. 643 644## Arguments passed to FindProxyForURL() in PAC scripts 645 646PAC scripts in Chrome are expected to define a JavaScript function 647`FindProxyForURL`. 648 649The historical signature for this function is: 650 651``` 652function FindProxyForURL(url, host) { 653 ... 654} 655``` 656 657Scripts can expect to be called with string arguments `url` and `host` such 658that: 659 660* `url` is a *sanitized* version of the request's URL 661* `host` is the unbracketed host portion of the origin. 662 663Sanitization of the URL means that the path, query, fragment, and identity 664portions of the URL are stripped. Effectively `url` will be 665limited to a `scheme://host:port/` style URL 666 667Examples of how `FindProxyForURL()` will be called: 668 669``` 670// Actual URL: https://www.google.com/Foo 671FindProxyForURL('https://www.google.com/', 'www.google.com') 672 673// Actual URL: https://[dead::beef]/foo?bar 674FindProxyForURL('https://[dead::beef]/', 'dead::beef') 675 676// Actual URL: https://www.example.com:8080#search 677FindProxyForURL('https://www.example.com:8080/', 'example.com') 678 679// Actual URL: https://username:password@www.example.com 680FindProxyForURL('https://www.example.com/', 'example.com') 681``` 682 683Stripping the path and query from the `url` is a departure from the original 684Netscape implementation of PAC. It was introduced in Chrome 52 for [security 685reasons](https://bugs.chromium.org/p/chromium/issues/detail?id=593759). 686 687There is currently no option to turn off sanitization of URLs passed to PAC 688scripts (removed in Chrome 75). 689 690The sanitization of http:// URLs currently has a different policy, and does not 691strip query and path portions of the URL. That said, users are advised not to 692depend on reading the query/path portion of any URL 693type, since future versions of Chrome may [deprecate that 694capability](https://bugs.chromium.org/p/chromium/issues/detail?id=882536) in 695favor of a consistent policy. 696 697## Resolving client's IP address within a PAC script using myIpAddress() 698 699PAC scripts can invoke `myIpAddress()` to obtain the client's IP address. This 700function returns a single IP literal, or `"127.0.0.1"` on failure. 701 702This API is [inherently ambiguous when used on multi-homed 703hosts](#myIpAddress_myIpAddressEx_and-multi_homed-hosts), as such hosts can 704have multiple IP addresses and yet the browser can pick just one to return. 705 706Chrome's algorithm for `myIpAddress()` favors returning the IP that would be 707used if we were to connect to the public internet, by executing the following 708ordered steps and short-circuiting once the first candidate IP is found: 709 7101. Select the IP of an interface that can route to public Internet: 711 * Probe for route to `8.8.8.8`. 712 * Probe for route to `2001:4860:4860::8888`. 7132. Select an IP by doing a DNS resolve of the machine's hostname: 714 * Select the first IPv4 result if there is one. 715 * Select the first IP result if there is one. 7163. Select the IP of an interface that can route to private IP space: 717 * Probe for route to `10.0.0.0`. 718 * Probe for route to `172.16.0.0`. 719 * Probe for route to `192.168.0.0`. 720 * Probe for route to `FC00::`. 721 722Note that when searching for candidate IP addresses, link-local and loopback 723addresses are skipped over. Link-local or loopback address will only be returned as a 724last resort when no other IP address was found by following these steps. 725 726This sequence of steps explicitly favors IPv4 over IPv6 results, to match 727Internet Explorer's IPv6 support. 728 729*Historical note*: Prior to M72, Chrome's implementation of `myIpAddress()` was 730effectively just `getaddrinfo(gethostname)`. This is now step 2 of the heuristic. 731 732## Resolving client's IP address within a PAC script using myIpAddressEx() 733 734Chrome supports the [Microsoft PAC 735extension](https://docs.microsoft.com/en-us/windows/desktop/winhttp/myipaddressex) 736`myIpAddressEx()`. 737 738This is like `myIpAddress()`, but instead of returning a single IP address, it 739can return multiple IP addresses. It returns a string containing a semi-colon 740separated list of addresses. On failure it returns an empty string to indicate 741no results (whereas `myIpAddress()` returns `127.0.0.1`). 742 743There are some differences with Chrome's implementation: 744 745* In Chrome the function is unconditionally defined, whereas in Internet 746 Explorer one must have used the `FindProxyForURLEx` entrypoint. 747* Chrome [does not necessarily enumerate all of the host's network 748 interfaces](#myIpAddress_myIpAddressEx_and-multi_homed-hosts) 749* Chrome does not return link-local or loopback addresses (except if no other 750 addresses were found). 751 752The algorithm that Chrome uses is nearly identical to that of `myIpAddress()` 753described earlier, but in certain cases may return multiple IPs. 754 7551. Select all the IPs of interfaces that can route to public Internet: 756 * Probe for route to `8.8.8.8`. 757 * Probe for route to `2001:4860:4860::8888`. 758 * If any IPs were found, return them, and finish. 7592. Select an IP by doing a DNS resolve of the machine's hostname: 760 * If any IPs were found, return them, and finish. 7613. Select the IP of an interface that can route to private IP space: 762 * Probe for route to `10.0.0.0`. 763 * Probe for route to `172.16.0.0`. 764 * Probe for route to `192.168.0.0`. 765 * Probe for route to `FC00::`. 766 * If any IPs were found, return them, and finish. 767 768Note that short-circuiting happens whenever steps 1-3 find a candidate IP. So 769for example if at least one IP address was discovered by checking routes to 770public Internet, only those IPs will be returned, and steps 2-3 will not run. 771 772## myIpAddress() / myIpAddressEx() and multi-homed hosts 773 774`myIpAddress()` is a poor API for hosts that have multiple IP addresses, as it 775can only return a single IP, which may or may not be the one you wanted. Both 776`myIpAddress()` and `myIpAddressEx()` favor returning the IP for the interface 777that would be used to route to the public internet. 778 779As an API, `myIpAddressEx()` offers more flexibility since it can return 780multiple IP addresses. However Chrome's implementation restricts which IPs a 781PAC script can see [due to privacy 782concerns](https://bugs.chromium.org/p/chromium/issues/detail?id=905366). So 783using `myIpAddressEx()` is not as powerful as enumerating all the host's IPs, 784and may not address all use-cases. 785 786A more reliable strategy for PAC scripts to check which network(s) a user is on 787is to probe test domains using `dnsResolve()` / `dnsResolveEx()`. 788 789Moreover, note that Chrome does not support the Firefox-specific 790`pacUseMultihomedDNS` option, so adding that global to a PAC script has no 791special side-effect in Chrome. Whereas in Firefox it reconfigures 792`myIpAddress()` to be dependent on the target URL that `FindProxyForURL()` was 793called with. 794 795## Android quirks 796 797Proxy resolving via PAC works differently on Android than other desktop Chrome 798platforms: 799 800* Android Chrome uses the same Chromium PAC resolver, however does not run it 801 out-of-process as on Desktop Chrome. This architectural difference is 802 due to the higher process cost on Android, and means Android Chrome is more 803 susceptible to malicious PAC scripts. The other consequence is that Android 804 Chrome can have distinct regressions from Desktop Chrome as the service setup 805 is quite different (and most `browser_tests` are not run on Android either). 806 807* [WebView does not use Chrome's PAC 808 resolver](https://bugs.chromium.org/p/chromium/issues/detail?id=989667). 809 Instead Android WebView uses the Android system's PAC resolver, which is less 810 optimized and uses an old build of V8. When the system is configured to use 811 PAC, Android WebView's net code will see the proxy settings as being a 812 single HTTP proxy on `localhost`. The system localhost proxy will in turn 813 evaluate the PAC script and forward the HTTP request on to the resolved 814 proxy. This translation has a number of effects, including what proxy 815 schemes are supported, the maximum connection limits, how proxy fallback 816 works, and overall performance (the current Android PAC evaluator blocks on 817 DNS). 818 819* Android system log messages for `PacProcessor` are not related to Chrome or 820 its PAC evaluator. Rather, these are log messages generated by the Android 821 system's PAC implementation. This confusion can arise when users add 822 `alert()` to debug PAC script logic, and then refer to output in `logcat` to 823 try and diagnose a resolving issue in Android Chrome. 824 825## Downloading PAC scripts 826 827When a network context is configured to use a PAC script, proxy resolution will 828stall while downloading the PAC script. 829 830Fetches for PAC URLs are initiated by the network stack, and behave differently 831from ordinary web visible requests: 832 833* Must complete within 30 seconds. 834* Must complete with an HTTP response code of exactly 200. 835* Must have an uncompressed body smaller than 1 MB. 836* Do not follow ordinary HTTP caching semantics. 837* Are never fetched through a proxy 838* Are not visible to the WebRequest extension API, or to service workers. 839* Do not support HTTP authentication (ambient authentication may work, but 840 cannot prompt UI for credentials). 841* Do not support client certificates (including `AutoSelectCertificateForUrls`) 842* Do not support auxiliary certificate network fetches (will only used cached 843 OCSP, AIA, and CRL responses during certificate verification). 844 845### Caching of successful PAC fetches 846 847PAC URLs are always fetched from the network, and never from the HTTP cache. 848After a PAC URL is successfully fetched, its contents (which are used to create 849a long-lived Java Script context) will be assumed to be fresh until either: 850 851* The network changes (IP address changes, DNS configuration changes) 852* The response becomes older than 12 hours 853* A user explicitly invalidates PAC through `chrome://net-internals#proxy` 854 855Once considered stale, the PAC URL will be re-fetched the next time proxy 856resolution is requested. 857 858### Fallback for failed PAC fetches 859 860When the proxy settings are configured to use a PAC URL, and that PAC URL 861cannot be fetched, proxy resolution will fallback to the next option, which is 862often `DIRECT`: 863 864* If using system proxy settings, and the platform supports fallback to manual 865 proxy settings (e.g. Windows), the specified manual proxy servers will be 866 used after the PAC fetch fails. 867* If using Chrome's proxy settings, and the PAC script was marked as 868 [mandatory](https://developer.chrome.com/extensions/proxy), fallback to 869 `DIRECT` is not permitted. Subsequent network requests will fail proxy 870 resolution and complete with `ERR_MANDATORY_PROXY_CONFIGURATION_FAILED`. 871* Otherwise proxy resolution will silently fall back to `DIRECT`. 872 873### Recovering from failed PAC fetches 874 875When fetching an explicitly configured PAC URL fails, the browser will try to 876re-fetch it: 877 878* In exactly 8 seconds 879* 32 seconds after that 880* 2 minutes after that 881* Every 4 hours thereafter 882 883This background polling of the PAC URL is only initiated in response to an 884incoming proxy resolution request, so it will not trigger work when the browser 885is otherwise idle. 886 887Similarly to successful fetches, the PAC URL will be also be re-fetched 888whenever the network changes, the proxy settings change, or it was manually 889invalidated via `chrome://net-internals#proxy`. 890 891### Text encoding 892 893Note that UTF-8 is *not* the default interpretation of PAC response bodies. 894 895The priority for encoding is determined in this order: 896 8971. The `charset` property of the HTTP response's `Content-Type` 8982. Any BOM at the start of response body 8993. Otherwise defaults to ISO-8859-1. 900 901When setting the `Content-Type`, servers should prefer using a mime type of 902`application/x-ns-proxy-autoconfig` or `application/x-javascript-config`. 903However in practice, Chrome does not enforce the mime type. 904 905## Capturing a Net Log for debugging proxy resolution issues 906 907Issues in proxy resolution are best investigated using a Net Log. 908 909A good starting point is to follow the [general instructions for 910net-export](https://www.chromium.org/for-testers/providing-network-details), 911*and while the Net Log is being captured perform these steps*: 912 9131. Reproduce the failure (ex: load a URL that fails) 9142. If you can reproduce a success, do so (ex: load a different URL that succeeds). 9153. In a new tab, navigate to `chrome://net-internals/#proxy` and click both 916 buttons ("Re-apply settings" and "Clear bad proxies"). 9174. Repeat step (1) 9185. Stop the Net Log and save the file. 919 920The resulting Net Log should have enough information to diagnose common 921problems. It can be attached to a bug report, or explored using the [Net Log 922Viewer](https://netlog-viewer.appspot.com/). See the next section for some tips 923on analyzing it. 924 925## Analyzing Net Logs for proxy issues 926 927Load saved Net Logs using [Net Log Viewer](https://netlog-viewer.appspot.com/). 928 929### Proxy overview tab 930 931Start by getting a big-picture view of the proxy settings by clicking to the 932"Proxy" tab on the left. This summarizes the proxy settings at the time the 933_capture ended_. 934 935* Does the _original_ proxy settings match expectation? 936 The proxy settings might be coming from: 937 * Managed Chrome policy (chrome://policy) 938 * Command line flags (ex: `--proxy-server`) 939 * (per-profile) Chrome extensions (ex: [chrome.proxy](https://developer.chrome.com/extensions/proxy)) 940 * (per-network) System proxy settings 941 942* Was [proxy autodetect (WPAD)](#Web-Proxy-Auto_Discovery-WPAD) specified? In 943 this case the final URL probed will be reflected by the difference between 944 the "Effective" and "Original" settings. 945 946* Internally, proxy settings are per-NetworkContext. The proxy 947 overview tab shows settings for a *particular* NetworkContext, namely the 948 one associated with the Profile used to navigate to `chrome://net-export`. For 949 instance if the net-export was initiated from an Incognito window, it may 950 show different proxy settings here than a net-export capture initiated by a 951 non-Incognito window. When the net-export was triggered from command line 952 (`--log-net-log`) no particular NetworkContext is associated with the 953 capture and hence no proxy settings will be shown in this overview. 954 955* Were any proxies marked as bad? 956 957### Import tab 958 959Skim through the Import tab and look for relevant command line flags and active 960field trials. A find-in-page for `proxy` is a good starting point. Be on the lookout for 961[`--winhttp-proxy-resolver`](#winhttp_proxy_resolver-command-line-switch) which 962has [known problems](https://bugs.chromium.org/p/chromium/issues/detail?id=644030). 963 964### Events tab 965 966To deep dive into proxy resolution, switch to the Events tab. 967 968You can start by filtering on `type:URL_REQUEST` to see all the top level 969requests, and then keep click through the dependency links to 970trace the proxy resolution steps and outcome. 971 972The most relevant events have either `PROXY_`, `PAC_`, or 973`WPAD_` in their names. You can also try filtering for each of those. 974 975Documentation on specific events is available in 976[net_log_event_type_list.h](https://chromium.googlesource.com/chromium/src/+/HEAD/net/log/net_log_event_type_list.h). 977 978Network change events can also be key to understanding proxy issues. After 979switching networks (ex VPN), the effective proxy settings, as well as content 980of any PAC scripts/auto-detect can change. 981 982## Web Proxy Auto-Discovery (WPAD) 983 984When configured to use WPAD (aka "autotmaticaly detect proxy settings"), Chrome 985will prioritize: 986 9871. DHCP-based WPAD (option 252) 9882. DNS-based WPAD 989 990These are tried in order, however DHCP-based WPAD is only supported for Chrome 991on Windows and Chrome on Chrome OS. 992 993WPAD is the system default for many home and Enterprise users. 994 995### Chrome on macOS support for DHCP-based WPAD 996 997Chrome on macOS does not support DHCP-based WPAD when configured to use 998"autodetect". 999 1000However, macOS might perform DHCP-based WPAD and embed this discovered PAC URL 1001as part of the system proxy settings. So effectively when Chrome is configured 1002to "use system proxy settings" it may behave as if it supports DHCP-based WPAD. 1003 1004### Dangers of DNS-based WPAD and DNS search suffix list 1005 1006DNS-based WPAD involves probing for the non-FQDN `wpad`. This means 1007WPAD's performance and security is directly tied to the user's DNS search 1008suffix list. 1009 1010When resolving `wpad`, the host's DNS resolver will complete the hostname using 1011each of the suffixes in the search list: 1012 10131. If the suffix list is long this process can very slow, as it triggers a 1014 cascade of NXDOMAIN. 10152. If the suffix list includes domains *outside of the administrative domain*, 1016 WPAD may select an attacker controlled PAC server, and can subsequently 1017 funnel the user's traffic through a proxy server of their choice. The 1018 evolution of TLDs further increases this risk, since what were previously 1019 private suffixes used by an enterprise can become publicly registerable. 1020 See also [WPAD Name Collision 1021 Vulnerability](https://www.us-cert.gov/ncas/alerts/TA16-144A) 1022 1023## --winhttp-proxy-resolver command line switch 1024 1025Passing the `--winhttp-proxy-resolver` command line argument instructs Chrome 1026to use the system libraries for *one narrow part of proxy resolution*: evaluating 1027a given PAC script. 1028 1029Use of this flag is NOT a supported mode, and has [known 1030problems](https://bugs.chromium.org/p/chromium/issues/detail?id=644030): It 1031can break Chrome extensions (`chrome.proxy` API), the interpretation of 1032Proxy policies, hurt performance, and doesn't ensure full fidelity 1033interpretation of system proxy settings. 1034 1035Another oddity of this switch is that it actually gets interpreted with a 1036smilar meaning on other platforms (macOS), despite its Windows-specific naming. 1037 1038This flag was historically exposed for debugging, and to mitigate unresolved 1039policy differences in PAC execution. In the future this switch [will be 1040removed](https://bugs.chromium.org/p/chromium/issues/detail?id=644030). 1041 1042Although Chrome would like full fidelity with Windows proxy settings, there are 1043limits to those integrations. Dependencies like NRPT for proxy 1044resolution necessitate using Windows proxy resolution libraries directly 1045instead of Chrome's. We hope these less common use cases will be fully 1046addressed by [this 1047feature](https://bugs.chromium.org/p/chromium/issues/detail?id=1032820) 1048