@beliand

Как организовать два активных канала интернет, FreeBSD 11?

Добрый день! Возникла необходимость развернуть сервер (FreeBSD 11) с двумя активными каналами интернет. Один канал - местный провайдер (ррр-подключение, tun0), другой 3G модем Intertelecom (tun1). На обеих каналах необходимо настроить перенаправление портов на компьютер в локальной сети. IP-адреса обеих провайдеров выделенные.
Проблема возникает в том, что на втором канале перенаправление не работает. Если каналы "поменять местами" - ситуация повторяется: тот который стал первым (Intertelecom) перенаправляет, который стал вторым - нет. Перечитал кучу информации, форумов, у ребят получается - у меня нет. Чем больше читаю на эту тему - тем больше каши в голове... Что я упустил или что делаю не так?

Описание адресов:

XXX.XXX.XXX.XX1 - IP-адрес шлюза провайдера 1
XXX.XXX.XXX.XX2 - Выделенный IP-адрес провайдера 1
YYY.YYY.YYY.YY1 - IP-адрес шлюза провайдера 2
YYY.YYY.YYY.YY2 - Выделенный IP-адрес провайдера 1
192.168.0.100 - IP-адрес компьютера в локальной сети, на который необходимо настроить перенаправление

Ядро скомпилировано со следующими опциями:

options         IPFIREWALL                     
options         IPFIREWALL_DEFAULT_TO_ACCEPT    
options         IPFIREWALL_VERBOSE              
options         IPFIREWALL_VERBOSE_LIMIT=50     
options         IPDIVERT                       
options         IPFIREWALL_NAT                  
options         LIBALIAS                    
options         ROUTETABLES=2
options         DUMMYNET
options         HZ="1000"


Настройки rc.conf:

ifconfig_re1="inet 192.168.0.2 netmask 255.255.255.0"
sshd_enable="YES"
ntpd_enable="YES"
# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable
dumpdev="AUTO"

gateway_enable="YES"            # разрешаем пересылку пакетов между се
firewall_nat_enable="YES"       # включаем ядерный nat
firewall_nat_interface="re0"    # указываем внешний интерфейс для nat
firewall_enable="YES"           # включаем ipfw
firewall_script="/usr/local/etc/ipfw/rc.firewall" # указываем путь, где будут

usbd_enable="YES"

ppp_enable="YES"
ppp_mode="ddial"
ppp_nat="YES"
ppp_profile="ISP1"
ppp_user="root"


Подключение tun1 подымается командой:
ppp -ddial -unit 1 ISP2

ifconfig:
re0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=8209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE>
        ether 98:de:d0:03:11:57
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
re1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=8209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE>
        ether 98:de:d0:03:f4:e1
        inet 192.168.0.2 netmask 0xffffff00 broadcast 192.168.0.255
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
        media: Ethernet autoselect (1000baseT <full-duplex,master>)
        status: active
re2: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=8209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE>
        ether 38:d5:47:a9:84:52
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
        media: Ethernet autoselect (none)
        status: no carrier
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
        options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x4
        inet 127.0.0.1 netmask 0xff000000
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
        groups: lo
tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1492
        options=80000<LINKSTATE>
        inet XXX.XXX.XXX.XX2 --> XXX.XXX.XXX.XX1  netmask 0xffffffff
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
        groups: tun
        Opened by PID 581
tun1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
        options=80000<LINKSTATE>
        inet YYY.YYY.YYY.YY2 --> YYY.YYY.YYY.YY1  netmask 0xffffffff
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
        groups: tun
        Opened by PID 1168


Правила ipfw:

# XXX.XXX.XXX.XX1 - IP-адрес шлюза провайдера 1
# XXX.XXX.XXX.XX2 - Выделенный IP-адрес провайдера 1
# YYY.YYY.YYY.YY1 - IP-адрес шлюза провайдера 2
# YYY.YYY.YYY.YY2 - Выделенный IP-адрес провайдера 1
# 192.168.0.100 - IP-адрес компьютера в локальной сети, на который необходимо настроить перенаправление

cmd="ipfw -q"

$cmd -f flush

$cmd add 100 allow ip from any to any via lo0

# Запрещаем доступ из вне к нутреннему интерфейсу
$cmd add 200 deny ip from any to 127.0.0.0/8
$cmd add 300 deny ip from 127.0.0.0/8 to any


