Маршрутизация с 3-мя интерфейсами

Имеем: шлюз с тремя сетевыми интерфейсами на openSUSE linux 11.3 (32bit). Два внешних смотрят в интернет (два разных провайдера). Внутренний интерфейс смотрит в локальную сеть. Также на шлюзе поднят squid (v3.0.STABLE25) и suseFirewall. Первый провайдер выдает адреса через DHCP, у второго - внешний IP.
Необходимо: http-запросы из локалки в зависимости от ip-шников юзеров посылать через squid либо к одному провайдеру, либо к другому.
Ознакомившись с темой принял решение делать маршрутизацию через iproute.
Для этого создал две дополнительные таблицы маршрутизации provider_1 и provider_2. Прописал таблицы в /etc/iproute2/rt_tables. Указал маршруты к соответствующим сетям (ip route add), указал правила для маршрутизации (ip rule add), написал скрипт в автозагрузку (/etc/init.d/after.local). В squid’е прописал acl и указал “tcp_outgoing_address” и “server_persistent_connections off” как и рекомендуют. В suseFirewall’е включил роутинг и маскарадинг.
Но… При попытке обращения к любому сайту через любого провайдера выдается сообщение что не удается определить ip-адрес источника:

"ERROR
The requested URL could not be retrieved

The following error was encountered while trying to retrieve the URL: Google

Unable to determine IP address from host name “www.google.ru

The DNS server returned:
Server Failure: The name server was unable to process this query.

Допустим, у нас такие сетевые параметры:
Провайдер 1 (DHCP), eth1:
IP: 10.8.5.14
Mask: 255.255.0.0
Gate: 10.8.0.1
DNS1: 10.8.0.101
DNS2: 192.168.10.101
DNS3: 192.168.10.102

Провайдер 2 (Manual), eth2:
IP: 80.242.156.56
Mask: 255.255.255.252
Gate: 80.247.156.55
DNS1: 192.8.128.130
DNS2: 192.8.128.137

Локальная сеть, eth0:
IP: 192.168.0.10
Mask: 255.255.255.0

Содержимое скрипта (адаптировано для перезапуска):

#!/bin/sh
#Manual policy routing for 2 internet providers

ip route flush table provider_1
ip route flush table provider_2

ip route add default via 10.8.0.1 table provider_1
ip route add default via 80.242.156.55 table provider_2

ip route add 10.8.0.0/16 dev eth1 src 10.8.5.14 table provider_1
ip route add 80.242.156.56/30 dev eth2 src 80.242.156.56 table provider_2

ip route add 195.8.128.130 dev eth2
ip route add 195.8.128.137 dev eth2
ip route add 10.8.0.101 dev eth1
ip route add 192.168.10.101 dev eth1
ip route add 192.168.10.102 dev eth1

ip route add 192.168.0.0/24 dev eth0 table provider_1
ip route add 192.168.0.0/24 dev eth0 table provider_2

ip rule del table provider_1
ip rule del table provider_2

ip rule add from 10.8.5.14 lookup provider_1
ip rule add from 80.242.156.56 lookup provider_2

ip route flush cache

В squid’е прописано:

http_port 192.168.0.10:3128

acl prov_1 src 192.168.0.15-192.168.0.32
acl prov_1 src 192.168.0.44-192.168.0.128

tcp_outgoing_address 10.8.5.14 prov_1
tcp_outgoing_address 80.242.156.56 prov_2

server_persistent_connections off

В suseFirewall’е прописано:
FW_ROUTE=“yes”
FW_MASQUERADE=“yes”
FW_MASQ_DEV=“zone:ext”
FW_MASQ_NETS=“192.168.0.0/24”

Вывод route -n:

Kernel IP routing table
Destination		Gateway	Genmask         	Flags Metric Ref    Use 	Iface
80.242.156.56		0.0.0.0         	255.255.255.252 	U     	0      	0        	0 	eth2
192.168.0.0		0.0.0.0         	255.255.255.0   	U     	0      	0        	0 	eth0
10.8.0.0        		0.0.0.0         	255.255.0.0     	U     	0      	0        	0 	eth1
169.254.0.0     	0.0.0.0         	255.255.0.0     	U     	0      	0        	0 	eth0
127.0.0.0       		0.0.0.0         	255.0.0.0       		U     	0      	0        	0 	lo

