iptables --set-mark - маршрутизировать разные порты через разные интерфейсы

14

Короткая история,
3 интерфейса, eth0 (LAN), eth1 (ADSL), eth2 (4G).
eth0 -> eth1: работает
(порты 80, 443, 4070) eth0 -> eth2: не происходит


Это графическое представление идеи:

Порт 80 и 443 через eth2
и остальные через eth1
введите описание изображения здесь

Netscheme:

eth0: -ip 10.0.0.1 -net 10.0.0.0/8 -gw 10.0.0.1 (the servers own intf) 
eth1: -ip 192.168.1.74 -net 192.168.1.0/24 -gw 192.168.1.254 
eth2: -ip 192.168.1.91 -net 192.168.0.0/24 -gw 192.168.0.1 






Я думаю, что этот новый скрипт перенаправляет 22 и 4070 в нужную таблицу.
Тем не менее, после получения этого стола он не перенаправляется на eth2.




Этот скрипт работает, кроме 22 и 4070!

(Порт 80 не прокомментирован и работает, но через eth1, что неправильно.)

modprobe iptable_nat
modprobe ip_conntrack

echo "1" > /proc/sys/net/ipv4/ip_forward

iptables -P INPUT ACCEPT
iptables -F INPUT
iptables -P OUTPUT ACCEPT
iptables -F OUTPUT
iptables -P FORWARD DROP
iptables -F FORWARD
iptables -F PREROUTING
iptables -t nat -F
iptables -t mangle -F
iptables -F
# This next line restores any issues trying to connect to something
# if you get weird ACK packets when trying to connect (at least i did)!
iptables -t mangle -A PREROUTING -p tcp -j CONNMARK --restore-mark
ip route flush table main

iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 22 -j MARK --set-mark 1
###  iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 80 -j MARK --set-mark 1
iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 4070 -j MARK --set-mark 1

## Setup routes
# LAN
route add -net 10.0.0.0 netmask 255.0.0.0 dev eth0
# ADSL
route add -net 192.168.1.0 netmask 255.255.255.0 dev eth1
# 4G (Only accessible if marking packages with \x01
route add -net 192.168.0.0 netmask 255.255.255.0 dev eth2
# Default via ADSL
## -- Does the same as ip route below? route add default gw 192.168.1.254


echo "201 eth2.out" >> /etc/iproute2/rt_tables

ip rule add fwmark 1 table eth2.out
ip route add default via 192.168.0.1 dev eth2 table eth2.out
ip route add default via 192.168.1.254 dev eth1



## Setup forwards
# From 4G to LAN
iptables -A FORWARD -i eth2 -o eth0 -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT
# From ADSL to LAN
iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT
# From LAN to ADSL (Default route out)
# - Note: If marked packages is sent to ADSL they will be mangled and rerouted to 4G
iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE









Старый скрипт:


  Ignore everything below unless you're interested in retracing my steps!!




Я создал скрипт router.sh для настройки своего окружения на случай, если я сделаю что-то плохое. У меня есть 3 порта, которые я хочу отправить на соединение 4G, а остальные через стационарное ADSL-соединение. Для этого я поручил iptables манипулировать пакетами по маршруту по умолчанию и отправлять их через мой интерфейс 4G, если --dport == 443 | 80 | 4070

Тем не менее, это не работает; Я все еще пробираюсь через мой стационарный телефон, несмотря ни на что.

Вот как выглядит мой скрипт:

#!/bin/bash

## routing tables
# wireless = 4G via eth2
# adsl = adsl via eth1

modprobe iptable_nat
modprobe ip_conntrack

echo "1" > /proc/sys/net/ipv4/ip_forward

iptables -P INPUT ACCEPT
iptables -F INPUT
iptables -P OUTPUT ACCEPT
iptables -F OUTPUT
iptables -P FORWARD DROP
iptables -F FORWARD
iptables -t nat -F
ip route flush table main
ip route flush table wireless
ip route flush table adsl

## Setup routing tables
# ADSL
ip route add table adsl to 192.168.1.0/24 dev eth1
# 4G
ip route add table wireless to 192.168.0.0 dev eth2
ip rule add fwmark 0x1 table wireless

