Skip to main content

6 posts tagged with "DN42"

View All Tags

· 3 min read

DN42 是一个由社区维护的实验网络。参与者通过隧道互联,用 BGP 交换路由,并在 .dn42 域名空间内提供服务。它不是公网互联网,也不是商用 VPN,而是一个非常适合学习 BGP、路由策略、隧道、RPKI/ROA 和网络运维的实验环境。

本系列按照真实上线顺序组织:

1. 了解 DN42 社区和 registry2. 准备 ASN、地址段和 route/route6 对象3. 配置 Linux 转发、dummy 地址和防火墙4. 使用 WireGuard 与 peer 建立隧道5. 使用 BIRD2 建立 BGP 邻居并过滤路由6. 做日常运维、监控和 Looking Glass

示例信息#

后续文章统一使用下面这组示例。实际部署时请替换成你自己的信息。

ASN:        AS4242423777Router ID: 172.22.107.1IPv4 Host:  172.22.107.1/32IPv4 Net:   172.22.107.0/27IPv6 Host:  fd42:3777:3777::1/128IPv6 Net:   fd42:3777:3777::/48Loopback:   dn42WG IF:      wg-peer1WG LLA:     fe80::3777WG Port:    23777

示例 peer:

Peer ASN:       AS4242420001Peer endpoint:  peer.example.net:23777Peer WG pubkey: <PEER_PUBLIC_KEY>Peer WG LLA:    fe80::1

推荐阅读顺序#

  • 01-registry-and-peering.md:申请资源、理解社区规则、找 peer。
  • 02-linux-network-basics.md:配置 Linux 内核转发、dummy 接口、防火墙和 DNS。
  • 03-wireguard-for-dn42.md:用 WireGuard 建立 DN42 隧道。
  • 04-bird2-routing.md:用 BIRD2 建 BGP 邻居、过滤路由、导入内核。
  • 05-operations-and-looking-glass.md:排障、监控、ROA 更新、bird-lg-go。

上线心法#

DN42 配置最容易出错的地方不是某一条命令,而是概念边界混在一起:

  • WireGuard 负责隧道,不负责选择全网最佳路由。
  • BIRD 负责 BGP 和路由策略,不负责创建 WireGuard 隧道。
  • Linux kernel 负责实际转发,BIRD 学到路由后还需要正确安装进 kernel。
  • DN42 registry 负责声明资源归属,ROA/route 对象缺失会导致路由被过滤。
  • 防火墙负责边界控制,不应该用 iptables -P FORWARD ACCEPT 简单放开一切。

每一步都可以独立验证。新手不要一次性复制整套配置上线,应该按“隧道通、BGP 通、路由通、服务通”的顺序逐层排查。

主要参考资料#

· 5 min read

接入 DN42 之前,先要在 registry 中声明“我是谁、我拥有哪些资源、哪些路由允许由我的 AS 宣告”。这一步做不好,后面的 BGP 即使建立成功,路由也可能被对方 ROA 过滤器拒绝。

Registry 是什么#

DN42 registry 是一个 Git 仓库,里面保存社区资源对象。常见对象如下:

mntner    维护者对象,记录认证方式和维护者信息person    联系人对象aut-num   AS 号对象inetnum   IPv4 地址段对象inet6num  IPv6 地址段对象route     IPv4 路由授权对象route6    IPv6 路由授权对象domain    .dn42 域名对象,可选

典型流程:

fork registry添加自己的对象运行 registry 检查脚本提交一个经过 squash 的 commit按要求签名 commit发起 Pull Request等待 maintainer review

不要直接用网页编辑器一点点改文件。网页编辑容易产生多个散乱 commit,也不方便运行检查脚本。

资源对象之间的关系#

一套最小可用资源通常包含:

FOO-MNTFOO-DN42AS4242423777172.22.107.0/27fd42:3777:3777::/48route:  172.22.107.0/27 origin AS4242423777route6: fd42:3777:3777::/48 origin AS4242423777

inetnum / inet6num 表示地址段归属,route / route6 表示这个前缀允许由哪个 AS 宣告。BGP 过滤时通常会用 route/route6 生成 ROA 表,所以这两个对象非常关键。

