Прокси-серверы и туннелирование: файл Proxy Auto-Configuration (PAC)
Файл Proxy Auto-Configuration (PAC)
Файл Proxy Auto-Configuration (PAC) — это функция JavaScript, которая определяет, будут ли запросы веб-браузера (HTTP, HTTPS и FTP) направляться непосредственно к месту назначения или перенаправляться на прокси-сервер. Функция JavaScript, содержащаяся в файле PAC, определяет функцию:
Синтаксис
function FindProxyForURL(url, host) {
// …
}
Параметры
url-
URL, к которому осуществляется доступ. Компоненты пути и запроса URL-адресов
https://удаляются. В Chrome (версии 52–73) это можно отключить, установивPacHttpsUrlStrippingEnabledв значениеfalseв политике или запустив браузер с флагом командной строки--unsafe-pac-url(в Chrome 74 работает только флаг, а начиная с версии 75 удаление пути отключить нельзя; в Chrome 81 удаление пути не применяется к URL-адресам HTTP, но рассматривается возможность изменить это поведение, чтобы оно соответствовало HTTPS); в Firefox используется настройкаnetwork.proxy.autoconfig_url.include_path. host-
Имя хоста, извлечённое из URL. Это сделано только для удобства: это та же строка, что находится между
://и первым:или/после него. Номер порта в этот параметр не включается. При необходимости его можно извлечь из URL.
Описание
Возвращает строку с описанием конфигурации. Формат этой строки определён ниже в разделе формат возвращаемого значения.
Формат возвращаемого значения
- Функция JavaScript возвращает одну строку
- Если строка равна null, прокси использовать не следует
- Строка может содержать любое количество следующих элементов, разделённых точкой с запятой:
DIRECT-
Соединения должны устанавливаться напрямую, без использования прокси
PROXY host:port-
Следует использовать указанный прокси
SOCKS host:port-
Следует использовать указанный SOCKS-сервер
В последних версиях Firefox также поддерживаются:
HTTP host:port-
Следует использовать указанный прокси
HTTPS host:port-
Следует использовать указанный HTTPS-прокси
SOCKS4 host:port,SOCKS5 host:port-
Следует использовать указанный SOCKS-сервер (с указанной версией SOCKS)
Если указано несколько параметров, разделённых точкой с запятой, будет использоваться самый левый параметр, пока Firefox не сможет установить соединение с прокси. В этом случае будет использовано следующее значение и т. д.
Браузер автоматически повторит попытку подключиться к прокси, который ранее не отвечал, через 30 минут. Последующие попытки будут выполняться с интервалом от одного часа, каждый раз увеличивая время между попытками на 30 минут.
Если все прокси недоступны и параметр DIRECT не указан, браузер спросит, следует ли временно игнорировать прокси и попробовать установить прямые соединения. Через 20 минут браузер спросит, следует ли повторить попытку подключения к прокси, а затем будет задавать этот вопрос каждые 40 минут. Запросы будут продолжаться с увеличением интервала между ними на 20 минут.
Примеры
PROXY w3proxy.netscape.com:8080; PROXY mozilla.netscape.com:8081-
Основной прокси — w3proxy:8080; если он станет недоступен, начнёт использоваться mozilla:8081, пока основной прокси снова не заработает.
PROXY w3proxy.netscape.com:8080; PROXY mozilla.netscape.com:8081; DIRECT-
То же, что и выше, но если оба прокси станут недоступны, браузер автоматически начнёт устанавливать прямые соединения. (В первом примере выше Netscape запросит у пользователя подтверждение для установки прямых соединений; в этом случае вмешательство пользователя не потребуется.)
PROXY w3proxy.netscape.com:8080; SOCKS socks:1080-
Использовать SOCKS, если основной прокси станет недоступен.
Файл автоконфигурации следует сохранить с расширением имени файла .pac: proxy.pac.
Для MIME-типа следует установить значение application/x-ns-proxy-autoconfig.
Затем настройте сервер так, чтобы расширению имени файла .pac соответствовал этот MIME-тип.
Примечание:
- Функцию JavaScript следует сохранять в отдельный файл, а не встраивать в HTML-файл или любой другой файл.
- Примеры в конце этого документа являются полными. Для сохранения в файл и использования не требуется дополнительный синтаксис. (Разумеется, код JavaScript необходимо изменить с учётом доменного имени и/или подсетей вашего сайта.)
Предопределённые функции и среда
При создании файла PAC можно использовать следующие функции:
-
Условия на основе имени хоста
-
Вспомогательные функции
-
Условия на основе URL/имени хоста
-
Условия на основе времени
-
Вспомогательная функция для ведения журнала
-
Также был заранее определён один ассоциативный массив (объект), поскольку на тот момент код JavaScript не мог создать его самостоятельно:
-
ProxyConfig.bindings
-
Примечание: для проверки примеров синтаксиса ниже использовалась утилита pactester (входит в пакет pacparser).
- Файл PAC называется
proxy.pac - Командная строка:
pactester -p ~/pacparser-master/tests/proxy.pac -u https://www.mozilla.org(передаёт параметрhostсо значениемwww.mozilla.orgи параметрurlсо значениемhttps://www.mozilla.org)
isPlainHostName()
Синтаксис
isPlainHostName(host)
Параметры
- host
-
Имя хоста из URL (без номера порта).
Описание
Возвращает true тогда и только тогда, когда в имени хоста нет доменного имени (нет точек).
Примеры
isPlainHostName("www.mozilla.org"); // false
isPlainHostName("www"); // true
dnsDomainIs()
Синтаксис
dnsDomainIs(host, domain)
Параметры
- host
-
Имя хоста из URL.
- domain
-
Доменное имя, с которым нужно сравнить имя хоста.
Описание
Возвращает true тогда и только тогда, когда домен имени хоста совпадает.
Примеры
dnsDomainIs("www.mozilla.org", ".mozilla.org") // true
dnsDomainIs("www", ".mozilla.org") // false
localHostOrDomainIs()
Синтаксис
localHostOrDomainIs(host, hostDom)
Параметры
- host
-
Имя хоста из URL.
- hostDom
-
Полное доменное имя хоста для сравнения.
Описание
Возвращает true, если имя хоста точно совпадает с указанным именем хоста либо если в имени хоста нет доменной части, но совпадает имя хоста без домена.
Примеры
localHostOrDomainIs("www.mozilla.org", "www.mozilla.org") // true (exact match)
localHostOrDomainIs("www", "www.mozilla.org") // true (hostname match, domain not specified)
localHostOrDomainIs("www.google.com", "www.mozilla.org") // false (domain name mismatch)
localHostOrDomainIs("home.mozilla.org", "www.mozilla.org") // false (hostname mismatch)
isResolvable()
Синтаксис
isResolvable(host)
Параметры
- host
-
Имя хоста из URL.
Пытается разрешить имя хоста. Возвращает true в случае успеха.
Примеры
isResolvable("www.mozilla.org") // true
isInNet()
Синтаксис
isInNet(host, pattern, mask)
Параметры
- host
-
Имя хоста DNS или IP-адрес. Если передано имя хоста, эта функция разрешит его в IP-адрес.
- pattern
-
Шаблон IP-адреса в формате с точками-разделителями.
- mask
-
Маска для шаблона IP-адреса, указывающая, какие части IP-адреса необходимо сопоставить. Значение 0 означает, что часть нужно игнорировать, а 255 — что её нужно сопоставить.
Возвращает true тогда и только тогда, когда IP-адрес хоста соответствует указанному шаблону IP-адреса.
Шаблон и маска задаются так же, как и при настройке SOCKS.
Примеры
function FindProxyForURL(url, host) {
alert(isInNet(host, "192.0.2.172", "255.255.255.255"));
// "PAC-alert: true"
}
dnsResolve()
dnsResolve(host)
Параметры
- host
-
Имя хоста для разрешения.
Разрешает указанное имя хоста DNS в IP-адрес и возвращает его в виде строки в формате с точками-разделителями.
Пример
dnsResolve("www.mozilla.org"); // returns the string "104.16.41.2"
convert_addr()
Синтаксис
convert_addr(ipaddr)
Параметры
- ipaddr
-
Адрес с точками, например IP-адрес или маска.
Объединяет четыре байта, разделённые точками, в одно 4-байтовое слово и преобразует его в десятичное число.
Пример
convert_addr("192.0.2.172"); // returns the decimal number 1745889538
myIpAddress()
Синтаксис
myIpAddress()
Параметры
(нет)
Возвращаемое значение
Возвращает IP-адрес сервера компьютера, на котором запущен Firefox, в виде строки с целыми числами, разделёнными точками. Чтобы предоставить более полезный результат, функция попробует несколько вариантов, прежде чем вернуться к адресу обратной связи (например, 127.0.0.1).
Пример
myIpAddress()
dnsDomainLevels()
Синтаксис
dnsDomainLevels(host)
Параметры
- host
-
Имя хоста из URL.
Возвращает количество уровней домена DNS (количество точек) в имени хоста в виде целого числа.
Примеры
dnsDomainLevels("www") // 0
dnsDomainLevels("mozilla.org") // 1
dnsDomainLevels("www.mozilla.org"); // 2
shExpMatch()
Синтаксис
shExpMatch(str, shExp)
Параметры
- str
-
Любая строка для сравнения (например, URL или имя хоста).
- shExp
-
Шаблон оболочки для сравнения.
Возвращает true, если строка соответствует указанному шаблону оболочки с подстановочными знаками.
Поддержка конкретного синтаксиса шаблонов с подстановочными знаками различается в браузерах: * (совпадение с любым количеством символов) и ? (совпадение с одним символом) поддерживаются всегда, а [characters] и [^characters] поддерживаются дополнительно в некоторых реализациях (включая Firefox).
Примечание: Если клиент поддерживает регулярные выражения JavaScript, они обычно обеспечивают более гибкий и единообразный способ сопоставления URL (и других строк) с шаблоном.
Примеры
shExpMatch("http://home.netscape.com/people/ari/index.html", "*/ari/*"); // returns true
shExpMatch("http://home.netscape.com/people/montulli/index.html", "*/ari/*"); // returns false
weekdayRange()
Синтаксис
weekdayRange(wd1, wd2) weekdayRange(wd1, wd2, gmt)
Примечание: (До Firefox 49) wd1 должно быть меньше wd2, если нужно, чтобы функция интерпретировала эти параметры как диапазон. См. предупреждение ниже.
Параметры
- wd1 и wd2
-
Одна из строк с упорядоченными названиями дней недели:
"SUN","MON","TUE","WED","THU","FRI","SAT" - gmt
-
Либо строка "GMT", либо параметр не указывается.
Обязателен только первый параметр. Второй, третий или оба параметра можно не указывать.
Если указан только один параметр, функция возвращает true в день недели, соответствующий этому параметру. Если в качестве второго параметра указана строка "GMT", время считается временем по Гринвичу (GMT). В противном случае используется местный часовой пояс.
Если заданы оба параметра — wd1 и wd2, — условие истинно, если текущий день недели находится между этими двумя упорядоченными днями. Границы включаются, но дни должны быть указаны в правильном порядке. Если задан параметр "GMT", время считается временем по Гринвичу (GMT). В противном случае используется местный часовой пояс.
Предупреждение: Порядок дней имеет значение. До Firefox 49 weekdayRange("SUN", "SAT") всегда возвращало true. Теперь weekdayRange("WED", "SUN") вернёт true, только если сегодня среда или воскресенье.
Примеры
weekdayRange("MON", "FRI") // returns true Monday through Friday (local timezone)
weekdayRange("MON", "FRI", "GMT") // returns true Monday through Friday (GMT timezone)
weekdayRange("SAT") // returns true on Saturdays local time
weekdayRange("SAT", "GMT") // returns true on Saturdays GMT time
weekdayRange("FRI", "MON") // returns true Friday and Monday only (note, the order does matter!)
dateRange()
Синтаксис
dateRange(dayOrMonthOrYear) dateRange(dayOrMonthOrYear, gmt) // ambiguity is resolved by assuming year is greater than 31 dateRange(day1, day2) dateRange(day1, day2, gmt) dateRange(month1, month2) dateRange(month1, month2, gmt) dateRange(year1, year2) dateRange(year1, year2, gmt) dateRange(day1, month1, day2, month2) dateRange(day1, month1, day2, month2, gmt) dateRange(month1, year1, month2, year2) dateRange(month1, year1, month2, year2, gmt) dateRange(day1, month1, year1, day2, month2, year2) dateRange(day1, month1, year1, day2, month2, year2, gmt)
Примечание: (До Firefox 49) day1 должно быть меньше day2, month1 должно быть меньше month2, а year1 должно быть меньше year2, если нужно, чтобы функция интерпретировала эти параметры как диапазон. См. предупреждение ниже.
Параметры
- day
-
Порядковый день месяца от 1 до 31 (целое число).
- month
-
Одна из строк с упорядоченными названиями месяцев:
"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC". - year
-
Упорядоченное целое число, обозначающее полный год. Например, 2016 (не 16).
- gmt
-
Либо строка "GMT", при которой сравнение времени выполняется в часовом поясе GMT, либо параметр не указывается. Если параметр не задан, время считается местным.
Если указано только одно значение (из каждой категории: день, месяц, год), функция возвращает true только в дни, соответствующие этому значению. Если указаны оба значения, результат будет true в промежутке между ними, включая границы, но границы должны быть указаны в правильном порядке.
Предупреждение: Порядок дней, месяцев и лет имеет значение. До Firefox 49 dateRange("JAN", "DEC") всегда возвращало true. Теперь dateRange("DEC", "JAN") вернёт true, только если текущий месяц — декабрь или январь.
Примеры
dateRange(1) // returns true on the first day of each month, local timezone
dateRange(1, "GMT") // returns true on the first day of each month, GMT timezone
dateRange(1, 15) // returns true on the first half of each month
dateRange(24, "DEC");// returns true on 24th of December each year
dateRange("JAN", "MAR"); // returns true on the first quarter of the year
dateRange(1, "JUN", 15, "AUG");
// returns true from June 1st until August 15th, each year
// (including June 1st and August 15th)
dateRange(1, "JUN", 1995, 15, "AUG", 1995);
// returns true from June 1st, 1995, until August 15th, same year
dateRange("OCT", 1995, "MAR", 1996);
// returns true from October 1995 until March 1996
// (including the entire month of October 1995 and March 1996)
dateRange(1995);
// returns true during the entire year of 1995
dateRange(1995, 1997);
// returns true from beginning of year 1995 until the end of year 1997
timeRange()
Синтаксис
// The full range of expansions is analogous to dateRange. timeRange(hour1, min1, sec1, hour2, min2, sec2) timeRange(hour1, min1, sec1, hour2, min2, sec2, gmt)
Примечание: (До Firefox 49) значения из категории hour1, min1, sec1 должны быть меньше значений из категории hour2, min2, sec2, если нужно, чтобы функция интерпретировала эти параметры как диапазон. См. предупреждение ниже.
Параметры
- hour
-
Час от 0 до 23 (0 — полночь, 23 — 23:00).
- min
-
Минуты от 0 до 59.
- sec
-
Секунды от 0 до 59.
- gmt
-
Строка "GMT" для часового пояса GMT или отсутствие параметра для местного часового пояса.
Если указано только одно значение (из каждой категории: час, минута, секунда), функция возвращает true только в момент времени, соответствующий этому значению. Если указаны оба значения, результат будет true в промежутке между ними, включая границы, но границы должны быть указаны в правильном порядке.
Предупреждение: Порядок часов, минут и секунд имеет значение. До Firefox 49 timeRange(0, 23) всегда возвращало true. Теперь timeRange(23, 0) вернёт true, только если текущее время — 23:00 или полночь.
Примеры
timeRange(12); // returns true from noon to 1pm timeRange(12, 13) // returns true from noon to 1pm timeRange(12, "GMT") // returns true from noon to 1pm, in the GMT timezone timeRange(9, 17) // returns true from 9am to 5pm timeRange(8, 30, 17, 0) // returns true from 8:30am to 5:00pm timeRange(0, 0, 0, 0, 0, 30) // returns true between midnight and 30 seconds past midnight
alert()
Синтаксис
alert(message)
Параметры
- message
-
Строка для записи в журнал
Записывает сообщение в консоль браузера.
Примеры
alert(`${host} = ${dnsResolve(host)}`) // logs the host name and its IP address
alert("Error: shouldn't reach this clause.") // log a message
Пример 1
>Использование прокси для всех узлов, кроме локальных
Примечание: Поскольку все приведённые далее примеры очень специфичны, они не проверялись.
Соединения со всеми узлами, имена которых не являются полными, а также с узлами в локальном домене будут устанавливаться напрямую. Все остальные соединения будут проходить через w3proxy.mozilla.org:8080. Если прокси станет недоступен, соединения автоматически будут устанавливаться напрямую:
function FindProxyForURL(url, host) {
if (isPlainHostName(host) || dnsDomainIs(host, ".mozilla.org")) {
return "DIRECT";
}
return "PROXY w3proxy.mozilla.org:8080; DIRECT";
}
Примечание: Это самый простой и эффективный файл автоконфигурации для случаев, когда используется только один прокси.
Пример 2
>Как выше, но с использованием прокси для локальных серверов за пределами брандмауэра
Если существуют узлы (например, основной веб-сервер), которые относятся к локальному домену, но находятся за пределами брандмауэра и доступны только через прокси-сервер, эти исключения можно обработать с помощью функции localHostOrDomainIs():
function FindProxyForURL(url, host) {
if (
(isPlainHostName(host) || dnsDomainIs(host, ".mozilla.org")) &&
!localHostOrDomainIs(host, "www.mozilla.org") &&
!localHostOrDomainIs(host, "merchant.mozilla.org")
) {
return "DIRECT";
}
return "PROXY w3proxy.mozilla.org:8080; DIRECT";
}
В приведённом выше примере прокси используется для всех узлов, кроме локальных узлов в домене mozilla.org. Исключение составляют узлы www.mozilla.org и merchant.mozilla.org, соединения с которыми будут проходить через прокси.
Примечание: Указанный выше порядок исключений повышает эффективность: функции localHostOrDomainIs() выполняются только для URL в локальном домене, а не для каждого URL. Обратите внимание на скобки вокруг выражения или, стоящего перед выражением и: именно они обеспечивают описанную выше эффективность.
Пример 3
>Использование прокси, только если имя хоста не удаётся разрешить
Этот пример подходит для среды, в которой внутренний DNS-сервер настроен так, что может разрешать только внутренние имена хостов, а прокси требуется использовать только для узлов, имена которых не удаётся разрешить:
function FindProxyForURL(url, host) {
if (isResolvable(host)) {
return "DIRECT";
}
return "PROXY proxy.example.com:8080";
}
В приведённом выше примере DNS-сервер проверяется при каждом запросе. Это можно разумно объединить с другими правилами, чтобы обращаться к DNS-серверу только в том случае, если другие правила не дали результата:
function FindProxyForURL(url, host) {
if (
isPlainHostName(host) ||
dnsDomainIs(host, ".example.com") ||
isResolvable(host)
) {
return "DIRECT";
}
return "PROXY proxy.example.com:8080";
}
Пример 4
>Решения на основе подсетей
В этом примере соединения со всеми узлами в заданной подсети устанавливаются напрямую, а с остальными — через прокси:
function FindProxyForURL(url, host) {
if (isInNet(host, "192.0.2.172", "255.255.0.0")) {
return "DIRECT";
}
return "PROXY proxy.example.com:8080";
}
И в этом случае использование DNS-сервера в приведённом выше примере можно свести к минимуму, добавив в начало избыточные правила:
function FindProxyForURL(url, host) {
if (
isPlainHostName(host) ||
dnsDomainIs(host, ".example.com") ||
isInNet(host, "192.0.2.0", "255.255.0.0")
) {
return "DIRECT";
}
return "PROXY proxy.example.com:8080";
}
Пример 5
>Балансировка нагрузки и маршрутизация на основе шаблонов URL
Это более сложный пример. Есть четыре (4) прокси-сервера; один из них является горячим резервом для остальных, поэтому, если любой из трёх оставшихся серверов станет недоступен, его заменит четвёртый. Кроме того, три основных прокси-сервера распределяют нагрузку на основе шаблонов URL, что повышает эффективность кэширования (на трёх серверах хранится только одна копия каждого документа, а не по одной копии на каждом). Нагрузка распределяется следующим образом:
| Прокси | Назначение |
|---|---|
| #1 | домен .com |
| #2 | домен .edu |
| #3 | все остальные домены |
| #4 | горячий резерв |
Все локальные запросы должны обрабатываться напрямую. Все прокси-серверы работают на порту 8080 (это необязательно: можно изменить порт, но не забудьте изменить настройки с обеих сторон). Обратите внимание, что в JavaScript строки можно объединять оператором +.
function FindProxyForURL(url, host) {
if (isPlainHostName(host) || dnsDomainIs(host, ".example.com")) {
return "DIRECT";
} else if (shExpMatch(host, "*.com")) {
return "PROXY proxy1.example.com:8080; PROXY proxy4.example.com:8080";
} else if (shExpMatch(host, "*.edu")) {
return "PROXY proxy2.example.com:8080; PROXY proxy4.example.com:8080";
}
return "PROXY proxy3.example.com:8080; PROXY proxy4.example.com:8080";
}
Пример 6
>Настройка прокси для определённого протокола
В функции FindProxyForURL() можно использовать большую часть стандартных возможностей JavaScript. Например, чтобы задавать разные прокси в зависимости от протокола, можно использовать функцию startsWith():
function FindProxyForURL(url, host) {
if (url.startsWith("http:")) {
return "PROXY http-proxy.example.com:8080";
} else if (url.startsWith("ftp:")) {
return "PROXY ftp-proxy.example.com:8080";
} else if (url.startsWith("gopher:")) {
return "PROXY gopher-proxy.example.com:8080";
} else if (url.startsWith("https:") || url.startsWith("snews:")) {
return "PROXY security-proxy.example.com:8080";
}
return "DIRECT";
}
Примечание: То же самое можно сделать с помощью описанной ранее функции shExpMatch().
Например:
if (shExpMatch(url, "http:*")) {
return "PROXY http-proxy.example.com:8080";
}
Примечание: Файл автоконфигурации может генерироваться сценарием CGI. Это полезно, например, если нужно, чтобы файл автоконфигурации работал по-разному в зависимости от IP-адреса клиента (переменная среды CGI REMOTE_ADDR).
Использование функций isInNet(), isResolvable() и dnsResolve() следует тщательно обдумать, поскольку для их работы требуется обращаться к DNS-серверу. Все остальные функции автоконфигурации лишь сравнивают строки и не требуют использования DNS-сервера. Если используется прокси, поиск DNS будет выполнять сам прокси, что удвоит нагрузку на DNS-сервер. В большинстве случаев эти функции не нужны для достижения желаемого результата.
История и реализация
Автоконфигурация прокси появилась в Netscape Navigator 2.0 в конце 1990-х годов, одновременно с JavaScript. Впоследствии открытие исходного кода Netscape привело к появлению самого Firefox.
Поэтому наиболее «оригинальная» реализация PAC и её библиотек JavaScript — это nsProxyAutoConfig.js, найденная в ранних версиях Firefox. Эти утилиты используются во многих других системах с открытым исходным кодом, в том числе в Chromium. Позднее Firefox встроил этот файл в ProxyAutoConfig.cpp в виде строкового литерала C++. Чтобы извлечь его в отдельный файл, достаточно скопировать этот фрагмент в JavaScript с директивой console.log для его вывода.
Microsoft, как правило, разрабатывала собственную реализацию. Ранее в их библиотеках возникали некоторые проблемы, но сейчас большинство из них устранено. Для поддержки IPv6 были добавлены новые функции с суффиксом «Ex», связанные с обработкой адресов. Эта возможность поддерживается Chromium, но пока не поддерживается Firefox (ошибка bugzilla #558253).
См. также
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file