PAC: различия между версиями

Материал из ALT Linux Wiki
 
(не показано 16 промежуточных версий этого же участника)
Строка 1: Строка 1:
==Введение==
==История==
'''Файлы Proxy Auto-Config''' (сокращенно '''PAC-файлы''') и поддерживающие их браузеры были впервые созданы компанией Netscape в 1995-1996 гг. для обеспечения большей гибкости при перенаправлении трафика веб-браузера через прокси-сервер, расположенный выше по маршруту сети.  
'''Файлы Proxy Auto-Config''' (сокращенно '''PAC-файлы''') и поддерживающие их браузеры были впервые созданы компанией Netscape в 1995-1996 гг. для обеспечения большей гибкости при перенаправлении трафика веб-браузера через прокси-сервер, расположенный выше по маршруту сети.  


Строка 81: Строка 81:


====dnsDomainIs====
====dnsDomainIs====
Evaluates hostnames and returns true if hostnames match. Used mainly to match and exception individual hostnames.
Оценивает имена хостов и возвращает true, если имена хостов совпадают. Используется в основном для сопоставления и исключения отдельных имен хостов.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If the hostname matches google.com or www.google.com  
// Если имя хоста совпадает с google.com или www.google.com,
// send direct to the Internet.  
// выполняется перенаправлние в Интернет.
if (dnsDomainIs(host, "google.com") || dnsDomainIs(host, "www.google.com"))  
if (dnsDomainIs(host, "google.com") || dnsDomainIs(host, "www.google.com"))  
     return "DIRECT";
     return "DIRECT";
Строка 90: Строка 90:


====shExpMatch====
====shExpMatch====
Will attempt to match hostname or URL to a specified shell expression, and returns true if matched.
Попытается сопоставить имя хоста или URL с указанным выражением оболочки и в случае совпадения возвратит true.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// Any requests with a hostname ending with the extension .local
// Все запросы с именем хоста, заканчивающимся расширением .local,
// will be sent direct to the Internet.
// будут направлены напрямую в Интернет.
if (shExpMatch(host, "*.local"))
if (shExpMatch(host, "*.local"))
     return "DIRECT";
     return "DIRECT";
// A request for the host vpn.domain.com or any request for a file or folder in the
// Запрос к хосту vpn.domain.com или любой запрос к файлу или папке в
// location http://abcdomain.com/folder/ will be sent direct to the Internet.
// расположении http://abcdomain.com/folder/ будет направлен напрямую в Интернет.
if (shExpMatch(host, "vpn.domain.com") ||
if (shExpMatch(host, "vpn.domain.com") ||
     shExpMatch(url, "http://abcdomain.com/folder/*"))
     shExpMatch(url, "http://abcdomain.com/folder/*"))
Строка 104: Строка 104:


