服务计算相关 - 端口转发

By gyakkun


服务计算要写博客, 鉴于此前这方面的实践太多, 就不另写了, 相关过程及成果见构想网络拓扑-实践笔记以及ASC19系统组任务报告。这里稍微讲下怎么把端口转发出去的问题, 因为见到有人写博客用到了第三方的工具。事实上, Linux自带的隧道以及网络实用程序足以完成这种任务。

Environment - 环境

假设我们配置了一台装有Linux发行版的虚拟机, 称vm; 另有一台公网上的运行Linux发行版的云主机, 拥有公网ip: 224.0.0.233, 甚至v6地址: 2001:db8::233, 称其作cloud。

这里Linux发行版可以是Ubuntu, CentOS, 基本上网络栈的实用程序都已经默认安装。如果是Debian等需要大量手动配置的发行版, 也只需要根据包管理的不同通过yum / apt 等高级包管理或是 dpkg / rpm 等底层包管理命令安装即可, 无需自行编译。

Mechanism - 原理

以下内容需要一定的计算机网络知识。之所以可以进行端口转发, 是因为隧道这种特殊的网络设备(Linux中dev为tun/tap, 可当成网络界面/网卡)将本地的虚拟机和远端的云主机置于同一个子网/广播域下面, 此时两主机都有两个网卡, 就具备路由转发的能力。

我们的目标是: 访问cloud的10022端口(因为其22端口用作cloud的ssh)能够连上vm的22端口, 从而进行ssh操作。

这要求: cloud接收到访问本机的IP分组, 识别其端口号, 若为10022, 则对其目标地址(Destination IP)进行修改(NAT), 改为隧道上vm的地址, 然后交给内核进行路由, 将该包转发到vm上。

Linux提供的网络实用程序里面, iptables拥有强大的网络层及以上的包识别、探测、修改能力。

因此, 我们要做的有

  • 开启cloud的包转发功能, 使之充当路由器
  • 利用iptables, 对识别到的访问10022端口的包做NAT
  • 利用iptables, 对从隧道出去的包做NAT, 否则这些分组会因为源地址为私有地址而被干道上的路由器丢弃

Step 1 - Tunneling 架设隧道, 开启转发

以最简单的不带加密的隧道——IP in IP (下简称ipip)隧道为例。实际操作中, 往往会实用带加密的隧道/虚拟专用网络协议, 比如openv*n, tinc, wireguard, 或是在应用层上套一层ss, v2ray等。

先找到vm侧的公网出口地址与内网地址(通常是192.168.#.#/24):

$ curl ifconfig.me

> 224.0.0.1 # 假设为 224.0.0.1

cloud侧开启转发:

$ cd /etc
$ sudo nano sysctl.conf
net.ipv4.ip_forward = 1 # 去掉这行的注释

$ sudo sysctl -p

vm/cloud 两侧假设隧道:

$ modprobe ipip
$ ip link add tun0 mode ipip remote 224.0.0.233 local 224.0.0.1 ttl 64
# 注意在另一侧调换remote 和 local 的地址
$ ip link set tun0 up
$ ip addr add 10.0.0.1/24 dev tun0
# 另一侧用另一个地址, 如 ip addr add 10.0.0.2/24 dev tun0

Step 2 - iptables

根据需求, 在cloud侧写iptables规则。默认三个表都为ACCEPT, 如需要单独开放端口请自行研究。

$ sudo iptables -t nat -A POSTROUTING -p tcp -m tcp --dport 10022 -j DNAT --to-destination 10.0.0.2:22
# 10.0.0.2 为vm在隧道侧的地址, 对特定端口10022改写其目的地址+端口为vm的22端口
$ sudo iptables -t nat -A POSTROUTING -i tun0 -o eth0 -j MASQUERADE
# 对从隧道上收到的要到外网的包, 在选路之后(POSTROUTING)对其进行NAT(MASQUERADE)

成功与否测试方法: 可以telnet 224.0.0.233 10022看端口是否打开, 若打开, 则可以用vm的账号ssh过去

$ telnet 224.0.0.233 10022
$ ssh [email protected] -p 10022