ASN 选择#

DN42 常见私有 ASN 段包括 4242420000-4242423999。选择前请先确认 registry 中没有被占用。

建议:

  • 选择一个未使用的 ASN。
  • AS 名称简短、稳定。
  • 不要使用公网 ASN,除非你清楚它和 DN42 社区规则的关系。
  • 后续配置 BIRD 时只写数字部分,例如 define OWNAS = 4242423777;

地址选择#

IPv4 常见从 172.20.0.0/14 等 DN42 地址空间中申请。IPv6 使用 fd00::/8 ULA。

建议:

  • IPv4 新手选择社区允许范围内的合适前缀,不要太大。
  • IPv6 可以使用 ULA 生成工具生成随机 /48
  • loopback 地址从自己的前缀里取一个稳定地址,例如 172.22.107.1/32fd42:3777:3777::1/128
  • router id 使用稳定 IPv4 地址,例如 172.22.107.1

找 peer#

DN42 中通常没有严格的“上游”和“客户”区分,大多数 peer 都会互相提供 transit。找 peer 时建议优先选择:

  • 地理位置接近。
  • 延迟较低,通常同洲 peer 更合适。
  • 有稳定在线时间。
  • peering 页面写得清楚。
  • 支持 WireGuard 和 BIRD/FRR 常见配置。

你需要和对方交换:

你的 ASN你的 DN42 IPv4/IPv6 地址或 link-local 地址你的 WireGuard 公钥你的公网 endpoint 和 UDP 端口你的 DN42 前缀你的 peering 联系方式

不要发送:

WireGuard private key服务器密码SSH 私钥Grafana/API token

Peering 信息模板#

可以给对方这样的信息:

ASN: AS4242423777DN42 IPv4: 172.22.107.1DN42 IPv6: fd42:3777:3777::1WireGuard public key: <LOCAL_PUBLIC_KEY>WireGuard endpoint: your.example.com:23777WireGuard link-local: fe80::3777Preferred BGP transport: IPv6 link-local

如果你在 NAT 后面,没有固定公网入口,也可以只主动连接对方 endpoint,并设置 PersistentKeepalive = 25

PR 通过后再做什么#

PR 合并后,等待 registry 镜像和 ROA 数据更新。然后再:

配置 Linux 网络基础配置 WireGuard配置 BIRD2更新 ROA 表和 peer 联调

如果你的 BGP session 已经 established 但对方不接受你的前缀,优先检查:

  • route / route6 对象是否存在。
  • origin ASN 是否写对。
  • 前缀长度是否和 registry 一致。
  • ROA 数据是否已经更新。

参考资料#

· 5 min read

在 WireGuard 和 BIRD 之前,先把 Linux 本身配置成一台合格的路由器:能转发、能承载本机 DN42 地址、防火墙边界清晰、不会因为反向路径检查丢包。

安装基础工具#

sudo apt updatesudo apt install -y iproute2 curl jq tcpdump wireguard bird2

确认 WireGuard 能创建接口:

sudo ip link add wg-test type wireguardsudo ip link del wg-test

开启转发并关闭 rp_filter#

创建 /etc/sysctl.d/99-dn42.conf

sudo tee /etc/sysctl.d/99-dn42.conf >/dev/null <<'EOF'net.ipv4.ip_forward=1net.ipv6.conf.all.forwarding=1net.ipv6.conf.default.forwarding=1
net.ipv4.conf.all.rp_filter=0net.ipv4.conf.default.rp_filter=0EOF
sudo sysctl --system

rp_filter 会检查包的返回路径是否和入接口匹配。DN42 经常有多条隧道和非对称路径,开启它可能导致“对端能发来、我回不去”或“BGP 建立但业务不通”。

检查:

sysctl net.ipv4.ip_forwardsysctl net.ipv6.conf.all.forwardingsysctl net.ipv4.conf.all.rp_filter

配置 dummy/loopback 地址#

给本节点配置稳定 DN42 地址:

sudo modprobe dummysudo ip link add dn42 type dummysudo ip addr add 172.22.107.1/32 dev dn42sudo ip addr add fd42:3777:3777::1/128 dev dn42sudo ip link set dn42 up

临时命令重启后会失效,推荐使用 systemd-networkd 持久化。

/etc/systemd/network/10-dn42.netdev

[NetDev]Name=dn42Kind=dummy

/etc/systemd/network/10-dn42.network

[Match]Name=dn42
[Network]Address=172.22.107.1/32Address=fd42:3777:3777::1/128

启用:

sudo systemctl enable --now systemd-networkdsudo networkctl reloadip addr show dev dn42

如果你的公网网卡由云厂商 agent、NetworkManager 或 netplan 管理,不要盲目切换整机网络管理方式。只用 systemd-networkd 管 dummy 接口即可。

netplan 注意事项#

普通 netplan ethernets: 配置不会凭空创建 dummy 接口。也就是说,仅写下面内容通常不够:

network:  version: 2  ethernets:    dn42:      addresses:        - 172.22.107.1/32

要么使用 .netdev 创建 dummy,要么确认当前 netplan 版本明确支持你要使用的虚拟接口类型。

防火墙#

不要直接:

iptables -P FORWARD ACCEPT

更稳妥的做法是只放行 DN42 隧道相关转发。示例:

sudo iptables -A FORWARD -i wg+ -o wg+ -j ACCEPTsudo iptables -A FORWARD -i wg+ -o dn42 -j ACCEPTsudo iptables -A FORWARD -i dn42 -o wg+ -j ACCEPT
sudo ip6tables -A FORWARD -i wg+ -o wg+ -j ACCEPTsudo ip6tables -A FORWARD -i wg+ -o dn42 -j ACCEPTsudo ip6tables -A FORWARD -i dn42 -o wg+ -j ACCEPT

nftables 思路:

table inet filter {  chain forward {    type filter hook forward priority filter; policy drop;    iifname "wg*" oifname "wg*" accept    iifname "wg*" oifname "dn42" accept    iifname "dn42" oifname "wg*" accept  }}

如果系统已有 firewalld、ufw 或自写 nftables 规则,应合并到现有规则集中,不要混用多套工具制造顺序问题。

NAT 边界#

DN42 是路由网络。拥有并宣告自己的 DN42 前缀后,应让对端看到真实 DN42 源地址,不应该默认 MASQUERADE。

正常方式:

服务绑定在 172.22.107.1 / fd42:3777:3777::1BIRD 宣告 172.22.107.0/27 / fd42:3777:3777::/48peer 通过 BGP 学到你的前缀

只有本地普通 LAN 临时访问 DN42 时才考虑 NAT:

sudo iptables -t nat -A POSTROUTING \  -s 192.168.100.0/24 -d 172.20.0.0/14 -o wg+ -j MASQUERADE

IPv6 场景优先路由自己的 ULA 前缀,不推荐 NAT66。

DNS#

Linux 使用 systemd-resolved 时,可以把 .dn42 查询转发到 DN42 DNS:

sudo resolvectl dns wg-peer1 172.20.0.53sudo resolvectl domain wg-peer1 '~dn42'

DNS 服务器地址请替换成你信任且可达的 DN42 resolver。DN42 wiki 也提供 DNS 服务说明。

自检#

ip addr show dev dn42ip route showip -6 route showsysctl net.ipv4.ip_forwardsysctl net.ipv6.conf.all.forwardingsysctl net.ipv4.conf.all.rp_filteriptables -S FORWARDnft list ruleset

进入下一篇 WireGuard 配置前,至少确认:

  • dn42 接口存在。
  • 本机 DN42 IPv4/IPv6 地址存在。
  • IPv4/IPv6 forwarding 已开启。
  • rp_filter 已关闭。
  • 防火墙不会阻断后续 WireGuard/BGP 流量。

参考资料#

· 5 min read

DN42 peer 之间通常不在同一个物理网络,需要先建立隧道。WireGuard 是 DN42 中最常见的隧道方案之一:配置简单、性能好、跨平台。

