Рейтинг:5

Использование переадресации iptables при правильном сохранении IP-адреса источника

флаг ng

У меня есть сервер, на котором работает Wireguard (поэтому требуется маскарад) и контейнер, работающий на порту 2525.

у меня есть следующее iptables правила:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 172.18.0.1:2525
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

При подключении к сервер: 2525 напрямую, контейнер Docker может видеть мой реальный IP-адрес (1.2.3.4). При подключении к порту сервер:25, контейнер Docker видит локальный IP-адрес, предоставленный докер сеть:

07 апр., 12:45:46 mx postfix/smtpd[87]: потеря соединения после CONNECT от unknown[172.18.0.1]
07 апр., 12:45:46 mx postfix/smtpd[87]: отключиться от неизвестных[172.18.0.1] команд=0/0

Как убедиться, что контейнер Docker правильно видит общедоступный IP-адрес при подключении к порту 25 (а не только при подключении к порту 2525).

Спасибо

# iptables -L -n -v -t физ
Цепочка PREROUTING (политика ACCEPT 0 пакетов, 0 байт)
 pkts bytes target prot opt ​​in out source target
52300 3131K DNAT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:25 to:172.18.0.1:2525
 150K 8524K DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE соответствует dst-type LOCAL

Цепочка INPUT (политика ACCEPT 0 пакетов, 0 байтов)
 pkts bytes target prot opt ​​in out source target

Цепочка OUTPUT (политика ACCEPT 0 пакетов, 0 байт)
 pkts bytes target prot opt ​​in out source target
    2 120 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE соответствует dst-типу LOCAL

Цепочка POSTROUTING (политика ACCEPT 0 пакетов, 0 байт)
 pkts bytes target prot opt ​​in out source target
 3385 256K МАСКАРАД все -- * !docker0 172.17.0.0/16 0.0.0.0/0
1733K 104M МАСКАРАД все -- * !br-b147ffdbc9f3 172.18.0.0/16 0.0.0.0/0
    0 0 МАСКАРАД tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:53
    0 0 MASQUERADE udp -- * * 172.17.0.2 172.17.0.2 udp dpt:53
    0 0 МАСКАРАД tcp -- * * 172.18.0.2 172.18.0.2 tcp dpt:25

Сеть DOCKER (2 ссылки)
 pkts bytes target prot opt ​​in out source target
   12 1419 ВОЗВРАТ все -- docker0 * 0.0.0.0/0 0.0.0.0/0
    0 0 ВОЗВРАТИТЬ все -- br-b147ffdbc9f3 * 0.0.0.0/0 0.0.0.0/0
   56 3192 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:5354 to:172.17.0.2:53
    0 0 DNAT udp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 udp dpt:5354 to:172.17.0.2:53
  107 6020 DNAT TCP -- !br-b147ffdbc9f3 * 0.0.0.0/0 0.0.0.0/0 TCP dpt:2525 to:172.18.0.2:25
# ip адрес
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    ссылка/петля 00:00:00:00:00:00 брд 00:00:00:00:00:00
    инет 127.0.0.1/8 область хоста lo
       valid_lft навсегда
    inet6 :: 1/128 узел области видимости
       valid_lft навсегда
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast состояние UP группа по умолчанию qlen 1000
    ссылка/эфир 32:d0:56:15:0a:64 brd ff:ff:ff:ff:ff:ff
    альтернативное имя enp0s3
    альтернативное имя ens3
    инет 159.223.80.86/20 brd 159.223.95.255 глобальный охват eth0
       valid_lft навсегда
    inet 10.15.0.19/16 brd 10.15.255.255 глобальная область eth0:1
       valid_lft навсегда
    inet6 2400:6180:0:d0::f57:6001/64 область глобальная
       valid_lft навсегда
    ссылка на область inet6 fe80::30d0:56ff:fe15:a64/64
       valid_lft навсегда
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast состояние UP группа по умолчанию qlen 1000
    ссылка/эфир 32:dc:4a:e4:27:be brd ff:ff:ff:ff:ff:ff
    альтернативное имя enp0s4
    альтернативное имя ens4
    инет 10.130.244.15/16 brd 10.130.255.255 глобальный охват eth1
       valid_lft навсегда
    ссылка на область inet6 fe80::30dc:4aff:fee4:27be/64
       valid_lft навсегда
