Думаю, у многих сисадминов (и не только сисадминов), хоть раз настраивавших браузер на выход в Internet через прокси-сервер, возникал вопрос: что такое сценарий автоматической настройки и зачем его указывать в свойствах подключения браузера?
По сути, сценарий представляет из себя файл автоматической конфигурации с расширением *.pac, написанный на JavaScript. Он должен обязательно содержать в себе функцию:
function FindProxyForURL(url, host)
{
...
}
Эта функция должна быть НЕ включена в HTML. Выкладывается файл автоматической конфигурации (назовем его proxy.pac для примера) на веб-сайте, доступном без участия прокси-сервера (к которому есть прямой доступ, говоря иначе).
У многих, наверное, уже возник вопрос: какие же преимущества дает использование файла автоматической конфигурации? Думаю, вы сами поймете эти преимущества и по достоинству их оцените по ходу чтения статьи. Итак, опишу используемые при написании сценария функции и команды.
Команда DIRECT - устанавливает прямое соединение (без участия прокси).
Команда PROXY host:port - устанавливает соединение через прокси:порт.
Команда SOCKS host:port - устанавливает Socks-серевер для подключений.
Даже с помощью таких примитивных команд можно добиться гораздо большего результата, нежели при настройке браузера вручную. Вот попробуйте, например, в окне настроек подключения прописать сразу несколько прокси-серверов. Слабо? А вот файл автоматической конфигурации предоставляет такую возможность. Рассмотрим два примера:
Пример 1:
function FindProxyForURL(url, host)
{
PROXY proxy1.gorod.ru:8080; proxy2.gorod.ru:3128; DIRECT
}
Алгоритм действия браузера при таком содержимом файла-сценария будет таким: первым будет использоваться прокси-сервер proxy1.gorod.ru:8080. Если он не работает, то будет использоваться резервный прокси-сервер proxy2.gorod.ru:8080. В случае, если не работают оба прокси, используется прямое подключение DIRECT (без участия прокси).
Пример 2:
function FindProxyForURL(url, host)
{
PROXY proxy1.gorod.ru:8080; SOCKS socks.gorod.ru:1080
}
В этом случае при неработающем прокси proxy1.gorod.ru:8080 подключение будет идти через SOCKS-сервер socks.gorod.ru:1080.
Функция isPlainHostName(host)
Здесь host - имя хоста в адресе URL (исключая номер порта).
Функция возвращает два значения: true (истина) и false (ложь). True (истина) - если имя домена не содержится в имени хоста (нет точки).
Например:
isPlainHostName("www") - возвратит значение true (истина).
isPlainHostName("www.yandex.ru") - возвратит значение false (ложь).
Функция dnsDomainIs(host, domain)
host - имя хоста в адресе URL.
domain - имя домена для сравнения с именем хоста.
Функция возвращает значение true (истина), если имя хоста содержит в себе имя домена, и false (ложь), если не содержит.
Например:
dnsDomainIs("www.yandex.ru", ".yandex.ru") - значение true (истина).
dnsDomainIs("www", ".yandex.ru") - значение false (ложь).
dnsDomainIs("www.rambler.ru", ".yandex.ru") - значение false (ложь).
Функция localHostOrDomainIs(host, hostdom)
host - имя хоста в адресе URL.
hostdom - полное имя хоста для сравнения с именем хоста в адресе URL.
Функция возвращает значение true (истина), если имя хоста содержит в себе частично или полностью имя хоста для сравнения, и false (ложь), если не содержит.
Например:
localHostOrDomainIs("www.yandex.ru", "www.yandex.ru") - true (истина) - точное соответствие.
localHostOrDomainIs("www", "www.yandex.ru") - true (истина) - соответствует имя хоста.
localHostOrDomainIs("www.rambler.ru", "www.yandex.ru") - false (ложь) - имя домена не соответствует.
localHostOrDomainIs("webmaster.yandex.ru", "www.yandex.ru") - false (ложь) - имя хоста не соответствует.
Функция isResolvable(host)
host - имя хоста в адресе URL.
Функция возвращает значение true (истина), если имя хоста разрешается доменной системой имен (DNS), и false (ложь), если не разрешается.
Например:
isResolvable("www.yandex.ru") - true (истина), если разрешению не воспрепятствует файервол или какая-либо другая причина.
isResolvable("hochu.mnogo.deneg") - false (ложь).
Функция isInNet(host, pattern, mask)
host - DNS-имя или IP-адрес хоста. Если было введено DNS-имя, оно автоматически разрешится в IP-адрес этой функцией.
pattern - IP-адрес для сравнения.
mask - маска подсети сравнения.
Функция возвращает значение true (истина), если IP-адрес хоста совпадает с IP-адресом для сравнения или если IP-адрес хоста входит в подсеть сравнения, и false (ложь), если не совпадает или не входит.
Например:
isInNet(host, "198.162.24.79", "255.255.255.255") - true (истина), если IP-адрес указанного хоста равен 198.162.24.79, иначе false (ложь).
isInNet(host, "198.162.0.0", "255.255.0.0") - true (истина), если IP-адрес указанного хоста принадлежит области 198.162.*.*, иначе false (ложь).
Функция dnsResolve(host)
host - имя хоста для разрешения.
Функция разрешает DNS-имя хоста в IP-адрес с помощью службы DNS, и возвращает значение IP-адреса.
Например:
dnsResolve("istu.edu") - функция вернет строку "62.76.19.33".
Функция myIpAddress()
Возвращает в виде строки адрес компьютера, на котором запущен браузер.
Например:
myIpAddress() - вернет IP-адрес компьютера, на котором запущен браузер ("172.27.33.31" - мой IP-адрес).
Функция dnsDomainLevels(host)
host - имя хоста в адресе URL.
Возвращает значение уровня доменного имени (число точек в имени хоста).
Например:
dnsDomainLevels("www") - возвращает число "0".
dnsDomainLevels("www.mail.ru") - возвращает число "2".
Функция shExpMatch(str, shexp)
str - любая строка для сравнения (может быть URL или имя хоста).
shexp - выражение для сравнения.
Возвращает значение true (истина), если строка для сравнения содержит в себе выражение для сравнения. В противном случае возвращает false (ложь).
Например:
shExpMatch("http://www.site.ru/category/job/it/", "*/job/*") - возвращает значение true (истина).
shExpMatch("http://www.site.ru/category/game/mobila/", "*/job/*") - возвращает значение false (ложь).
Функция weekdayRange(wd1, wd2, gmt)
wd1 и wd2 - дни недели из списка: SUN MON TUE WED THU FRI SAT
gmt - параметр учета времени по Гринвичу.
Обязательным является только первый параметр wd1. Остальные могут отсутствовать. Если присутствует только первый параметр wd1, функция возвращает значение true (истина) только на протяжении указанного дня недели. Если присутсвует второй параметр wd2 - функция возвращает значение true (истина) с дня недели wd1 по день недели wd2. Параметр gmt при своем присутствии указывает на то, что время следует исчислять по Гринвичу, иначе время исчисляется по местному часовому поясу.
Например:
weekdayRange("MON", "FRI") - возвращает значение true (истина) с понедельника по пятницу включительно.
weekdayRange("MON", "FRI", "GMT") - возвращает значение true (истина) с понедельника по пятницу включительно по Гринвичу.
weekdayRange("SUN") - возвращает значение true (истина) на протяжении всего воскресенья.
weekdayRange("SUN", "GMT") - возвращает значение true (истина) на протяжении всего воскресенья по Гринвичу.
weekdayRange("FRI", "MON") - возвращает значение true (истина) с пятницы по понедельник включительно.
Функция dateRange. Возможные вариации этой функции:
dateRange(day)
dateRange(day1, day2)
dateRange(month)
dateRange(month1, month2)
dateRange(year)
dateRange(year1, year2)
dateRange(day1, month1, day2, month2)
dateRange(month1, year1, month2, year2)
dateRange(day1, month1, year1, day2, month2, year2)
dateRange(day1, month1, year1, day2, month2, year2, gmt)
day - день месяца с 1 по 31.
month - месяц из списка: JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC.
year - полный номер года (например, 2004, значение 04 не подойдет).
gmt - параметр учета времени по Гринвичу.
Функция возвращает значение true (истина) на протяжении всего указанного промежутка времени.
Например:
dateRange(1) - возвращает значение true (истина) каждого первого числа каждого месяца каждого года по местному часовому поясу.
dateRange(1, "GMT") - возвращает значение true (истина) каждого первого числа каждого месяца каждого года по Гринвичу.
dateRange(1, 15) - возвращает значение true (истина) первых 15 дней каждого месяца каждого года.
dateRange(24, "DEC") - возвращает значение true (истина) 24-го декабря каждого года.
dateRange(24, "DEC", 2005) - возвращает значение true (истина) 24-го декабря 2005 года.
dateRange("JAN", "MAR") - возвращает значение true (истина) с января по март каждого года.
dateRange(1, "JAN", 15, "AUG") - возвращает значение true (истина) с 1-го января по 15-ое августа каждого года.
dateRange(1, "JUN", 15, 2005, "AUG", 2005) - возвращает значение true (истина) с 1-го июня по 15-ое августа 2005 года.
dateRange("OCT", 2005, "MAR", 2006) - возвращает значение true (истина) с октября 2005 года по март 2006 года включительно.
dateRange(2005) - возвращает значение true (истина) на протяжении всего 2005 года.
dateRange(2005, 2007) - возвращает значение true (истина) с 2005 года по 2007 год включительно (с начала 2005 года до конца 2007 года).
Функция timeRange. Ее возможные вариации:
timeRange(hour)
timeRange(hour1, hour2)
timeRange(hour1, min1, hour2, min2)
timeRange(hour1, min1, sec1, hour2, min2, sec2)
timeRange(hour1, min1, sec1, hour2, min2, sec2, gmt)
hour - часы с 0 до 23. (полночь - 0 часов).
min - минуты с 0 по 59.
sec - секунды с 0 по 59.
gmt - параметр учета времени по Гринвичу.
Функция возвращает значение true (истина) на протяжении всего указанного промежутка времени.
Например:
timerange(12) - возвращает значение true (истина) до 13 часов (1 часа дня).
timerange(12, 13) - то же самое, что и выше.
timerange(12, "GMT") - возвращает значение true (истина) до 13 часов (1 часа дня) по Гринвичу.
timerange(9, 17) - возвращает значение true (истина) с 9 до 17 часов.
timerange(8, 30, 17, 00) - возвращает значение true (истина) с 8 часов 30 минут до 17 часов 00 минут.
timerange(0, 0, 0, 0, 0, 30) - возвращает значение true (истина) в течении первых 30-ти секунд каждую полночь.
В завершение я рассмотрю еще несколько примеров.
Пример 1
function FindProxyForURL(url, host)
{
if (isPlainHostName(host) ||
dnsDomainIs(host, ".domen.ru"))
return "DIRECT";
else
return "PROXY w3proxy.domen.ru:8080; DIRECT";
}
Работать такой сценарии будет следующим образом. Если в имени хоста (host) не содержится имени домена или имя хоста принадлежит домену domen.ru, произойдет прямое подключение (без участия прокси). Иначе подключение к Internet идет через прокси w3proxy.domen.ru:8080. Если прокси не работает - идет прямое подключение DIRECT.
Пример 2
function FindProxyForURL(url, host)
{
if (isResolvable(host))
return "DIRECT";
else
return "PROXY proxy.domain.com:8080";
}
В этом примере подключение через прокси proxy.domain.com:8080 идет только в случае, если служба DNS не может разрешить имя хоста (host).
Рассмотрим немногим более сложный случай:
function FindProxyForURL(url, host)
{
if (isPlainHostName(host) ||
dnsDomainIs(host, ".domain.com") ||
isResolvable(host))
return "DIRECT";
else
return "PROXY proxy.domain.com:8080";
}
В этом сценарии алгоритм действий следующий: если в имени хоста (host) не содержится имени домена, или имя хоста принадлежит домену domain.com, или имя хоста может быть разрешено службой DNS - идет прямое подключение (DIRECT). В противном случае подключение идет через прокси proxy.domain.com:8080.
Пример 3
function FindProxyForURL(url, host)
{
if (isInNet(host, "198.95.0.0", "255.255.0.0"))
return "DIRECT";
else
return "PROXY proxy.domain.com:8080";
}
Здесь, если IP-адрес хоста принадлежит области 198.95.*.*, идет прямое подключение, иначе - через прокси proxy.domain.com:8080.
function FindProxyForURL(url, host)
{
if (isPlainHostName(host) ||
dnsDomainIs(host, ".domain.com") ||
isInNet(host, "198.95.0.0", "255.255.0.0"))
return "DIRECT";
else
return "PROXY proxy.domain.com:8080";
}
Здесь прямое подключение идет в случаях, когда в имени хоста не содержится имени домена, когда имя хоста принадлежит домену domain.com или когда IP-адрес хоста принадлежит области 198.95.*.*. Во всех остальных случаях подключение идет через прокси proxy.domain.com:8080.
Пример 4
Тут задача несколько сложнее. Необходимо распределить нагрузку на прокси-сервера в зависимости от доменного имени. Нужно, чтобы при доменных именах *.com связь шла через прокси proxy1.domain.com:8080, при именах *.edu - через прокси proxy2.domain.com:8080, при прочих доменных именах - через прокси proxy3.domain.com:8080, и во всех трех предыдущих случаях в качестве альтернативного использовался прокси proxy4.domain.com:8080. Помимо этого, нужно чтобы при принадлежности хоста к домену domain.com происходило прямое подключение. Сценарий, реализующий решение такой задачи, приведен ниже.
function FindProxyForURL(url, host)
{
if (isPlainHostName(host) || dnsDomainIs(host, ".domain.com"))
return "DIRECT";
else if (shExpMatch(host, "*.com"))
return "PROXY proxy1.domain.com:8080; " +
"PROXY proxy4.domain.com:8080";
else if (shExpMatch(host, "*.edu"))
return "PROXY proxy2.domain.com:8080; " +
"PROXY proxy4.domain.com:8080";
else
return "PROXY proxy3.domain.com:8080; " +
"PROXY proxy4.domain.com:8080";
}
Пример 5
В этом примере мы рассмотрим, как можно назначить различные прокси в зависимости от протоколов подключения. Для этого используем функцию url.substring(a,b). Эта функция возвращает в виде строки b букв из набранного в браузере адреса URL. То есть, если мы набрали адрес http://www.yandex.ru/, то функция url.substring(0,5) вернет нам строку "http:" (состоящую из первых 5 символов). Если мы заменим в функции число 5 на 7 - url.substring(0,7), то при том же введенном адресе функция вернет нам строку "http://" и т.д.
Итак, нам нужно, что бы при протоколе HTTP подключение шло через прокси http-proxy.domain.com:8080, при FTP - через ftp-proxy.domain.com:8080, при GOPHER - через gopher-proxy.domain.com:8080 и при протколах HTTPS и SNEWS - через security-proxy.domain.com:8080. В противном случае должно инициироваться прямое подключение (DIRECT). Решение будет следующим:
function FindProxyForURL(url, host)
{
if (url.substring(0, 5) == "http:")
{
return "PROXY http-proxy.mydomain.com:8080";
}
else if (url.substring(0, 4) == "ftp:")
{
return "PROXY ftp-proxy.mydomain.com:8080";
}
else if (url.substring(0, 7) == "gopher:")
{
return "PROXY gopher-proxy.mydomain.com:8080";
}
else if (url.substring(0, 6) == "https:" ||
url.substring(0, 6) == "snews:")
{
return "PROXY security-proxy.mydomain.com:8080";
}
else
{
return "DIRECT";
}
}
В принципе, для решения этой задачи можно использовать и функцию shExpMatch(). Тогда строки для HTTP протокола будут выглядеть так (как для остальных протоколов, я полагаю, вполне додумаетесь сами):
...
if (shExpMatch(url, "http:*"))
{
return "PROXY http-proxy.domain.com:8080;
}
...
Функцию shExpMatch() можно использовать и для ограничения доступа пользователей к неугодным вам сайтам. Правда, это будет весьма неэффективное и трудоемкое решение данной задачи, но, за неимением лучшего, это выход. Для примера рассмотрим сценарий, запрещающий доступ к сайтам, содержащим в своем адресе URL слова sex, porno, xxx, chat.
function FindProxyForURL(url, host)
{
if (shExpMatch(host, "*sex*") || shExpMatch(host, "*porno*")
|| shExpMatch(host, "*xxx*") || shExpMatch(host, "*chat*"))
{
return "PROXY zapret.domen.ru:80";
}
else if (dnsDomainIs(host, ".domen.ru"))
{
return "DIRECT";
}
else
{
return "PROXY proxy.domen.ru:8080";
}
}
На хосте zapret.domen.ru можно создать веб-сайт с запрещающей страничкой, объясняющей пользователям, почему доступ к данной информации запрещен, либо вместо zapret.domen.ru можно указать заведомо не существующий хост, и тогда вместо запрещенных адресов URL пользователи будут получать страничку с сообщением о DNS-ошибке.
На этом все!
[Вернутся к списку статей]
© Drakon, 2005-2006
Сайт управляется системой
uCoz