Работа одновременно с двумя выделенными линиями. Часть 1.

(Оригинал написан для linuxetc.ru) По ряду причин я решил купить домой вторую выделенную линию. Пришли монтажники из Корбины, провели мне вторую линию, воткнули во вторую сетевую карту, проверили на работоспособность и ушли. А я остался настраивать оба интернета :-). Поднял вчерне оба интернета -- от районной сети GolNet и от Корбины -- и решил пропинговать извне одновременно оба своих ip. Результат: корбиновский ip пингуется, голнетовский нет. Через минуту я понял, что так и должно быть -- ответ на пакет от GolNet уходил по дефолтному роутингу на корбиновский интерфейс и, естественно, не получался тем, кто пингует голнетовский ip-адрес. Поскольку одна из задач второй выделенной линии заключалась как раз в возможности доступа к моему компьютеру с любого из двух ip из интернета, такое поведение меня ни капли не устроило и я стал искать решение. Поиск в интернете в конце концов вывел меня на пакет iproute2 -- подсистема расширенного роутинга под Linux. Изучив главу из Linux Advanced Routing & Traffic Control HOWTO, я решил для начала построить нечто аналогичное для интерфейсов в локальные сети GolNet и Corbina соответственно. Вот что получилось в итоге. Всё проверено на системе на базе Gentoo, в других системах расположение системных файлов и их содержимое может сегка различаться.

Необходимые условия

Убедитесь, что в ядре включены все необходимые опции. Это опция Networking -> Networking options -> TCP/IP networking и её подопции "IP: advanced router", "IP: Policy routing", "IP: use netfilter MARK value as routing key", "IP: equal cost multipath". Две последние опции пригодятся позднее при настройке интернета. Пересоберите ядро. Убедитесь также, что оба сетевых интерфейса получают свои адреса по DHCP, а клиент dhcpcd сохраняет свою информацию в файлы /var/lib/dhcpcd/dhcpcd-ethN.info (смотрите скрипт ниже, функцию write_resolv_conf). Убедитесь, что в системе есть iproute2. Обычно все эти условия выполнены, но для Gentoo может понадобиться выполнить команды
emerge dhcpcd

emerge iproute2

Конфигурирование

Выдержка из /etc/conf.d/net:
modules=("iproute2") config_eth0=( "dhcp" ) dhcp_eth0="nodns nogateway" config_eth1=( "dhcp" ) dhcp_eth1="nodns nogateway"
Здесь важно обратить внимание на опции dhcp для обоих интерфейсов -- /etc/resolv.conf не перезаписывается и роутинги на шлюзы в локалки автоматом не прописываются. Всё это происходит чуть позднее, в /etc/conf.d/local.start (в других unix-системах это, возможно, надо писать куда-то вроде /etc/rc.local). Однако, прежде чем вносить записи о роутингах, надо указать системе iproute2 имена таблиц роутинга, по которым мы разложим правила роутинга. Выдержка из /etc/iproute2/rt_tables:
1 local_golnet 2 local_corbina
Главное, чтобы номера таблиц нигде больше в /etc/iproute2/rt_tables не повторялись. Теперь можно заполнить таблицы локальных роутингов. Выдержка из /etc/conf.d/local.start:
# функция write_resolv_conf просто заполняет /etc/resolv.conf записями относительно dns-серверов # локалок в указанном порядке интерфейсов.
function write_resolv_conf()

{

 interfaces=$*

 rm -f /etc/resolv.conf

 for int in $interfaces; do

    for i in `grep DNSSERVERS /var/lib/dhcpcd/dhcpcd-$int.info |cut - -c 13- | tr -d "'"`; do

       echo "nameserver $i" >> /etc/resolv.conf

    done;

 done;

}
# перечисляем параметры сети GolNet
IF1="eth0" # сетевая карта GolNet

LOCAL_GOLNET=192.168.0.0/16 # сеть GolNet

LOCAL_GOLNET_MY_SEGMENT=192.168.5.0 # мой сегмент в сети GolNet

MY_LOCAL_IP_GOLNET=192.168.5.47 # мой ip в локалке GolNet

LOCAL_GW_GOLNET=192.168.5.7 # шлюз в локалку GolNetecho Прописываем нужный порядок DNS серверов в /etc/resolv.conf

write_resolv_conf "$IF1 $IF2" && echo OK

echo GOLNET
# очищаем таблицу маршрутизации local_golnet
ip route flush table local_golnetecho Определяем статические маршруты в таблице маршрутизации local_golnet
# прописываем в таблицу local_golnet путь к моему сегменту...
ip route add $LOCAL_GOLNET_MY_SEGMENT dev $IF1 src $MY_LOCAL_IP_GOLNET table local_golnet && echo OK
# ...и шлюз для всего сегмента...
ip route add $LOCAL_GOLNET_MY_SEGMENT via $LOCAL_GW_GOLNET table local_golnet && echo OK
# а также шлюз по умолчанию для таблицы local_golnet
ip route add default via $LOCAL_GW_GOLNET table local_golnet && echo OK
# следующие две строки укажут ядру, в каком случае использовать таблицу local_golnet # в данном случае -- при всех обращениях с адресом источника $MY_LOCAL_IP_GOLNET. # именно эта строка ответственна за уход ответа по тому же интерфейсу # по которому пришёл запрос!
ip rule add from $MY_LOCAL_IP_GOLNET table local_golnet
# ...и при всех обращениях в локалку Golnet
ip rule add to $LOCAL_GOLNET table local_golnet && echo OK
# перечисляем параметры сети Corbina
IF2="eth1" # сетевая карта Corbina

