iptables - цель для маршрутизации пакета на определенный интерфейс?

25

Мой домашний сервер имеет два основных интерфейса eth1(стандартное подключение к Интернету) и tun0(туннель OpenVPN). Я хотел бы использовать iptablesдля принудительного завершения всех пакетов, сгенерированных локальным процессом, принадлежащим UID 1002tun0 , и всех других пакетов для выхода eth1.

Я могу легко пометить совпадающие пакеты:

iptables -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11

Теперь я хотел бы поместить какое-то правило в цепочку POSTROUTING (возможно, из таблицы mangle), чтобы сопоставлять пакеты, отмеченные 11, и отправлять их в tun0 , после чего следует правило, которое сопоставляет все пакеты и отправляет их eth1.

Я нашел цель ROUTE, но это, кажется, только переписывает исходный интерфейс (если я не читаю это неправильно).

Iptables способен на это? Должен ли я возиться с таблицей маршрутизации (через ip routeили просто устаревшееroute вместо этого командами)?

Изменить: Я подумал, что, возможно, я должен предоставить больше информации. У меня нет других правил iptables в настоящее время (хотя я могу создать некоторые правила для выполнения несвязанных задач в будущем). Кроме того, вывод ip route:

default via 192.168.1.254 dev eth1  metric 203
10.32.0.49 dev tun0  proto kernel  scope link  src 10.32.0.50
85.17.27.71 via 192.168.1.254 dev eth1
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.73  metric 203

Я не коснулся таблицы маршрутизации - это так, как она есть в настоящее время (хотя выглядит довольно грязно). Извините, но у меня не установлена ​​устаревшая routeкоманда на этом компьютере.

И вывод ip addr(конечно, eth0 и eth2 можно игнорировать - это сетевые адаптеры, которые в настоящее время не используются):

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 1c:6f:65:2a:73:3f brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast     state UP qlen 1000
    link/ether 00:1b:21:9d:4e:bb brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.73/24 brd 192.168.1.255 scope global eth1
    inet6 fe80::21b:21ff:fe9d:4ebb/64 scope link
       valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:1b:21:6a:c0:4b brd ff:ff:ff:ff:ff:ff
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc     pfifo_fast state UNKNOWN qlen 100
    link/none
    inet 10.32.0.50 peer 10.32.0.49/32 scope global tun0

Редактировать: я получил что-то вроде работы, но он не пересылает помеченные пакеты на tun0. По сути, я добавил таблицу (11) и использовал:

ip route add table 11 via 10.32.0.49 dev tun0
ip rule add priority 10000 fwmark 11 table 11

Когда я просто sudo -u user1000 wget -qO- whatismyip.org, я получаю внешний IP-адрес моего дома, но если я делаюsudo -u user1002 wget -qO- whatismyip.org , я также получаю IP-адрес своего дома (но я должен получать IP-адрес на другом конце туннеля OpenVPN).

Запуск iptables -vLподтверждает, что пакеты соответствуют правилу маркировки, но они не соответствуют правилу маршрутизации.

РЕДАКТИРОВАТЬ: я провел много времени на это, и хотя это все еще не работает, я думаю, что я немного ближе.

Правило iptables должно быть в mangleцепочке OUTPUT таблицы. Я думаю, что мне также нужно правило natMASQUERADE в цепочке POSTROUTING таблицы, чтобы установить адрес источника. Однако повторная маршрутизация, которая происходит после искажения OUTPUT, работает неправильно.

Я потратил 5 часов на это сейчас, поэтому я делаю перерыв и, возможно, вернусь к нему сегодня вечером или завтра.

Итан
источник

Ответы:

26

Я недавно столкнулся с подобной проблемой, хотя и немного другой. Я хотел только маршрут направить TCP-порт 25 (SMTP) через интерфейс tap0 OpenVPN, в то же время перенаправляя весь другой трафик (даже для того же хоста) через интерфейс по умолчанию.

