Fork me on GitHub

聊聊内网穿透

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

什么是内网

网络中进程怎么通信

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

私有 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) 104 8576
192.168.0.0 - 192.168.255.255 192.168.0.0/16(255.255.0.0) 6 5536

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

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

1
networksetup -listallhardwareports

IP 数据报

IP 数据报(datagram)可分为 Head 和 Data 两个部分。

IPv4 datagram format

由上图我们可以发现,每个 IP 数据报中都包含了源 IP 地址、目的 IP 地址两个字段,分别用来标识数据报的发送主机 IP 和目标主机 IP。

问题 1
假设我现在要访问 Google 的搜索服务(216.58.200.36),那么由我的主机发送出的每个 IP 报文中的源 IP 地址就是 10.100.21.4,目的地址就是 216.58.200.36。但是, 10.100.21.4 是一个私有 IP 地址,之前说过,私有 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
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
回到我们之前提出的问题 1,当我向 Google 的搜索服务(216.58.200.36:80)发送的报文到达路由器时,它会将报文中的源 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

frp 介绍

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透。

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 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x

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

[web]
type = http
local_port = 8080
custom_domains = x.x.x.x

启动 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 映射,快去验证一下吧。


frps 日志

拓展

正向代理和反向代理

引用

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------本文结束感谢阅读-------------
0%