Skip to main content

2 posts tagged with "BGP"

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 通、路由通、服务通”的顺序逐层排查。

主要参考资料#

· 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;    };}

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

参考资料#