Для этого мне пришлось пометить пакеты и установить правила для их обработки. Сначала добавьте правило, которое делает пакеты маршрутизации ядра помеченными 2через таблицу 3(объяснено позже):

ip rule add fwmark 2 table 3

Вы могли бы добавить символическое имя /etc/iproute2/rt_tables, но я не стал этого делать. Количество 2и 3выбирается случайным образом. Фактически, они могут быть одинаковыми, но для ясности я не делал этого в этом примере (хотя я делаю это в моей собственной настройке).

Добавьте маршрут для перенаправления трафика через другой интерфейс, предполагая, что шлюз 10.0.0.1:

ip route add default via 10.0.0.1 table 3

Очень важный! Очистите кеш маршрутизации, в противном случае вы не получите ответ и посидите с руками в волосах несколько часов:

ip route flush cache

Теперь установите правило брандмауэра для маркировки назначенных пакетов:

iptables -t mangle -A OUTPUT -p tcp --dport 465 -j MARK --set-mark 2

Вышеуказанное правило применяется только в том случае, если пакеты приходят с локального компьютера. Смотрите http://inai.de/images/nf-packet-flow.png . Настройте его в соответствии с вашими требованиями. Например, если вы хотите только направить исходящий HTTP-трафик через tap0интерфейс, измените 465 на 80.

Чтобы предотвратить отправку пакетов через tap0ваш LAN-адрес в качестве IP-адреса источника, используйте следующее правило, чтобы изменить его на адрес вашего интерфейса (в 10.0.0.2качестве IP-адреса для интерфейса tap0):

iptables -t nat -A POSTROUTING -o tap0 -j SNAT --to-source 10.0.0.2

Наконец, ослабьте проверку источника обратного пути. Некоторые предлагают вам установить его 0, но 2, по мнению https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt, это лучший выбор . Если вы пропустите это, вы получите пакеты (это можно подтвердить с помощью tcpdump -i tap0 -n), но пакеты не будут приняты. Команда для изменения настройки, чтобы пакеты были приняты:

sysctl -w net.ipv4.conf.tap0.rp_filter=2
Lekensteyn
источник
Почему вы используете SNAT вместо MASQUERADE? Разве MASQUERADE не делает то же самое, за исключением того, что IP-адрес собирается из интерфейса во время выполнения и не жестко запрограммирован в файле конфигурации?
Итан
6
@Ethan From man iptables: он должен использоваться только с динамически назначаемыми IP-соединениями (dialup): если у вас статический IP-адрес, вы должны использовать цель SNAT. Маскарадинг эквивалентен указанию сопоставления с IP-адресом интерфейса, из которого выходит пакет, но также имеет эффект того, что соединения теряются при отключении интерфейса. Вы правы, но, поскольку мой IP-адрес никогда не изменится, я решил использовать SNAT в соответствии с рекомендациями на странице руководства.
Лекенштейн
Я думаю (хотя и не проверял) последний шаг (проверка источника обратного пути) не является необходимым. Вы можете просто добавить другое правило в PREROUTINGцепочку к DNATправильному адресу источника (в соответствии с вашим шлюзом по умолчанию).
Кристиан Вольф
7

Я решил это. Проблема заключалась в правилах маршрутизации, приведенных в таблице 11. Таблица 11 была повреждена, но правила маршрутизации делают ее неработоспособной. Этот скрипт - то, что я сейчас использую, и он, кажется, работает хорошо (хотя он, очевидно, специфичен для моей установки). Также я создал новую таблицу 21, посвященную основному каналу связи (eth1).

# Add relevant iptables entries.
iptables -t mangle -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

# Flush ALL THE THINGS.
ip route flush table main
ip route flush table 11
ip route flush table 21
ip rule flush

