聊聊内网穿透

最近在开发支付系统,在和第三方支付渠道联调时碰到一个问题:我的电脑是在公司的内网中,无法收到渠道发出的异步回调通知。要想解决这个问题,就需要进行内网穿透,于是在内网穿透工具 frp 的帮助下,成功的解决了这个问题。

什么是内网

网络中进程怎么通信

我们知道,IP 地址相当于计算机在网络中的唯一编号,端口号(Port)则是运行在这台计算机中进程的唯一编号。利用 IP + Port 就能在互联网中实现进程间的通信

私有 IP 地址

在互联网的地址架构中,有一些 IP 地址是 私有 IP 地址 ,这些地址无法直接连接互联网。与公网 IP 相比,私有 IP 是免费的,同时节省了 IP 地址资源,适合在局域网使用。

IPv4 私有地址

IP 地址区块 最大 CIDR 区块(子网掩码) IP 数量(允许的主机数量)
10.0.0.0 - 10.255.255.255 10.0.0.0/8(255.0.0.0) 1677 7216
172.16.0.0 - 172.31.255.255 172.16.0.0/12(255.240.0.0) 104 8576
192.168.0.0 - 192.168.255.255 192.168.0.0/16(255.255.0.0) 6 5536

Mac 电脑上可以用 ifconfig 命令来查看自己的 IP 地址。

展示出来的有 en0 en1 en2 en3 en4。到底那个才是我正在使用的 IP 地址呢,运行一下命令:

1
networksetup -listallhardwareports

IP 数据报

每个 IP 数据报都包含了源 IP 地址和目的 IP 地址,用来标识数据报的发送主机和接收主机

IPv4 datagram format

问题 1
假设我现在要访问 Google 的搜索服务(216.58.200.36),那么由我发送出的每个 IP 报文中的源 IP 地址就是 10.100.21.4,目的 IP 地址就是 216.58.200.36。但 10.100.21.4 是一个私有 IP 地址,无法直接和互联网相连,那么我们又是怎么上网的呢?(假设路由器的内网 IP 地址为 10.100.20.254,公网 IP 地址为 118.184.5.17。)

怎么穿透

这就要用到 NAT(Network Address Translation)技术,它是一种在 IP 数据报通过路由器或防火墙时重写源 IP 地址或目的 IP 地址的技术

Basic NAT

它的功能比较简单,仅支持地址转换(不支持端口映射)。Basic NAT 要求每一个连接都要对应一个公网 IP 地址。Basic NAT 要维护一个 IP 转换表:

内网 IP 公网 IP
192.168.1.220 169.254.34.148
192.168.1.221 169.254.34.149
192.168.1.222 169.254.34.150

缺点是:很多时候我们没有大量的公网 IP 地址,无法做到一一映射

NAPT

网络地址端口转换(Network Address Port Translation),这种方式支持端口映射,允许多台主机共享一个公网 IP 地址。NAPT 要维护一个 IP + Port 的转换表:

内网 IP 公网 IP
192.168.1.220:7788 169.254.34.148:10001
192.168.1.221:80 169.254.34.149:10002
192.168.1.222:443 169.254.34.150:10003

回答 1
当我向 Google 的搜索服务(216.58.200.36:80)发送的 IP 数据报到达路由器时,它会将报文中的源 IP 地址改为它自己的公网 IP 地址(118.184.5.17),并且随机分配一个未被占用的端口号 9102(1024-65535),最后在转换表中插入一条这样的记录:

内网 IP 公网 IP
10.100.21.4:2048 118.184.5.17:9102

当 IP 数据报到达 Google 的搜索服务之后,Google 给我们回复的 IP 数据报中的源 IP 地址就为 216.58.200.36:80,而目的 IP 地址就是我们路由器的 IP 地址 118.184.5.17:9102。而路由器接收到这份报文之后,根据转换表中的记录,将数据报中的目的 IP 地址替换成 10.100.21.4:2048,这样就能正确地转发 IP 数据报到我的主机上了。

小结一下

完成内网穿透的三要素:

  • 一台内网中的主机。
  • 一台拥有公网 IP 的 NAT 服务器。
  • 一台公网中的主机。

内网穿透工具

很多工具都能实现内网穿透,像 nogrok、花生壳、frp 等,这里使用的是 frp

step0

建议先看一下 README.md

step1

去 github 上下载 RELESAE 包。

先利用 ssh 命令登录到公网 Linux 服务器,然后按顺序执行以下命令:

1
2
3
wget https://github.com/fatedier/frp/releases/download/v0.24.1/frp_0.24.1_linux_amd64.tar.gz
tar -zxvf frp_0.24.1_linux_amd64.tar.gz
cd frp_0.24.1_linux_amd64

解压之后的目录

step3

修改 frps.ini 文件。

1
2
3
4
#frps.ini
[common]
bind_port = 7000
vhost_http_port = 8080

启动 frps。

1
./frps -c frps.ini

frps 启动成功日志

step4

修改 frpc.int 文件,假设 Linux 服务器的公网 IP 为 45.77.99.210

1
2
3
4
5
6
7
8
9
#frpc.ini
[common]
server_addr = 45.77.99.210
server_port = 7000

[web]
type = http
local_port = 8080
custom_domains = 45.77.99.210

启动 frpc。

1
./frpc -c frpc.ini

frpc 日志

frps 日志

启动过程中可能会遇到的问题:

  • 服务器/客户端指定的端口已经被占用。
    • Linux 通过 netstat -nap | grep 7000 命令查看 7000 端口是否已经被占用。
    • Mac 通过 netstat -nap tcp | grep 8080 命令查看 8080 端口是否已经被占用。
  • 服务器的 7000 端口没有开放。
    • firewall-cmd --query-port=7000/tcp --zone=public 命令看看是否已经打开。
    • 如果关闭着,用 firewall-cmd --zone=public --add-port=7000/tcp --permanent 命令打开,然后重启服务器。
  • 其它问题。

step5

至此,你已经成功的建立起了一个 NAT 映射,快去验证一下吧。

拓展

正向代理和反向代理

引用