一条 peer 一个接口#

WireGuard 可以在一个接口上放多个 peer,但它会根据 peer 的 public key 和 AllowedIPs 做内部选择。DN42 的路由选择应该交给 BGP,因此更推荐:

每个 DN42 peer 一个独立 WireGuard 接口每个接口一个 BGP session路由选择交给 BIRD

这样排障清楚,也避免多个 peer 的 AllowedIPs 重叠。

生成密钥#

sudo install -d -m 700 /etc/wireguardumask 077wg genkey | sudo tee /etc/wireguard/wg-peer1.key |  wg pubkey | sudo tee /etc/wireguard/wg-peer1.pub

把公钥发给 peer:

sudo cat /etc/wireguard/wg-peer1.pub

private key 永远不要发给别人。

wg-quick 配置#

创建 /etc/wireguard/wg-peer1.conf

[Interface]PrivateKey = <LOCAL_PRIVATE_KEY>ListenPort = 23777Address = fe80::3777/64Table = offMTU = 1420
[Peer]PublicKey = <PEER_PUBLIC_KEY>Endpoint = peer.example.net:23777AllowedIPs = 172.20.0.0/14, 172.31.0.0/16, 10.0.0.0/8, fd00::/8, fe80::/10PersistentKeepalive = 25

重点解释:

  • Table = off 非常重要。wg-quick 默认会把 AllowedIPs 写进路由表,但 DN42 的路由应由 BIRD 决定。
  • Address = fe80::3777/64 给接口配置 link-local 地址,后续可用 IPv6 link-local 建 BGP。
  • AllowedIPs 必须至少覆盖 BGP 邻居地址和你希望这条 WireGuard 链路承载的 DN42 地址空间。DN42 wiki 示例中也提醒,如果使用很宽的 AllowedIPs,没有 Table = off 可能把流量错误导向 peer。
  • PersistentKeepalive = 25 适合 NAT 后面的节点。

启动:

sudo systemctl enable --now wg-quick@wg-peer1sudo wg show wg-peer1

你应该看到:

latest handshake: 几秒或几分钟前transfer: rx/tx 都有计数

点对点地址#

DN42 中常用 IPv6 link-local 建 BGP,不一定需要给每条隧道分配 IPv4 点对点地址。

如果 peer 要求配置 IPv4/IPv6 点对点地址,wg-quick 不擅长直接表达 /32 peer /32 这种关系,可以使用 PostUp

PostUp = /sbin/ip addr add dev %i 172.22.107.1/32 peer 172.22.144.66/32PostDown = /sbin/ip addr del dev %i 172.22.107.1/32 peer 172.22.144.66/32

/sbin/ip 的实际路径可以用 which ip 查询。

动态 DNS endpoint#

WireGuard 只在接口启动时解析一次 Endpoint 域名。如果 peer 的公网地址经常变化,需要周期性重新解析并更新 endpoint。

常见做法:

使用 WireGuard 官方 reresolve-dns 脚本或者定时重启对应 wg-quick 接口或者让 peer 提供稳定地址

生产环境更推荐使用重新解析脚本,而不是频繁重启接口。

MTU#

普通公网 IPv4/IPv6 上跑 WireGuard,MTU = 1420 是常见起点。以下场景需要降低:

  • PPPoE。
  • WireGuard 外面还有 VMess/Trojan/QUIC。
  • 底层又套了 VXLAN/GRE/IPIP。
  • 发现小包通、大包不通。

测试:

ping -M do -s 1372 172.20.0.1ping6 -M do -s 1352 fd00::1tracepath 172.20.0.1tracepath6 fd00::1

TCP 可以使用 MSS clamp 辅助:

sudo iptables -t mangle -A FORWARD \  -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
sudo ip6tables -t mangle -A FORWARD \  -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

但 MSS clamp 只影响 TCP,不会修复 UDP、ICMP、QUIC。接口 MTU 仍然要测准。

排障#

没有 handshake:

sudo wg show wg-peer1sudo tcpdump -ni any udp port 23777