Вывод ip ro:
80.242.156.56/30 dev eth2 proto kernel scope link src 80.242.156.56
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.10
10.8.0.0/16 dev eth1 proto kernel scope link src 10.8.5.14
169.254.0.0/16 dev eth0 scope link
127.0.0.0/8 dev lo scope link

Вывод ip ru:
0: from all lookup local
32764: from 80.242.156.56 lookup provider_metrocom
32765: from 10.8.5.14 lookup provider_lenreg
32766: from all lookup main
32767: from all lookup default

Не могу понять в чем дело. Люди пишут у них все работает! Конфиги, вроде, теже у всех. Переписывал скрипт с легкими вариациями на тему “ip route add 127.0.0.0/8 dev lo table provider_1” [provider_2] – добавление локального маршрута в таблицу первого/второго провайдера; “ip route add 195.8.128.130 dev eth2 table provider_2”, " ip route add 10.8.0.101 dev eth1 table provider_1" – помещал DNS’ы из основной таблицы main в таблицы провайдеров. Но это ничего не дает.
В логах файрвола ничего криминального не обнаружил, блокированных соединений нет (даже с FW_LOG_DROP_ALL=“yes”). На всякий случай пробовал отключать: rcSuSEfirewall2 stop – без результата.
Что самое интересное: по отдельности каналы работают. Т.е. если вставить один кабель в сетевуху и указать соответствующий дефолтный шлюз в таблице main (именно в main!!!) – все живет прекрасно! Такое впечатление, что не обрабатываются дополнительные таблицы маршрутизации provider_1 и provider_2 (или криво обрабатываются как-то…).
Судя по выводу браузера есть проблемы с DNS. Но почему squid не может определить DNS-сервера – это вопрос. Кстати, в /etc/resolve.conf nameserver’ы прописаны, а squid оттуда должен считывать. Логи squid’а тоже малоинформативны - ничего не увидел.
Хотя squid -k parse выдает замечание:
“WARNING: failed to resolve 192.168.0.10 to a fully qualified hostname”, но с этим, по идее, должно все работать (можно вылечить с помощью visible_hostname). Пробовал подключаться и без сквида.
Нашел также что-то про “rp_filter”, но делу это не помогло.

Приветствуется любая помощь сообщества!

Ситуация немного изменилась путем дописывания дефолтного шлюза в таблицу main и переписывания dns в resolve.conf на соответствие сети провайдера. Теперь нормально работает сеть1 (с dhcp), а для сети2 не резолвятся dns-запросы.

Кажется, дело тронулось! В сквиде ставлю “udp_outgoing_address 80.242.156.56” и все работает! Т.о. сквид берет dns’ы из сети2. Выходит первый провайдер как-то хитро блокирует dns-запросы (до этого шло через дефолтный шлюз сети1).

Уважаемый Outloader,
Если я правильно вас понял, то задача сводится к тому, что бы squid, работающий на сервере с тремя eth, обращался по очереди то к одному (ISP1) то к другому (ISP2) провайдеру. При этом, алгоритм выбора провайдера должен зависеть от того, какой внутренний клиент обратиться к squid. Кстати, это ошибка копирования или в squid.conf действительно допущена опечатка- один и тот же access list для разных клиентов:

acl **prov_1** src 192.168.0.15-192.168.0.32
acl **prov_1** src 192.168.0.44-192.168.0.128

