简述问题和目标
node A 公网 IP:[usVDS ip]
node A GRE IP:192.168.200.1/24
node B 公网 IP:[usWest ip]
node A GRE IP:192.168.200.2/24
系统环境:均为 debian 12
目标:node A 的私网 IP 可以与 node B 的私网 IP 加密互联。
我有一台美东 VDS 和美西的 VPS,其中美东的 VDS 性能强但是线路差,美西的 VPS 线路好,但是性能差。为了实现美东 VDS 跑后端服务,美西 VPS 作为出口,故决定使用 gre over ipsec 构建点对点隧道。
为什么不直接使用代理:性能差且我不希望流量未加密在公网跑(即使是 TLS 加密过的)
为什么不使用 wireguard:wireguard 使用 UDP,众所周知,UDP 被大多数国内外 ISP 强制 QOS。如果使用 udp2raw 转为 TCP 模式,那我认为着实没必要。
配置GRE隧道
启用 GRE 内核模块:
echo "ip_gre" >> /etc/modules
modprobe ip_gre
启用内核 ipv4转发参数:
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv4.conf.default.send_redirects = 0" >> /etc/sysctl.conf
echo "net.ipv4.conf.default.accept_redirects = 0" >> /etc/sysctl.conf
sysctl -p
配置GRE网络接口:
usVDS节点:
auto gre_to_west
iface gre_to_west inet tunnel
address 192.168.200.1
netmask 30
mode gre
endpoint [usWest public IP]
ttl 64
usWest节点:
auto gre_to_vds
iface gre_to_vds inet tunnel
address 192.168.200.2
netmask 30
mode gre
endpoint [usVDS public IP]
ttl 64
启用 GRE 网口:
放行 gre 协议:
# 在 usVDS 执行
ufw allow proto gre from [usWest IP] to [usVDS ip]
# 在 usWest 执行
ufw allow proto gre from [usVDS ip] to [usWest IP]
验证结果:
在 usWest 使用 tcpdump 抓取 gre 隧道的包:
显而易见,GRE 隧道是明文传输,在公网是极度不安全的,所以我们让 GRE 隧道构建在 ipsec 中。
配置 ipsec
安装 ipsec 相关工具并且初始化:
apt install -y libreswan
生成需要的 key,并且做记录
在 usWest、usVDS 上执行:
ipsec showhostkey --list
ipsec showhostkey --left --rsaid [keyid]
返回结果如下图所示:
在 usVDS 上创建 /etc/ipsec.d/ipsec.conf
配置文件,并且填入下面的配置:
# /etc/ipsec.conf - Node A (IP: usVDS) IPsec 配置
config setup
protostack=netkey # 使用 netkey 协议栈
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
authby=secret # 使用预共享密钥 (PSK)
# 配置 GRE over IPsec 连接
conn gre-ipsec
left=[usVDS ip] # 本地端 IP 地址 (Node A)
leftsubnet=192.168.200.0/30 # 只让 GRE 隧道子网的流量走 IPsec 隧道
right=[usWest ip] # 远程端 IP 地址 (Node B)
rightsubnet=192.168.200.0/30 # 只让 GRE 隧道子网的流量走 IPsec 隧道
ike=aes256-sha2_256 # IKE 协议配置
esp=aes256-sha2_256 # ESP 协议配置
auto=start # 自动启动连接
在 usWest上创建 /etc/ipsec.d/ipsec.conf
配置文件,并且填入下面的配置:
# /etc/ipsec.conf - Node B (IP: usWest) IPsec 配置
config setup
protostack=netkey # 使用 netkey 协议栈
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
authby=secret # 使用预共享密钥 (PSK)
# 配置 GRE over IPsec 连接
conn gre-ipsec
left=[usWest ip] # 本地端 IP 地址 (Node B)
leftsubnet=192.168.200.0/30 # 只让 GRE 隧道子网的流量走 IPsec 隧道
right=[usVDS ip] # 远程端 IP 地址 (Node A)
rightsubnet=192.168.200.0/30 # 只让 GRE 隧道子网的流量走 IPsec 隧道
ike=aes256-sha2_256 # IKE 协议配置
esp=aes256-sha2_256 # ESP 协议配置
auto=start # 自动启动连接
在 usWest 上的/etc/ipsec.secrets
创建 secret 文件,填入下述内容:
# /etc/ipsec.secrets - Node B (IP: usWest) 预共享密钥配置
[usWest ip] [usVDS ip] : PSK "your_secret_key"
在 usWest 上的/etc/ipsec.secrets
创建 secret 文件,填入下述内容:
# /etc/ipsec.secrets - Node A (IP: usVDS) 预共享密钥配置
[usVDS ip] [usWest ip] : PSK "your_secret_key"
放行防火墙,在 usVDS 执行:
# 允许从节点 B (usWest) 到节点 A (usVDS) 的 ESP 协议
ufw allow proto esp from [usWest ip] to [usVDS ip]
# 允许从节点 B (usWest) 到节点 A (usVDS) 的 UDP 500 端口 (IKE 协商)
ufw allow proto udp from [usWest ip] to [usVDS ip] port 500
# 允许从节点 B (usWest) 到节点 A (usVDS) 的 UDP 4500 端口 (NAT-T 保护 IPsec 流量)
ufw allow proto udp from [usWest ip] to [usVDS ip] port 4500
放行防火墙,在 usWest 执行:
# 允许从节点 A (usVDS) 到节点 B (usWest) 的 ESP 协议
sudo ufw allow proto esp from [usVDS ip] to [usWest ip]
# 允许从节点 A (usVDS) 到节点 B (usWest) 的 UDP 500 端口 (IKE 协商)
sudo ufw allow proto udp from [usVDS ip] to [usWest ip] port 500
# 允许从节点 A (usVDS) 到节点 B (usWest) 的 UDP 4500 端口 (NAT-T 保护 IPsec 流量)
sudo ufw allow proto udp from [usVDS ip] to [usWest ip] port 4500
在两个节点使用ipsec start
启动 ipsec 服务,并且使用 systemctl status ipsec.service
和 ipsec verify
查看服务状态是否正常。
验证,如下图所示,gre 隧道是通的:
通过在对端抓包,发现此时已经不是明文传输,ICMP 的包被封装到了 ESP 包中
同理,再次监控 gre 接口,可以发现已经没有明文数据包了。