LOCAL_CORBINA=10.72.0.0/16 # сеть Corbina

LOCAL_GW_CORBINA=10.72.0.17 # шлюз в локалку Corbina

MY_LOCAL_IP_CORBINA=10.72.43.81 # мой ip в локалке Corbinaecho Прописываем нужный порядок DNS серверов в /etc/resolv.conf

write_resolv_conf "$IF2 $IF1" && echo OK

echo CORBINA
# очищаем таблицу маршрутизации local_corbina
ip route flush table local_corbinaecho Определяем маршруты в таблице маршрутизации local_corbina
# прописываем в таблицу local_corbina путь к локалке Corbina...
ip route add $LOCAL_CORBINA dev $IF2 src $MY_LOCAL_IP_CORBINA table local_corbina && echo OK
# ...и шлюз для всего сегмента...
ip route add $LOCAL_CORBINA via $LOCAL_GW_CORBINA table local_corbina && echo OK
# а также шлюз по умолчанию для таблицы local_corbina
ip route add default via $LOCAL_GW_CORBINA table local_corbina && echo OK
# следующие две строки укажут ядру, в каком случае использовать таблицу local_golnet # в данном случае -- при всех обращениях с адресом источника $MY_LOCAL_IP_GOLNET. # именно эта строка ответственна за уход ответа по тому же интерфейсу # по которому пришёл запрос!
ip rule add from $MY_LOCAL_IP_CORBINA table local_corbina
# ...и при всех обращениях в локалку Golnet
ip rule add to $LOCAL_CORBINA table local_corbina && echo OK
# Все оставшиеся строчки -- дань особенностям построения сети корбины. # Они заполняют таблицу правилами (ip rule, НЕ ip route!) для # dns и vpn серверов корбины, причем сначала для dns. # Вообще настройка интернета от Корбины под Linux-- это совсем другая история, # об этом немного подробнее будет рассказано в другом месте.
echo Обращения к DNS Корбины маршрутизировать согласно local_corbina

for DNS in `grep DNSSERVERS /var/lib/dhcpcd/dhcpcd-$IF2.info |cut - -c 13- | tr -d "'"`; do

   ip rule add to $DNS table local_corbina

done;

echo Обращения к VPN Корбины маршрутизировать согласно local_corbina

HOST_CMD="hostx"

VPN_SERVER="vpn.corbina.net"

IP_LIST="`${HOST_CMD} ${VPN_SERVER} | awk '{print $3}' `"

for ADDRESS in `echo "${IP_LIST}"`

do

   ip rule add to $ADDRESS table local_corbina

done

Заключительная проверка

Если всё прошло нормально, то после перезагрузки можно будет наблюдать примерно следующее:
testcomp # route -n

Kernel IP routing table

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

192.168.5.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

10.72.0.0       0.0.0.0         255.255.0.0     U     1      0        0 eth1

127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
Но хосты обеих локалок чудесно пингуются:
testcomp # ping -c3 192.168.4.5 PING 192.168.4.5 (192.168.4.5) 56(84) bytes of data. 64 bytes from 192.168.4.5: icmp_seq=1 ttl=63 time=12.0 ms testcomp # ping -c1 10.72.0.17 PING 10.72.0.17 (10.72.0.17) 56(84) bytes of data. 64 bytes from 10.72.0.17: icmp_seq=1 ttl=255 time=0.609 ms
Вы просто не там смотрите. Помните, iproute2 позволяет задавать не только маршруты, но и правила их выбора:
testcomp # ip route show table local_golnet

192.168.5.0 dev eth0  scope link  src 192.168.5.47

192.168.0.0/16 via 192.168.5.7 dev eth0

default via 192.168.5.7 dev eth0testcomp # ip route show table local_corbina

10.72.0.0/16 dev eth1  scope link  src 10.72.43.81

default via 10.72.0.17 dev eth1

testcomp # ip rule

0:      from all lookup local

32753:  from 192.168.5.47 lookup local_golnet

32754:  from all to 85.21.0.0/16 lookup local_corbina

32757:  from all to 85.21.0.6 lookup local_corbina

32758:  from all to 85.21.0.5 lookup local_corbina

32759:  from all to 85.21.0.8 lookup local_corbina

32760:  from all to 85.21.0.7 lookup local_corbina

32761:  from all to 85.21.192.3 lookup local_corbina

32762:  from all to 213.234.192.8 lookup local_corbina

32763:  from all to 10.72.0.0/16 lookup local_corbina

32764:  from 10.72.43.81 lookup local_corbina

32765:  from all to 192.168.0.0/16 lookup local_golnet

32766:  from all lookup main

32767:  from all lookup default

Источники информации

Следующие ссылки могут оказать помощь в понимании механизма работы iproute2