如何使用 iptables 进行端口转发?

Stu*_*Stu 126 linux iptables port-forwarding

我希望在端口 8001 上进入 ppp0 的连接路由到端口 8080 上的 eth0 上的 192.168.1.200。

我有这两条规则

-A PREROUTING  -p tcp -m tcp --dport 8001 -j DNAT --to-destination 192.168.1.200:8080

-A FORWARD -m state -p tcp -d 192.168.1.200 --dport 8080 --state NEW,ESTABLISHED,RELATED -j ACCEPT
Run Code Online (Sandbox Code Playgroud)

它不起作用。我错过了什么?

小智 105

首先 - 您应该检查是否允许转发:

cat /proc/sys/net/ipv4/conf/ppp0/forwarding 
cat /proc/sys/net/ipv4/conf/eth0/forwarding 
Run Code Online (Sandbox Code Playgroud)

如果两者都返回1就可以了。如果没有,请执行以下操作:

echo '1' | sudo tee /proc/sys/net/ipv4/conf/ppp0/forwarding
echo '1' | sudo tee /proc/sys/net/ipv4/conf/eth0/forwarding
Run Code Online (Sandbox Code Playgroud)

第二件事 -DNAT只能应用于nat桌子。因此,您的规则也应该通过添加表规范来扩展 ( -t nat):

iptables -t nat -A PREROUTING -p tcp -i ppp0 --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
iptables -A FORWARD -p tcp -d 192.168.1.200 --dport 8080 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
Run Code Online (Sandbox Code Playgroud)

这两个规则都只适用于 TCP 流量(如果你也想改变 UDP,你需要提供类似的规则,但-p udp设置了选项)。

最后但并非最不重要的是路由配置。类型:

ip route
Run Code Online (Sandbox Code Playgroud)

并检查是否192.168.1.0/24在返回的路由条目中。

  • 我个人更喜欢像 `sysctl net.ipv4.conf.eth0.forwarding=1` 这样的 `sysctl` 语法 (17认同)
  • 第二行:如果您没有防火墙限制/安全性,则不需要“iptables -A FORWARD -p tcp -d 192.168.1.200 --dport 8080 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT”大多数家庭局域网都是这种情况,否则要小心 -A,因为它会在限制/安全之后添加它并且可能不起作用(因此请检查 -I,即在 iptables 规则的前面添加) (2认同)
  • @ÁronLőrincz,否。除非在启动时显式加载,否则 Iptables 规则是不稳定的。 (2认同)
  • @Nickolai Leschov,输入相同内容,用“-D”替换“-A” (2认同)

rus*_*tyx 18

当目标主机和网关位于同一子网时(就像您的情况一样,两者都位于eth0192.168.1.0/24),可接受的解决方案有效。

\n

以下是当网关、源和目标都位于不同子网时的通用解决方案。

\n

1)启用IP转发:

\n
sysctl net.ipv4.conf.eth0.forwarding=1 \nsysctl net.ipv6.conf.eth0.forwarding=1 \n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x83 //注意:如果转发到/来自localhost,还设置sysctl net.ipv4.conf.eth0.route_localnet=1

\n
\n

2)添加2条iptables规则来转发特定的TCP端口:

\n

重写数据包的目标IP(并返回到回复数据包中):

\n
iptables -A PREROUTING -t nat -p tcp -i ppp0 --dport 8001 -j DNAT --to-destination 192.168.1.200:8080  \n
Run Code Online (Sandbox Code Playgroud)\n

要将数据包的源IP重写为网关的 IP(并返回到回复数据包中):

\n
iptables -A POSTROUTING -t nat -p tcp -d 192.168.1.200 --dport 8080 -j MASQUERADE\n
Run Code Online (Sandbox Code Playgroud)\n
\n

3)如果您没有默认ACCEPT防火墙规则,则允许流量到达目的地:

\n
iptables -A FORWARD -p tcp -d 192.168.1.200 --dport 8080 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT\n
Run Code Online (Sandbox Code Playgroud)\n
\n

4)测试新设置。如果有效,请确保更改在重新启动后仍然存在:

\n
cat <<EOF > /etc/sysctl.d/99-forwarding.conf\nsysctl net.ipv4.conf.eth0.forwarding=1 \nsysctl net.ipv6.conf.eth0.forwarding=1 \nEOF\n\niptables-save > /etc/network/iptables.up.rules\n\necho '#!/bin/sh' > /etc/network/if-pre-up.d/iptables\necho "`which iptables-restore` < /etc/network/iptables.up.rules" >> /etc/network/if-pre-up.d/iptables\nchmod +x /etc/network/if-pre-up.d/iptables\n
Run Code Online (Sandbox Code Playgroud)\n

  • 我想这应该是公认的答案,因为其他人没有考虑解决从 LAN 调用 wanIP:8081 问题的 POSTROUTING 部分。 (4认同)

