源地址与iptables端口转发

我使用iptables为端口80设置端口转发

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

此外,我有IP转发启用来路由不同子网的连接。

我在同一台机器上的端口10080上运行我自己的标准套接字服务器,当我收到一个到端口80的传入连接时,它会按照预期转发到我的服务器。

我的问题是,当我打印出使用getsockname和getpeername的套接字信息时,源地址始终是服务器的。 如果我通过一个不受iptables规则影响的端口直接连接到服务器,我会看到预期的客户端地址。 为什么端口转发影响源地址?

我不认为redirect目标是正确的,在这种情况下,dynamicNAT目标会更合适。

摘自https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Security_Guide/s1-firewall-ipt-fwd.html

如果您的内部networking上有一台服务器可以在外部使用,则可以使用NAT中PREROUTING链的-j DNAT目标指定一个目标IP地址和端口,请求连接到您的内部服务的传入数据包可以是转发。 例如,如果您想要将传入的HTTP请求转发到您的专用Apache HTTP Server服务器系统(位于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)。

在你的服务器上,数据包被redirect到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目标必须创build一个临时的四元映射:

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

(x是允许build立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目标,你的Linux服务器充当一个完整的路由器。 假设您的实际服务器有一个本地LAN地址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) 

而且一切都很好。