4: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    ссылка/нет
    инет 10.200.200.52/24 глобальная область WG0
       valid_lft навсегда
5: wg1: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    ссылка/нет
    инет 10.222.111.1/24 область глобальная WG1
       valid_lft навсегда
6: br-b147ffdbc9f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    ссылка/эфир 02:42:46:21:70:c0 brd ff:ff:ff:ff:ff:ff
    инет 172.18.0.1/16 brd 172.18.255.255 глобальная область действия br-b147ffdbc9f3
       valid_lft навсегда
    ссылка на область inet6 fe80::42:46ff:fe21:70c0/64
       valid_lft навсегда
7: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    ссылка/эфир 02:42:66:22:41:91 брд ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 глобальная область действия docker0
       valid_lft навсегда
    ссылка на область inet6 fe80::42:66ff:fe22:4191/64
       valid_lft навсегда
9: veth31eff9d@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    ссылка/эфир e6:fb:80:5d:c7:a3 brd ff:ff:ff:ff:ff:ff ссылка-netnsid 0
    ссылка на область inet6 fe80::e4fb:80ff:fe5d:c7a3/64
       valid_lft навсегда
19: veth01269f5@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-b147ffdbc9f3 состояние UP группа по умолчанию
    ссылка/эфир 36:f4:e7:43:5f:da brd ff:ff:ff:ff:ff:ff ссылка-netnsid 2
    ссылка на область inet6 fe80::34f4:e7ff:fe43:5fda/64
       valid_lft навсегда
setenforce 1 avatar
флаг us
похоже, что у вас есть правило постмаршрутизации SNAT при переходе к интерфейсу докера, которое вы можете удалить. Не могли бы вы добавить результат `iptables -L -n -v -t nat`?
eKKiM avatar
флаг lr
Можете ли вы подробнее рассказать о своей сетевой инфраструктуре/настройке, включая часть wireguard? Для меня (на данный момент) непонятно, зачем нужен маскарад.
флаг ng
@setenforce1 добавлено в начальный пост
флаг ng
@eKKiM Я считаю, что необходимо правильно маршрутизировать (т. Е. Он действует как шлюз / VPN: клиент -> сервер WG -> Интернет)
eKKiM avatar
флаг lr
Является ли сервер WG также шлюзом по умолчанию в вашей сети? Можете ли вы добавить вывод `ifconfig -a` или `ip-адрес`?
флаг ng
Нет, это цифровой морской сервер. eth0 имеет общедоступный IP-адрес. Добавлен `ip addr` к исходному сообщению.
eKKiM avatar
флаг lr
Не вижу смысла во всех этих РАЗМЕЩАЮЩИХ правила маскарада. Не могли бы вы заменить его одним `iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE`
флаг ng
Я удалил один, у меня сейчас есть это: ``` ip6tables -A INPUT -i eth0 -m tcp -p tcp --dport 25 -j ОТКЛОНИТЬ ip6tables -A INPUT -i eth0 -m tcp -p tcp --dport 2525 -j ОТКЛОНИТЬ iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE ```
Рейтинг:2
флаг cl
A.B

Просто позвольте Docker управлять перенаправлением, которое является динамическим и может меняться при добавлении, удалении или перезапуске контейнеров. Но см. ОБНОВИТЬ ниже.

Это перенаправление не должно быть на 172.18.0.1, который является хостом, а не контейнером. Когда хост получает такое соединение, оно обрабатывается докер-прокси который проксирует его в контейнер, теряя при этом исходный IP-адрес.

