wireguard_netmaker

十一月 19, 2022 [wireguard] #wireguard

wireguard_netmaker

Wireguard

新内核一般都已经支持了wireguard,使用如下命令验证

modprobe wireguard
dkms status
lsmod | grep wireguard
modinfo wireguard

如果kernel低于5.6需要自己安装wireguar的支持

apt-get update
sudo apt install resolvconf
sudo apt-get install -y wireguard-dkms wireguard-tools linux-headers-$(uname -r) 
dpkg -l | grep wire

wireguard详细配置

vps服务器(可以做中继)开启forward转发

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.proxy_arp = 1" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
# 插入转发规则(否则有可能会被其他规则丢掉)
sudo iptables -I FORWARD -i wg00 -j ACCEPT

配置密钥公钥

cd /etc/wireguard/
chmod 0777 /etc/wireguard#调整目录默认权限
umask 077
wg genkey | tee /etc/wireguard/server00.key| wg pubkey > /etc/wireguard/server00.key.pub
wg genkey | tee /etc/wireguard/client01.key| wg pubkey > /etc/wireguard/client01.key.pub
wg genkey | tee /etc/wireguard/client02.key| wg pubkey > /etc/wireguard/client02.key.pub
wg genkey | tee /etc/wireguard/client03.key| wg pubkey > /etc/wireguard/client03.key.pub
wg genkey | tee /etc/wireguard/client04.key| wg pubkey > /etc/wireguard/client04.key.pub
wg genkey | tee /etc/wireguard/client05.key| wg pubkey > /etc/wireguard/client05.key.pub
wg genkey | tee /etc/wireguard/client06.key| wg pubkey > /etc/wireguard/client06.key.pub
wg genkey | tee /etc/wireguard/client07.key| wg pubkey > /etc/wireguard/client07.key.pub

配置中继服务

echo "
[Interface]
PrivateKey = $(cat server00.key)
Address = 10.2.1.254
PostUp = iptables -I FORWARD -i %i -j ACCEPT  # 使用-I插入到最前面不然还是会被reject
PostUp = iptables -I FORWARD -o %i -j ACCEPT
# PostUp = iptables -t nat -A POSTROUTING -o ens192 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT
PostDown = iptables -D FORWARD -o %i -j ACCEPT
# PostDown = iptables -t nat -D POSTROUTING -o ens192 -j MASQUERADE
ListenPort = 50815
DNS = 8.8.8.8
MTU = 1420
[Peer]
PublicKey =  $(cat server00.key.pub)  
AllowedIPs = 10.2.1.254/24
PersistentKeepalive = 15
Endpoint = domain.com:50815
[Peer]
PublicKey =  $(cat client01.key.pub)  
# 局域网ip配置的位置:中继配置在对应的peer节中,客户端配置在想访问对方局域网的client中
AllowedIPs = 192.168.1.58/32,192.168.1.23/32,192.168.1.62/32,192.168.1.154/32
AllowedIPs = 10.2.1.1/32
[Peer]
PublicKey =  $(cat client02.key.pub)  
AllowedIPs = 10.2.1.2/32
[Peer]
PublicKey =  $(cat client03.key.pub)  
AllowedIPs = 10.2.1.3/32
[Peer]
PublicKey =  $(cat client04.key.pub)  
AllowedIPs = 10.2.1.4/32
" > wg00.conf

配置客户端

echo "
[Interface]
PrivateKey = $(cat client01.key)
Address = 10.2.1.1
DNS = 8.8.8.8
MTU = 1420
# 内网的wireguard节点需要开启snat 或者masquerade(访问内网修改源地址(* ̄▽ ̄*)ブ)
# 从而实现wg01进来的流量经过enp0s3物理网卡进入nat内网环境时会修改源地址,保证回报正确
# 另外配置snat 不需要配置对应的dnat,dnat也不需要配置对应的snat;
# 这两个是独立的功能, 在配置snat的时, 也会设置上对应的网络的回程包路由
PostUp = iptables -I FORWARD -i %i -j ACCEPT; 
PostUp = iptables -I FORWARD -o %i -j ACCEPT; 
PostUp = iptables -I INPUT -i %i -j ACCEPT; 
PostUp = iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; 
PostDown = iptables -D FORWARD -o %i -j ACCEPT; 
PostDown = iptables -D INPUT -i %i -j ACCEPT; 
PostDown = iptables -t nat -D POSTROUTING -o enp0s3 -j MASQUERADE
[Peer]
PublicKey =  $(cat server00.key.pub)  
AllowedIPs = 10.2.1.0/24
PersistentKeepalive = 15
Endpoint = domain.com:50815
" > wg01.conf