====isInNet====
====isInNet====
This function evaluates the IP address of a hostname, and if within a specified subnet returns true. If a hostname is passed the function will resolve the hostname to an IP address.
Данная функция определяет IP-адрес имени хоста и, если он находится в пределах указанной подсети, возвращает true. Если передается имя хоста, то функция преобразует его в IP-адрес.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If IP of requested website website falls within IP range, send direct to the Internet.  
// Если IP-адрес запрашиваемого сайта попадает в указанный диапазон IP-адресов, то происходит перенаправление в Интернет.  
if (isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0"))  
if (isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0"))  
     return "DIRECT";
     return "DIRECT";
Строка 112: Строка 112:


====myIpAddress====
====myIpAddress====
Returns the IP address of the host machine. However, with the rise of IPv6 and no ability to distinguish between multiple active network adapters, this function should be avoided.
Возвращает IP-адрес хост-машины. Однако с появлением протокола IPv6 и отсутствием возможности различать несколько активных сетевых адаптеров от использования этой функции следует отказаться.
 
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If the machine requesting a website falls within IP range,  
// Если машина, запрашивающая сайт, попадает в диапазон IP-адресов,
// send traffic via proxy 10.10.5.1 running on port 8080.  
// отправьте трафик через прокси 10.10.5.1, работающий на порту 8080.  
if (isInNet(myIpAddress(), "10.10.1.0", "255.255.255.0"))  
if (isInNet(myIpAddress(), "10.10.1.0", "255.255.255.0"))  
     return "PROXY 10.10.5.1:8080";
     return "PROXY 10.10.5.1:8080";
Строка 121: Строка 122:


====dnsResolve====
====dnsResolve====
Resolves a hostname to an IP address. Note that browsers do not perform unique DNS lookups for the same host per function-use – local DNS caching is respected and multiple uses of this function will not have a DNS load or performance impact.
Данная функция преобразовывает имя хоста в IP-адрес. Обратите внимание, что браузеры не выполняют уникальный поиск DNS для одного и того же хоста при каждом использовании функции - соблюдается локальное кэширование DNS, и многократное использование этой функции не повлияет на нагрузку DNS или производительность.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// Example #1 - If IP of the requested host falls within any of the ranges specified, send direct.  
// Пример №1 - Если IP запрашиваемого хоста попадает в любой из указанных диапазонов, отправлять напрямую.  
if (isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0") ||  
if (isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0") ||  
     isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") ||  
     isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") ||  
Строка 129: Строка 130:
     isInNet(dnsResolve(host), "127.0.0.0", "255.255.255.0"))  
     isInNet(dnsResolve(host), "127.0.0.0", "255.255.255.0"))  
     return "DIRECT";
     return "DIRECT";
// Example #2 - If IP of the requested host falls within any of the ranges specified, send direct.  
// Пример №2 - Если IP запрашиваемого хоста попадает в любой из указанных диапазонов, то отправлять напрямую.  
resolvedHost = dnsResolve(host);
if (isInNet(resolvedHost, "10.0.0.0", "255.0.0.0") ||  
if (isInNet(resolvedHost, "10.0.0.0", "255.0.0.0") ||  
     isInNet(resolvedHost, "172.16.0.0", "255.240.0.0") ||  
     isInNet(resolvedHost, "172.16.0.0", "255.240.0.0") ||  
Строка 139: Строка 139:


====isPlainHostName====
====isPlainHostName====
This function will return true if the hostname contains no dots, e.g. http://intranet – useful when applying exceptions for internal websites.
Данная функция возвращает true, если имя хоста не содержит точек, например, http://intranet - полезно при применении исключений для внутренних сайтов.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If user requests plain hostnames, e.g. http://intranet/, // http://webserver-name01/, send direct.  
// Если пользователь запрашивает простые имена хостов, например, http://intranet/, // http://webserver-name01/, то отправлять напрямую в Интернет.  
if (isPlainHostName(host))  
if (isPlainHostName(host))  
     return "DIRECT";
     return "DIRECT";
Строка 147: Строка 147:


====localHostOrDomainIs====
====localHostOrDomainIs====
Evaluates hostname and only returns true if exact hostname match is found.
Данная функция оценивает имя хоста и возвращает true только в том случае, если найдено точное совпадение в его имени.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If the Host requested is "www" or "www.google.com", send direct.  
// Отправить напрямую, если запрашиваемый хост - "www" или "www.google.com".  
if (localHostOrDomainIs(host, "www.google.com"))  
if (localHostOrDomainIs(host, "www.google.com"))  
     return "DIRECT";
     return "DIRECT";
Строка 155: Строка 155:


====isResolvable====
====isResolvable====
Attempts to resolve a hostname to an IP address and returns true if successful.
Попытаться преобразовать имя хоста в IP-адрес и в случае успеха вернуть true.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If the host requested can be resolved by DNS, send via proxy1.example.com.  
// Если запрашиваемый хост может быть разрешен с помощью DNS, отправьте его через proxy1.example.com.  
if (isResolvable(host))  
if (isResolvable(host))  
     return "PROXY proxy1.example.com:8080";
     return "PROXY proxy1.example.com:8080";
Строка 163: Строка 163:


====dnsDomainLevels====
====dnsDomainLevels====
This function returns the number of DNS domain levels (number of dots) in the hostname. Can be used to exception internal websites which use short DNS names, e.g. http://intranet
Данная функция возвращает количество уровней DNS-домена (количество точек) в имени хоста. Может использоваться для исключения внутренних сайтов, использующих короткие DNS-имена, например, http://intranet.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If hostname contains any dots, send via proxy1.example.com, otherwise send direct.  
// Если имя хоста содержит точки, отправлять через proxy1.example.com, в противном случае использовать прямое соединение.  
if (dnsDomainLevels(host) > 0)  
if (dnsDomainLevels(host) > 0)  
     return "PROXY proxy1.example.com:8080";  
     return "PROXY proxy1.example.com:8080";  
Строка 172: Строка 172:


====weekdayRange====
====weekdayRange====
Allows rules to be time based, e.g. only return a proxy during specific days.
Позволяет устанавливать правила по времени, например, разрешать работу с прокси только в определенные дни.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If during the period of Monday to Friday, proxy1.example.com will be returned, otherwise
//Согласно указанным параметрам, с понедельника по пятницу будет использоваться прокси proxy1.example.com,
// users will go direct for any day outside this period.  
// в противном случае пользователи будут использовать прямое соединение, в любой день за пределами данного периода.  
if (weekdayRange("MON", "FRI"))  
if (weekdayRange("MON", "FRI"))  
     return "PROXY proxy1.example.com:8080";  
     return "PROXY proxy1.example.com:8080";  
Строка 182: Строка 182:


====dateRange====
====dateRange====
Allows rules to be time based, e.g. only return a proxy during specific months.
Позволяет создавать правила, основанные на времени, например, разрешать использование прокси только в определенные месяцы.
 
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If during the period of January to March, proxy1.example.com will be returned, otherwise
// В данном случае, в период с января по март, будет использоваться прокси proxy1.example.com,
// users will go direct for any month outside this period.  
// в противном случае пользователи будут использовать прямое соединение в любой месяц за пределами этого периода.
if (dateRange("JAN", "MAR"))  
if (dateRange("JAN", "MAR"))  
     return "PROXY proxy1.example.com:8080";  
     return "PROXY proxy1.example.com:8080";  
Строка 192: Строка 193:


====timeRange====
====timeRange====
Allows rules to be time based, e.g. only return a proxy during specific hours.
Позволяет устанавливать правила с учетом времени, например, разрешать работу с прокси только в определенные часы.
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
// If during the period 8am to 6pm, proxy1.example.com will be returned, otherwise
//В период с 8 утра до 6 вечера, будет использоваться прокси proxy1.example.com,
// users will go direct for any time outside this period.  
//в остальное время будет использовано прямое соединение.  
if (timeRange(8, 18))  
if (timeRange(8, 18))  
     return "PROXY proxy1.example.com:8080";  
     return "PROXY proxy1.example.com:8080";  

Текущая версия от 15:34, 24 ноября 2023

История

Файлы Proxy Auto-Config (сокращенно PAC-файлы) и поддерживающие их браузеры были впервые созданы компанией Netscape в 1995-1996 гг. для обеспечения большей гибкости при перенаправлении трафика веб-браузера через прокси-сервер, расположенный выше по маршруту сети.

Возможности того времени позволяли пользователю или ИТ-администратору настраивать браузер на пересылку трафика через прокси-сервер, явно определяя хост, порт и список явных исключений или протоколов. Хотя это было весьма полезно, такая конфигурация не поддерживала и до сих пор не поддерживает переключение между прокси-серверами и не имеет какого-либо разумного управления трафиком. Например, если прокси содержит IP-адрес сервера, а пользователь вводит полное доменное имя (FQDN), указывающее на этот IP-адрес, то совпадения не будет, и трафик все равно пойдет через прокси.

Вместо того чтобы определять правила переадресации прокси непосредственно в самом браузере, компания Netscape выбрала в качестве основы язык программирования JavaScript, основанный на стандартах, и создала набор гибких функций на базе JavaScript, которые можно использовать в файле, обычно предоставляемом веб-сервером (хотя он мог распологаться и на локальной файловой системе), определяющем набор правил для веб-браузера по переадресации веб-трафика через прокси. Это позволяет управлять трафиком браузера из единого централизованного файла без необходимости вносить изменения на каждое пользовательское устройство.

В Netscape были реализованы функции, позволяющие создавать правила для FQDN, URL и IP-адресов, к которым осуществляется доступ, а также вспомогательные функции для преобразования FQDN в IP-адрес, определения принадлежности IP-адреса к определенной подсети, а также менее распространенные возможности, поддерживающие правила на основе даты и времени и IP-адреса устройства. Кроме того, с помощью PAC-файлов можно настроить несколько прокси-серверов для резервирования и восстановления работоспособности.

Благодаря этим возможностям пользователь или администратор может легко перенаправлять трафик на вышестоящий прокси-сервер, автоматически обходить трафик локальной сети, а также реализовать обход отказа между прокси-серверами.

Пример PAC-файла

PAC-файлы, написанные на языке JavaScript, могут быть очень мощными, но эти возможности также могут привести к усложнению и раздуванию кода, поэтому рекомендуется разрабатывать PAC-файл, постоянно помня о двух вопросах:

  • Какой трафик должен и не должен передаваться через прокси?
  • Будет ли текущая и будущая поддержка PAC-файла осуществляться людьми, имеющими опыт работы с JavaScript?

Особенности файла PAC

  • Правила обхода прокси-сервера для частных IP-сетей, внутренних имен хостов и хостов с расширением домена .local.
  • Пример правила обхода имени хоста.
  • Пример правила обхода протоколов и URL.
  • Пример правила обхода IP-маршрутизации на основе машин.
  • Правило обхода прокси по умолчанию, если все вышеперечисленные правила не подходят.

Пример файла PAC

Приведенный ниже пример PAC-файла демонстрирует свою гибкость, разборчивость и простоту обновления. Такие простые блоки кода могут служить примером того, что они могут быть скопированы, отредактированы и созданы людьми с ограниченным опытом работы с JavaScript.

function FindProxyForURL(url, host) { 
// If the hostname matches, send direct. 
    if (dnsDomainIs(host, "intranet.domain.com") || 
        shExpMatch(host, "(*.abcdomain.com|abcdomain.com)")) 
        return "DIRECT"; 

// If the protocol or URL matches, send direct. 
    if (url.substring(0, 4)=="ftp:" || 
        shExpMatch(url, "http://abcdomain.com/folder/*")) 
        return "DIRECT"; 

// If the requested website is hosted within the internal network, send direct. 
    if (isPlainHostName(host) || 
        shExpMatch(host, "*.local") || 
        isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0") || 
        isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") || 
        isInNet(dnsResolve(host), "192.168.0.0", "255.255.0.0") || 
        isInNet(dnsResolve(host), "127.0.0.0", "255.255.255.0")) 
        return "DIRECT"; 

// If the IP address of the local machine is within a defined 
// subnet, send to a specific proxy. 
    if (isInNet(myIpAddress(), "10.10.5.0", "255.255.255.0")) 
        return "PROXY 1.2.3.4:8080"; 

// DEFAULT RULE: All other traffic, use below proxies, in fail-over order. 
    return "PROXY 4.5.6.7:8080; PROXY 7.8.9.10:8080"; }

Рекомендации

При развертывании правил для URL и хостов необходимо следить за тем, чтобы правила были как можно более явными. В приведенных ниже примерах подробно описано, как должны быть реализованы правила для хостов и URL.

if (dnsDomainIs(host, "abcdomain.com") || dnsDomainIs(host, "www.abcdomain.com"))
        return "DIRECT";
if (shExpMatch(url, "http://abcdomain.com/folder/*"))
        return "DIRECT";

Предостережения

Приведенный ниже код является примером, который может иметь непредвиденные последствия из-за широкой интерпретации при использовании функции shExpMatch с подстановочными знаками и именами хостов.

// Would send both of the following requests direct to the Internet:
// 1. www.hotmail.com 2. phishing-scam.com?email=someone@hotmail.com
if (shExpMatch(url, "*hotmail.com*"))
        return "DIRECT";
// Would send only traffic to the the host and subdomains of hotmail.com
if (shExpMatch(host, "*.hotmail.com"))
        return "DIRECT";

Функции PAC

Все современные браузеры поддерживают набор функций, явно предназначенных для использования в PAC-файлах. PAC-файлы работают в "песочнице", и хотя многие стандартные функции JavaScript могут поддерживаться, "песочница" не позволяет PAC-файлам выполнять действия, основанные на содержимом веб-страницы, а также не дает им доступа к функциям, позволяющим получить доступ к пользовательскому агенту браузера или узнать публичный IP-адрес пользователя.

Функции

dnsDomainIs

Оценивает имена хостов и возвращает true, если имена хостов совпадают. Используется в основном для сопоставления и исключения отдельных имен хостов.

// Если имя хоста совпадает с google.com или www.google.com, 
// выполняется перенаправлние в Интернет.
if (dnsDomainIs(host, "google.com") || dnsDomainIs(host, "www.google.com")) 
    return "DIRECT";

shExpMatch

Попытается сопоставить имя хоста или URL с указанным выражением оболочки и в случае совпадения возвратит true.

// Все запросы с именем хоста, заканчивающимся расширением .local,
// будут направлены напрямую в Интернет.
if (shExpMatch(host, "*.local"))
    return "DIRECT";
// Запрос к хосту vpn.domain.com или любой запрос к файлу или папке в
// расположении http://abcdomain.com/folder/ будет направлен напрямую в Интернет.
if (shExpMatch(host, "vpn.domain.com") ||
    shExpMatch(url, "http://abcdomain.com/folder/*"))
    return "DIRECT";

isInNet

Данная функция определяет IP-адрес имени хоста и, если он находится в пределах указанной подсети, возвращает true. Если передается имя хоста, то функция преобразует его в IP-адрес.

// Если IP-адрес запрашиваемого сайта попадает в указанный диапазон IP-адресов, то происходит перенаправление в Интернет. 
if (isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0")) 
    return "DIRECT";

myIpAddress

Возвращает IP-адрес хост-машины. Однако с появлением протокола IPv6 и отсутствием возможности различать несколько активных сетевых адаптеров от использования этой функции следует отказаться.

// Если машина, запрашивающая сайт, попадает в диапазон IP-адресов,
// отправьте трафик через прокси 10.10.5.1, работающий на порту 8080. 
if (isInNet(myIpAddress(), "10.10.1.0", "255.255.255.0")) 
    return "PROXY 10.10.5.1:8080";

dnsResolve

Данная функция преобразовывает имя хоста в IP-адрес. Обратите внимание, что браузеры не выполняют уникальный поиск DNS для одного и того же хоста при каждом использовании функции - соблюдается локальное кэширование DNS, и многократное использование этой функции не повлияет на нагрузку DNS или производительность.

// Пример №1 - Если IP запрашиваемого хоста попадает в любой из указанных диапазонов, отправлять напрямую. 
if (isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0") || 
    isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") || 
    isInNet(dnsResolve(host), "192.168.0.0", "255.255.0.0") || 
    isInNet(dnsResolve(host), "127.0.0.0", "255.255.255.0")) 
    return "DIRECT";
// Пример №2 - Если IP запрашиваемого хоста попадает в любой из указанных диапазонов, то отправлять напрямую. 
if (isInNet(resolvedHost, "10.0.0.0", "255.0.0.0") || 
    isInNet(resolvedHost, "172.16.0.0", "255.240.0.0") || 
    isInNet(resolvedHost, "192.168.0.0", "255.255.0.0") || 
    isInNet(resolvedHost, "127.0.0.0", "255.255.255.0")) 
    return "DIRECT";

isPlainHostName

Данная функция возвращает true, если имя хоста не содержит точек, например, http://intranet - полезно при применении исключений для внутренних сайтов.

// Если пользователь запрашивает простые имена хостов, например, http://intranet/, // http://webserver-name01/, то отправлять напрямую в Интернет. 
if (isPlainHostName(host)) 
    return "DIRECT";

localHostOrDomainIs

Данная функция оценивает имя хоста и возвращает true только в том случае, если найдено точное совпадение в его имени.

// Отправить напрямую, если запрашиваемый хост - "www" или "www.google.com". 
if (localHostOrDomainIs(host, "www.google.com")) 
    return "DIRECT";

isResolvable

Попытаться преобразовать имя хоста в IP-адрес и в случае успеха вернуть true.

// Если запрашиваемый хост может быть разрешен с помощью DNS, отправьте его через proxy1.example.com. 
if (isResolvable(host)) 
    return "PROXY proxy1.example.com:8080";

dnsDomainLevels

Данная функция возвращает количество уровней DNS-домена (количество точек) в имени хоста. Может использоваться для исключения внутренних сайтов, использующих короткие DNS-имена, например, http://intranet.

// Если имя хоста содержит точки, отправлять через proxy1.example.com, в противном случае использовать прямое соединение. 
if (dnsDomainLevels(host) > 0) 
    return "PROXY proxy1.example.com:8080"; 
        else return "DIRECT";

weekdayRange

Позволяет устанавливать правила по времени, например, разрешать работу с прокси только в определенные дни.

//Согласно указанным параметрам, с понедельника по пятницу будет использоваться прокси proxy1.example.com,
// в противном случае пользователи будут использовать прямое соединение, в любой день за пределами данного периода. 
if (weekdayRange("MON", "FRI")) 
    return "PROXY proxy1.example.com:8080"; 
        else return "DIRECT";

dateRange

Позволяет создавать правила, основанные на времени, например, разрешать использование прокси только в определенные месяцы.

// В данном случае, в период с января по март, будет использоваться прокси proxy1.example.com,
// в противном случае пользователи будут использовать прямое соединение в любой месяц за пределами этого периода.
if (dateRange("JAN", "MAR")) 
    return "PROXY proxy1.example.com:8080"; 
        else return "DIRECT";

timeRange

Позволяет устанавливать правила с учетом времени, например, разрешать работу с прокси только в определенные часы.

//В период с 8 утра до 6 вечера, будет использоваться прокси proxy1.example.com,
//в остальное время будет использовано прямое соединение. 
if (timeRange(8, 18)) 
    return "PROXY proxy1.example.com:8080"; 
        else return "DIRECT";

Источник