小智 16

我想你想要的是:

iptables -A FORWARD -m state -p tcp -d 192.168.1.200 --dport 8080 --state 
    NEW,ESTABLISHED,RELATED -j ACCEPT

iptables -t nat -A PREROUTING -p tcp --dport 8001 -j DNAT --to-destination
    192.168.1.200:8080
Run Code Online (Sandbox Code Playgroud)

  • 嗯……这就是我已经拥有的。我使用 iptables-restore 来加载它,所以每个都在它自己的部分,但这就是我上面写的。 (3认同)

小智 16

你忘记了 postrouting 源地址 SNAT 'ing:

sysctl net.ipv4.ip_forward=1
yours_wan_ip=101.23.3.1
-A PREROUTING  -p tcp -m tcp -d $yours_wan_ip --dport 8001 -j DNAT --to-destination 192.168.1.200:8080

-A FORWARD -m state -p tcp -d 192.168.1.200 --dport 8080 --state NEW,ESTABLISHED,RELATED -j ACCEPT

-A POSTROUTING -t nat -p tcp -m tcp -s 192.168.1.200 --sport 8080 -j SNAT --to-source $yours_wan_ip
Run Code Online (Sandbox Code Playgroud)

并且不要忘记将您的 linux 防火墙设置为地址为 192.168.1.200 的计算机上的默认网关。


小智 8

我创建了以下 bash 脚本,用于在我的 linux 路由器上执行此操作。它会自动推断 WAN IP 并在继续之前确认您的选择。

#!/bin/bash

# decide which action to use
action="add"
if [[ "-r" == "$1" ]]; then
  action="remove"
  shift
fi

# break out components
dest_addr_lan="$1"
dest_port_wan="$2"
dest_port_lan="$3"

# figure out our WAN ip
wan_addr=`curl -4 -s icanhazip.com`

# auto fill our dest lan port if we need to
if [ -z $dest_port_lan ]; then
  dest_port_lan="$dest_port_wan"
fi

# print info for review
echo "Destination LAN Address: $dest_addr_lan"
echo "Destination Port WAN: $dest_port_wan"
echo "Destination Port LAN: $dest_port_lan"
echo "WAN Address: $wan_addr"

# confirm with user
read -p "Does everything look correct? " -n 1 -r
echo    # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]; then
  if [[ "remove" == "$action" ]]; then
    iptables -t nat -D PREROUTING  -p tcp -m tcp -d $wan_addr --dport     $dest_port_wan -j DNAT --to-destination $dest_addr_lan:$dest_port_lan
    iptables -D FORWARD -m state -p tcp -d $dest_addr_lan --dport     $dest_port_lan --state NEW,ESTABLISHED,RELATED -j ACCEPT
    iptables -t nat -D POSTROUTING -p tcp -m tcp -s $dest_addr_lan --sport     $dest_port_lan -j SNAT --to-source $wan_addr
    echo "Forwarding rule removed"
  else
    iptables -t nat -A PREROUTING  -p tcp -m tcp -d $wan_addr --dport     $dest_port_wan -j DNAT --to-destination $dest_addr_lan:$dest_port_lan
    iptables -A FORWARD -m state -p tcp -d $dest_addr_lan --dport     $dest_port_lan --state NEW,ESTABLISHED,RELATED -j ACCEPT
    iptables -t nat -A POSTROUTING -p tcp -m tcp -s $dest_addr_lan --sport $dest_port_lan -j SNAT --to-source $wan_addr
    echo "Forwarding rule added"
  fi
else
  echo "Info not confirmed, exiting..."
fi
Run Code Online (Sandbox Code Playgroud)

该脚本的使用很简单,只需将其复制并粘贴到文件中即可。

# chmod +x port_forward.sh
# ./port_forward.sh 192.168.1.100 3000
... confirm details ... press y
# Forwarding rule added
Run Code Online (Sandbox Code Playgroud)

删除相同的规则

# ./port_forward.sh -r 192.168.1.100 3000
... confirm details ... press y
# Forwarding rule removed
Run Code Online (Sandbox Code Playgroud)

我认为这可能会在他们各自的路由器上节省一些时间。