echo "
[Interface]
PrivateKey = $(cat client02.key)
Address = 10.2.1.2
DNS = 8.8.8.8
MTU = 1420
[Peer]
PublicKey =  $(cat server00.key.pub)  
AllowedIPs = 192.168.1.58/32,192.168.1.23/32,192.168.1.62/32,192.168.1.154/32
AllowedIPs = 10.2.1.0/24
PersistentKeepalive = 15
Endpoint = domain.com:50815
" > wg02.conf

echo "
[Interface]
PrivateKey = $(cat client03.key)
Address = 10.2.1.3
DNS = 8.8.8.8
MTU = 1420
[Peer]
PublicKey =  $(cat server00.key.pub)  
AllowedIPs = 192.168.1.58/32,192.168.1.23/32,192.168.1.62/32,192.168.1.154/32
AllowedIPs = 10.2.1.0/24
PersistentKeepalive = 15
Endpoint = domain.com:50815
" > wg03.conf

开启wg服务

# vps上开启wg
systemctl start wg-quick@wg00
systemctl enable wg-quick@wg00

# 配置客户端
# copy wg01.conf to client01 && at client01 run command
systemctl start  wg-quick@wg01
systemctl enable wg-quick@wg01

# copy wg02.conf to client02 && at client02 run command
wg-quick down wg02 ; wg-quick up wg02

同时需要在云服务提供商开放对应端口,如下图所示

sudo firewall-cmd --zone=public --add-port=50815/udp --permanent
sudo firewall-cmd --zone=public --remove-port=50815/udp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-ports

sudo systemctl start wg-quick@wg00.service
sudo wg-quick up wg00
sudo wg show wg00

systemctl enable firewalld
sudo firewall-cmd --zone=public --add-port=7000-7500/tcp --permanent
sudo firewall-cmd --zone=public --remove-port=7000-7500/tcp --permanent
firewall-cmd --reload

firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.0.200" port protocol="tcp" port="80" reject"
firewall-cmd --zone=public --list-rich-rules

firewall-cmd --query-service ssh
firewall-cmd --list-services

# 或者ufw工具
sudo ufw allow 50814/udp
sudo ufw allow from 1.2.3.4 to any port 22
sudo ufw status
sudo ufw enable

对于代理内网整个网段另一种解决方案

这个需要在需要代理的机器上LocalMachionC上配置网关 这样就不要在wg client节点上进行nat masquerade了

# on client1's local vlan's machions即需要被wg client代理的机器
ip route add 10.2.2.0/24 via 192.168.1.154  # this is client1 ip
# on client1, so client1 can do the gate way role
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

手动操作wireguard设备一些命令

ip link add dev wg0 type wireguard
ip address add dev wg0 192.168.1.1/32
wg set wg0 listen-port 6789 private-key /etc/wireguard/privatekey
ip link set wg0 up
wg set wg0 peer $(cat publickey_cli) allowed-ips 192.168.1.2/32
wg showconf wg0 > /etc/wireguard/wg0.conf
sed -i '1a Address = 192.168.1.1/32' /etc/wireguard/wg0.conf
wg-quick down /etc/wireguard/wg0.conf
wg-quick up /etc/wireguard/wg0.conf
## 输出 # 所以wg-quick是ip link的包装脚本
#[#] ip link add wg0 type wireguard
#[#] wg setconf wg0 /dev/fd/63
#[#] ip -4 address add 192.168.1.1/32 dev wg0
#[#] ip link set mtu 1420 up dev wg0
#[#] ip -4 route add 192.168.1.2/32 dev wg
#上面添加了一条路由192.168.1.2/32 dev wg0,这样所有目的地址是192.168.1.2的包都会被丢到wg0网卡中,以便wireguard处理。
wg show wg0
可以看到,这个peer没有endpoint,也没有握手信息。接下来我们开始设置客户端

systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0

问题排查

可能原因:

  1. MTU过大调小?1280?
  2. 检查防火墙!!firewall-cmd --zone=public --remove-port=50814/udp --permanent

排查工具

# 抓包
tcpdump -i eth0  host domain.com and port 50814 -tnX

# 手动发udp包
nc -u domain.com  50814

# 检查心跳
grep CONFIG_DYNAMIC_DEBUG /boot/config-$(uname -r)  #  检查内核编译时是否支持
sudo modprobe wireguard
echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control  # 开启调试
echo module wireguard -p > /sys/kernel/debug/dynamic_debug/control  # 关闭调试
dmesg -wT 
journalctl -kf

看到的一些失败信息含义

# The icmp-host-prohibited is just the reject message with whom the packet gets rejected. That means that your server will notify the sender that the packet was rejected with that message.
# 查看哪些规则会reject并返回icmp-host-prohibited信息
iptables -L INPUT/FORWARD | grep icmp  

image

强调容易犯错的位置