# Restore the basic rules and add our own.
ip rule add lookup default priority 32767
ip rule add lookup main priority 32766
ip rule add fwmark 11 priority 1000 table 11
# This next rule basically sends all other traffic down eth1.
ip rule add priority 2000 table 21

# Restore the main table.  I flushed it because OpenVPN does weird things to it.
ip route add 127.0.0.0/8 via 127.0.0.1 dev lo
ip route add 192.168.1.0/24 dev eth1 src 192.168.1.73
ip route add default via 192.168.1.254

# Set up table 21.  This sends all traffic to eth1.
ip route add 192.168.1.0/24 dev eth1 table 21
ip route add default via 192.168.1.254 dev eth1 table 21

# Set up table 11.  I honestly don't know why 'default' won't work, or
# why the second line here is needed.  But it works this way.
ip route add 10.32.0.49/32 dev tun0 table 11
ip route add 10.32.0.1 via 10.32.0.50 dev tun0 table 11
ip route add 0.0.0.0/1 via 10.32.0.50 dev tun0 table 11

ip route flush cache

## MeanderingCode edit (потому что я пока не могу комментировать)

Спасибо за этот ответ! Кажется, что это может привести к путанице, так как вам придется хранить здесь информацию о маршруте (возможно, дублировать или ломать другие вещи, которые могут захотеть установить маршруты).

Возможно, вы испытываете «странные вещи» в своей таблице маршрутизации из OpenVPN, потому что сервер настроен для «проталкивания» маршрутов, позволяя всему трафику маршрутизировать через сетевой интерфейс VPN, а не из «пустого» Интернета. Или ваша конфигурация OpenVPN или любой сценарий / приложение, которое она настраивает, устанавливает маршруты.

В первом случае, вы можете изменить конфигурацию OpenVPN и поместить в строке , содержащую «рут-nopull»
В последней, конфигурации проверки для OpenVPN или любой обертки (сети-менеджер-OpenVPN, например , на многих современных настольную Linux дистрибутивов)
в системе в любом случае устранение конфигурации маршрутизации, в которой она устанавливается, будет более чистым и безопасным, чем очистка таблицы, в зависимости от того, когда вы запускаете этот скрипт и что еще делает ваша система.

Ура!

Итан
источник
2

Я думаю, что вы хотите:

/sbin/ip route add default via 10.32.0.49 dev tun0 table 11
/sbin/ip rule add priority 10000 fwmark 11 table 11

http://lartc.org/howto/lartc.netfilter.html

Но я не проверял выше.

mfarver
источник
Первая команда возвращает «Ошибка: либо« to »является дубликатом, либо« 10.32.0.49 »является мусором».
Итан,
Извините, забыл переход между по умолчанию и IP.
mfarver
Я попробовал это. Похоже, это имеет тот же эффект, что и опущение defaultключевого слова.
Итан
Чтобы исключить варианты, вы можете попытаться выполнить захват пакета на tun0 и посмотреть, заканчиваются ли пакеты на этом интерфейсе. tcpdump -i tun0 .. в качестве альтернативы, вам нужно основывать его на ID пользователя? Не могли бы вы сделать это на основе IP-адреса назначения (проще)? Маршрут добавить <удаленный хост> через 10.32.0.49
mfarver
Я не могу основать, если с IP-адреса назначения - их было бы много. Я также мог бы теоретически основать его на pid, но это еще сложнее, потому что я не буду знать pid, пока не запустятся демоны.
Итан
0

Это можно сделать без команды iptables. Выполнить простую команду ip.

Для UID 1002:

ip rule add uidrange 1002-1002 table 502

Добавьте маршрут по умолчанию для таблицы 502 через интерфейс, который вы хотите сказать

eth0 ip rule add default via a.b.c.d dev eth0
jainendra
источник
Я проверил эту команду, и она не сработала:Error: argument "uidrange" is wrong: Failed to parse rule type
kasperd
@ kasperd ты, должно быть, делал это неправильно, потому что у меня все работает нормально.
скакун