PAC-P001 · dns-function-on-hot-path

DNS lookup on every request

high · Performance · Top 20 #13

dnsResolve, isResolvable and isInNet on a hostname each cost a DNS round trip inside proxy resolution, for every connection, before the page starts loading. They also make routing depend on the resolver being reachable and honest. Most PACs can decide on the hostname string alone.

Why it matters

Every connection runs FindProxyForURL. A DNS call there adds the resolver’s latency to every first byte (tens of milliseconds normally, seconds on a degraded resolver, a hang on a broken one), and Firefox and WinHTTP block the resolver thread while waiting. The dependency is binary: one DNS call makes the PAC depend on DNS, zero calls do not; “minimising” lookups does not remove the dependency. DNS answers are also the one input an attacker on a hostile network controls, and a failed lookup returns a null-like value that makes isInNet false, so the request silently takes the default route.

Order the function so that string rules (isPlainHostName, dnsDomainIs, shExpMatch, IP-literal isInNet) return first, and keep DNS-dependent rules for the few cases that cannot be expressed on the hostname, after everything else.

How to fix

Decide on hostname patterns; if an address check is unavoidable, guard it with an IP-literal test or place it after all string rules and hoist the dnsResolve result.

Examples

Bad

function FindProxyForURL(url, host) {
  if (isInNet(host, "10.0.0.0", "255.0.0.0")) {
    return "DIRECT";
  }
  return "PROXY proxy.corp.example:8080";
}
Open bad example in checker

Good

function FindProxyForURL(url, host) {
  if (isPlainHostName(host) || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }
  if (/^\d+\.\d+\.\d+\.\d+$/.test(host) && isInNet(host, "10.0.0.0", "255.0.0.0")) {
    return "DIRECT";
  }
  return "PROXY proxy.corp.example:8080";
}
Open good example in checker

Engine behaviour

EngineBehaviourSource
chromiumResolution goes through the network service; the PAC evaluation waits for the answer.expert, unverified
firefoxdnsResolve is synchronous on the PAC thread.expert, unverified

Source: code = read in the engine's source, doc = vendor documentation, lab = observed in a lab run, expert = practitioner knowledge, not yet verified.

Related rules

References