# Разрешаем подключение по ssh
$cmd add 400 allow tcp from any to XXX.XXX.XXX.XX2 22 in via tun0
$cmd add 410 allow tcp from XXX.XXX.XXX.XX2 22 to any out via tun0 established

$cmd add 420 allow tcp from any to YYY.YYY.YYY.YY2 22 in via tun1
$cmd add 430 allow tcp from YYY.YYY.YYY.YY2 22 to any out via tun1 established

# Разрешаем DNS запросы
$cmd add 500 allow udp from any to XXX.XXX.XXX.XX2 53 in via tun0
$cmd add 510 allow udp from XXX.XXX.XXX.XX2 53 to any out via tun0 established

$cmd add 520 allow udp from any to YYY.YYY.YYY.YY2 53 in via tun1
$cmd add 530 allow udp from YYY.YYY.YYY.YY2 53 to any out via tun1 established


# Эти правила должны обеспечить активность двух каналов 
$cmd add 600 fwd XXX.XXX.XXX.XX1 ip from XXX.XXX.XXX.XX2 to any
$cmd add 610 fwd YYY.YYY.YYY.YY1 ip from YYY.YYY.YYY.YY2 to any


# Разрешаем некоторые типы ICMP траффика - эхо-запрос, эхо-ответ и время жизни пакета истекло
$cmd add 700  allow icmp from any to any icmptypes 0,8,11


# Разрешаем все соединения на локальном интерфейсе
$cmd add 800 allow all from any to any via re1


# Первый NAT
$cmd nat 1 config log if tun0 reset same_ports deny_in redirect_port tcp 192.168.0.100:3389 3389
$cmd add 1100 nat 1 ip from any to any via tun0

# Второй NAT
$cmd nat 2 config log if tun1 reset same_ports deny_in redirect_port tcp 192.168.0.100:3389 3389
$cmd add 1200 nat 2 ip from any to any via tun1


# Разрешаем все остальные
$cmd add 65535 allow ip from any to any


sysctl.conf:

net.inet.ip.fw.one_pass=0

setfib 0 netstat -rn:

Internet:
Destination        Gateway            Flags     Netif Expire
default            XXX.XXX.XXX.XX1    UGS        tun0
XXX.XXX.XXX.XX1    link#5             UHS        tun0
127.0.0.1          link#4             UH          lo0
YYY.YYY.YYY.YY1    link#6             UHS        tun1
192.168.0.0/24     link#2             U           re1
192.168.0.2        link#2             UHS         lo0
XXX.XXX.XXX.XX2    link#5             UHS         lo0
YYY.YYY.YYY.YY2    link#6             UHS         lo0


setfib 1 netstat -rn:

Internet:
Destination        Gateway            Flags     Netif Expire
default            YYY.YYY.YYY.YY1    UGS        tun1
XXX.XXX.XXX.XX1    link#5             UH         tun0
127.0.0.1          link#4             UH          lo0
YYY.YYY.YYY.YY1    link#6             UH         tun1
192.168.0.0/24     link#2             U           re1


ipfw show:

00100    0      0 allow ip from any to any via lo0
00200    0      0 deny ip from any to 127.0.0.0/8
00300    0      0 deny ip from 127.0.0.0/8 to any
00400  207  29610 allow tcp from any to XXX.XXX.XXX.XX2 dst-port 22 in via tun0
00410  151  47696 allow tcp from XXX.XXX.XXX.XX2 22 to any out via tun0 established
00420   23   3278 allow tcp from any to YYY.YYY.YYY.YY2 dst-port 22 in via tun1
00430   14   6180 allow tcp from YYY.YYY.YYY.YY2 22 to any out via tun1 established
00500    0      0 allow udp from any to XXX.XXX.XXX.XX2 dst-port 53 in via tun0
00510    0      0 allow udp from XXX.XXX.XXX.XX2 53 to any out via tun0 established
00520    0      0 allow udp from any to YYY.YYY.YYY.YY2 dst-port 53 in via tun1
00530    0      0 allow udp from YYY.YYY.YYY.YY2 53 to any out via tun1 established
00600  108   7484 fwd XXX.XXX.XXX.XX1 ip from XXX.XXX.XXX.XX2 to any
00610   28   1596 fwd YYY.YYY.YYY.YY1 ip from YYY.YYY.YYY.YY2 to any
00700   20   1120 allow icmp from any to any icmptypes 0,8,11
00800 2846 708794 allow ip from any to any via re1
01100 1305 445563 nat 1 ip from any to any via tun0
01200   16   1159 nat 2 ip from any to any via tun1
65535 2155 835010 allow ip from any to any


