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

исходный адрес с переадресацией портов iptables

Я настроил переадресацию порта для порта 80 с помощью iptables:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 10080  

Кроме того, у меня включена переадресация ip для маршрутизации соединений из другой подсети.

Я использую свой собственный стандартный сервер сокетов на порту 10080 на той же машине, и когда я получаю входящее соединение на порт 80, оно, как и ожидалось, перенаправляется на мой сервер.

Моя проблема в том, что когда я распечатываю информацию о сокете, используя getsockname и getpeername, исходным адресом всегда является адрес сервера. Если я подключаюсь к серверу напрямую через порт, на который не влияет правило iptables, я вижу адрес клиента, как и ожидалось. Почему переадресация портов влияет на исходный адрес?

Я не думаю, что цель перенаправления является правильной для использования в этом случае, динамическая цель NAT была бы более подходящей.

Отрывок из https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Security_Guide/s1-firewall-ipt-fwd.html:

Если у вас есть сервер во внутренней сети, который вы хотите сделать доступным извне, вы можете использовать -j DNAT target цепочки PREROUTING в NAT, чтобы указать IP-адрес и порт назначения, на которые могут быть перенаправлены входящие пакеты, запрашивающие соединение с вашей внутренней службой. Например, если вы хотите перенаправить входящие HTTP-запросы на выделенный сервер HTTP-сервера Apache по адресу 172.31.0.23, выполните следующую команду:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT \
  --to 172.31.0.23:80

Моя проблема в том, что когда я распечатываю информацию о сокете, используя getsockname и getpeername, исходным адресом всегда является адрес сервера. Если я подключаюсь к серверу напрямую через порт, на который не влияет правило iptables, я вижу адрес клиента, как и ожидалось. Почему переадресация портов влияет на исходный адрес?

Я объясню, но предупреждаю, что это будет длинное объяснение.

Давайте сначала разберемся, что такое TCP соединение: Это обмен данными с отслеживанием состояния между «кортежем инициатора». (IP,Port) и "терминатор кортеж" (IP,port).

Другими словами, TCP-соединение определяется четырехместный из (Client_IP,Client_Port,Server_IP,Server_Port).

Это означает, что вся передача информации для этого TCP-соединения должна соответствовать четырехэтапному определению.

Теперь предположим, что ваш сервер расположен по адресу 1.1.1.1, а клиент - по адресу 2.2.2.2. Клиент открывает соединение с портом 80 вашего сервера. Предполагая, что эфемерный порт клиента - 34567, у нас есть четырехпозиционный порт (2.2.2.2,34567,1.1.1.1,80).

На вашем сервере пакет перенаправляется на 1.1.1.1:10080. Но это приводит к другим четырем видам связи! Например, (2.2.2.2,34567,1.1.1.1,10080).

Что будет делать настоящий слушатель? Почему он будет отвечать напрямую на 2.2.2.2:34567, в результате чего пакет будет отброшен клиентом, потому что у клиента есть четыре элемента (2.2.2.2,34567,1.1.1.1,80), а не (2.2. 2.2,34567,1.1.1.1,10080).

Итак, в этом случае REDIRECT target должен создать временное четырехэлементное отображение:

(2.2.2.2,34567,1.1.1.1,80) --> (1.1.1.1,x,1.1.1.1,10080)

(x - временный эфемерный порт, позволяющий устанавливать TCP-соединение).

С помощью этого временного сопоставления сервер на 10080 отвечает на netfilter, и происходит обратное отображение:

(1.1.1.1,x,1.1.1.1,10080) --> (2.2.2.2,34567,1.1.1.1,80)

netfilter отправляет клиенту пакет с обратным отображением, и все в порядке.

Итак, если вам нужно знать IP-адрес клиента, вы не может использовать REDIRECT цель. Лучше поместите свой фактический сервер в другую подсеть и используйте DNAT target, при этом ваш сервер Linux действует как полноценный маршрутизатор. Предполагая, что ваш фактический сервер имеет адрес локальной сети 192.168.1.51, отображение будет следующим:

(2.2.2.2,34567,1.1.1.1,80) --> (2.2.2.2,34567,192.168.1.51,80)

Сервер с адресом 192.168.1.51 ответит на 2.2.2.2, а маршрутизатор перевернет карту:

(2.2.2.2,34567,192.168.1.51,80) --> (2.2.2.2,34567,1.1.1.1,80)

И все хорошо.