Docker уже DNAT + правильно маршрутизирует этот порт (за исключением самого хоста, где докер-прокси играет эту роль) в самом последнем правиле набора правил к запущенному контейнеру с адресом 172.18.0.2. За исключением того, что он настроен на использование порта 2525, а не порта 25.

  107 6020 DNAT TCP -- !br-b147ffdbc9f3 * 0.0.0.0/0 0.0.0.0/0 TCP dpt:2525 to:172.18.0.2:25

Это должно быть исправлено с помощью настроек Docker, а не вручную. iptables правила, которые не могут измениться при изменении макета контейнера. Поскольку порт 25 является привилегированным, если Docker работает без рута, необходимы дополнительные настройки, проверьте документация по раскрытию привилегированных портов.


ОБНОВИТЬ (с учетом комментариев OP): OP в настоящее время не может использовать -п 25:25 так как докер-прокси конфликтует с SMTP-сервером локального хоста и конкурирует за прослушивание порта 25 на хосте. Вот почему первоначальный (неправильный) iptables перенаправление было сделано OP.

Можно:

  • отключить глобально докер-прокси запустив докерд с имуществом userland-прокси установить на ложь

    либо как параметр --userland-proxy=false или как собственность "userland-прокси": ложь добавлен /etc/докер/daemon.json.

    Затем это позволит использовать докер запустить... -p 25:25... (как задокументировано) без конфликтов: хост достигнет самого себя при достижении локального хоста или $HOSTNAME, удаленные системы получат доступ к контейнеру, и никакой «адрес уже используется» не приведет к сбою демона SMTP хоста или контейнера Docker при запуске.

  • или же добавьте ручное перенаправление (с длительной настройкой ниже, чтобы сделать это почти автоматически)

    Всякий раз, когда контейнер перезапускается, существует риск изменения его (внутреннего) IP-адреса. Так что это надо вычислить. Итак, с контейнером с именем МХ используя сеть с именем МХ и с одним задействованным IP-адресом это можно сделать, как описано ниже.

    Создайте отдельную цепочку предварительной маршрутизации (чтобы ее можно было сбросить без необходимости сбрасывать что-либо еще) и сначала вызовите ее:

    iptables -t nat -N mynat
    iptables -t nat -I PREROUTING -j mynat
    

    IP-адрес контейнера можно получить программно (для простого случая контейнера с именем МХ с одним адресом):

    containerip=$(docker container inspect --format '{{.NetworkSettings.IPAddress}}' mx)
    

    (или можно было бы использовать jq: containerip=$(docker container inspect mx | jq '.[].NetworkSettings.IPAddress')

    Поиск имени интерфейса моста более запутан, или, по крайней мере, я не смог найти способ, используя только докер ... проверить. Итак, найдите его IP-адрес на хосте и запросите хост, используя айпи адрес чтобы найти только интерфейс моста, на котором установлен этот конкретный IP-адрес (требуется jq команда.)

     bridgeip=$(docker network inspect --format '{{(index .IPAM.Config 0).Gateway}}' mx)
     bridgeinterface=$(ip -json показывает адрес "$bridgeip"/32 | jq -r '.[].ifname')
    

    Сбросьте и заполните заново майнат каждый раз, когда контейнер (пере)запускается:

    iptables -t nat -F mynat
    iptables -t nat -A mynat ! -i "$bridgeinterface" -p tcp --dport 25 -j DNAT --to-destination "$containerip":25
    

    что было бы для текущего случая:

    iptables -t nat -I mynat ! -i br-b147ffdbc9f3 -p tcp --dport 25 -j DNAT --назначение 172.18.0.2:25

    И чтобы убедиться, что собственные правила брандмауэра Docker не блокируют такой трафик, сделайте что-то подобное, начиная с filter/ВПЕРЕД от DOCKER-ПОЛЬЗОВАТЕЛЬ цепь.

    Первоначально (если из загрузки, вам, возможно, придется сначала создать DOCKER-ПОЛЬЗОВАТЕЛЬ):

    iptables -N мой форвард
    iptables -I DOCKER-USER 1 -j myforward
    

    Затем позже каждый раз, когда контейнер (пере)запускается:

    iptables -F мой форвард
    iptables -A myforward -p TCP ! -i "$bridgeinterface" -d "$containerip" -p tcp --dport 25 -j ПРИНЯТЬ
    

    что было бы для текущего случая:

    iptables -A myforward -p TCP ! -i br-b147ffdbc9f3 -d 172.18.0.2 -p tcp --dport 25 -j ПРИНЯТЬ
    

Примечания:

  • Чтобы упростить приведенные выше правила и избежать некоторых вычислений, контейнер и его мостовую сеть можно запустить с фиксированными IP-адресами.См., например, этот SO Q/A: Назначить статический IP контейнеру Docker.

  • Вот также UL SE Q/A с моим ответом о проблемах при взаимодействии с Docker (он предназначен для nftables но некоторые части о DOCKER-ПОЛЬЗОВАТЕЛЬ цепь или br_netfilter мостовые взаимодействия по-прежнему представляют интерес): Докер белого списка nftables

флаг ng
Спасибо. Это использует `docker run`: `docker run -d -P --network mx -p 2525:25 -v /srv/mx/:/mx/ --restart always --name mx mx`
флаг ng
Я использую порт 2525, потому что, если я не запускаю постфикс на локальном хосте, команда `mail` не работает, и электронная почта не доставляется. https://pastebin.com/RR2mDx9T (при запуске контейнера на порту 25)
eKKiM avatar
флаг lr
Прокси-сервер afaik docker userland буквально проксирует соединение, поэтому исходный IP-адрес будет изменен.
A.B avatar
флаг cl
A.B
@eKKiM действительно, это то, что я освещаю в `docker-proxy`.
A.B avatar
флаг cl
A.B
@Tuinslak, поэтому в этом контексте (нельзя использовать порт 25) правило Docker, уже установленное (самое последнее правило, отображаемое в наборе правил, отображаемом в вопросе, заданном с помощью `-p 2525:25`), уже обрабатывает его. Почему вы тогда добавляете правило, переопределяющее его?
eKKiM avatar
флаг lr
@A.B формулировка «Просто позвольте Docker обработать перенаправление», позвольте мне предположить, что это будет обрабатываться docker-proxy
A.B avatar
флаг cl
A.B
@eKKiM docker-proxy задействован только для хоста: 172.18.0.1. Он не задействован при маршрутизации в контейнер 172.18.0.2. Но добавленное правило iptables OP заставляет поток принудительно использовать докер-прокси вместо маршрутизации.
флаг ng
Если я не запускаю `iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE`, сервер не пересылает пакеты, и я не могу использовать его как VPN/пропинговать любой хост за пределами сервера - https:// pastebin.com/uY0Rka6Z
флаг ng
Похоже, `iptables -t nat -I PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 172.18.0.2:25` работает. Итак, я не могу использовать прокси-сервер docker (`172.18.0.1`), но мне нужно использовать фактический IP-адрес контейнера?
A.B avatar
флаг cl
A.B
Моя ссылка о `docker-proxy` говорит о том, что его можно отключить глобально с помощью `--userland-proxy=false`. Или `"userland-proxy": false` в [`/etc/docker/daemon.json`](https://docs.docker.com/engine/reference/commandline/dockerd/). Если вам не нужно обращаться к своим контейнерам (всем, а не только к этому: он глобальный) с помощью самого хоста, вы можете просто использовать `-p 25:25`.Это проблема только тогда, когда задействована шпилька NAT, поэтому, когда контейнеру необходимо связаться с другим контейнером, используя общедоступный (адрес eth0) IP-адрес хоста.
A.B avatar
флаг cl
A.B
Вы можете без проблем использовать `172.18.0.2:25`, но имейте в виду, что этот адрес не является постоянным, он может измениться при запуске других контейнеров в зависимости от конфигурации.
A.B avatar
флаг cl
A.B
Я изменил свой ответ, чтобы обратиться к информации в комментариях и сделать некоторую автоматизацию.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.