#1. 内网和中继都需要开启转发功能
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.proxy_arp = 1" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf

#2. 转发的ip需要在中继和客户端上配置对应的路由(peer中的AllowIps配置)

#3. 内网的wireguard节点需要开启snat 或者masquerade(访问内网修改源地址(* ̄▽ ̄*)ブ)
# 从而实现wg3进来的流量经过enp0s3物理网卡进入nat内网环境时会修改源地址,保证回报可以正确返回(不然源地址是10.2.2.xx,目标机器找不到会走默认路由网关,而我们的内网节点不是网关就会出问题)
iptables -I FORWARD -i wg3 -j ACCEPT; iptables -I FORWARD -o wg3 -j ACCEPT; 
iptables -I INPUT -i wg3 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE

#4 中继上的防火墙关闭后可以正常访问, 开启后需要配置/(ㄒoㄒ)/~~
# iptables -L -t filter/nat/mangle/raw/security  INPUT/PREROUTING/OUTPUT/POSTROUTING/FORWARD/SECMARK/CONNSECMARK
iptables -I FORWARD -j ACCEPT # 开启;-I 插入到最前面不然还是会被reject,报错如下图
systemctl restart firewalld   # firewalld 应该需要重启生效?
iptables-save > /root/dsl.fw
iptables-restore < /root/dsl.fw

full mesh netmaker

快速安装netmaker 和netclient客户端

sudo apt-get install -y docker.io docker-compose wireguard
wget -qO - https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh | sudo bash -s -- -d mynetmaker.domain.com -e peter@163.com

curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/netclient-install.sh | VERSION=v0.9.1 KEY=$NETMAKER_TOKEN bash -

centos不能用-使用docker启动

sudo yum install -y yum-utils   device-mapper-persistent-data   lvm2
sudo yum-config-manager     --add-repo     https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce
sudo docker -v
sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

wget https://cdn.jsdelivr.net/gh/gravitl/netmaker@master/compose/docker-compose.yml
/usr/local/bin/docker-compose up --help
/usr/local/bin/docker-compose up # docker-compose.yml  
/usr/local/bin/docker-compose down

完整安装步骤

Prepare DNS

# Create a wildcard A record pointing to the public IP of your VM. As an example, *.netmaker.example.com. Alternatively, create records for these specific subdomains:

dashboard.domain
api.domain
broker.domain

防火墙

sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow 51821:51830/udp
iptables --policy FORWARD ACCEPT

配置docker-compose

SERVER_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
# SERVER_IP 可能不是公网IP,docker-compose.yml中直接替换为公网IP好像有问题,这里用服务器IP替换
*COREDNS_ADDR: "SERVER_PUBLIC_IP"*

wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.yml
sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' docker-compose.yml
sed -i 's/SERVER_PUBLIC_IP/<your server ip>/g' docker-compose.yml
sed -i 's/YOUR_EMAIL/<your email>/g' docker-compose.yml

# Generate a unique master key and insert it:
tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo ''
sed -i 's/REPLACE_MASTER_KEY/<your generated key>/g' docker-compose.yml

export MQ_ADMIN_PASSWORD=my_password
sed -i "s/REPLACE_MQ_ADMIN_PASSWORD/$MQ_ADMIN_PASSWORD/g" /root/docker-compose.yml

wget -O */root/mosquitto.conf* https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf
wget -q -O */root/wait.sh* https://raw.githubusercontent.com/gravitl/netmaker/develop/docker/wait.sh
chmod +x /root/wait.sh

# mq报错处理, 不知道会不会引入安全问题?需要把几个docker镜像详细看一下
sed -i 's/allow_anonymous true/# allow_anonymous true/g' mosquitto.conf
sed -i '/allow_anonymous true/a allow_anonymous false' mosquitto.conf

sudo docker-compose up -d
docker logs netmaker
docker-compose logs --tail 20 --follow
docker exec -it netmaker bash
docker exec -it mq bash

客户端使用docker启动

docker run -d --network host  --privileged -e TOKEN=$toker -v /etc/netclient:/etc/netclient --name netclient gravitl/netclient:v0.16.3
但是在win11上--network host并没有生效?!新生成的nm-netmaker虚拟网卡只能在docker-desk中看到,在host主机上看不到??

UDP hole punching

简单介绍影响p2p打洞的因素

NAT类型介绍

内部Tuple:(源)内网IP+PORT(例如:192.168.1.5:50007) 外部Tuple:(源)公网IP+PORT 目标Tuple:(目标)公网IP+PORT

