N2N VPN 应用指南
N2N 是一个P2P的开源VPN项目,具有内网穿透成功率高,去中心化,流量加密,使用简单的特点, 在笔者公司内部已经有近3年的使用经验,实践证明,N2N具备较为优秀的稳定性和安全性,,具备低成本替代专线需求的能力。在笔者的实践经验中,N2N用在多IDC之间的网络互通,多IDC上容器网络的互通。 表现的都很出色。
98.png

一、 N2N通信原理

N2N 是基于P2P协议的加密2层专用网络, 使用UDP协议进行封包传输,使用UDP协议带来了高性能和便捷性,例如利用很多场景下不会封锁DNS的UDP端口来打通网络,例如UDP原生优于TCP的传输性能。在NAT条件允许的情况下, edge节点间流量直连,无需通过supernode转发。

1. NAT的原理

想要理解UDP穿透的原理,就需要先了解NAT 的原理, 都知道NAT是地址转换,哪怎么个转换法哪?
SNAT: 源地址转换,当请求本文经过NAT网关时。NAT网关会将报文中的源地址替换掉,替换成能与目标地址路由互通的地址,此时目标地址不变,所以最终报文抵达目标服务。
DNAT: 目标地址转换,当service完成处理后返回数据,返回报文时的源地址和目标地址反过来,抵达NAT网关后NAT网关根据请求出去的时候的SNAT记录做反转,将目标地址转换成内网地址,最终抵达客户端。

2. NAPT

NAPT与NAT的唯一区别就是:NAT只转换IP地址,这种方式受限于对外的地址数量,是IP到IP的转换。所以常规NAT的方式的主要应用场景现实里可类比阿里云或者各种云的EIP。而NAPT同时会对源和目标端口进行转换,这就可以实现了一个公网IP可以满足多个后端主机同时访问外部网络,NAPT的常用场景例如家庭宽带、阿里云的NAT网关等。儿N2N的生存环境中,主要的场景基本都是NAPT,NAPT也是目前应用最为广泛的NAT方案,其有如下几种模式:
锥形NAT与对称NAT的区别,锥形NAT:只要是从同一个内部地址和端口出来的包,无论目的地址是否相同,NAT 都将它转换成同一个外部地址和端口。不满足这个条件的即可称之为对称NAT。
Full Cone NAT
锥形NAT, 当发出一个外部请求时, NAT网关会打开一个端口创建一个公网映射,然后会将传入这个端口的数据全部转发给内部主机。Full Cone NAT是最宽松的NAT规则,一旦映射建立,那么只要到公网的映射端口发送数据就可以直接到达后端服务。

Address Restricted Cone NAT

受限的锥形NAT, 当发出一个外部请求时,NAT网关会打开一个端口创建一个公网映射, 同时记录外部的主机IP,然后会将已经有记录IP地址并且从这个地址传来的数据转发给内部主机,其他数据会被丢弃。Address Restricted Cone NAT只限制IP不限制端口。
Port Restricted Cone NAT
严格限制的锥形NAT,同时记录外部主机的IP和端口, 然后校验传入端口的数据报文,必须地址和端口和记录的一致才会转发到对应的内部主机,否则会丢弃。Port Restricted Cone NAT同时校验和限制IP和端口。

Symmetric NAT

又叫对称NAT,每一个来自相同内部IP与端口,到一个特定目的地地址和端口的请求,都映射到一个独特的外部IP地址和端口。同一内部IP与端口发到不同的目的地和端口的信息包,都使用不同的映射。只有曾经收到过内部主机数据包的外部主机,才能够把数据包发回。
NAT的优缺点:
优点: 解决了IPV4 公网地址不够用的问题。能够隐藏和保护内网主机的地址。方便在NAT层扩展防火墙,负载均衡功能。
缺点:NAT网关对报文进行地址转换的本质是对报文源和目标的修改,这会导致额外的延迟和开销。

3.关于内网穿透

内网穿透俗称打洞,其实就是透过NAT对外提供服务的方式。当下流行的内网穿透工具ngrok和frp本质上是通过应用层的端口映射实现。即服务端监听一个公网端口,当外部用户请求到这个公网端口时,ngrok通过与客户端建立的连接来进行请求的转发。这种工具只能做到4层或者7层的内网穿透,而N2N 实现了2层的网络穿透。
对于锥形NAT来说,supernode节点像是个中介,介绍edge互相认识后,之间的交互直接就是edge与edge的交互了。这也是N2N 最优势与其他中心化方案的地方。流量直连。避免中间转发的开销。
对于对称NAT来说, supernode就是个邮局,所有到达对端的数据报文都要由supernode中转。所以两端交互不但会产生额外的消耗,还会受限于supernode节点的带宽。

