ПРОЕКТЫ 


  АРХИВ 


  СТАТЬИ 


Антиспам-технологии 

Internet, WWW, UNIX 

Фото 

  ПЕРСОНАЛЬНОЕ 


  ПРОГРАММЫ 



ПИШИТЕ
ПИСЬМА

беспроводные звонки купить













     СТАТЬИ :: Internet, WWW, UNIX

How To Make a Transparent WWW Proxy

[english version]

Введение в проблему

В некоторый момент я обнаружил, что большую часть входящего траффика в моей сети составляет WWW. При этом клиенты не пользовались Proxy, хотя это заметно ускорило бы их работу (hit ratio составляет у нас почти 50%), а пройтись по всем клиентам и поправить настройки их броузеров я не имел возможности (да и желания тоже). Думаю, подобные проблемы часто возникают и у ISP, когда поправить настройки клиентов просто нельзя.

Почитав Squid'овский FAQ, я нашел там описание того, как заставить клиентов насильно использовать Proxy, проблема заключалась только в том, что предложенный способ не работал. С другой стороны, я знал, что в RadioMSU таки заставили работать всех своих клиентов через Proxy.
После консультации с Ярославом Тихим все стало на свои места и окончательное решение было сделано за пару часов.

Как это у меня работает

Действующие лица и исполнители:

  • Роутер Cisco 2511 производства Cisco Systems. К нему подключены все клиенты (локальная сеть на Ethernet и клиенты по Dialup), внешний канал на Demos тоже включен туда же. Для простоты представим, что LAN имеет адреса/маску 192.168.1/24, а dialup-клиенты - 192.168.2/24.
  • Машина на которой установлен кэширующий proxy - Pentium-200, 64M RAM, 8Gb дисков. Работает под управлением FreeBSD 2.2.5. На машине установлен IPFilter 3.2.3 и Squid 1.NOVM.20. Для простоты изложения, представим, что адрес этой машины - 192.168.1.1

Настройки

На Cisco
Нужно завернуть все транзитные пакетики с destination eq 80 на Proxy. Это делается примерно так:
! Prevent loops
access-list 101 deny tcp host 192.168.1.1 any eq 80
! All other clients:
access-list 101 permit tcp 192.168.1.0 0.0.0.255 any eq 80
access-list 101 permit tcp 192.168.2.0 0.0.0.255 any eq 80
! Route-map
route-map forced-proxy permit 10
 match ip address 101
 set ip next-hop 192.168.1.1
!
! Интерфейсы:
! LAN
interface Ethernet 0
 ip policy route-map forced-proxy
!
! Dialup
interface Group-Async 1
 group-range 1 16
 ip policy route-map forced-proxy
	
На машине с proxy
Первым делом нужно завернуть приходящие на 80-й порт пакеты на proxy. Предполагая, что proxy работает на порту 3128, это делается как-то так:
ipnat -f - <<EOM
rdr ed0 192.168.1.1/32 port 80 -> 192.168.1.1 port 80
rdr ed0 0.0.0.0/0 port 80 -> 192.168.1.1 port 3128
EOM
	
Первое правило позволяет работать локальному WWW-серверу - он будет продолжать получать свои пакетики. Вторая строчка перенаправит все остальные пакеты с destination port 80 на локальный Squid.

В squid.conf пишутся строчки вида

httpd_accel www.your.domain 80
httpd_accel_with_proxy on
httpd_accel_uses_host_header on
	
В FAQ рекомендовано вместо имени сервера в строчке httpd_accel писать слово virtual. Это - неверно, во всяком случае для Squid-1.NOVM.18..20. Проблема в том, что в этом режиме Squid определяет destination server по вызову getsockname(2), однако этим вызовом он может получить только один из своих адресов, а это явно не подходит к условиям задачи.
Получившаяся конструкция работает по такой вот схеме (я рисовал эту картинку минут 10 и хотя она тут почти не нужна, не пропадать же добру):
Data Flow

Улучшения

При такой настройке, адрес реального сервера к которому обращается пользователь будет браться из заголовка Host: HTTP-запроса. Для подавляющего большинства клиентов этого достаточно - все сколько-нибудь распространенные броузеры этот заголовок ставят. Однако хочется большего.

В-принципе, можно было бы написать отдельную маленькую программу (вместо proxy), которая спрашивала бы у IPFilter реальный destination-address пакета, формировала бы заголовок Host: и отдавала бы все это кэширующему proxy. Однако такой подход имеет свои недостатки - в логах Squid будут только локальные адреса и сопоставить, скажем, Hit Ratio с конкретным клиентом будет непросто. Я пошел по другому пути и встроил необходимую функциональность прямо в Squid. Патч для версии 1.NOVM.20 вы можете взять прямо отсюда ( для версии 1.NOVM.20, для версии 1.NOVM.22). (Необходимые замечания: Патч предполагает, что *.h-файлы от ipfilter лежат у вас в /sys/netinet, а все прочие добавленные includes необходимы на FreeBSD 2.2.x, а про прочие системы я не в курсе).

После установки этого патча, Squid начнет понимать директиву httpd_accel_uses_ipfilter_redirect в конфигурационном файле. Использовать ее нужно так:

httpd_accel_uses_ipfilter_redirect on
    
И еще одно замечание - для пользователя с правами которого работает squid файл /dev/ipnat должен быть доступен на чтение.

В squid 2.x эта функциональность присутствует, если запускать configure --enable-ipf-transparent, при этом никаких дополнительных директив не нужно, это включено по умолчанию.

После всех этих изменений все работает и без заголовка Host. Правда требование, чтобы клиент был HTTP-1.x (а не HTTP/0.9) остается, но уж HTTP/0.9 клиентов я вообще очень давно не встречал.

Возможные проблемы

Возможные проблемы связаны с ICMP-сообщениями 'packet too big'. Дело тут вот в чем. Допустим, между HTTP-Proxy и клиентом есть линк с маленьким MTU, при этом и клиент и proxy живут на media с большим MTU. Представим, что proxy начинает отвечать клиенту с каким-то размером пакета, который не пролезет через этот тонкий линк. Ipnat подменит source-address у этого пакета на IP-address сервера к которому обращался клиент. Если на пути встретится слишком маленький MTU, то ICMP-сообщение об этом уедет на какой- нибудь www.microsoft.com, которому он совершенно ни к чему.

Идея лечения понятна - завернуть на той же Cisco все ICMP-пакеты на хост с WWW-proxy, там их проверять на предмет соответствия с какой-то строчкой из таблицы трансляции Ipnat, все которые "неправильные" отдавать прямо местному TCP-стеку, все прочие - отсылать дальше (можно при этом подменять у них source address на какой-то левый). Это теория. До практики у меня руки пока не дошли за полной ненадобностью - у меня все клиенты имеют MTU 1500.


 




Copyright © Lexa Software, 1996-2009.