## Setup routes
# LAN
route add -net 10.0.0.0 netmask 255.0.0.0 dev eth0
# ADSL
route add -net 192.168.1.0 netmask 255.255.255.0 dev eth1
# 4G (Only accessible if marking packages with \x01
route add -net 192.168.0.0 netmask 255.255.255.0 dev eth2
# Default via ADSL
route add default gw 192.168.1.254


## Forward ports into the LAN
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j DNAT --to 10.0.0.3:80


## Lets mark all packets we want for 4G forward
# HTTPS
iptables -A OUTPUT -t mangle -o eth1 -p tcp --dport 443 -j MARK --set-mark 1
# HTTP
iptables -A OUTPUT -t mangle -o eth1 -p tcp --dport 80 -j MARK --set-mark 1
# Spotify
iptables -A OUTPUT -t mangle -o eth1 -p tcp --dport 4070 -j MARK --set-mark 1

## Setup forwards
# From 4G to LAN
iptables -A FORWARD -i eth2 -o eth0 -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT
# From ADSL to LAN
iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
# From LAN to ADSL (Default route out)
# - Note: If marked packages is sent to ADSL they will be mangled and rerouted to 4G
iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT
iptables -A FORWARD -j LOG
#iptables --table nat --append POSTROUTING --out-interface eth2 --jump SNAT --to-source "192.168.1.74"
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

Я также попытался добавить эти 3 в нижнюю часть скрипта:

iptables -t nat -A POSTROUTING -o eth2 -p tcp --dport 80 -j SNAT --to "192.168.0.91"
iptables -t nat -A POSTROUTING -o eth2 -p tcp --dport 443 -j SNAT --to "192.168.0.91"
iptables -t nat -A POSTROUTING -o eth2 -p tcp --dport 4070 -j SNAT --to "192.168.0.91"

Также попробовал без успеха:

iptables -A PREROUTING -t mangle -i eth0 -p tcp --dport 80 -j MARK --set-mark 1

И последнее, но не менее важное:

## Lets mark all packets we want for 4G forward
# HTTPS
iptables -A POSTROUTING -t mangle -o eth1 -p tcp --dport 443 -j MARK --set-mark 1
# HTTP
iptables -A POSTROUTING -t mangle -o eth1 -p tcp --dport 80 -j MARK --set-mark 1
# Spotify
iptables -A POSTROUTING -t mangle -o eth1 -p tcp --dport 4070 -j MARK --set-mark 1

Маршрутизация работает, я могу просматривать веб-страницы, слушать музыку и что-то еще, но я делаю это через неправильный интерфейс. Я долго гуглил и нашел кусочки, чтобы понять, что я делаю и почему я это делаю. Я мог бы формировать трафик через tc, но если бы это было возможно с помощью маркировки пакетов в iptables, это бы мне очень помогло.

Я предполагаю, что я делаю заказ неправильно по различным правилам, в основном, в части MASQUERADE ? или если это вообще должно быть там?

Может кто-нибудь объяснить, как порт DNAT, скажем, tcp: 80 с внешнего интерфейса (один или оба протокола) во внутреннее адресное пространство 10.0.0.0?



Выходы:

root@Netbridge:~# route -n Kernel IP routing table Destination    

Gateway         Genmask         Flags Metric Ref    Use Iface<br>
0.0.0.0         192.168.1.254   0.0.0.0         UG    0      0        0 eth1<br>
10.0.0.0        0.0.0.0         255.0.0.0       U     0      0        0 eth0<br>
192.168.0.0     0.0.0.0         255.255.255.0   U     0      0        0 eth2<br>
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1


root@Netbridge:~# ifconfig

eth0      Link encap:Ethernet  HWaddr 00:0c:29:7e:9e:4e  
          inet addr:10.0.0.1  Bcast:10.255.255.255  Mask:255.0.0.0

eth1      Link encap:Ethernet  HWaddr 00:0c:29:7e:9e:58  
          inet addr:192.168.1.74  Bcast:192.168.1.255  Mask:255.255.255.0

eth2      Link encap:Ethernet  HWaddr 00:0c:29:7e:9e:62  
          inet addr:192.168.0.91  Bcast:192.168.0.255  Mask:255.255.255.0

