From: Трифонов Евгений aka ieroglif aka Sart <astahe@mail.ru.>
Date: Mon, 6 Mar 2008 14:31:37 +0000 (UTC)
Subject: Linux маршрутизатор с несколькими внешними интерфейсами.
Настройка линукс маршрутизатора через iptables + iproute2 на два (и
больше) внешних интерфейса.
Предполагается:
- то вы уже знакомы с понятием маршрутизации и ната.
- теоретически понимаете как работает нат, что такое маршрутизация и
файрвол, но не знаете как это реализовать на вашей системе.
Имеется:
- две входящие сетевые соски от двух разных провайдеров.
- локальная сеть
- три сетевых интерфейса на маршрутизаторе.
Задача:
Объеденить всех пользователей в одну локальную сеть и пускать одних
пользователей в интернет через одного провайдера, других - через
другого.
В рассматриваемом примере, все пользователи в локальной сети будут
находиться в сети 172.16.0.0/16, при этом пользователей из подсети
172.16.0.0/24 надо пропускать в интернет через первого провайдера, а
пользователей 172.16.1.0/24 - через второго.
Будем использовать iproute2 для таблиц маршуризации и iptables для ната.
Обозначим:
$IP_LOCAL="172.16.0.1" - адрес нашего маршрутизатора в локальной сети.
$IP_INET1="1.1.1.2" - адрес нашего маршрутизатора в сети первого провайдера.
$IP_INET2="2.2.2.2" - адрес нашего марщрутизатора в сети второго провайдера.
$IF_LOCAL="eth0" - имя интерфейса на локальную сеть
$IF_INET1="eth1" - имя интерфейса на первого провайдера.
$IF_INET2="eth2" - имя интерфейса на второго провайдера.
$NET_LOCAL="172.16.0.0/16" - локальная сеть.
$NET_INET1="1.1.1.0/24" - адрес сети в которой гейт нашего первого провайдера.
$NET_INET2="2.2.2.0/24" - адрес сети в которой гейт нашего второго провайдера.
$NET_SUB1="172.16.0.0/24" - подсеть пользователей на первого провайдера
$NET_SUB2="172.16.1.0/24" - подсеть пользователей на второго провайдера
$GW1="1.1.1.1" - гейт первого провайдера.
$GW2="2.2.2.1" - гейт второго провайдера.
#inet 2
auto eth2
iface eth2 inet static
#если надо - меняем мак адреса
# pre-up ifconfig eth2 hw ether aa:bb:cc:cc:bb:aa
address 2.2.2.2
netmask 2.2.2.0
# себе я второй гейт не прописываю, в следствии чего сам маршрутизатор ходит в инет через первый инет
# gateway 2.2.2.1
network 2.2.2.0
broadcast 2.2.2.255
тем самым мы сказали, что все сетвые у нас имеют статические адреса, и
указали их.
Настаиваем маршрутизацию с утилитой ip.
Утилита route позволяет нам обратиться к таблице маршртизации.
Сила утилиты ip в том, что она позволяет создать большое количество
таблиц для самых разных потребностей, а так же, способна считывать
флаги, которые расставляет файрвол iptables (об этом ниже) и на их
основе тоже делать какие-то действия.
Основа маршрутизации через разные таблицы - правила (rule)
А сила различных таблиц в том, что мы можем хранить огромное количество
различных таблиц маршрутизации, через которые и будем пропускать пакеты.
Просмотреть список уже имеющихся таблиц можно командой
ip rule list
0: from all lookup 255
32766: from all lookup main
32767: from all lookup default
Мы видим, что у нас есть три правила: таблица 255, main и default.
То, что выдает нам route - хранится в таблице main, что можно увидеть командой
ip route list table main
В качестве номеров таблиц можно использовать цифры, ( пример: 0: from
all lookup 255 ), а можно прописать на эти цифры какие-то более понятные
простым смертным имена ( пример: 32766: from all lookup main ).
Так что обозначим свои таблицы:
Редактируем файл
/etc/iproute2/rt_tables
и добавляем туда записи вида:
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
#1 inr.ruhep
10 T1
20 T2
номер - это то самое число, которое мы можем использовать если не
именовать таблицы, а строковое значение - то, что мы в действительности
будем использовать. (кстати, тут же мы видим и уже встречавшиеся нам в
списке правил таблицы)
Теперь создаем некий скрипт, который в последствии будет все нам
прописывать при старте системы.
Понятное дело, что каждый использует свой любимый редактор =)
/etc/init.d/route
#!/bin/sh
IP_LOCAL="172.16.0.1" # адрес нашего маршрутизатора в локальной сети.
IP_INET1="1.1.1.2" # адрес нашего маршрутизатора в сети первого провайдера.
IP_INET2="2.2.2.2" # адрес нашего марщрутизатора в сети второго провайдера.
IF_LOCAL="eth0" # имя интерфейса на локальную сеть
IF_INET1="eth1" # имя интерфейса на первого провайдера.
IF_INET2="eth2" # имя интерфейса на второго провайдера.
NET_LOCAL="172.16.0.0/16" # локальная сеть.
NET_INET1="1.1.1.0/24" # адрес сети в которой гейт нашего первого провайдера.
NET_INET2="2.2.2.0/24" # адрес сети в которой гейт нашего второго провайдера.
GW1="1.1.1.1" # гейт первого провайдера.
GW2="2.2.2.1" # гейт второго провайдера.
ip route flush table T1 #обнуляем первую таблицу маршрутов
ip route flush table T2 #обнуляем вторую таблицу маршрутов
ip route add $NET_INET1 dev $IF_INET1 src $IP_INET1 table T1 #закидываем в первую таблицу инфу о сети первого провайдера
ip route add $NET_LOCAL dev $IF_LOCAL table T1 #закидываем в первую таблицу инфу о том, что у нас существует локальная сеть
ip route add $NET_INET2 dev $IF_INET2 table T1 #закидываем в первую таблицу инфу о том, что у нас существует еще одна сеть
ip route add 127.0.0.0/8 dev lo table T1 #закидываем в первую таблицу инфу о существовании лупбека
ip route add default via $GW_INET1 table T1 #закидываем в первую таблицу дефолтный гейт на первого провайдера
ip route add $NET_INET2 dev $IF_INET2 src $IP_INET2 table T2 #закидываем во вторую таблицу инфу о сети второго провайдера
ip route add $NET_LOCAL dev $IF_LOCAL table T2 #закидываем во вторую таблицу инфу о том, что у нас существует локальная сеть.
ip route add $NET_INET1 dev $IF_INET1 table T2 #закидываем во вторую таблицу инфу о том, что у нас существует еще одна сеть.
ip route add 127.0.0.0/8 dev lo table T2 #закидываем во вторую таблицу инфу о существовании лупбека.
ip route add default via $GW_INET2 table T2 #закидываем во вторую таблицу дефолтный гейт на второго провайдера
ip route add $NET_INET1 dev $IF_INET1 src $IP_INET1 #заполняем основную таблицу адресов. сеть на первого провайдера
ip route add $NET_INET2 dev $IF_INET2 src $IP_INET2 #заполняем основную таблицу адресов. сеть на второго провайдера
ip route add default via $GW_INET1 #заполняем основную таблицу адресов. дефолтный гейт.
ip rule delete table T1 #удаляем наши таблицы, если они присутсвуют в текущей конфигурации (вдруг мы просто перезапускаем скрипт?)
ip rule delete table T2 #аналогично для второй.
ip rule delete table T1 #и делаем это два раза, так как у нас два правила на каждую таблицу.
ip rule delete table T2 #аналогично для второй.
#а вот это важно для понимая! если понять что происходит в следующих строчках - то можно настраивать любые правила маршрутизации.
ip rule add from $IP_INET1 table T1 #все пакеты от ip адреса первого провайдера маршрутизировать по таблице T1
ip rule add from $IP_INET2 table T2 #все пакеты от ip адреса второго провайдера маршрутизировать по таблице T2
ip rule add fwmark 10 table T1 #все пакеты, которые имеют метку 10 маршрутизировать по таблице T1
ip rule add fwmark 11 table T2 #все пакеты, которые имеют метку 11 маршрутизировать по таблицу T2
ip route flush cache #ну и на последок очистить кеш
exit 0
В целом, понятно все, за исключением одного вопроса - что же это за
метка такая в последних строчках?
Тут мы обращаемся к утилите iptables.
Краткая теория. (полную и на русском языке можно, а вообще-то, даже
нужно, читать тут http://www.opennet.ru/docs/RUS/iptables/ )
Утилита iptables так же основана на таблицах. только таблиц в ней
фиксированно - три.
mangles - таблица используется для изменений заголовков пакетов.
filter - самая наша основаная таблица для файрвола - тут мы производим все блокировки, разрешения.
nat - таблица, как понятно из названия для ната.
Каждая таблица уже имеет некоторые предлопределенные цепочки, в которые
можно добавлять правила, а так же поддерживает создание пользовательские
цепочки.
Когда паркт попадает на интерфейс, и, его ловит iptables, то он проходит
следующие таблицы и цепочки, важные для нас:
1. таблица mangle цепочка PREROUTING
2. обработка маршрутизации.
3. таблица nat цепочка POSTROUTING
(в действительно пакет проходит еще и через другие таблицы и цепочки,
но, для планируемой маршрутизации они нафик не сдались - изучение этого
вопроса уже полностью на вашей совести =) ).
Скрипт для маршрутизации:
/etc/init.d/iptables
#!/bin/sh
IP_LOCAL="172.16.0.1" # адрес нашего маршрутизатора в локальной сети.
IP_INET1="1.1.1.2" # адрес нашего маршрутизатора в сети первого провайдера.
IP_INET2="2.2.2.2" # адрес нашего марщрутизатора в сети второго провайдера.
IF_LOCAL="eth0" # имя интерфейса на локальную сеть
IF_INET1="eth1" # имя интерфейса на первого провайдера.
IF_INET2="eth2" # имя интерфейса на второго провайдера.
NET_LOCAL="172.16.0.0/16" # локальная сеть.
NET_INET1="1.1.1.0/24" # адрес сети в которой гейт нашего первого провайдера.
NET_INET2="2.2.2.0/24" # адрес сети в которой гейт нашего второго провайдера.
NET_SUB1="172.16.0.0/24" # подсеть пользователей на первого провайдера
NET_SUB2="172.16.1.0/24" # подсеть пользователей на второго провайдера
GW1="1.1.1.1" # гейт первого провайдера.
GW2="2.2.2.1" # гейт второго провайдера.
#все пакеты, которые попали в цепочку PREROUTING таблицы mangle обрабатываем по двум правилам:
$IPT -t mangle -A PREROUTING -s $NET_SUB1 -d ! $NET_LOCAL -j MARK --set-mark 10 # все пакеты которые идут от $NET_SUB1 и не в $NET_LOCAL маркируем меткой 10
$IPT -t mangle -A PREROUTING -s $NET_SUB2 -d ! $NET_LOCAL -j MARK --set-mark 11 # все пакеты которые идут от $NET_SUB1 и не в $NET_LOCAL маркируем меткой 10
#все пакеты, которые попали в цепочку POSTROUTING таблицы nat обрабатываем по двум правилам:
$IPT -t nat -A POTROUTING -m mark --mark 10 -j MASQUERADE # натим все пакеты которые имеют метку 10
$IPT -t nat -A POTROUTING -m mark --mark 11 -j MASQUERADE # натим все пакеты которые имеют метку 11
exit 0
И так, что же происходит.
Пусть адрес пользователя 172.16.0.2
У пользователя прописан дефолтный гейт 172.16.0.1 - т.е. все пакеты
которые направлены не в локальную сеть пойдут туда.
На наш маршрутизатор приходит пакет от 172.16.0.2 и на адрес (к примеру) 4.4.4.4
1. пакет попадает в таблицу mangle в цепоку PREROUTING и там по правилу
"все пакеты от $NET_SUB1 и не в $NET_LOCAL" маркируется меткой 10 и
попускается дальше.
2. пакет попадает в правила маршрутизации и обрабатывается по правилу
"все пакеты, которые имеют метку 10 маршрутизировать по таблице T1".
попав в эту таблицу маршрутизатор отправляет пакет в дефолтный гейт для
этой таблицы, т.к. адрес 4.4.4.4 не подходит ни под одну сеть, которые
есть в этой таблице.
3. пакет попадает в таблицу nat в цепочку POSTROUTING и там по правилу
"натим все пакеты которые имеют метку 10" натится наружу.
Важный момент: метка пакета существует только внутри нашего
марщрутизатора. выходящий пакет уже не имеет меток.
Сам факт подобной реализации маршрутизации возможен только из-за того,
что когда пакет обрабатывается правилами маршрутизации метка существует,
так как после пакет возвращается на обработку в таблицы iptables.
В целом, все =)
Осталось только сделать наши скрипты исполняемыми и закинуть их на
автозагрузку.
Важно обратить внимание, что данный маршрутизатор будет маршрутизировать
пакеты в обе стороны, так что если кто-то из внешних сетей пропишет себе
ip нашей локальной сети, и укажет в качестве маршрутизатора ip нашего
маршрутизатора - он спокойно попадет к нам.
Но настройка файрвола - это уже второй вопрос, который в эту статью не
входит.
1613 Прочтений • [Linux маршрутизатор с несколькими внешними интерфейсами. (debian ubuntu linux route iproute iptables nat)] [08.05.2012] [Комментариев: 0]