常见原因:

  • 公钥填错。
  • Endpoint 域名或端口填错。
  • 云安全组未放行 UDP。
  • NAT 后没有 keepalive。
  • 对端还没启动接口。

handshake 有了但 BGP 不通:

ip addr show wg-peer1ping6 -I wg-peer1 fe80::1

常见原因:

  • AllowedIPs 没有包含 fe80::/10
  • BIRD neighbor 没有写 %wg-peer1
  • 防火墙拦截 TCP 179。

参考资料#

· 7 min read

BIRD2 是 DN42 中最常用的 BGP 路由守护进程之一。WireGuard 让节点之间“连得上”,BIRD2 让节点之间“知道怎么走”。

安装#

sudo apt updatesudo apt install -y bird2sudo systemctl enable --now bird

检查:

sudo birdc show status

主配置#

创建 /etc/bird/bird.conf

define OWNAS = 4242423777;define OWNIP = 172.22.107.1;define OWNIPv6 = fd42:3777:3777::1;define OWNNET = 172.22.107.0/27;define OWNNETv6 = fd42:3777:3777::/48;define OWNNETSET = [ 172.22.107.0/27+ ];define OWNNETSETv6 = [ fd42:3777:3777::/48+ ];
router id OWNIP;
protocol device {    scan time 10;}
protocol kernel kernel4 {    ipv4 {        import none;        export filter {            if source = RTS_STATIC then reject;            krt_prefsrc = OWNIP;            accept;        };    };    scan time 20;}
protocol kernel kernel6 {    ipv6 {        import none;        export filter {            if source = RTS_STATIC then reject;            krt_prefsrc = OWNIPv6;            accept;        };    };    scan time 20;}
protocol static static4 {    route OWNNET reject;
    ipv4 {        import all;        export none;    };}
protocol static static6 {    route OWNNETv6 reject;
    ipv6 {        import all;        export none;    };}
include "/etc/bird/roa.conf";include "/etc/bird/filters.conf";include "/etc/bird/peers/*.conf";

关键点:

  • router id 是 IPv4 格式,即使你主要使用 IPv6。
  • static reject 让 BIRD 有稳定的本地前缀可宣告。
  • kernel 协议负责把 BIRD 选出的路由安装进 Linux 路由表。
  • krt_prefsrc 可以让 Linux 发起到 DN42 的连接时优先使用你的 DN42 loopback 地址作为源地址。
  • DN42 wiki 提醒,如果没有给本机配置 DN42 dummy 地址,内核安装路由时可能出现 netlink 错误。

ROA 更新#

创建 /etc/bird/roa.conf

roa4 table dn42_roa;roa6 table dn42_roa_v6;
protocol static roa_dn42_v4 {    roa4 { table dn42_roa; };    include "/etc/bird/roa_dn42.conf";}
protocol static roa_dn42_v6 {    roa6 { table dn42_roa_v6; };    include "/etc/bird/roa_dn42_v6.conf";}

Burble 生成的 ROA 文件内容类似 route 172.20.0.0/24 max 29 as 4242420000;,这些语句需要放在 protocol static 里导入对应的 ROA table。

创建更新脚本 /usr/local/sbin/update-dn42-roa.sh

#!/usr/bin/env bashset -euo pipefail
ROA4_URL="https://dn42.burble.com/roa/dn42_roa_bird2_4.conf"ROA6_URL="https://dn42.burble.com/roa/dn42_roa_bird2_6.conf"ROA4_FILE="/etc/bird/roa_dn42.conf"ROA6_FILE="/etc/bird/roa_dn42_v6.conf"BIRDC="/usr/sbin/birdc"[ -x "$BIRDC" ] || BIRDC="/usr/bin/birdc"
tmp4="$(mktemp)"tmp6="$(mktemp)"trap 'rm -f "$tmp4" "$tmp6"' EXIT
curl -fsSL -o "$tmp4" "$ROA4_URL"curl -fsSL -o "$tmp6" "$ROA6_URL"
[ -f "$ROA4_FILE" ] && cp -a "$ROA4_FILE" "$ROA4_FILE.bak"[ -f "$ROA6_FILE" ] && cp -a "$ROA6_FILE" "$ROA6_FILE.bak"
install -m 0644 "$tmp4" "$ROA4_FILE"install -m 0644 "$tmp6" "$ROA6_FILE"
if "$BIRDC" configure; then    rm -f "$ROA4_FILE.bak" "$ROA6_FILE.bak"else    [ -f "$ROA4_FILE.bak" ] && mv "$ROA4_FILE.bak" "$ROA4_FILE"    [ -f "$ROA6_FILE.bak" ] && mv "$ROA6_FILE.bak" "$ROA6_FILE"    "$BIRDC" configure || true    exit 1fi