Следовали этим инструкциям: iptables-forward-specific-port-to-specific-nic
выходной трафик на разных интерфейсах, основанный на назначении, среди нескольких других связанных потоков.

Torxed
источник
Извините, но есть ли причина не связывать apache только с localhostадресом eth2интерфейса?
Ян Марек
@JanMarek: здесь нет упоминания о Apache. И, к вашему сведению, привязка сокета к ethXIP-адресу ip не позволит узлам ethXлокальной сети получить доступ к локальному серверу с использованием ethYip-адреса и не помешает хостам с ethYдоступа к серверу с использованием ethXip-адреса. Помните, что Linux использует слабую модель хоста.
BatchyX
ОК, возможно, есть больше веб-серверов, а не только сервер Apache ... Я думаю, что привязка веб-сервера к интерфейсу eth2 может быть простым решением. Но я могу ошибаться, я знаю.
Ян Марек

Ответы:

5

BatchyX уже дает очень хорошее объяснение по поводу iptables и маршрутизации, поэтому я проявлю свою лень и сразу перейду к сценарию.

Это должно NAT весь трафик к порту 80,443,22,4070 через 192.168.0.91. Все остальное будет через NAT через 192.168.1.254.

Я повторно делаю свое тестирование и заканчиваю тем, что следовал этому руководству . Чего не хватает в этом руководстве - это последние 3 строки в моем сценарии. Который я узнал из другого порта, но я потерял эту ссылку.

Это проверенный рабочий скрипт.

Нужен маршрут по умолчанию

Одна вещь, которую я не включил в скрипт - это настройка маршрута по умолчанию. Так должно быть

route add default gw 192.168.1.254

Когда вы это сделаете route -n, это должен быть единственный маршрут по умолчанию (Dest: 0.0.0.0)

0.0.0.0    192.168.1.254    0.0.0.0    UG    0    0    0    eth1

fw-router.sh

# Сбросить / очистить iptables
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P ВВОД ПРИНЯТЬ
iptables -P FORWARD ACCEPT
iptables -P ВЫХОД ПРИНЯТЬ

# Сбросить / очистить / настроить IP-маршрут (таблица 4)
ip route flush таблица 4
ip route show table главная | grep -Ev ^ default | пока читаешь МАРШРУТ; сделать ip route добавить таблицу 4 $ ROUTE; сделано
ip route добавить таблицу 4 по умолчанию через 192.168.0.1

#Mark Packet с соответствующим D.Port
iptables -t mangle -A ПРЕДУПРЕЖДЕНИЕ -p tcp --dport 22 -s 10.0.0.0/24 -j MARK --set-mark 4
iptables -t mangle -A ПРЕДУПРЕЖДЕНИЕ -p tcp --dport 80 -s 10.0.0.0/24 -j MARK --set-mark 4
iptables -t mangle -A ПРЕДУПРЕЖДЕНИЕ -p tcp --dport 443 -s 10.0.0.0/24 -j MARK --set-mark 4
iptables -t mangle -A ПРЕДУПРЕЖДЕНИЕ -p tcp --dport 4070 -s 10.0.0.0/24 -j MARK --set-mark 4

#SNAT Rules
iptables -t nat -A POSTROUTING -o eth1 -j SNAT - к источнику 192.168.1.74
iptables -t nat -A POSTROUTING -o eth2 -j SNAT - к источнику 192.168.0.91

#IP Route
ip rule add fwmark 4 таблица 4
ip route flush cache

#IP Stack
# Это недостающая часть из руководства
echo 1> / proc / sys / net / ipv4 / ip_forward
для поиска в / proc / sys / net / ipv4 / conf / * / rp_filter; do echo 0> $ f; сделано
echo 0> / proc / sys / net / ipv4 / route / flush

PS1: Короче говоря, MASQUERADEне работает (в большинстве случаев, и определенно в вашем случае) для NAT с несколькими внешними IP-адресами, которые нуждаются в некотором распределении нагрузки или нуждаются в DNAT для обработки входящего трафика. Вам нужно SNATдля контроля направления.

PS2: Чистого iptables недостаточно.