二、 N2N组件及配置

1. 基本组件

supernode: 可以视为注册中心,用来注册各接入点的信息,相当于一张地址列表,在对称型或者端口受限型NAT的情况下,edge之间无法直接交互数据,此时需要通过supernode转发流量。
edge: 边缘节点, 负责与其他edge或者supernode进行数据交互,报文解密等, 会定时跟supernode通信,获取信息。

工作流程:

edge向supernode注册,supernode记下edge的信息,包括外网ip和端口,虚拟ip、虚拟mac地址、community等信息。
edge监听虚拟网卡,获取网卡要发送的数据。
当从虚拟网卡读取到数据时,将数据包发送到supernode。
supernode提取数据包中的mac地址,并查询注册列表,并附上来源地址和端口,转发到目标edge。
目标edge收到数据包,提取来源地址和端口,并尝试udp直连
若直连成功,数据包不再走supernode中转,否则一直从supernode中转。

2. 配置

edge配置

Welcome to n2n v.2.1.0 for Linux-3.10.0-514.26.2.el7.x86_64
Built on Oct 25 2017 21:02:37
Copyright 2007-09 - http://www.ntop.org

edge -d <tun device> -a [static:|dhcp:]<tun IP address> -c <community> [-k <encrypt key> | -K <key file>] [-s <netmask>] [-u <uid> -g <gid>][-f][-m <MAC address>]
-l <supernode host:port> [-p <local port>] [-M <mtu>] [-r] [-E] [-v] [-t <mgmt port>] [-b] [-h]

# 虚拟设备名称。
-d <tun device>          | tun device name  
# 虚拟网卡上的虚拟IP或者指定DHCP广播
-a <mode:address>        | Set interface address. For DHCP use '-r -a dhcp:0.0.0.0' 
# 组名,n2n只是多个隔离网络,隔离网络会以组名来区分。
-c <community>           | n2n community name the edge belongs to. 
# 指定秘钥N2N 使用twofish加密算法进行数据加密。同一个网络里面的秘钥需要保持一致,supernode并不存储秘钥
-k <encrypt key>         | Encryption key (ASCII) - also N2N_KEY=<encrypt key>. Not with -K. 
# 秘钥文件和小写的-k选择其一即可
-K <key file>            | Specify a key schedule file to load. Not with -k.
# 虚拟网络的子网掩码
-s <netmask>             | Edge interface netmask in dotted decimal notation (255.255.255.0).
# supernode 的服务端地址和端口, 最多可以指定2个,做supernode的高可用
-l <supernode host:port> | Supernode IP:port
# 添加本地IP
-L <local_ip>            | Add local ip to bypass between same nat problem
# 设置NAT打洞间隔,默认20秒
-i <interval>            | Set the NAT hole-punch interval (default 20seconds)
#定期解析supernode的地址,如果supernode是一个域名且后端IP会产生变化的时候比较有用。
-b                       | Periodically resolve supernode IP
                         : (when supernodes are running on dynamic IPs)
-p <local port>          | Fixed local UDP port.
# 设置运行用户
-u <UID>                 | User ID (numeric) to use when privileges are dropped.
-g <GID>                 | Group ID (numeric) to use when privileges are dropped.
# 设定运行方式默认情况相爱自动使用daemon的方式运行,加入-f直接运行在前台。
-f                       | Do not fork and run as a daemon; rather run in foreground.
# 设置虚拟网卡MAC地址
-m <MAC address>         | Fix MAC address for the TAP interface (otherwise it may be random)
                         : eg. -m 01:02:03:04:05:06
# 设定mtu, 默认情况下是1400,不建议做改动。                         
-M <mtu>                 | Specify n2n MTU of edge interface (default 1400).
-r                       | Enable packet forwarding through n2n community.
# 是否接受多播MAC地址,默认不允许
-E                       | Accept multicast MAC addresses (default=drop).
-v                       | Make more verbose. Repeat as required.
# 管理UDP port 当一台主机上运行多个edge时,需要单独指定。
-t                       | Management UDP Port (for multiple edges on a machine).

