最近租了一台便宜的云主机。我想把云主机的公网ip上的一些端口映射到宿舍台式机上的一些服务上(例如SSH、jupyter lab),这样就可以远程登陆管理自己的台式机了。
我采取的办法是
- 使用Zerotier组成一个局域网,使得云主机和宿舍台式机可以互相访问;
- 使用端口映射,将宿舍台式机的服务暴露到公网ip上;
在这个背景下,我写下这篇笔记来记录使用iptables配置端口映射的方法,同时顺带记录一下如何用ssh命令以及Windows下的netsh命令配置端口映射。这几种方法都很常用。
1 前置步骤:开启Linux的IP转发功能
在 Linux 系统中,IP 转发(IP Forwarding)功能允许数据包从一个网络接口转发到另一个网络接口。 默认情况下,大多数 Linux 系统将 IP 转发禁用,防止非路由器设备意外充当路由器。
请打开/etc/sysctl.conf
文件,例如
sudo nano /etc/sysctl.conf
然后添加或确保以下行存在:
net.ipv4.ip_forward = 1
然后加载配置:
sudo sysctl -p
2 用iptables配置端口映射
在Linux系统上,可以使用iptables命令来配置端口的转发规则。端口转发技术允许网络流量从一个端口转发到另一个端口,通常是将流量从一个网络接口转发到另一个网络接口上的不同端口。
例如,假设我们有A主机及其端口P_A, B主机及其端口P_B,我们想将P_A端口映射到B主机的P_B端口。假如P_B端口对应著B主机的ssh服务,那么经过端口映射,我们可以使用
ssh ${USER_NAME}@${A} -p ${P_A}
命令来访问P_B主机的服务。这里我用${A}
表示A主机的IP地址,${P_A}
表示端口号。
2.1 添加规则
要实现这个任务,可以在A主机上使用以下命令:
sudo iptables -t nat -A PREROUTING -p tcp --dport ${P_A} -j DNAT --to-destination ${B}:${P_B}
这里-t nat
选项指定了要操作的表(table)。nat(network address translation)表用于网络地址转换,包括源地址转换(SNAT)和目的地址转换(DNAT)。-A
是Append的缩写,表示将一条规则添加到指定的链(chain)的末尾。PREROUTING是nat表中的一个链,用于处理进入(ingress)流量,在路由决策之前应用NAT规则。-p tcp
这个选项指定了要匹配的协议类型,这里是tcp,表示这条规则只适用于TCP协议的流量。--dport
指定了要匹配的目的端口。-j
是jump的缩写,指定了匹配规则后的动作。DNAT表示目的地址转换,即修改流量的目的IP地址。--to-destination
选项指定了DNAT的目标地址和端口。
除了PREROUTING规则,你还需要添加一条命令处理POSTROUTING时的转发:
sudo iptables -t nat -A POSTROUTING -p tcp -d ${B} --dport ${P_B} -j MASQUERADE
这里MASQUERADE是一种特殊的NAT操作,用于动态地将出站流量的源地址替换为出口接口的地址。这通常用于拨号或移动网络,其中IP地址可能会变化。
这时,你就可以从第三个主机C尝试访问主机A上的P_A端口了。
假如不使用第三台机器,而是从主机A上访问P_A端口,流量会无法转发到B主机的P_B端口。这是因为来自主机A内部的连接不会经过PREROUTE规则。如果你想处理来自主机A内部的连接,可以增加一条命令:
sudo iptables -t nat -A OUTPUT -p tcp --dport ${P_A} -j DNAT --to-destination ${B}:${P_B}
这条命令应用于OUTPUT链,可以处理从主机A内部发起的连接。
2.2 罗列现有的NAT规则
可以用如下命令列出所有的NAT规则。
sudo iptables -t nat -L
2.3 删除iptables的NAT规则
在罗列NAT规则时,我们可以让iptables命令显示每条规则的行号,然后用行号告诉iptables我们想删除哪条规则:
sudo iptables --list -t nat -n --line-numbers
sudo iptables -t nat -D POSTROUTING 2 # ←删除POSTROUTING链下的第二条规则
2.4 iptables规则的保存
用上面的命令设置的规则在机器重启后将会丢失,你需要通过额外的命令将iptables的规则保存下来。
在Ubuntu 18.04 LTS系统上,可以用下面的命令保存iptables的规则:
sudo apt install iptables-persistent
执行该命令后,程序将询问你是否保存规则。
后续你还可以通过使用sudo netfilter-persistent save
命令,将iptables规则的更改保存下来。
3 SSH搭建端口映射
ssh命令也提供了一个非常方便的搭建端口映射的办法:
ssh -L <本地的一个空闲端口>:$B:$P_B <用户名>@$A
这段命令会将指定的本地端口映射到B主机的P_B端口。前提是你能登陆A主机,且A主机能够访问B主机的P_B端口。
4 在Windows的Powershell中配置端口映射
Windows系统带有netsh命令,可以帮助你配置端口映射规则,使用方法如下。
首先你需要以管理员身份打开Powershell,然后才能执行各命令。
查看所有端口映射规则:
netsh interface portproxy show all
添加端口映射规则,(以8888端口为例):
=0.0.0.0 listenport=8888 connectaddress=localhost connectport=8888 netsh interface portproxy add v4tov4 listenaddress
删除转发规则:
=0.0.0.0 listenport=8888 netsh interface portproxy delete v4tov4 listenaddress
5 后记
本文的背景是将自己台式机上的一些网络服务暴露到公网。这其实还蛮危险的,需要注意
- 可以尽量改用比较复杂的密码
- 不使用默认的端口号,例如不把SSH服务开放在22端口,而是随机选择一个端口
- 能不开放的服务尽量不开放,而只在要使用的时候,临时搭一个端口映射。例如可以临时用ssh命令搭一个端口映射,用完就关闭