Я пытаюсь настроить прозрачные прокси-сети на своем хосте.
Реальные цели клиента и прокси являются контейнерами, но в этом эксперименте я использую среду, разделенную netns (сетевое пространство имен).
Чтобы прозрачно перенаправлять клиентский трафик на прокси, я использую маршрутизацию политик.
Client (C) Proxy (P)
10.10.1.1/24 10.10.2.1/24
veth0 veth0
| |
veth pair veth pair
| |
-----------(HOST)--------------
client-veth0 proxy-veth0
10.10.1.2/24 10.10.2.2/24
| | 172.16.202.30
+-----------------+-------------- enp4s0 ---- INTERNET
# Policy Routing on Host
# [Client->Proxy]
# ip rule: from 10.10.1.0/24 iif client-veth0 lookup 100
# ip route: (100) default via 10.10.2.1 dev proxy-veth0
# [Proxy->Internet]
# ip route: (master) default via 172.16.202.1 dev enp4s0 proto static metric 100
# iptables: -t nat -A POSTROUTING -s 10.10.1.1/32 -o enp4s0 -j MASQUERADE
# [Internet->Proxy]
# ip rule: from all to 10.10.1.0/24 iif enp4s0 lookup 100
# ip route: (100) default via 10.10.2.1 dev proxy-veth0
# [Proxy->Client]
# ip rule: from all to 10.10.1.0/24 iif proxy-veth0 lookup 101
# ip route: (101) default via 10.10.1.1 dev client-veth0
Проблема в том, что когда я пингую 8.8.8.8 от клиента в клиентских netns, маскировки исходных ip не происходит. Правило маскарада iptables не совпадает и по умолчанию принимается. Я ожидаю, что tcpdump на enp4s0 покажет 172.16.202.30 --> 8.8.8.8
, но это показывает 10.10.1.1 --> 8.8.8.8
, без маскировки исходного IP-адреса.
Я записал pcap в Интернете, чтобы уточнить, что SNAT не происходит. client_to_goolge
записывается с отдельной машины вне enp4s0:
$ tcpdump -r client_to_google -n
reading from file client_to_google, link-type EN10MB (Ethernet)
23:35:40.852257 IP 10.10.1.1 > 8.8.8.8: ICMP echo request, id 14867, seq 1, length 64
23:35:41.865269 IP 10.10.1.1 > 8.8.8.8: ICMP echo request, id 14867, seq 2, length 64
Когда я проверил таблицу iptables mangle, пакеты текут по заданной политике:
PREROUTING: client-veth0, 10.10.1.1 --> 8.8.8.8
POSTROUTING: proxy-veth0, 10.10.1.1 --> 8.8.8.8
PREROUTING: proxy-veth0, 10.10.1.1 --> 8.8.8.8
POSTROUTING: enp4s0, 10.10.1.1 --> 8.8.8.8
Однако, когда я изменяю правило маскарада на proxy-veth0
из интерфейса, вот так iptables: -t nat -A POSTROUTING -s 10.10.10.1/32 -o proxy-veth0 -j MASQUERADE
маскировка случается. То есть 10.10.2.2 --> 8.8.8.8
пакеты захватываются.
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
...
11 0 0 MASQUERADE all -- * enp4s0 10.10.1.1 0.0.0.0/0
12 1 84 MASQUERADE all -- * proxy-veth0 10.10.1.1 0.0.0.0/0
В таблице выше показано, что правило №11 enp4s0
условие вывода не сработало. Правило №12 было вставлено после нескольких тестов с правилом №11. Правило № 12 показывает, что proxy-veth0
условие вывода сработало. Есть ли различия между enp4s0
мастер Ник и proxy-veth0
виртный интерфейс с iptables?
Любые комментарии будут глубоко признательны, спасибо.
Я должен предположить, что прозрачный прокси-сервер действует как маршрутизатор, по крайней мере, для ICMP, поэтому он направит обратно эхо ICMP, откуда оно пришло (veth0).
При воспроизведении вашей настройки и наблюдении за вашей проблемой я добавил TRACE на хосте с помощью iptables (наследие, которое может немного отличаться от iptables-nftверсия) вот так (я также принудительно создал таблицу фильтров (iptables -S
) чтобы он был в следах):
iptables -t raw -A PREROUTING -j TRACE
И в журналах ядра отображается единичный пинг (подсказка, если хозяин не фактический начальный хост: sysctl -w net.netfilter.nf_log_all_netns=1
):
TRACE: raw:PREROUTING:policy:2 IN=client-veth0 OUT= MAC=66:f2:08:79:d0:df:be:1e:05:c1:c1:4b:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=7200 DF PROTO=ICMP TYPE=8 CODE=0 ID=3508 SEQ=1
TRACE: nat:PREROUTING:policy:1 IN=client-veth0 OUT= MAC=66:f2:08:79:d0:df:be:1e:05:c1:c1:4b:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=7200 DF PROTO=ICMP TYPE=8 CODE=0 ID=3508 SEQ=1
TRACE: filter:FORWARD:policy:1 IN=client-veth0 OUT=proxy-veth0 MAC=66:f2:08:79:d0:df:be:1e:05:c1:c1:4b:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=7200 DF PROTO=ICMP TYPE=8 CODE=0 ID=3508 SEQ=1
TRACE: nat:POSTROUTING:policy:2 IN=client-veth0 OUT=proxy-veth0 MAC=66:f2:08:79:d0:df:be:1e:05:c1:c1:4b:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=7200 DF PROTO=ICMP TYPE=8 CODE=0 ID=3508 SEQ=1
TRACE: raw:PREROUTING:policy:2 IN=proxy-veth0 OUT= MAC=16:c9:3c:d4:ad:8c:8a:84:06:5d:88:e2:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=62 ID=7200 DF PROTO=ICMP TYPE=8 CODE=0 ID=3508 SEQ=1
TRACE: filter:FORWARD:policy:1 IN=proxy-veth0 OUT=enp4s0 MAC=16:c9:3c:d4:ad:8c:8a:84:06:5d:88:e2:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=61 ID=7200 DF PROTO=ICMP TYPE=8 CODE=0 ID=3508 SEQ=1
В то же время, имея conntrack -E
запущенный на хосте показывает соответствие:
# conntrack -E
[NEW] icmp 1 30 src=10.10.1.1 dst=8.8.8.8 type=8 code=0 id=3508 [UNREPLIED] src=8.8.8.8 dst=10.10.1.1 type=0 code=0 id=3508
Что произошло:
Поскольку это ConntrackОграничение препятствовало некоторым вариантам использования в прошлом, например, вашему, была добавлена дополнительная функция:
Зона - это просто числовой идентификатор, связанный с сетевым устройством, который включен в различные хэши и используется для различения записей в дополнение к кортежам соединений.
[...]
Это в основном полезно при подключении нескольких частных сетей с использованием одних и тех же адресов (что, к сожалению, иногда случается) для передачи пакетов через набор veth-устройств и SNAT каждой сети на уникальный адрес, после чего они могут проходить через «основную» зону и обрабатываться как обычные неконфликтующие пакеты и / или применять NAT во второй раз на основе fi на исходящем интерфейсе.
Это позволяет как бы дублировать Conntrack средства, включая обработку NAT, но должны выполняться вручную и соответствовать проблеме: здесь топология маршрутизации.
Итак, здесь трафик client <-> прокси, в Conntrackс точки зрения, нужно отделить от остального трафика.
Я бы предпочел также отделить интернет-трафик прокси <-> от общего трафика хоста, но это слишком сложно, потому что сырой таблица, в которой зоны должны быть назначены пакету, видит только трафик без де-NAT, поэтому все ответы Интернета будут приходить с адресом 172.16.202.30). В любом случае, здесь нет дублированного потока между обоими, как с потоком прокси client <->, так что это действительно не нужно.
зона 0 (0 означает отсутствие специальной зоны): общий трафик хоста вместе с прокси <-> Интернет-трафиком.
Делать особо нечего, это по умолчанию.
зона 1: трафик клиент <-> прокси. В CT --zone
цель используется. Значение здесь выбрано произвольно и в данном случае больше нигде не требуется.
iptables -t raw -A PREROUTING -i client-veth0 -j CT --zone 1
iptables -t raw -A PREROUTING -i proxy-veth0 -d 10.10.1.0/24 -j CT --zone 1
Правильные результаты (я объединил результаты обоих инструментов) теперь:
TRACE: raw:PREROUTING:rule:2 IN=client-veth0 OUT= MAC=4e:e7:2f:3f:a3:6c:4a:b9:40:66:60:32:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
TRACE: raw:PREROUTING:policy:4 IN=client-veth0 OUT= MAC=4e:e7:2f:3f:a3:6c:4a:b9:40:66:60:32:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
TRACE: nat:PREROUTING:policy:1 IN=client-veth0 OUT= MAC=4e:e7:2f:3f:a3:6c:4a:b9:40:66:60:32:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
TRACE: filter:FORWARD:policy:1 IN=client-veth0 OUT=proxy-veth0 MAC=4e:e7:2f:3f:a3:6c:4a:b9:40:66:60:32:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
TRACE: nat:POSTROUTING:policy:2 IN=client-veth0 OUT=proxy-veth0 MAC=4e:e7:2f:3f:a3:6c:4a:b9:40:66:60:32:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
[NEW] icmp 1 30 src=10.10.1.1 dst=8.8.8.8 type=8 code=0 id=4079 [UNREPLIED] src=8.8.8.8 dst=10.10.1.1 type=0 code=0 id=4079 zone=1
TRACE: raw:PREROUTING:policy:4 IN=proxy-veth0 OUT= MAC=86:c8:4b:5f:16:fc:ba:76:80:0f:20:7d:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=62 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
TRACE: nat:PREROUTING:policy:1 IN=proxy-veth0 OUT= MAC=86:c8:4b:5f:16:fc:ba:76:80:0f:20:7d:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=62 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
TRACE: filter:FORWARD:policy:1 IN=proxy-veth0 OUT=enp4s0 MAC=86:c8:4b:5f:16:fc:ba:76:80:0f:20:7d:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=61 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
TRACE: nat:POSTROUTING:rule:1 IN=proxy-veth0 OUT=enp4s0 MAC=86:c8:4b:5f:16:fc:ba:76:80:0f:20:7d:08:00 SRC=10.10.1.1 DST=8.8.8.8 LEN=84 TOS=0x00 PREC=0x00 TTL=61 ID=58185 DF PROTO=ICMP TYPE=8 CODE=0 ID=4079 SEQ=1
[NEW] icmp 1 30 src=10.10.1.1 dst=8.8.8.8 type=8 code=0 id=4079 [UNREPLIED] src=8.8.8.8 dst=172.16.202.30 type=0 code=0 id=4079
TRACE: raw:PREROUTING:policy:4 IN=enp4s0 OUT= MAC=5e:e8:0c:bf:96:d9:b2:e7:bc:df:1f:8e:08:00 SRC=8.8.8.8 DST=172.16.202.30 LEN=84 TOS=0x00 PREC=0x00 TTL=62 ID=12099 PROTO=ICMP TYPE=0 CODE=0 ID=4079 SEQ=1
TRACE: filter:FORWARD:policy:1 IN=enp4s0 OUT=proxy-veth0 MAC=5e:e8:0c:bf:96:d9:b2:e7:bc:df:1f:8e:08:00 SRC=8.8.8.8 DST=10.10.1.1 LEN=84 TOS=0x00 PREC=0x00 TTL=61 ID=12099 PROTO=ICMP TYPE=0 CODE=0 ID=4079 SEQ=1
[UPDATE] icmp 1 30 src=10.10.1.1 dst=8.8.8.8 type=8 code=0 id=4079 src=8.8.8.8 dst=172.16.202.30 type=0 code=0 id=4079
TRACE: raw:PREROUTING:rule:3 IN=proxy-veth0 OUT= MAC=86:c8:4b:5f:16:fc:ba:76:80:0f:20:7d:08:00 SRC=8.8.8.8 DST=10.10.1.1 LEN=84 TOS=0x00 PREC=0x00 TTL=60 ID=12099 PROTO=ICMP TYPE=0 CODE=0 ID=4079 SEQ=1
TRACE: raw:PREROUTING:policy:4 IN=proxy-veth0 OUT= MAC=86:c8:4b:5f:16:fc:ba:76:80:0f:20:7d:08:00 SRC=8.8.8.8 DST=10.10.1.1 LEN=84 TOS=0x00 PREC=0x00 TTL=60 ID=12099 PROTO=ICMP TYPE=0 CODE=0 ID=4079 SEQ=1
TRACE: filter:FORWARD:policy:1 IN=proxy-veth0 OUT=client-veth0 MAC=86:c8:4b:5f:16:fc:ba:76:80:0f:20:7d:08:00 SRC=8.8.8.8 DST=10.10.1.1 LEN=84 TOS=0x00 PREC=0x00 TTL=59 ID=12099 PROTO=ICMP TYPE=0 CODE=0 ID=4079 SEQ=1
[UPDATE] icmp 1 30 src=10.10.1.1 dst=8.8.8.8 type=8 code=0 id=4079 src=8.8.8.8 dst=10.10.1.1 type=0 code=0 id=4079 zone=1
Здесь один первый пакет из нового потока дважды запускает iptables ' нац таблица, первый раз без эффекта. Фактически Conntrack считает, что есть два потока, потому что первый поток имеет дополнительный атрибут zone=1
.
Это нормальное поведение iptables NAT. Сейчас тестирую с tcpdump, использую три виртуальные машины, на каждой виртуальной машине я установил правило SNAT
vm1 (10.10.1.1) ---> vm2 (10.10.2.2) ---> vm3 (1.2.3.4) (общедоступный IP-адрес)
Затем я пробую ping 8.8.8.8 из 10.10.1.1, запускаю tcpdump на всех трех машинах, и результаты были следующими: на vm2 10.10.1.1 ---> 8.8.8.8 на vm3 10.10.2.2 ---> 8.8.8.8
Теоретически, если бы у меня была vm4, я бы увидел 1.2.3.4 ---> 8.8.8.8
Не могли бы вы показать конфигурацию вашего прокси?
Борис