授权:

sudo chmod +x /usr/local/sbin/update-dn42-roa.sh

创建 systemd service:

# /etc/systemd/system/dn42-roa.service[Unit]Description=Update DN42 ROA tables
[Service]Type=oneshotExecStart=/usr/local/sbin/update-dn42-roa.sh

创建 timer:

# /etc/systemd/system/dn42-roa.timer[Unit]Description=Update DN42 ROA periodically
[Timer]OnBootSec=2minOnUnitActiveSec=15minAccuracySec=1min
[Install]WantedBy=timers.target

启用:

sudo systemctl daemon-reloadsudo systemctl enable --now dn42-roa.timersudo systemctl start dn42-roa.service

检查:

sudo birdc show route table dn42_roasudo birdc show route table dn42_roa_v6

过滤器#

创建 /etc/bird/filters.conf

define DN42_ASNS = [ 64511..64855, 76100..76199, 4242420000..4242423999 ];
function is_valid_network_v4() -> bool {    return net ~ [        172.20.0.0/14{21,29},        172.20.0.0/24{28,32},        172.21.0.0/24{28,32},        172.22.0.0/24{28,32},        172.23.0.0/24{28,32},        172.31.0.0/16+,        10.100.0.0/14+,        10.127.0.0/16+,        10.0.0.0/8{15,24}    ];}
function is_valid_network_v6() -> bool {    return net ~ [ fd00::/8{44,64} ];}
filter dn42_import_filter_v4 {    if !is_valid_network_v4() then reject;    if net ~ OWNNETSET then reject;    if bgp_path.first !~ DN42_ASNS then reject;    if roa_check(dn42_roa, net, bgp_path.last) != ROA_VALID then reject;    accept;}
filter dn42_import_filter_v6 {    if !is_valid_network_v6() then reject;    if net ~ OWNNETSETv6 then reject;    if bgp_path.first !~ DN42_ASNS then reject;    if roa_check(dn42_roa_v6, net, bgp_path.last) != ROA_VALID then reject;    accept;}
filter dn42_export_filter_v4 {    if net ~ [ OWNNET ] then accept;    reject;}
filter dn42_export_filter_v6 {    if net ~ [ OWNNETv6 ] then accept;    reject;}

这是严格 ROA 策略:只有 ROA_VALID 才接受。如果想兼容尚未生成 ROA 的路由,可以只拒绝 invalid:

if roa_check(dn42_roa, net, bgp_path.last) = ROA_INVALID then reject;

严格模式更安全,宽松模式兼容性更强。生产网络建议理解差异后再选择。

上面的 export filter 只向 peer 宣告自己的前缀,适合刚入门、暂时不想给别人提供 transit 的节点。如果你已经理解 DN42 的 transit 关系,并愿意把从其他 peer 学到的合法路由继续转发给当前 peer,可以改成下面这种策略:

filter dn42_transit_export_filter_v4 {    if is_valid_network_v4() && source ~ [ RTS_STATIC, RTS_BGP ] then accept;    reject;}
filter dn42_transit_export_filter_v6 {    if is_valid_network_v6() && source ~ [ RTS_STATIC, RTS_BGP ] then accept;    reject;}

然后在对应 peer 的 export filter 中引用 transit 版本。是否提供 transit,最好提前和 peer 说明清楚。

BGP peer 模板#

创建 /etc/bird/peers/peer1.conf