Environment variables:
  N2N_KEY                | Encryption key (ASCII). Not with -K or -k.
supernode配置
supernode usage
# 指定UDP监听端口
-l <lport>  Set UDP main listen port to <lport>
#设定运行方式默认情况相爱自动使用daemon的方式运行,加入-f直接运行在前台。
-f          Run in foreground.
-u <UID>    User ID (numeric) to use when privileges are dropped.
-g <GID>    Group ID (numeric) to use when privileges are dropped.
-v          Increase verbosity. Can be used multiple times.
-h          This help message.

三、实战

1. 编译构建

#clone 源码
git clone https://github.com/meyerd/n2n.git

#安装依赖
yum install cmake openssl openssl-devel gcc-c++ git -y

#编译
cd n2n/n2n_v2
mkdir build 
cd build
cmake ..
make && make install
# 会生成edge、supernode可执行文件。

2. 多IDC间的网络互通

场景:
有杭州、北京2个IDC机房:杭州机房网络:172.16.0.0/16、北京机房网络:172.17.0.0/16
杭州IDC 的edge节点IP: 172.16.0.1/北京IDC的edge节点IP: 172.17.0.1
办公网网络:192.168.0.0/16
外网服务器(112.112.112.112和113.113.113.113)两台部署supernode

# 在外网服务器执行以下命令即可启动supernode:
supernode -l 1024

#办公网主机上执行
edge -r -a 10.0.0.1 -l 112.112.112.112:1024 -l 113.113.113.113:1024 -d edge1 -c 网络组 -k 秘钥

#杭州IDC机房主机上执行
edge -r -a 10.0.0.2 -l 112.112.112.112:1024 -l 113.113.113.113:1024 -d edge1 -c 网络组 -k 秘钥

#北京IDC机房主机上执行
edge -r -a 10.0.0.3 -l 112.112.112.112:1024 -l 113.113.113.113:1024 -d edge1 -c 网络组 -k 秘钥

# 所有节点开启路由转发
sysctl -w net.ipv4.ip_forward=1

#=========如果IDC网关可控可维护规则==========
#办公网主机上和核心交换上添加路由表
route add -net 172.16.0.0/16 gw 10.0.0.2
route add -net 172.17.0.0/16 gw 10.0.0.3

#在杭州IDC 网关上添加路由表:
route add -net 192.168.0.0/16 gw 172.16.0.1

#在北京IDC 网关上添加路由表:
route add -net 192.168.0.0/16 gw 172.17.0.1

# 在杭州和北京的edge上维护路由表
route add -net 192.168.0.0/16 gw 10.0.0.1

#=========如果IDC网关不可维护规则==========
# 在所有的edge上添加iptables规则:
iptables -t nat -A POSTROUTING -d 172.16.0.0/16 -j MASQUERADE # 杭州
iptables -t nat -A POSTROUTING -d 172.17.0.0/16 -j MASQUERADE # 北京

这里是利用iptables做了SNAT, 做SNAT的原因是,当无法维护网关上的路由规则,外部请求过来的报文源地址是N2N 的虚拟地址,且这个虚拟地址除了edge所在的主机外其他主机均无法识别,导致无法回包,所以需要经过snat将地址转换成edge节点的主机IP。
引申思考:假设上面的场景里面还有一个kubernetes集群,我们需要在办公网直接连接kubernetes集群网络中的某一个pod,需要怎么做?答案其实非常简单,假设上例中的杭州IDC的edge节点同时是一个kubernetes的node。是不是只需要在办公网添加一条路由,把容器网络的下一跳指向到杭州edge节点的虚拟IP就行了?按照这个道理,结合实际的场景灵活应对即可。可继续关注本专栏,后面会有实际场景中的容器网络方案分享的文章。

四、注意事项

NAT 的模式直接决定流量是要通过supernode中转,所以在使用对称NAT的场景下流量使用supernode进行流量转发,需要注意supernode的带宽会成为edge间数据交互的瓶颈。
当一些场景下,网关不可控时需要通过地址伪装(SNAT)的方式保证网络的连通性,但只因为经过了地址转换,请求业务时获取到的客户端IP地址会是转换后的地址。一些针对IP的审计无法做到。
supernode 与edge间的网络通信使用UDP协议,请注意网络策略要放开。
iptables规则、本地路由表默认情况下重启会清空,需要注意持久化问题。