пятница, 20 марта 2009 г.

Используем 2+ провайдера (вторая часть)

Продолжим настройку нашего шлюза, про который я говорил в предыдущей статье. Напомню, там мы настроили правила маршрутизации, теперь нам надо заняться iptables. Сейчас мы настроим сеть состоящую из шлюза и сервера. На шлюзе будет работать SSH и DNS, а сервер у нас будет виндовый на нем у нас RDP и SMTP. Сеть будет настроена таким образом, что через любой из внешних айпишников мы сможем подключаться к любому из серверов, а SMTP сервер будет выходить наружу через основного провайдера.
Ну и конечно, же начнем с переменных, причем вынесем следующие настройки в отдельный файл, это нам сильно пригодиться в будущем:

#!/bin/bash

export GLOBAL_ETH_PRIM=eth1
export GLOBAL_ETH_SEC=eth2
export GLOBAL_IP_PRIM=10.10.10.10
export GLOBAL_IP_SEC=20.20.20.20
export MARK_PRIM=10
export MARK_SEC=20

Назовем этот файл ipt_p1.conf. А содержит он данные о том, какой из интерфейсов является главным, а какой запасным (PRIM и SEC соответственно) и значения для маркировки пакетов.
Перейдем к основному файлу конфигурации iptables, назовем его ipt.conf. Запишем переменные ;-)

#!/bin/bash
IPTABLES=/sbin/iptables
MODPROBE=/sbin/modprobe

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

LOCAL_ETH=eth0
GLOBAL_ETH_P1=eth1
GLOBAL_ETH_P2=eth2
LOCAL_IP=192.168.0.1
LOCAL_NET=192.168.0.0/24
GLOBAL_IP_P1=10.10.10.10
GLOBAL_IP_P2=20.20.20.20

Тут мы описали конфигурацию нашей сети, по порядку: локальный интерфейс, интерфейсы, которые смотрят к провайдерам, локальный айпишник и подсеть, айпишники, которые выданы провайдерами.

SRV11=192.168.0.11
SRV12=192.168.0.12

А это наш сервер, для которого мы настраивали маршрутизацию на основе политик, используя метки. Как я уже говорил этот сервер на своем сетевом интерфейсе имеет два айпишника, чуть ниже я расскажу для чего это нам пригодиться.
. $1

Зацепили внешние настройки, в данном случае это будет наш файл ipt_p1.conf.
Хватит о скучном, приступим к настройке, причем попытаемся все сделать красиво:

echo "[+] Flushing existing iptables rules..."
$IPTABLES -F
$IPTABLES -F -t nat
$IPTABLES -F -t raw
$IPTABLES -F -t mangle
$IPTABLES -X
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT DROP
$IPTABLES -P FORWARD DROP

Очищаем все правила iptables, в первой строке говорим, что делаем, почему по английски, а чтобы не было проблем с кодировками. Последние три строчки устанавливают правила по умолчанию - все пакеты не подходящие под список правил будут просто отброшены.

$MODPROBE ip_conntrack
$MODPROBE iptable_nat

Загрузили модули ядра, которые будем использовать.
Теперь пройдемся по цепочкам iptables и заполним их необходимыми правилами:

echo "[+] Setting up INPUT chain..."

$IPTABLES -A INPUT -m state --state INVALID -j DROP
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Используя возможности модуля state мы отбрасываем некорректные пакеты и принимаем пакеты относящиеся к уже установленным соединениям либо ко вторичными соединениям (таким как передача данных в ftp).
$IPTABLES -A INPUT -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT

Принимаем подключения по SSH отовсюду.
$IPTABLES -A INPUT -i $LOCAL_ETH -s $LOCAL_NET -j ACCEPT

Локальный трафик будет ходить без ограничений, хотя это не всегда правильно.
$IPTABLES -A INPUT -i lo -j ACCEPT

Тоже на localhost.
Продолжаем с цепочкой OUTPUT:

echo "[+] Setting up OUTPUT chain..."

$IPTABLES -A OUTPUT -m state --state INVALID -j DROP
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Эти правила аналогичны правилам в цепочке INPUT.
$IPTABLES -A OUTPUT -o $GLOBAL_ETH_PRIM -p udp --dport 53 -j ACCEPT

Мы разрешили работать нашему DNS серверу через основного провайдера
$IPTABLES -A OUTPUT -o $GLOBAL_ETH_PRIM -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT

А также разрешили выходить наружу по SSH.
$IPTABLES -A OUTPUT -o $LOCAL_ETH -d $LOCAL_NET -m state --state NEW -j ACCEPT

Опять же на исходящий локальный трафик ограничений нет.
Переходим к обработке трафика из локальной сети:

echo "[+] Setting up FORWARD chain..."

$IPTABLES -A FORWARD -m state --state INVALID -j DROP
$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

Все те же два удобных правила.
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P1 -d $SRV11 -p tcp --dport 25 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P2 -d $SRV12 -p tcp --dport 25 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P1 -d $SRV11 -p tcp --dport 3389 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P2 -d $SRV12 -p tcp --dport 3389 --syn -m state --state NEW -j ACCEPT

Так у нас получается, что пакеты приходящие на первого провайдера пропускаются только на первый айпишник сервера, второго - на второй.

$IPTABLES -A FORWARD -i $LOCAL_ETH -s $SRV11 -j ACCEPT
$IPTABLES -A FORWARD -i $LOCAL_ETH -s $SRV12 -j ACCEPT

Разрашаем весь исходящий трафик с нашего сервера, опять же это не совсем правильно.
Далее идут правила NAT:

$IPTABLES -t nat -A POSTROUTING -s $SRV11 -p tcp --dport 25 -j SNAT --to-source $GLOBAL_IP_PRIM
$IPTABLES -t nat -A POSTROUTING -s $SRV12 -p tcp --dport 25 -j SNAT --to-source $GLOBAL_IP_PRIM

Все, что наш сервер попытается отправить по SMTP пойдет через основного провайдера.
И опять самое интересное нам осталось на последок. Переходим к PREROUTING, здесь то мы и воспользуемся возможностью маркировать пакеты, которая нам понадобится для маршрутизации вот в этих двух строчках:

ip rule add from $SRV11 fwmark 10 table T1
ip rule add from $SRV12 fwmark 20 table T2

Итак, наши правила:

$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV11 -p tcp --dport 25 -j MARK --set-mark $MARK_PRIM
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV12 -p tcp --dport 25 -j MARK --set-mark $MARK_PRIM

Все пакеты уходящие с нашего внутреннего сервера на 25 порт мы маркируем значением $MARK_PRIM. Давайте проследим, что это нам дает: исходящий пакет маркируется значением 10, значит маршрутизироваться он будет по таблице T1, а соответствуя этой таблице пакет должен уйти через первого провайдера, в цепочке FORWARD есть разрешающее правило, поэтому пакет безпрепятственно проходит - все правильно это нам и требовалось.
Теперь нам надо разобраться с соединениями идущими к нам. Сначала, конечно же, должен отработать DNAT:

$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P1 -d $GLOBAL_IP_P1 -p tcp --dport 25 -j DNAT --to-destination $SRV11
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P1 -d $GLOBAL_IP_P1 -p tcp --dport 3389 -j DNAT --to-destination $SRV11
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P2 -d $GLOBAL_IP_P2 -p tcp --dport 25 -j DNAT --to-destination $SRV12
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P2 -d $GLOBAL_IP_P2 -p tcp --dport 3389 -j DNAT --to-destination $SRV12

Вроде бы все правильно, проверяем: пакет приходит на внешний интерфейс шлюза, в зависимости от принадлежности интерфейса провайдеру, он перенаправляется на первый или второй айпишник внутреннего сервера, сервер отвечает с того же(!) айпишника, пакет на шлюзе маршрутизируется по основной таблице, проходит через FORWARD и отправляется через основного провайдера, а вот это уже не правильно, ведь пакет мог прийти и через запасного провайдера. Исправляем, добавляя правила:

$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV11 -p tcp --sport 25 -j MARK --set-mark $MARK_PRIM
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV11 -p tcp --sport 3389 -j MARK --set-mark $MARK_PRIM
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV12 -p tcp --sport 25 -j MARK --set-mark $MARK_SEC
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV12 -p tcp --sport 3389 -j MARK --set-mark $MARK_SEC

Теперь на обратном пути мы маркируем пакеты в соответствии с адресом, с которого они отправляются. Далее в дело вступают таблицы маршрутизации T1 и T2, поэтому решение через какой интерфейс отправлять пакеты принимается правильное.
Все! Готово. Для применения правил выполняем команду "./ipt.conf ipt_p1.conf". Теперь наши сервера доступны, пока хотя бы один из провайдеров дает нам доступ в интернет.
Еще хотел рассказать, как можно переключаться между провайдерами и сделать парочку замечаний, но объем статьи и так уже слишком большой, видимо будет третья часть.

Скачать скрипты из первой и второй части. (зеркало)


p.s. Написано, чтобы понять самому и рассказать другим.©

9 комментариев:

Дмитрий Алтухов комментирует...

Для переключения между провайдерами использую PHP-скрипт (WEB-интерфес), который предоставляет пользователю выбор провайдера. При изменении запускает через exec() изменение route и iptables.

olegus комментирует...

Отлично, как раз то, что надо. А как теперь юзерей запустить в нет через второй канал?

olegus комментирует...

а откуда взялись переменные $P1_NET в первой части? И что в них содержится?

Роман комментирует...

в $Px_NET провайдерский подсети

Unknown комментирует...

$IPTABLES -t nat -A POSTROUTING -s $SRV11 -p tcp --dport 25 -j SNAT --to-source $GLOBAL_IP_PRIM
$IPTABLES -t nat -A POSTROUTING -s $SRV12 -p tcp --dport 25 -j SNAT --to-source $GLOBAL_IP_PRIM


А какой смысл здесь делать SNAT 25 порта с двух IP сервера на один IP $GLOBAL_IP_PRIM, если ниже вы приводите DNAT на $GLOBAL_IP_P1 и $GLOBAL_IP_P2

P.S. статью нашел на хабре, там отписаться не смог, т.к. нет аккаунта.

Unknown комментирует...

А когда-нить будет часть про то как переключаться между провайдерам? если один вдруг отвалился...

newssoft комментирует...

Есть вариант немного проще http://traffpro.ru позволяет иметь два провайдера и более, резервировать каналы, аварийно переключать при падении одно из них и так далее. Плюс много вкусностей по учёту и детализации, встроенный шейпер, файрвол, контроль, и так далее.

toxi комментирует...

Может быть "Система TraffPro Office" удобнее в использовании и настройке для непосвящённых пользователей, но лично я люблю больше использовать встроенный функционал, если он это позволяет сделать, чтобы не нагружать систему лишним софтом.

toxi комментирует...

Когда будет статься о том, как сделать так, что если один из провайдеров отвалился, то чтобы активировалась автоматически другая сетевая карта с другим провайдером?