iptables port forwarding with internal SNAT

Iai*_*own 4 port-forwarding iptables

I would like to forward an external port to a different port on a machine on a private network. However, I need to SNAT the traffic to appear to be from the gateway's internal IP, since the destination machine has a totally different outbound route. I'm combining two questions here, but I'm not sure if I can merge the results of asking them separately.

Gateway = 1.2.3.4/192.168.2.5, internal server = 192.168.2.10

  1. Forwarding to different port

I'm used to doing this, and it seems to be pretty much the only answer Google finds for me:

iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 12345 -j DNAT --to-destination 192.168.2.10:12345
iptables -A FORWARD -p tcp -d 192.168.2.10 --dport 12345 -j ACCEPT
iptables -A POSTROUTING -t nat -d 192.168.2.10 -s 192.168.2.0/24 -p tcp --dport 12345 -j SNAT --to 1.2.3.4
Run Code Online (Sandbox Code Playgroud)

which will forward port 12345 from my external IP of 1.2.3.4 to 192.168.2.10:12345. What if I want to forward to port 54321? I get confused about which port reference matches which machine; I've solved this by trial and error in the past only to find later that it didn't really work.

  1. Forwarding from the LAN address

我不确定这部分是否可能。我想要的是传入 192.168.2.10:54321 的流量源自网关计算机的 LAN 地址,而不是来自互联网。(我尝试将端口 443 转发到 ssh 服务器,但该服务器已经在不同的 IP 地址上在外部可见,因此回复流量将采用不同的路由。)

我修改了上面的标准规则:

iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 12345 -j DNAT --to-destination 192.168.2.10:12345
iptables -A POSTROUTING -t nat -p tcp -d 192.168.2.10 --dport 12345 -j SNAT --to-source 192.168.2.5
iptables -A FORWARD -p tcp -d 192.168.2.10 --dport 12345 -j ACCEPT
iptables -A POSTROUTING -t nat -d 192.168.2.10 -s 192.168.2.0/24 -p tcp --dport 12345 -j SNAT --to 1.2.3.4
Run Code Online (Sandbox Code Playgroud)

tcpdump 显示流量现在来自网关的 LAN 地址 192.168.2.5,并且服务器正在回复,但不会转发到外部地址。我怀疑这甚至是不可能的,回复流量需要将客户端的地址作为其目的地,但如果 iptables可以正确重定向回复,我将不胜感激有关如何重定向的线索。

另外,如果可能的话,包括更改目标端口的正确语法,如第 1 部分所示。

Iai*_*own 7

经过一些实验,我想我已经回答了我的问题,所以我应该将其发布在这里,以防其他人发现它有用。是的,这是可能的,而且相当简单,只需获得正确的地址和端口组合即可。

注意:下面的示例需要使用以下命令启用内核 IP 转发

echo 1 > /proc/sys/net/ipv4/ip_forward
Run Code Online (Sandbox Code Playgroud)

在任何这些片段之前。

我的脚本的评论:

# summary:
# allow forwarding *to* destination ip:port
# allow forwarding *from* destination ip:port
# nat packets identified by arrival at external IP / port to have
#  *destination* internal ip:port
# nat packets identified by arrival at internal IP / port to have
#  *source* internal network IP of gateway machine
Run Code Online (Sandbox Code Playgroud)

对于问题中的例子:

# allow inbound and outbound forwarding
iptables -A FORWARD -p tcp -d 192.168.2.10 --dport 54321 -j ACCEPT
iptables -A FORWARD -p tcp -s 192.168.2.10 --sport 54321 -j ACCEPT

# route packets arriving at external IP/port to LAN machine
iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 12345 -j DNAT --to-destination 192.168.2.10:54321
# rewrite packets going to LAN machine (identified by address/port)
# to originate from gateway's internal address
iptables -A POSTROUTING -t nat -p tcp -d 192.168.2.10 --dport 54321 -j SNAT --to-source 192.168.2.5
Run Code Online (Sandbox Code Playgroud)

实际的脚本,因为这应该更容易直接应用:

# EXTIP = external IP of gateway (1.2.3.4)
# EPORT = external port (12345)
# DIP   = destination IP in local network (192.168.2.10)
# DPORT = destination port (54321)
# INTIP = internal IP of gateway (192.168.2.5)

iptables -A FORWARD -p tcp -d $DIP --dport $DPORT -j ACCEPT
iptables -A FORWARD -p tcp -s $DIP --sport $DPORT -j ACCEPT

iptables -A PREROUTING -t nat -p tcp -d $EXTIP --dport $EPORT -j DNAT --to-destination $DIP:$DPORT
iptables -A POSTROUTING -t nat -p tcp -d $DIP --dport $DPORT -j SNAT --to-source $INTIP
Run Code Online (Sandbox Code Playgroud)

我希望答案对其他人有用,并且我不会用已经处理过多次的内容弄乱网站。