John Siu
источник
Прежде всего, ура за то, что вы обратились непосредственно к сценарию :) Я попробую это сегодня вечером, когда вернусь к среде, в которой это будет происходить!
Торксед
хм, может понадобиться тяжелый пересмотр. Дайте мне знать результат.
Джон Сиу
Пересмотрено, должно работать сейчас.
Джон Сиу
Сладкая, скоро вернусь к тебе: D
Torxed
Я люблю тебя, такая сильная головная боль, и ты решил ее! Спасибо!
Торксед
6

Примечание: я рассмотрел только первый скрипт, игнорируя старый.

  • Вам не нужно вручную проверять модули netfilter с текущими iptables. Это необходимо только для пользовательских трекеров подключения.
  • Не перепутай routeи ip route. Это чистое зло. Просто используйте ipвезде и забыть о ifconfigиroute
  • /etc/iproute2/rt_tablesне сбрасывается при перезагрузках. Повторное добавление одной и той же записи не является хорошей идеей, вам нужно сделать это только один раз. Помните, что rt_tablesпросто определяйте псевдонимы имен для числовых значений, это не меняет никакой конфигурации.

  • Теперь для iptables: В вашей FORWARDцепочке вы отбрасываете пакеты, приходящие из локальной сети в 4G. Это плохо. FORWARDкрючок используется после маршрутизации выполняется. На этом этапе вся политика маршрутизации выполнена, и уже известно, должен ли пакет быть отправлен в 4G или ADSL. Переназначение не выполняется ни в, FORWARDни после FORWARD(ну, технически, перенаправление может быть выполнено после POSTROUTINGсерьезных случаев, но вернемся к сути).

Теперь для вашей маршрутизации: помните, что Ubuntu по умолчанию включает фильтрацию обратного пути. Фильтрация обратного пути работает следующим образом: когда ядро ​​получает пакет (может быть он переслан или нет) от интерфейса A, оно инвертирует адрес источника и адрес назначения и проверяет, должен ли полученный пакет маршрутизироваться через интерфейс A. Если это не так, пакет отбрасывается как попытка подмены адреса.

Для пакетов, полученных от eth0, это не проблема. Для пакетов, полученных от eth1, это также не является проблемой, поскольку при обращении IP-адреса источника и IP-адреса назначения ядро ​​будет использовать маршрут по умолчанию в таблице main. Для пакетов, полученных от eth2, которые вы не помечаете, это проблема, потому что ядро ​​будет использовать маршрут по умолчанию в таблице mainи считать, что эти пакеты должны были быть получены eth1. Самое простое решение - отключить фильтрацию обратного пути на eth1:

sysctl -w net.ipv4.conf.eth1.rp_filter=0
BatchyX
источник
Все отличные комментарии и да, с моей стороны есть некоторая ошибочная логика, например, добавление к rt_tables каждый раз и, в особенности, не очистка определенных таблиц так, как мне следовало бы, но я доберусь до цели :) Я все проверю и посмотрю если это сработает, если да, +50 к вам, и самое главное, вы спасли человека от того, что его разрубили на кусочки и покои! :)
Torxed
1
Приведенный ниже сценарий работает, но вы, сэр, также заслуживаете всей благодарности, вы дали мне одну-две вещи, о которых нужно подумать, и rp_filter = 0 очень помог! : D
Torxed
@BatchyX очень информативно, голосование за вас тоже.
Джон Сиу
@Torxed В сообщении, которое я видел, упоминалось, что rp_filter для ВСЕГО интерфейса необходимо отключить. Я не уверен, что это работает по-другому.
Джон Сиу
@JohnSiu: Вам просто нужно отключить фильтр rp на интерфейсах, где это проблематично. В этом случае это eth1, потому что нет маршрута к этому интерфейсу, когда метки не установлены. У eth2 такой проблемы нет, так как маршрут по умолчанию идет в этот интерфейс. Для eth0 на самом деле полезно оставить фильтр rp включенным, иначе кто-то в локальной сети может подделать IP-пакет с адресом источника в Интернете и адресом назначения в локальной сети, и маршрутизатор с радостью примет его и отправит вернемся к ... эт0.
BatchyX 22.12.12