NAT分为Symmetric和Cone两种,其中Cone又分为Full Cone、Restricted Cone、Port Restricted Cone三种类型。基本不同是NAT将内部Tuple与外部Tuple的转换和映射关系的不同。Cone NAT与目标Tuple无关,Symmetric NAT将目标Tuple作为建立转换关系之前的重要参考项,与目标Tuple严格一一映射。

  1. Full Cone: 内部Tuple X经过NAT转换至外部Tuple Y,X-Y的建立转换关系,任意外部节点且无限制Tuple Z都可以将Tuple Y作为目标Tuple,向我们的内部Tuple X发送UDP报文。
  2. Restricted Cone: 与Full Cone不同的是:多了一个限制,限制是什么,出于安全考虑,NAT设备只转发已知的外部Tuple的IP报文,只有当内部Tuple X曾经发送过UDP报文给目标Tuple Z,才可以与Tuple X发送报文。
  3. Port Restricted Cone NAT: 在Restricted Cone上的基础上,出于更加安全的考虑,NAT设备只转发已知的外部Tuple的IP+PORT(过滤条件更为苛刻)报文。
  4. Symmetric 通过严格的NAT方式,与目标Tuple建立严格的一一映射关系,确保安全性。

所以,从安全角度考虑:Symmetric > Port Restricted Cone NAT > Restricted Cone > Full Cone。相反,如果我们做P2P,打通点对点的通信方式的简单程度,与上面排序就相反,最友好的NAT类型就是Full Cone,任意节点且无限制。

验证NAT类型

git clone https://github.com/laike9m/PyPunchP2P
cd PyPunchP2P && python2 client.py stun.voipbuster.com 3478 1

# stun.xten.com 3478
# stun.voipbuster.com 3478
# stun.voxgratia.org 3478
# stun.sipgate.net 10000
# stun.ekiga.net 3478
# stun.ideasip.com 3478
# stun.schlund.de 3478
# stun.voiparound.com 3478
# stun.voipbuster.com 3478
# stun.voipstunt.com 3478
# numb.viagenie.ca 3478
# stun.counterpath.com 3478
# stun.1und1.de 3478
# stun.gmx.net 3478
# stun.callwithus.com 3478
# stun.counterpath.net 3478
# stun.internetcalls.com 3478
# stun.voip.aebc.com 3478

目标内网是对称NAT,白折腾了ORZ

对于「对称 NAT」等更严格的 NAT,是否还可以打洞?

按照一般逻辑,「对称 NAT」是无法打洞成功的。但是,事实真的是这样吗? 实际上,运用一点点概率知识,对称 NAT 也是可以打动成功的。让我们先来了解一下「生日问题」:

生日问题是指,如果在一个房间要多少人,则两个人的生日相同的概率要大于50%? 答案是23人。 这就意味着在一个典型的标准小学班级(30人)中,存在两人生日相同的可能性更高。对于60或者更多的人,这种概率要大于99%。 — Wikipedia

假设内网设备 A 位于「圆锥形 NAT」之后,内网设备 B 位于「对称 NAT」之后。这时候 A 向 B 发送报文,B 并不知道 A 的报文经过 NAT 之后,公网端口号会被转换为什么,所以无法向 A 发送数据。 当然,在 B 不知道 A 的外部端口的情况下,也可以用不同的端口号,依次尝试向 A 发送报文,直到发送成功为止。但端口号一共有 65535 个,扫描所有端口并不现实….. 那么,如果我们运用上「生日问题」,A 随机向 B 以不同的源端口号,发送 256 个报文,形成 256 个 NAT 表项;B 同时也随机以不同的目的端口号,向 A 发送 256 个报文进行探测,打洞成功率就能达到 64%。如果随机探测 1024 个端口,打洞成功率则能达到 98%。

需要注意的点

COREDNS_ADDR: "SERVER_PUBLIC_IP"

SERVER_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
# SERVER_IP 可能不是公网IP,docker-compose.yml中直接替换为公网IP好像有问题,这里用服务器IP替换

这些位置一定要和docker-compose.yml的目录信息一致
注意yml中的volumes(可以都创建在一个位置中,如:~/project/netmaker/)
/root/mosquitto.conf
/root/wait.sh   # 这个需要有执行权限
chmod a+x /root/wait.sh

重要:

https://icloudnative.io/posts/wireguard-docs-practice/
https://zhuanlan.zhihu.com/p/447375895
https://zhuanlan.zhihu.com/p/404402933
https://zhuanlan.zhihu.com/p/157121608
https://www.zhihu.com/column/c_1498091755665240064
https://new.negoces.top/posts/2fcbf547/
https://juejin.cn/post/7080010903256563748
https://netmaker.readthedocs.io/en/master/netclient.html
https://github.com/gravitl/netmaker
https://netmaker.readthedocs.io/en/v0.7.1/quick-start.html
https://blanboom.org/2021/nat/#-nat-nat-
https://blog.csdn.net/dlphay/article/details/106243041