Skip to main content

Command Palette

Search for a command to run...

Linux WireGuard 和策略路由

Published
Linux WireGuard 和策略路由

本文不涉及任何 Wireguard 安装及配置教程,也无深入讨论 Wireguard/Wireguard-DKMS 的工作原理;仅对配套工具 wireguard-tools (及其Linux命令 wg/wg-quick )所产生的过程和结果作讨论。

测试环境为 Debian GNU/Linux 10 (buster),内核版本 4.19.0-10-amd64

On 28 January 2020, Linus Torvalds merged David Miller's net-next tree, and WireGuard entered the mainline Linux kernel tree.Wireguard 已被并入 Linux 5.6 内核主线中,成为 Linux VPN 的新标准。

本文的灵感来源于两次折腾 wg 而导致的服务器失联问题,其关键参数为:

[Peer]
AllowedIPs = 0.0.0.0/0

问题表现和知识储备

启用服务时,所有入站流量 (inbound traffic) 均被断开,但出站流量 (outbound traffic) 均能够正常透过 Wireguard 隧道访问。

Wireguard 在路由所有流量至隧道时(即设置 AllowedIps = 0.0.0.0/0 (IPv4) 或 ::/0 (IPv6)),wg-quick 会配置一系列的策略路由规则和默认路由来完成这一目标。

wg-quick 做了什么?

wg-quick 通过等价以下命令的结果完成路由所有流量的目标:

# wg set wg0 fwmark 51820
# ip route add default dev wg0 table 51820
# ip rule add not fwmark 51820 table 51820
# ip rule add table main suppress_prefixlength 0

使用以下命令查看结果

# ip route list 51820
default dev wg0 scope link

# ip rule list
0:      from all lookup local
32764: from all lookup main suppress_prefixlength 0
32765: not from all fwmark 0xca6c lookup 51820
32766: from all lookup main
32767: from all lookup default

注:51820 (DEC) = 0xca6c (HEX)

  • 首先,绑定一个 fwmark (firewall mark, 防火墙标记) == 0xca6c 到接口 wg0 上,使得所有从这个接口发出的流量均带上标记 0xca6c 。
  • 之后,创建 ID 为 51820 的路由表,添加一条默认路由,使得所有匹配至这张表的流量路由至 wg0 接口。
  • 最后,添加两条策略路由(下详解),其优先级于上述结果中为 32765 和 32764 。

策略路由做了什么?

  • 所有流量先匹配 local 路由表(私有地址会匹配到相应的记录)
  • 再匹配主路由表中,除了默认路由 (default) 以外的记录**
  • 如果带有 fwmark:0xca6c,则忽略本规则,否则匹配 51820 路由表*
  • 匹配主路由表和默认路由

*suppress_prefixlength NUMBER

reject routing decisions that have a prefix length of NUMBER or less.


suppress_prefixlength 会在查找目标路由表时拒绝前缀等于或低于 NUMBER 的路由决策。在此处即查找 main 路由表时,拒绝匹配到长度等于(或低于,但不可能)0 bit 的 CIDR 前缀,然后进入下一条策略路由;但高于 0 bit 的记录则会被正确匹配。换句话说,因为默认路由的子网掩码是 /0(即前缀长度为0),所以未能匹配到 main 表中其他记录的流量会进入下一条策略路由规则中。

注**:因为 Wireguard 发出的流量都含 fwmark:0xca6c ,故 peer 的 endpoint 会忽略本条规则走主路由表通过物理接口传出,其他流量则走 51820 路由表从 wg0 接口传出。这种写法在 endpoint的 IP 地址发生变化时无需修改 main 路由表,解决了 endpoint 频繁变化导致的问题。

问题成因

利用 tcpdump 观察网卡接口(eth0)和 wg0 的流量情况

# tcpdump -i eth0 host <client_ip>

IP <client_ip>.<port> > <eth0_ip>.<listen_port>: Flags [.], ack 1, win 1028, length 0
......

发现只有入向流量,没有出向流量。

# tcpdump -i wg0

IP <eth0_ip>.<listen_port> > <client_ip>.<port>: Flags [S.], seq 4067566177, ack 2424611520, win 65520, options [mss 1260,nop,nop,sackOK,nop,wscale 6], length 0

本应由 eth0 返回的流量却进了 wg0 接口。

流量的实际情况就变成了这样:

客户端请求 -> CGNAT -> Internet -> 服务器

服务器回包 -> Internet -> Wireguard VPN Peer -> Internet -> CGNAT -->客户端

