Итак, о задаче: есть два канала интернет, шлюз на FreeBSD
gate# uname -a FreeBSD gate 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Thu Nov 1 06:48:52 OMST 2012 root@gate:/usr/obj/usr/src/sys/GATE amd64
Не то, чтобы необходимость, но желание создать гибкую систему с балансировкой трафика по каналам и желание получить премию от руководства.
Канал №1: безлимитка, скорость 7 Мб, реальный ip-адрес
Канал №2: безлимитка, скорость до 60Мб, реальный ip-адрес.
Со стороны провайдера были установлены шлюзы, через которые реализую DMZ на «ловушки» для хакеров, поэтому настройки PF и SQUID минимальны
Описание поднятия балансировки
Все манипуляции от пользователя root. (Подключаемся к хосту любым пользователем, затем su, пароль root).
1. Опции ядра для включения PF:
Если не считать трафик средствами PF, то второй пункт можно отключить
cd /sys/amd64/conf cp GENERIC GATE ee GATE device pf device pflog options ALTQ options ALTQ_CBQ options ALTQ_RED options ALTQ_RIO options ALTQ_HFSC options ALTQ_PRIQ options ALTQ_NOPCC
2. сборка ядра
make kernel KERNCONF=GATE
3. В шлюз установлены 2 сетевых карты, одна интегрированная в материнскую плату:
re0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=389b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_UCAST,WOL_MCAST,WOL_MAGIC> inet 192.168.1.2 netmask 0xffffff00 broadcast 192.168.1.255 re1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=389b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_UCAST,WOL_MCAST,WOL_MAGIC> inet 192.168.63.26 netmask 0xfffffff8 broadcast 192.168.63.31 nfe0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=82008<VLAN_MTU,WOL_MAGIC,LINKSTATE> inet 10.1.1.30 netmask 0xffffff00 broadcast 10.1.1.255
re0 провайдер №1, re1 — провайдер №2. Внутренний интерфейс nfe0 (назначение ip адресов и масок сложилось исторически, я работаю с тем, что есть). И конечно же подняты vlan на внутреннем интерфейсе, раскидываю по ним систему ip видеонаблюдения и различные отделы компании.
4. Настройка rc.conf
ee /etc/rc.conf pf_enable=«YES» pf_rules=«/etc/pf.conf» squid_enable=«YES» reboot
То есть при загрузке выполняются правила из файла /etc/pf.conf.
5. Листинг pf.conf.
cat pf.conf #Задаем переменные, где int_if - внутренний интерфейс, ext_if - внешние. int_if=«nfe0» ext_if=«re1» ext_if2=«re0» int_net=«10.1.1.0/24» freeBSD=«10.1.1.30» icmp_types=«{ echoreq, unreach}» http=«80» https=«443» ssh=«22» #описываем шлюзы для каждого из провайдеров. gw1=«192.168.63.25» gw2=«192.168.1.1» #Для тех, кто должен идти с конкретного провайдера вводим принудительное направление траффика в обход балансировки. #Например, клиент-банки или тендерные площадки чувствительны к смене ip-адреса при балансировке. to_ertel=«{10.1.1.42, 10.1.1.33, 10.1.1.4, 10.1.1.12, 10.1.1.5, 10.1.1.48, 10.1.1.25, 10.1.1.3, 10.1.1.243, 10.1.1.5 }» to_trans=«{ 10.1.1.27, 10.1.1.2, 10.1.1.181, 10.1.1.46, 10.1.1.39, 10.1.1.27, 10.1.1.31, 10.1.1.113 }» #настройки политик файрвола - всех из вне посылать, set block-policy drop >set skip on lo #собирать все пакеты перед их отправкой. scrub in all #Нат на первый интернет-вход nat on $ext_if inet from any to any -> ($ext_if) #Нат на второй интернет-вход nat on $ext_if2 inet from any to any -> ($ext_if2) #Проброс на SQUID rdr on $int_if inet proto tcp from any to any port www -> 127.0.0.1 port 3128 block in from any to any block out from any to any #Антиспуфинг antispoof quick for $int_if inet # пропускаем все исходящие пакеты на внутреннем интерфейсе pass out on $int_if from any to $int_net #проброс без балансировки (согласно списку адресов) pass in quick on $int_if route-to ($ext_if2 $gw2) from $to_trans to !$int_net keep state pass in quick on $int_if route-to ($ext_if $gw1) from $to_ertel to !$int_net keep state # пропускаем (quick) пакеты предназначенные самому шлюзу pass in quick on $int_if from $int_net to $int_if pass in quick on $int_if route-to { ($ext_if $gw1), ($ext_if2 $gw2)} round-robin sticky-address proto tcp from $int_net to any flags S/SA keep state #Добавил sticky-address по дельному совету RicoX # балансировка исходящего icmp и udp трафика идущего из внутренней сети pass in on $int_if route-to { ($ext_if $gw1), ($ext_if2 $gw2) } round-robin proto { udp, icmp } from $int_net to any keep state # основные "выпускаюшие" правила на внешнем интерфейсе pass out on $ext_if proto tcp from any to any flags S/SA modulate state pass out on $ext_if proto { udp, icmp } from any to any keep state pass out on $ext_if2 proto tcp from any to any flags S/SA modulate state pass out on $ext_if2 proto { udp, icmp } from any to any keep state # маршрутизация пакетов идущих с любого IP на $ext_if1 через $ext_gw1 и # пакетов идущих на $ext_if2 через $ext_gw2 pass out on $ext_if route-to ($ext_if2 $gw2) from $ext_if2 to any pass out on $ext_if2 route-to ($ext_if $gw1) from $ext_if to any
Настройку полос пропускания не производил, так как не было необходимости. Включается достаточно просто и быстро, думаю в дальнейшем можно будет дописать конфиг.
Недостаток данного пути в том, что иногда, когда что-то случается со стороны одного из провайдеров, балансировка нагрузки работать перестает.
Для решения данной проблемы были созданы конфигурационные файлы: pf.conf.ertelecom и pf.conf.trans, которые отличаются от основного файла настроек только тем, что строка:
#pass in on $int_if route-to { ($ext_if $gw1), ($ext_if2 $gw2) } round-robin proto { udp, icmp } from $int_net to any keep state
из них выкинута. Вместо нее появляются две строки:
pass out route-to ($ext_if $gw1) from $int_if to any pass out route-to ($ext_if2 $gw2) from $int_if to any
одна из которых работает, в зависимости от того, какой шлюз по умолчанию установлен.
Скрипты переключения выглядит так:
cat er_conn.sh
#!/bin/sh GW1=«192.168.63.25» if1=«192.168.63.26» #отключаем файрволл /sbin/pfctl -d #и включаем файрволл с правилами провайдера №2 /sbin/pfctl -e -f /etc/pf.conf.dom #Убиваем шлюз по-умолчанию /sbin/route del default #Включаем шлюз по-умолчанию нашего провайдера №2 /sbin/route add default $GW1
Аналогично этому скрипту работают скрипты управления включением провайдера №1 и балансировки нагрузки. Меняется только адрес шлюза и файл правил настройки pf.
В cron подключаем скрипт, который каждые несколько (на выбор) минут проверяет на ответ от шлюза:
ping -S <ip адрес шлюза провайдера> <наш реальный ip-адрес>.
Если ответа нет, автоматически подгружаем правила живого канала.
Что касается настройки SQUID, то там я сделал вообще все примитивно. Собрал squid 3 из портов, не меняя ничего, кроме настройки transparent, то есть прозрачный прокси. Привожу его конфигурационный файл:
cat squid.conf
http_port 127.0.0.1:3128 transparent icp_port 0 hierarchy_stoplist cgi-bin ? acl QUERY urlpath_regex cgi-bin ? no_cache deny QUERY cache_mem 256 MB maximum_object_size 8092 KB maximum_object_size_in_memory 512 KB cache_dir ufs /bkp/var/squid/cache 2048 64 256 cache_access_log /bkp/var/squid/access.log cache_log /bkp/var/squid/cache.log cache_store_log /bkp/var/squid/store.log cache_mgr root@xxx.ru cache_effective_user squid cache_effective_group squid visible_hostname gate coredump_dir /bkp/var/squid/cache pid_filename /var/run/squid/squid.pid acl our_networks src 10.1.1.0/24 http_access allow our_networks
Вот с этим и работаем уже около двух лет, практически ничего не вылетает, шлюз перезагружается только по прихотям электриков, пользователи забыли, что такое проблемы с доступом интернет.
Трафик считаю спиртом (cnupm), с последующей выгрузкой его логов в базу MySQL.
Небольшой бонус: когда я принял хозяйство, все IP были выставлены вручную для машин. Кроме того, к этим IP (а не именам машин) была привязка некоторых сервисов локальной сети. Поэтому родился следующий скрипт для быстрого трансфера настроек IP в формат DHCP конфигурационного файла сервера, а именно той части, которая присваивает IP по МАК-адресу.
Привожу листинг:
gate# cat do_dhcp
#!/bin/sh arp -an | grep <Ваш локальный сетевой интерфейс> > /usr/arp.txt #В IFS указан пробел в кавычках IFS=« » cat /usr/arp.txt | while read line do set -- $line; echo -e «host $1 { hardware ethernet $4; fixed-address $2; }n» done
Вывод происходит на экран терминала, но если в echo добавить после последней кавычки > /usr/dhcp.txt, то вывод будет в файл. Далее произошел copy-paste вывода в соответствующий раздел файла dhcpd.conf. Можно так:
cat dhcpd.txt >> /usr/local/etc/dhcpd.conf
http://habrahabr.ru/post/177767/