开始前
先说下实现思路:我们使用socket 建立 nat server与nat client的长连接,nat server跑在有公网地址的机器上,nat client跑在需要暴露服务内网机器上,最终将内网服务暴露出去。
概念
外部的请求访问 <--> nat server <-socket-> nat client <--> 内网服务
socket: socket就是五元组,包含以下内容1)协议;2)本地地址; 3)外部地址; 4)状态;5)PID。(这里关注本地和外部地址中的 host
以及 监听端口
)
nat_server_host: 需要是个公网地址,比如10.10.2.2。
nat_server_port: 需要外部可以访问的端口,用于 NAT Client进行socket连接。
remote_port: 指由NAT Client向NAT Server发起注册请求时的端口,需要在NAT Server上暴露的端口,后续用户通过访问这个端口,穿透到内网的服务。
local_port: 指和NAT Client同机器,本地提供服务的端口。
实现和效果
操作步骤
需求:假设 需要将 自己设备上(只有内网地址) 的一个http服务,暴露到公网上,可以使用公网访问。
准备:一台有外网地址的开发机器,这里选的是阿里云ECS服务器(https://www.aliyun.com/product/ecs/) 新用户目前还有免费试用机会。
以下所有代码见文末:
- 先登录 公网机器(阿里云ECS服务器),执行
python3 nat_server.py --port 8080
注意 : 在公网机器ECS服务器上,无论是nat server的端口,还是要暴露到外网的端口 ,需要先确保可以访问,防火墙是放行的。
- 再在自己的需要暴露服务的设备上,执行
NAT_SERVER="${nat_server_host}:${nat_server_port}" python3 nat_client.py --type=http --local_port=8811 --remote_port=8172
这里的含义是,连接NAT_SERVER,将本地设备的http 8811端口
, 映射暴露到公网机器上的 8172端口
。
效果
网络结构
核心 :访问内网机器的地址,需要内网先连到公网机器,保持一个双工(双向通信)的长连接。
这里分如下几步,
1 - 创建连接 并 进行端口监听
1.1 创建`NAT server`与`NAT client`之间的socket长连接并各自保存。
1.2 `NAT Server`根据`NAT Client`的请求,进行端口监听。
2 - 转发流量,进行穿透
2.1 拥有外网地址的`NAT Server`收到外部流量请求。
2.2 `NAT Server`用刚刚保存的socket发送给`NAT Client`。
2.3 `NAT Client`转发给同机的http服务。
2.4 再通过保存的socket ,层层传递回去。
对应图示:
最后:把自己的开发机 或者 个人设备暴露到公网上,本身具有安全隐患,请评估具体需求,合理使用。
实现代码
https://github.com/Wunan777/nat_demo
标签:nat, socket, 网络编程, 穿透服务