template bgp dn42_peer {    local as OWNAS;    path metric on;    graceful restart on;
    ipv4 {        extended next hop on;        import keep filtered;        import filter dn42_import_filter_v4;        export filter dn42_export_filter_v4;    };
    ipv6 {        import keep filtered;        import filter dn42_import_filter_v6;        export filter dn42_export_filter_v6;    };}
protocol bgp peer1 from dn42_peer {    neighbor fe80::1%wg-peer1 as 4242420001;    interface "wg-peer1";}

DN42 中常用 IPv6 link-local 建 BGP。fe80::1%wg-peer1 中的 %wg-peer1 不能省略,因为 link-local 地址只在单条链路上有意义。

extended next hop on; 让 IPv4 路由可以使用 IPv6 next-hop,这样就不必为每条隧道额外分配 IPv4 点对点地址。

import keep filtered; 会保留被 import filter 拒绝的路由,方便用 birdc show route filtered protocol peer1 排查。路由很多的节点会增加一些内存开销,如果你不需要看 filtered route,可以去掉它。

应用配置#

sudo birdc configure checksudo birdc configuresudo birdc show protocolssudo birdc show protocols all peer1

如果配置有语法错误,先修正,不要用重启服务代替 configure check

查看路由#

sudo birdc show route countsudo birdc show route for 172.20.0.1sudo birdc show route for fd00::1sudo birdc show route protocol peer1sudo birdc show route export peer1sudo birdc show route filtered protocol peer1

查看 Linux kernel 是否拿到路由:

ip route get 172.20.0.1ip -6 route get fd00::1

多节点网络#

有多个自有节点时:

  • 小网络可以使用 iBGP 全互联。
  • 节点多了以后使用 route reflector。
  • OSPF/IS-IS 只承载内部 loopback 和基础设施路由。
  • 不要把所有 eBGP 学到的 DN42 路由灌进 OSPF。

一个简单 iBGP 模板:

template bgp ibgp_peer {    local as OWNAS;    direct;
    ipv4 {        next hop self;        import all;        export all;    };
    ipv6 {        next hop self;        import all;        export all;    };}

生产环境中应继续加内部过滤器,避免错误传播默认路由或测试前缀。

参考资料#

· 5 min read

DN42 节点上线后,真正消耗时间的是运维:peer flap、ROA 过期、MTU 黑洞、BGP 过滤器误杀、监控缺失。本文整理一套新手可用的检查和观测方式。

分层排障思路#

遇到“不通”时,按层排查:

1. WireGuard 是否 handshake2. BGP session 是否 established3. BIRD 是否收到路由4. filter/ROA 是否拒绝路由5. kernel 是否安装路由6. 防火墙是否允许转发7. MTU 是否导致大包黑洞

不要一上来重启所有服务。先定位在哪一层断了。

WireGuard 检查#

sudo wg showsudo wg show wg-peer1ip addr show wg-peer1

关注:

latest handshake 是否近期更新transfer rx/tx 是否增长endpoint 是否正确allowed ips 是否包含 DN42 地址和 fe80::/10

抓包:

sudo tcpdump -ni any udp port 23777

BIRD 检查#

sudo birdc show statussudo birdc show protocolssudo birdc show protocols all peer1

常见状态:

Established  正常Active       BIRD 正在尝试连接Connect      TCP 连接阶段Idle/Down    配置、接口或对端问题

查看路由:

sudo birdc show route countsudo birdc show route protocol peer1sudo birdc show route filtered protocol peer1sudo birdc show route export peer1

如果 filtered 中有大量路由,重点看 filter 和 ROA。

Kernel 路由检查#

BIRD 里有路由不代表 Linux kernel 一定能转发。检查:

ip route get 172.20.0.1ip -6 route get fd00::1ip route show proto birdip -6 route show proto bird

如果 BIRD log 中出现 netlink 相关错误,检查:

  • dummy 接口上是否配置了本机 DN42 地址。
  • krt_prefsrc 是否合理。
  • kernel protocol 是否启用。
  • 路由 next-hop 是否可达。

MTU 排查#

小包通、大包不通时优先看 MTU:

