When working with network routing and proxy configurations, Proxy Auto-Configuration (PAC) files provide a powerful mechanism for dynamically directing traffic. A PAC file is essentially a JavaScript-based script that determines how web requests should be handled—whether they should go directly to their destination or be routed through a proxy server.
The core of a PAC file is the FindProxyForURL function, which receives two parameters: the target URL and the hostname. Based on this information, the function returns routing instructions.
function FindProxyForURL(url, host) {
return "DIRECT";
}
This minimal example demonstrates a PAC file that routes all traffic directly without any proxy involvement.
Return Values and Routing Logic
The function can return three distinct directives: "DIRECT" for direct connections, "PROXY host:port" for HTTP proxy routing, and "SOCKS host:port" for SOCKS protocol routing. Multiple fallback options can be chained together:
return "PROXY 192.168.1.100:3128; SOCKS 192.168.1.100:1080; DIRECT";
This configuration attempts the primary proxy first, falls back to the SOCKS server if the primary fails, and defaults to a direct connection if both proxies are unavailable.
Built-in PAC Functions
PAC specifications include several utility functions for sophisticated routing decisions.
The dnsDomainIs function performs case-insensitive domain matching:
if (dnsDomainIs(host, "example.org") ||
dnsDomainIs(host, "www.example.org")) {
return "DIRECT";
}
The shExpMatch function provides shell-style pattern matching with wildcard support:
if (shExpMatch(host, "secure.gateway.net") ||
shExpMatch(url, "https://api.service.com/v1/*")) {
return "DIRECT";
}
The isInNet function checks whether an IP address falls within a specified subnet:
if (isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0")) {
return "DIRECT";
}
For obtaining the local machine's IP address, use myIpAddress:
if (isInNet(myIpAddress(), "192.168.0.0", "255.255.0.0")) {
return "PROXY 10.0.0.1:8080";
}
DNS resolution is handled through dnsResolve:
if (isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") ||
isInNet(dnsResolve(host), "192.168.0.0", "255.255.0.0")) {
return "DIRECT";
}
The isPlainHostName function identifies hosts without domain components:
if (isPlainHostName(host)) {
return "DIRECT";
}
Use isResolvable to check host accessibility:
if (isResolvable(host)) {
return "PROXY gateway.example.com:8080";
}
The dnsDomainLevels function counts domain depth:
if (dnsDomainLevels(host) > 0) {
return "PROXY gateway.example.com:8080";
} else {
return "DIRECT";
}
Time-based routing is supported through weekdayRange, dateRange, and timeRange:
if (weekdayRange("MON", "FRI")) {
return "PROXY gateway.example.com:8080";
}
if (dateRange("JAN", "MAY")) {
return "PROXY gateway.example.com:8080";
}
if (timeRange(8, 18)) {
return "PROXY gateway.example.com:8080";
}
Configuration and Deployment
On Windows systems, PAC files are configured through Internet Options under Connections tab and LAN settings. The script URI can reference local files using the file:/// protocol or remote servers via http:// or https://.
In Chrome, access these settings via chrome://settings/ under Advanced settings and proxy configuration options.
Important Considerations
When serving PAC files, ensure the Content-Type header is set to application/x-ns-proxy-autoconfig. Most browsers will still recognize the file without this header, but compliance ensures proper handling.
Host parameters in comparison functions are handled case-insensitively by the PAC engine, eliminating the need for manual case normalization.
The underlying DNS resolution layer automatically caches query results, so implementing application-level caching for dnsResolve results is unnecessary and redundant.