P2P的相关学习
Easul Lv6

本篇博客主要是基于 不良林这个视频 进行了相关学习,然后基于 easytier 进行了一些相关的 P2P 操作练习。
相关内容主要是 NAT的一些基本概念, P2P打洞的一些逻辑, easytier的使用相关P2P工具的收集
当然,部分操作依旧少不了AI工具的加持,再次感谢这个时代,让困难的问题变得更加容易解决🫡。

基本概念

名词

  • NAT: (Network Address Translation)用于流量的代收代发
  • LAN: (Local Area Network),局域网
  • WAN: (Wide Area Network),广域网
  • 端点: IP + 端口(IP也可以看做是网站地址,如 www.baidu.com
  • 内网端点: 内网IP+端口,如 192.168.1.12:9875
  • 公网端点: 公网IP+端口,如 5.5.5.5:7456,主要是 内网端点 在请求 目标端点 时需要将 内网端点 转换为 公网端点,以便 目标端点 可以将数据发送回原本请求的 公网端点,然后传输给 内网端点
  • 目标端点: 被请求的 公网地址+端口,如 www.baidu.com:443
  • NAT映射: (内网端点, 公网端点, 目标端点) 会作为一个映射记录,主要用于内部端点请求目标端点时公网端点的复用,以及相关映射记录
  • NAT过滤: (公网端点, 目标端点) 会作为一个过滤记录,主要用于外部数据请求过来时对于无关数据进行丢弃
  • 可以让外网主动连接到内网的几种方式
    • DMZ: 相当于把公网IP的端口流量直接转发给内网IP相同端口(已有规则匹配的DMZ端口除外)。但是这样不安全,所以可以通过DMZ转发部分端口
    • UPnP: (和 NATPMP 差不多)程序请求路由器将任意某个公网端口映射到我的内网端口,然后程序可以获取到分配的公网端口以及是否分配成功,那么这个时候端点信息可以传给信令服务器,信令服务器把这个端点信息发给对端设备,对端设备用这个端点连进来,就可以P2P成功
  • CGNAT: (Carrier-Grade NAT)电信级NAT,在内网和公网之间加一层大内网

NAT的三种出站映射类型

主要针对于内部向外部发送的数据包

全称 中文含义 作用
Endpoint-Independent Mapping 端点无关映射 当内网端点和公网端点做了映射后\n无论最开始访问的是哪个目标端点\n只要NAT映射表还存在映射记录\n就复用这个公网端点访问目标端点
Address and Port-Dependent Mapping 地址和端口相关映射 当内网端点到了路由表后\n即使内网端点不变,但目标端点变了\n会新建一个公网端点的映射来进行目标端点访问
Address-Dependent Mapping 地址相关映射 当内网端点到了路由表后\n只要目标IP地址不变\n就复用这个公网端点访问目标端点

NAT的三种入站过滤类型

主要针对外部向内部发送的数据包

全称 中文含义 作用
Endpoint-Independent Filtering 端点无关过滤 任何目标端点数据均可接收
Address-Dependent Filtering 地址相关过滤 目标端点对应的IP数据即接收,不限制端口
Address and Port-Dependent Filtering 地址和端口相关过滤 非目标端点的数据直接丢弃

TIPS: NAT出站和入站可查看如下图的演示

image

NAT类型定义

NAT的类型是由 出站映射类型入站过滤类型 两两组合组成的。

简称 全称 中文名 详细名称
NAT1 Full Cone 全锥 端点无关映射 + 端点无关过滤
NAT2 Restricted Cone IP限制锥 端点无关映射 + 地址相关过滤
NAT3 Port-Restricted Cone 端口限制锥 端点无关映射 + 地址和端口相关过滤
NAT4 Symmetric NAT 对称型 地址和端口相关映射 + 地址和端口相关过滤

在这里,只要是 端点无关映射 都是 Easy NAT,所以 NAT1 - NAT3 都是 Easy NAT, NAT4 是 Hard NAT。所有的定义可参考如下图

image

NAT类型检测网站

我使用不良林提供的这个网站,检查效果不是很好。所以不是很建议使用这个网站进行NAT类型检测。
在使用 easytier 的过程中,我使用他自带的功能进行了NAT检测,效果还是不错的。

对于P2P打洞的一些理解

NAT1 <-> NAT1

容易打洞。任意NAT1(A)给对方NAT1(B)发送数据。
因为NAT1是端点无关过滤,且是端点无关映射,所以A发给B的数据包,B可以直接接收,且A给B发送数据包时并没有新开公网端点,于是反过来,当B给A发送数据包时,也可以直接通过旧端点找到A。

NAT1 <-> NAT3

容易打洞。NAT3先访问NAT1,NAT3是端点无关映射,故不会创建新的公网端点,且此时NAT3的过滤表记录了NAT1的端点。由于NAT1是端点无关过滤,故可以接收NAT3的数据。而NAT1此时给NAT3的旧端点发送数据,NAT3的过滤表记录了NAT1的端点,可以放行通过,故此时NAT1访问成功。

NAT3 <-> NAT3

容易打洞。NAT3(A)先访问另一个NAT3(B)。
A是端点无关映射,所以不会创建新的公网端点,同时复用旧端点进行请求,而此时B的过滤表还没有A的记录,所以A请求失败,但A的过滤表记录了B的端点。
当B请求A时,请求的是旧端点,由于A的过滤表有了B的记录,所以B请求A会成功,此时B的过滤表也有了A,A再次请求即可成功。

NAT1 <-> NAT4

容易打洞。需要NAT4先请求NAT1。
NAT4是地址端口相关映射,所以会创建新的端点来访问NAT1,此时NAT4的过滤表中有了NAT1的记录。而NAT1是端点无关过滤,此时NAT4成功进入NAT1。而NAT1得到NAT4的新端点,且可以使用旧的NAT1请求NAT4,此时也可成功。

NAT3 <-> NAT4

不容易打洞。NAT4先请求NAT3,NAT4由于是地址端口相关映射,所以会用新端点访问NAT3,但NAT3是端点相关过滤,没有NAT4新端点的记录,故数据会被丢弃;NAT3访问NAT4时,尽管NAT3是端点无关映射,可以使用旧端点,但因为NAT4用了新的端点,NAT4的新旧端点均未记录NAT3的信息,故数据也会被丢弃。
此时相当于是两端数据都无法正常穿过端点。
这个时候要么NAT4多开一些端口,先访问NAT3的端点,在过滤表中存储NAT3的记录,然后NAT3不断碰撞尝试连接,直到成功。
NAT3成功后,自己的过滤表中也记录了新的NAT4的信息,此时NAT4再进行连接,双方打洞成功。
或者NAT4端路由器开启 UPnP(或者 NATPMP ,功能是类似的),让NAT4得到一个可以入站的端点,然后通过服务器交给NAT3,NAT3通过NAT4的新端点进行连接,然后NAT4得到了NAT3的端点,也就可以连过去了。

NAT4 <-> NAT4

不容易打洞。其中主要是端点预测太困难,且很可能会被运营商当做网络攻击,同时会疯狂占用NAT映射表,导致家庭网络出问题。
此时最好的选择是让一方脱离NAT4,如 将设备放入DMZ区域开启路由器的UPnP软路由的FullCone NAT

EasyTier组网相关记录

常用链接

服务端托管

BASH
1
2
3
4
5
# 指定信令只用udp的11010进行传输,且不进行数据中转
./easytier-core -l udp:11010 --relay-network-whitelist --relay-all-peer-rpc
# 如果想服务运行起来后既当服务端,也当客户端,那就只需IP为指定好的IP,虚拟网络和秘钥也和连接的网络一致即可。
# 由于需要使用 tun 模式,故需要提升权限
sudo ./easytier-core -l udp:11010 --relay-network-whitelist --relay-all-peer-rpc -i 10.126.126.1 --network-name abc --network-secret abc

新加其他节点

BASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 多个对等设备需要使用相同的配置
#
# -d: 自动分配虚拟IP,默认为 10.126.126.0/24 网段
# -i: 指定其他虚拟IP,如 10.11.11.0/24,也可以直接指定固定IP
# --network-name: 虚拟网络名称,同一网络内的用户可以互相访问
# --network-secret: 虚拟网络密码
# -p: 服务器节点地址,如 udp://1.1.1.1:11010,可以指定多个 -p 来设置共享节点来保证可用性
# -l: 当启动多个实例时,可用该参数指定监听端口和其类型,如 udp:11010 或 11010。
# --private-mode: 设置为 true 后,则只允许某个 虚拟网络名称 和 密码 的设备连到该网络
# --no-listener: 当不为服务端时,可以设置为不监听任何端口。但是好像就无法会用P2P了。
# --hostname: 设置自定义主机名
# --accept-dns: 设置为 true 后,指定电脑DNS为100.100.100.101,可以直接通过 主机名.et.net 进行服务访问
./easytier-core -d --network-name abc --network-secret abc -p tcp://public.easytier.cn:11010
# 常用命令模式,
sudo ./easytier-core -d --network-name abc --network-secret abc -p udp://public.easytier.cn:11010 --hostname myname --accept-dns true --private-mode true -l udp:11010

查看连接节点状态

BASH
1
2
3
4
5
6
# 查看虚拟网络状态
easytier-cli peer
# 查看虚拟网路由信息
easytier-cli route
# 查看本节点信息
easytier-cli node

web界面配置功能

BASH
1
2
3
4
5
6
7
8
9
10
# 托管带界面的客户端
#
# --api-server-port: 服务的前后端托管端口
# --api-host: 在页面中访问的后端服务。如果访问的是本机地址,直接填上即可
# --config-server-port: 给 easytier-core 进行配置下发的端口
# --config-server-protocol: 给 easytier-core 进行配置下发的端口协议
./easytier-web-embed --api-server-port 11211 --api-host "http://127.0.0.1:11211" --config-server-port 22020 --config-server-protocol udp
# 以下命令由于可能需要创建虚拟网卡,所以运行在root下比较方便
# -w: 指定 easytier-web-embed 下发配置的 协议://127.0.0.1:端口/注册的用户名
./easytier-core -w udp://127.0.0.1:22020/myname

连接多个虚拟网络

BASH
1
2
3
4
5
6
# 启动多个实例时可用如下方式,需用管理员权限运行,从而建立多个虚拟网络
./easytier-core --network-name net1 -p tcp://public.easytier.cn:11010 -l 11010
./easytier-core --network-name net2 -p tcp://public.easytier.cn:11010 -l 21010
# 连通后可以使用ping操作来测试网络连通性
ping 10.126.126.1
ping 10.126.126.2

安装为systemd服务

BASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 也可以放到 /etc/systemd/system/easytier.service 
sudo cat > /usr/lib/systemd/system/easytier.service <<-'EOF'
[Unit]
Description=EasyTier Service
After=network.target syslog.target
Wants=network.target

[Service]
Type=simple
ExecStart=/root/easytier-core --ipv4 x.x.x.x --network-name xxx --network-secret yyy --peers tcp://peer_host:11010

[Install]
WantedBy=multi-user.target
EOF
sudo chmod 644 /usr/lib/systemd/system/easytier.service
# 使用 start stop restart status 来进行服务操作
sudo systemctl restart easytier

虚拟组网工具

以下均使用 P2P 进行数据传输。

后记

这次花了较长时间来理解不良林的视频(这个是油管链接,另一个链接可查看这个),感觉收获颇多,对于路由器中常见的一些参数也有了新的功能理解。感觉后边还能从大佬身上挖掘出更多的东西🫨。

 评论