Если я правильно понял вашу задачу, то:

  1. Я не уверен на счет конкретно SuSE, на во всех остальных системах маршрут по-умолчанию может (и должен) быть один. На то он и “по-умолчанию”. или здесь как-то задается главный маршрут для таблиц provider_1 и provider_2?
  2. Зачем отдельно прописывать маршрут для вот этого DNS сервера:
    ip route add 10.8.0.101 dev eth1
    если чуть выше Вы уже задали маршрут для всей сети /16:
    ip route add 10.8.0.0/16 dev eth1 src 10.8.5.14 table provider_1
    С остальными DNS серверами я еще могу понять - они лежат вне сети 80.242.156.56/30 и 10.8.0.0/16.
  3. Зачем вы прописываете маршруты для внутренних клиентов?:
    ip route add 192.168.0.0/24 dev eth0 table provider_1
    ip route add 192.168.0.0/24 dev eth0 table provider_2
    Мало того, что у вас внутренние клиенты напрямую во внешние сети не ходят (вы про это ничего не писали), их http-запросы терминируются на squid, а запросы к web-сайтам генерируются вашим proxy-сервером.
    Но даже если бы речь шла о чистой маршрутизации (что встречается крайне редко в условиях нехватки IPv4), то из двух написанных строчек, вторая никогда бы не работала.
  4. Я не силен во командах SuSE’шного firewall, что означает команда “ip rule del/add” и в частности что должна делать вот эта часть скрипта? :
ip rule del table provider_1
ip rule del table provider_2
#
ip rule add from 10.8.5.14 lookup provider_1
ip rule add from 80.242.156.56 lookup provider_2
  1. Как делалась проверка “а для сети2 не резолвятся dns-запросы”?
  2. Как сейчас выглядит /etc/resolve.conf?
  3. Для директивы “udp_outgoing_address” в squid.conf можно задать дополнительно access list, как для директивы “tcp_outgoing_address 10.8.5.14 prov_1”?

Спасибо.

To izemliansky
Спасибо за ответ, но у меня уже действительно все заработало! Дело было связано с обработкой dns-запросов первым провайдером (у которого dhcp) Похоже, у него не обрабатываются рекурсивные запросы с чужих сетей (…хотя как он узнает, когда запрос, по идее, идет от адреса из его собственной сети…??)
Но, для ясности, все равно постараюсь ответить на ваши вопросы.
В списке acl squid.conf действительно допущена ошибка. На самом деле было написано так:

acl prov_1 src 192.168.0.15-192.168.0.32
acl prov_**2** src 192.168.0.44-192.168.0.128

Далее, отвечаю по порядку.

  1. Да, маршрут по умолчанию может быть только один (через default gateway в таблице маршрутизации main) А маршруты для сетей prov_1 и prov_2 задаются в соответствующих таблицах. Но здесь, у prov_1 запущен dhcp и маршрут по умолчанию автоматически заносится в таблицу main. Потом его, конечно, можно выкинуть и записать любой необходимый. Дело в том, что я вначале удалял дефолтный gate - думал что из-за него маршруты не идут куда надо… потом разобрался…
  2. Теперь уже ясно, что маршруты для dns прописывать вобще не нужно. Они сами найдутся через дефолный шлюз (если принадлежат сети шлюза).
  3. Вы совершенно правы.
  4. Это не команды suseFirewall, а команды iproute2 - основного пакета маршрутизации linux.
    ip rule del/add - удаление/добавление таблицы правил маршрутизации.
    Соответственно в коде сказано:
    Сначала удаляем ранее созданные правила маршрутизации из обоих таблиц провайдеров (нужно если перезапускаем скрипт). Затем, добавляем правила, что приходящие с адресов 10.8.5.14 и 80.242.156.56 пакеты маршрутизировать по таблицам provider_1 и provider_2 соответственно.
  5. Смотрел tcpdump для интерфеса первого провайдера по соответствующему ip (сейчас команду не вспомню…) Там были видны запросы к dns с адреса второго провайдера, а ответом шел бит servErr 0/0/0 (или как-то так…). В итоге срабатывал таймаут и squid выдавал ошибку dns через браузер.
  6. После внесения ясности в ситуацию привел resolve.conf к виду:
    search TST
    nameserver 192.8.128.130
    nameserver 192.8.128.137
  • Перечислены только dns второго провайдера.
  1. Нет нельзя.
    Сам думал об этом, даже прописывать пробовал (squid не ругался), но прокси упорно шел по первому адресу в списке! acl этот параметр воспринимать явно не умеет. Эй разработчики, отзовитесь!