不合理的返回路径导致回包的源 IP 变成了 Wireguard Endpoint 的 IP 地址,运营商防火墙无法识别其来源,故客户端无法收到回包。故服务器无法正常提供相应端口的服务。

解决问题

解决问题的关键在于将回包路径修改为:

服务器回包 -> Internet -> CGNAT ->客户端

即让源 IP 为的包通过eth0接口传出。

# ip rule add from <eth0_ip> lookup main

若要有更好的体验,可以使用 Wireguard 配置中的 PostUp 和 PostDown 控制

[Interface]
PostUp = ip rule add from <eth0_ip> lookup main
PostDown = ip rule del from <eth0_ip> lookup main

作者:Aiden
原文地址:https://telegra.ph/Linux-Wireguard%E5%92%8C%E7%AD%96%E7%95%A5%E8%B7%AF%E7%94%B1-03-17

More from this blog

Grafana 配置 Prometheus Proxmox VE Exporter

本文不做基础知识的扫盲。 我一直想将 PVE 上全量的虚拟机纳入 Grafana 中展示,然而又不想一台台的配置 node_exporter。偶然的机会听说了 Prometheus Proxmox VE Exporter 插件,索性配置一下这个插件,将 PVE 的数据接入 Grafana。 整体架构如下图: 1. 配置 PVE 用户 网上的很多教程都是直接拿 root@pam 账户来进行操作,但特权账号用作监控其实是安全风险蛮高的一件事情。这里我们单独建立一个审计(PVEAuditor)账户来...

May 23, 2025
Grafana 配置 Prometheus Proxmox VE Exporter

刘梦熊:问题在经济,根子在政治

导语:在美国和西方发达国家,经济繁荣、衰退、复苏、繁荣周而复始,有其周期性和相应的经济对策。但中国是政治挂帅,政治凌驾经济,而且习惯只算政治账,不算经济账。当前中国经济盛极而衰,正是由于中共只搞局部经济体制改革,迟迟不启动政治体制改革带来的恶果。 当前中国经济面临私企倒闭潮、外企撤离潮、投资大幅萎缩潮、出生人口下降潮、消费严重不足潮、债务连环爆煲潮,员工大规模失业潮,政府财税失血潮……投资、出口、消费三大经济引擎全部动力不足乃至死火。中国国家统计局日前公布的7月份经济数据,不是疲弱下挫就是远...

Aug 29, 2023
刘梦熊:问题在经济,根子在政治

WireGuard 配置 Global IPv6 (公网下放)

众所周知,IPv6 和 IPv4 不同,IPv6 的地址池更加丰富,也摒弃了 IPv4 中目前常见的 NAT 做法(虽然有 NAT6 的存在,但这终究是一种不受推荐的选择)。对于如果 WireGuard 中的一个 Peer 存在 IPv6 前缀(即 IP 地址不是/128),该设备就可以作为 Server,将前缀下的一部分地址分配给 VPN 中的其他设备的。 本文以 WireGuard 为例进行展示,IP地址均为静态指定,不涉及 DHCPv6。 首先给出网络拓扑图: 1. 更改 Linux 配...

Aug 14, 2023
WireGuard 配置 Global IPv6 (公网下放)

Kali 2021.2 安装搜狗输入法

我平时比较懒,不愿意手工安装系统,而是使用官方的 VMware 镜像,但官方镜像的语言支持只提供了 English。对于偶尔需要输入个中文的我来说,还是有些困扰的。 1、 换源 从官网下载 deb 包:https://pinyin.sogou.com/linux/?r=pinyin 推荐使用 apt install ./sogouxxxxx.deb,自动解决依赖问题,省心。 2、左上角图标,所有程序中输入input,找到 Input Method。 在一堆弹窗之后,将输入法切换到 Fcitx。...

Mar 10, 2023
Kali 2021.2 安装搜狗输入法

四种不同类型的 Nat

1 完全圆锥形 NAT(Full cone NAT) 对于完全圆锥形 NAT,内网 IP 和内网端口号,被映射为外部 IP 和外部端口号。当路由器收到来自外部的报文时,只要报文的目的 IP 和目的端口号,匹配到 NAT 表项的外部 IP 和外部端口号,都会转换为对应的内网 IP 和内网端口号,转发到内网设备。 对于外部报文,路由器并不关心报文的源 IP 和源端口号(即报文来自谁),只要收到匹配 NAT 表项的报文,都能发送到内网设备。所以,完全圆锥形 NAT 是最宽松的 NAT,打洞最方便。 ...

Jan 13, 2023
四种不同类型的 Nat

Xiaoxk's Blog

27 posts

你看那通天的巨塔,每时每刻都有人往下跳。我小时候不懂,以为那是雪花。