Складывается впечатление, что пакеты, которые приходят на второй канал, уходят через первый. Как можно решить эту проблему с использованием IPFW?

Заранее спасибо!
  • Вопрос задан
  • 1810 просмотров
Пригласить эксперта
Ответы на вопрос 3
athacker
@athacker
Опция IPDIVERT в ядре лишняя, она не нужна для работы ядерного NAT. Мешать она не мешает, но на всякий случай имейте в виду -- её можно спокойно убрать.

Первый fwd (правило 600) -- тоже не нужен, у вас и так трафик будет улетать в шлюз по умолчанию, и без этого правила.

А не работает у вас потому, что до второго NAT-а дело не доходит никогда. Схема такая:

  1. Пришёл пакет из интернета (допустим, с внешнего IP ZZZ) на X2:3389.
  2. Первый NAT его поймал и поменяв DST IP на 192.168.0100, отправил пакет в локалку.
  3. Хост 192.168.0.100 на него ответил, и отправил ответ через свой шлюз по умолчанию (это ваша фряха).
  4. Фряха получила пакет от клиента, предназначенный для некоего внешнего адреса ZZZ. Осознала, что он предназначен для внешнего адреса, и НАПРАВИЛА ЕГО В СВОЙ DEFAULT GW. А default GW у неё -- это шлюз на стороне провайдера 1. В сторону этого провайдера смотрит интерфейс tun0
  5. Дальше пакет идёт по правилам файрвола и натыкается на правило: $cmd add 1100 nat 1 ip from any to any via tun0. Пакет под него подпадает, так как он системой отправлен через tun0. Соответственно, согласно этому правилу пакет попадает в NAT, и его SRC IP меняется с 192.168.0.100 на X2.
  6. Дальнейшая обработка продолжается (так как one_pass=0), но мы уже получили что? Что у нас есть исходящий пакет (после обработки первым натом) с IP-адреса X2, предназначенный для внешнего адреса ZZZ и улетающий через интерфейс tun0. Соответственно, второй NAT его не обрабатывает, так как под его условия (via tun1) этот пакет уже не попадает. Поэтому пакет дальше просто уходит в сторону шлюза X1, и всё


В вашем случае самым простым способом будет выдать хосту 192.168.0.100 ещё один IP-шник (скажем, 192.168.0.101), и через провайдера 2 заворачивать пакеты именно на него. Тогда можно будет сделать так:

$cmd nat 1 config log if tun0 reset same_ports deny_in redirect_port tcp 192.168.0.100:3389 3389
$cmd add 1100 nat 1 ip from 192.168.0.100 to any via tun0

# Второй NAT
$cmd nat 2 config log if tun1 reset same_ports deny_in redirect_port tcp 192.168.0.101:3389 3389
$cmd add 1200 nat 2 ip from 192.168.0.101 to any via tun1

$cmd add 1300 fwd YYY.YYY.YYY.YY1 ip from YYY.YYY.YYY.YY2 to any out via tun0


Правила схематичные, и не учитывают, что нужен обычный нат для всех остальных клиентов. Просто демонстрация, для понимания логики.
Ответ написан
@res2001
Developer, ex-admin
Правильное впечатление создается - уходят на шлюз по умолчанию. И это нормальное поведение.
Хотя FreeBSD поддерживает множественные шлюзы по умолчанию, но при этом она работает не так как хочется (на сколько помню она по раунд-робину меняет эти шлюзы от пакета к пакету, это явно не то что нужно).
Можно это сделать с помощью nat global и множественных таблиц маршрутизации.
Для балансировки исходящих пакетов можно использовать ipfw probe.
Почитайте эту статью: ipfw.ism.kiev.ua/pbr.html, хотя она старая и там используется natd, но то же самое можно и на ядерном нате сделать.

PS: реализовывал эту задачу года 3 назад, ушло много времени на отладку. Правда у меня была конфигурация по сложней и вариант из статьи мне мало помог.
Ответ написан
Комментировать
@Z462
При отправке шлюз тоже укаживать надо (setfib 0-1 )
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы