Я настроил переадресацию порта для порта 80 с помощью iptables:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 10080
Кроме того, у меня включена переадресация ip для маршрутизации соединений из другой подсети.
Я использую свой собственный стандартный сервер сокетов на порту 10080 на той же машине, и когда я получаю входящее соединение на порт 80, оно, как и ожидалось, перенаправляется на мой сервер.
Моя проблема в том, что когда я распечатываю информацию о сокете, используя getsockname и getpeername, исходным адресом всегда является адрес сервера. Если я подключаюсь к серверу напрямую через порт, на который не влияет правило iptables, я вижу адрес клиента, как и ожидалось. Почему переадресация портов влияет на исходный адрес?
Я не думаю, что цель перенаправления является правильной для использования в этом случае, динамическая цель NAT была бы более подходящей.
Если у вас есть сервер во внутренней сети, который вы хотите сделать доступным извне, вы можете использовать
-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)
И все хорошо.