Назад | Перейти на главную страницу

Почему iptables NAT не выполняется в настройке прозрачного прокси-сервера, разделенной пространством имен сети?

Я пытаюсь настроить прозрачные прокси-сети на своем хосте.

Реальные цели клиента и прокси являются контейнерами, но в этом эксперименте я использую среду, разделенную 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 (который обрабатывает NAT) не заботится о маршрутах (например: в базе данных conntrack нет интерфейса), только об адресах,
  • в нац таблица будет видеть только пакеты в состоянии NEW,
  • время, когда Conntrack добавила НОВУЮ запись в свою базу данных, когда пакет был перенаправлен из client-veth0 к прокси-veth0: не соответствует правилу POSTROUTING,
  • второй раунд при маршрутизации из прокси-veth0 к enp4s0 пакет соответствует записи в Conntrack и в нац стол больше не вызывали,
  • пакет уходит в Интернет без NAT.

Поскольку это ConntrackОграничение препятствовало некоторым вариантам использования в прошлом, например, вашему, была добавлена ​​дополнительная функция:

зоны 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

Не могли бы вы показать конфигурацию вашего прокси?

Борис