PAC(Proxy Auto-Configuration) 는 요청마다 어느 프록시를 쓸지 정하는 규칙을 담은 JavaScript 파일이다. 브라우저나 OS 에 PAC 파일의 URL 을 등록해 두면, 클라이언트가 URL 을 요청할 때마다 이 파일의 함수를 호출해 결과에 따라 경로를 고른다. 사내망은 직접, 외부는 프록시 경유 같은 분기를 클라이언트마다 손으로 설정하지 않아도 되는 것이 이점이다.
파일은 반드시 FindProxyForURL(url, host) 함수를 정의하고 문자열을 돌려줘야 한다.
function FindProxyForURL(url, host) {
return "PROXY proxy.example.com:8080; DIRECT";
}
| 반환값 | 뜻 |
|---|---|
DIRECT |
프록시 없이 직접 접속 |
PROXY host:port |
지정한 HTTP 프록시 사용 |
SOCKS host:port · SOCKS5 host:port |
SOCKS 프록시 사용 |
HTTPS host:port |
프록시에 TLS 로 접속 (지원하는 클라이언트에서만) |
세미콜론으로 여러 개를 이으면 앞에서부터 시도하고 실패하면 다음으로 넘어간다. 마지막에 DIRECT 를 두면 프록시가 모두 죽어도 통신이 끊기지 않지만, 정책상 반드시 프록시를 거쳐야 한다면 넣지 않는다.
| 함수 | 용도 |
|---|---|
isPlainHostName(host) |
점이 없는 단일 이름인가 (intranet 같은) |
dnsDomainIs(host, ".example.com") |
해당 도메인에 속하는가 |
shExpMatch(str, "*.example.com") |
와일드카드 매칭 |
isInNet(host, "192.168.0.0", "255.255.0.0") |
지정 대역에 속하는가 |
dnsResolve(host) |
이름을 IP 로 해석 |
myIpAddress() |
클라이언트 자신의 IP |
localHostOrDomainIs(host, "www.example.com") |
정확히 그 호스트이거나 짧은 이름인가 |
weekdayRange("MON", "FRI") · timeRange(9, 18) |
요일 · 시간 조건 |
function FindProxyForURL(url, host) {
// 1. 점 없는 내부 호스트명
if (isPlainHostName(host)) {
return "DIRECT";
}
// 2. 사내 도메인
if (dnsDomainIs(host, ".corp.example") ||
shExpMatch(host, "*.internal.example")) {
return "DIRECT";
}
// 3. 로컬호스트
if (shExpMatch(host, "localhost") || shExpMatch(host, "127.*")) {
return "DIRECT";
}
// 4. 사내 IP 대역
var ip = dnsResolve(host);
if (ip &&
(isInNet(ip, "10.0.0.0", "255.0.0.0") ||
isInNet(ip, "172.16.0.0", "255.240.0.0") ||
isInNet(ip, "192.168.0.0", "255.255.0.0"))) {
return "DIRECT";
}
// 5. 그 밖에는 프록시
return "PROXY proxy.corp.example:3128; PROXY proxy2.corp.example:3128";
}
dnsResolve() 와 isInNet() 은 DNS 질의를 유발한다. 모든 요청마다 이 함수를 타면 지연이 쌓이므로, 이름만으로 판별할 수 있는 조건(dnsDomainIs · shExpMatch)을 앞에 두고 IP 기반 판별은 마지막에 둔다. 위 예시의 순서가 그 이유다.
PAC 은 FindProxyForURL 이 매 요청마다 호출되는 구조이므로 반복문이나 무거운 연산을 넣지 않는다.
배포는 웹 서버에 파일을 올리고 그 URL 을 등록하는 방식이다. MIME 타입을 application/x-ns-proxy-autoconfig 로 내려 줘야 인식하지 않는 클라이언트가 있다. 파일을 고쳐도 클라이언트가 캐시를 들고 있으므로 짧은 Cache-Control 을 주거나 배포 후 브라우저 재시작을 안내한다.
myIpAddress() 는 VPN 이나 다중 NIC 환경에서 기대와 다른 주소를 돌려주는 경우가 잦다. 이 값에 의존하는 분기는 되도록 피한다.
WPAD 로 자동 탐색(http://wpad.<도메인>/wpad.dat)을 쓰면 URL 등록조차 생략할 수 있지만, 사내 DNS 를 신뢰할 수 없는 환경에서는 탈취 위험이 있으므로 URL 을 명시적으로 배포하는 편이 안전하다.
문법 확인은 Node.js 로 간단히 할 수 있다.
node --check proxy.pac