tracepath 172.20.0.1tracepath6 fd00::1ping -M do -s 1372 172.20.0.1ping6 -M do -s 1352 fd00::1

如果底层有多层封装,WireGuard MTU 可能需要降到 13801360 甚至更低。TCP MSS clamp 可以缓解 TCP,但不能代替正确 MTU。

BGP flap 监控#

BGP flap 指 session 频繁 up/down。它通常由以下原因导致:

  • 隧道不稳定。
  • 对端重启。
  • MTU 或丢包导致 keepalive 超时。
  • BIRD 配置频繁 reload。
  • 防火墙或 NAT 映射过期。

简单人工查看:

journalctl -u bird --since "1 hour ago"sudo birdc show protocols all peer1

Prometheus 监控时,建议采集:

BGP session stateBGP established 时间BGP flap/change 次数每个 peer 的 import/export route 数量WireGuard latest handshakeWireGuard rx/tx bytes节点 CPU、内存、磁盘、网络

如果使用 bird_exporter,Grafana 中应重点做:

  • BGP session 状态表。
  • peer up/down 时间线。
  • prefix import/export 数量。
  • flap 计数或 state changes。
  • WireGuard handshake 延迟。

bird-lg-go Looking Glass#

Looking Glass 可以让外部用户查询你的 BGP 状态、路由、traceroute 和 whois。bird-lg-go 分为 frontend 和 proxy:

frontend: 面向用户,默认监听 :5000proxy:    部署在每个 BIRD 节点,默认监听 :8000

frontend Docker Compose 示例:

services:  bird-lg:    image: xddxdd/bird-lg-go    container_name: bird-lg    restart: unless-stopped    environment:      - BIRDLG_SERVERS=cn,jp,us,sg      - BIRDLG_DOMAIN=lg.example.com      - BIRDLG_PROXY_PORT=8000      - BIRDLG_WHOIS=whois.dn42      - BIRDLG_NET_SPECIFIC_MODE=dn42      - BIRDLG_PROTOCOL_FILTER=BGP    ports:      - "5000:5000"

这意味着 frontend 会尝试访问:

cn.lg.example.com:8000jp.lg.example.com:8000us.lg.example.com:8000sg.lg.example.com:8000

每个节点都需要对应 DNS 记录和 proxy。

proxy 安全#

proxy 可以执行 BIRD 查询和 traceroute,不应无保护暴露到公网。

bird-lg-go proxy 支持 ALLOWED_IPS,也可以配合防火墙限制来源。

systemd 示例:

[Unit]Description=bird-lg-go proxyAfter=network-online.target bird.serviceWants=network-online.target
[Service]User=bird-lgGroup=birdEnvironment=BIRD_SOCKET=/run/bird/bird.ctlEnvironment=BIRDLG_LISTEN=0.0.0.0:8000Environment=ALLOWED_IPS=203.0.113.10ExecStart=/usr/local/bin/bird-lgproxy-goRestart=on-failureNoNewPrivileges=truePrivateTmp=trueProtectSystem=fullProtectHome=true
[Install]WantedBy=multi-user.target

bird-lg-go 当前 proxy 使用 BIRD_SOCKET 指定 BIRD socket。实际路径请用下面命令确认:

ls -l /run/bird/bird.ctl /var/run/bird/bird.ctl 2>/dev/null

再用防火墙限制 8000 端口来源:

sudo iptables -A INPUT -p tcp -s 203.0.113.10 --dport 8000 -j ACCEPTsudo iptables -A INPUT -p tcp --dport 8000 -j DROP

日常维护清单#

每天或每次改配置后检查:

sudo wg showsudo birdc show protocolssudo birdc show route countsystemctl status dn42-roa.timerjournalctl -u bird --since "1 hour ago"

每次新增 peer 后检查:

sudo birdc configure checksudo birdc configuresudo birdc show protocols all <peer>sudo birdc show route protocol <peer>sudo birdc show route export <peer>

每次怀疑路由问题时检查:

sudo birdc show route filtered protocol <peer>ip route get <target-ipv4>ip -6 route get <target-ipv6>

参考资料#