У меня есть хост-машина (A
) с lxc-контейнером (B
). A
локальный IP-адрес 10.0.3.1 и общедоступный IP, скажем, 1.2.3.4. B
Локальный IP-адрес - 10.0.3.21.
Мне нужно, чтобы 1.2.3.4:7999 был перенаправлен на 10.0.3.1:7999, и я создал для этого следующие правила:
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 7999 -j DNAT --to 10.0.3.21:7999
iptables -A FORWARD -p tcp -d 10.0.3.21 --dport 7999 -j ACCEPT
Когда я подключаюсь к A
(1.2.3.4:7999) из внешнего мира я успешно подключаюсь. Но я падаю, когда пытаюсь подключиться к B
из A
(время соединения истекло).
Какие правила мне нужно создать, чтобы иметь возможность подключаться к 1.2.3.4:7999 из 10.0.3.1?
У тебя есть Шпилька NAT ситуация здесь, которую ваши текущие правила iptables не поддерживают. Когда контейнер отправляет запрос, пакет выглядит так:
10.0.3.21:12345 -> 1.2.3.4:7999
Затем шлюз отправляет пакет к этому DNAT и отправляет его обратно в контейнер:
10.0.3.21:12345 -> 10.0.3.21:7999
Контейнер получает пакеты и отправляет ответ, который выглядит следующим образом:
10.0.3.21:7999 -> 10.0.3.21:12345
т.е. он напрямую обращается к самому контейнеру. Но порт 12345 не знает о соединении с 10.0.3.21:7999, потому что соединение было с 1.2.3.4:7999, и поэтому ответ игнорируется.
Решение состоит в том, чтобы также SNAT пакет на шлюзе, чтобы ответ возвращался на шлюз, который затем отменяет оба NAT. Попробуйте добавить что-то вроде этого:
iptables -t NAT -A POSTROUTING -o lxcbr0 -d 10.0.3.21 -s 10.0.3.21 -j SNAT --to 10.0.3.1
Я думаю, что проблема, с которой вы столкнулись, заключается в том, что ответ возвращается в другом интерфейсе.
Первоначальный запрос
S: 1.2.3.4
D: 1.2.3.4
DNAT
S: 1.2.3.4
D: 10.0.3.21
На этом этапе хост A
принимает решение направиться к 10.0.3.21
используя частный сетевой интерфейс.
ОТВЕТИТЬ
S: (IP of default GW interface on B)
D: 1.2.3.4
Ответный пакет от B
пересечет шлюз по умолчанию и, скорее всего, вернется к A
на своем общедоступном интерфейсе, после чего пакет отбрасывается, поскольку в таблице отслеживания соединений нет соответствующей записи.
Решение
Добавьте следующее правило, чтобы ответ проходил по тому же пути, что и запрос.
iptables -t nat -I POSTROUTING -s 1.2.3.4 -d 10.0.3.21 -o (interface of 10.0.3.1) -j SNAT --to 10.0.3.1