0x01 前置工作

安装 Bird2(Ver > 2.16)wireguard

sudo apt update
sudo apt -y install apt-transport-https ca-certificates wget lsb-release
sudo wget -O /usr/share/keyrings/cznic-labs-pkg.gpg https://pkg.labs.nic.cz/gpg
echo "deb [signed-by=/usr/share/keyrings/cznic-labs-pkg.gpg] https://pkg.labs.nic.cz/bird2 $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/cznic-labs-bird2.list
sudo apt update && sudo apt install bird2 wireguard -y

这里使用systemd-networkd作为后端,netplan作为前端生成配置.

sudo tee /etc/systemd/network/10-dn42.netdev > /dev/null <<EOF
[NetDev]
Name=dn42
Kind=dummy
EOF

sudo tee /etc/netplan/99-dn42.yaml > /dev/null <<EOF
network:
    version: 2
    ethernets:
        dn42:
            addresses:
                - <DN42 IPv4>/32
EOF
sudo chmod 700 /etc/netplan/*.yaml
sudo systemctl restart systemd-networkd
sudo netplan apply

/etc/sysctl.conf

sudo tee /etc/sysctl.conf > /dev/null <<EOF
net.ipv4.tcp_no_metrics_save=1
net.ipv4.tcp_ecn=0
net.ipv4.tcp_frto=0
net.ipv4.tcp_mtu_probing=0
net.ipv4.tcp_rfc1337=0
net.ipv4.tcp_sack=1
net.ipv4.tcp_fack=1
net.ipv4.tcp_window_scaling=1
net.ipv4.tcp_adv_win_scale=1
net.ipv4.tcp_moderate_rcvbuf=1
net.core.rmem_max=33554432
net.core.wmem_max=33554432
net.ipv4.tcp_rmem=4096 87380 33554432
net.ipv4.tcp_wmem=4096 16384 33554432
net.ipv4.udp_rmem_min=8192
net.ipv4.udp_wmem_min=8192
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
net.ipv4.conf.all.route_localnet=1
net.ipv4.ip_forward=1
net.ipv4.conf.all.forwarding=1
net.ipv4.conf.default.forwarding=1
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.rp_filter=0
EOF
sysctl -p

/etc/bird/local/own.conf

define OWNAS       = 4242423997;           # 定义本地自治系统号
define OWNLLA      = fe80::3997;           # 定义链路本地地址
define OWNIP       = 172.21.95.33;         # 定义本地路由器的 IP 地址
define OWNNET      = 172.21.95.32/27;      # 定义申请到的网段
define OWNNETSET   = [ 172.21.95.32/27+ ];  # 定义本地网络集合
#define OWNIPv6 = xxxxxxxxx;
#define OWNNETv6 = xxxxxxxx;
#define OWNNETSETv6 = [xxxxxxxx];

router id OWNIP;

/etc/bird/local/kernel.conf

# master4 -> kernel
protocol kernel Kernel4 {
    ipv4 {
        import none;
        export all;
    };
}

# master6 -> kernel
protocol kernel Kernel6 {
    ipv6 {
        import none;
        export none;
    };
}

/etc/bird/local/table.conf

ipv4 table OSPF_table;
ipv6 table OSPF6_table;
ipv4 table BGP_table;
ipv6 table BGP6_table;
roa4 table ROA4_table;
roa6 table ROA6_table;

# OSPF 将v4路由输送到Master4
protocol pipe PipeOSPF4 {
    table OSPF_table;
    peer table master4;
    import none;
    export filter {
        krt_prefsrc = OWNIP;
        accept;
    };
}

# OSPF 将v6路由输送到Master6
protocol pipe PipeOSPF6 {
    table OSPF6_table;
    peer table master6;
    import none;
    export none;
}

# BGP 将v4路由输送到Master4
protocol pipe PipeBGP4 {
    table BGP_table;
    peer table master4;
    import none;
    export filter {
        # 仅允许路由来源是BGP的路由
        if source = RTS_BGP then {
            krt_prefsrc = OWNIP; # 为所有BGP来源的路由设置首选源IP
            accept; # 接受这条BGP路由(已修改prefsrc)
        }
        reject; # 拒绝非BGP来源的路由
    };
}

# BGP 将v6路由输送到Master6
protocol pipe PipeBGP6 {
    table BGP6_table;
    peer table master6;
    import none;
    export none;
}


# 下载ROA用作路由验证
protocol rpki DN42ROA {
        roa4 { table ROA4_table; };
        roa6 { table ROA6_table; };
        remote "hk1.dn42.bitrate.studio" port 8082;
        refresh 600;
        retry 300;
        expire 7200;
}

0x02 内网搭建

/etc/bird/local/ospf.conf

protocol ospf v3 OSPFv4 {
    ipv4 {
        table OSPF_table;
        import all;
        export all;
    };
    area 0.0.0.0 {
        interface "iGP_*" {
            type ptp;
        };
        interface "dn42" {
            stub;
        };
    };
};

protocol ospf v3 OSPFv6 {
    ipv6 {
        table OSPF6_table;
        import none;
        export none;
    };
    area 0.0.0.0 {
        interface "iGP_*" {
            type ptp;
        };
        interface "dn42" {
            stub;
        };
    };
};

0x03 外网搭建

/etc/bird/local/bgp.conf

protocol static Static4 {
    route OWNNET reject;
    ipv4 { table BGP_table; };
}

protocol static Static6{
#    route OWNNETv6 reject;
    ipv6 { table BGP6_table; };
}

template bgp OutNet {
    local as OWNAS;
    ipv4 {
        extended next hop on;
        graceful restart on;
        table BGP_table;
        import filter {
            # 从ROA表中判断收到的路由前缀信息是否和表中登记的源ASN一致
            if (roa_check(ROA4_table, net, bgp_path.last) != ROA_VALID) then {
                print "[Error] ROA 验证失败: 前缀 ", net, " 的 ASN ", bgp_path.last, " 不合法";
                reject;
            } else accept;
        };
        export filter {
            # 路由的来源(source) 仅允许导出 静态路由 和 BGP 路由
            if source ~ [RTS_STATIC, RTS_BGP] then accept;
            reject;
        };
    };
    ipv6 {
        import none;
        export none;
    };
}

template bgp SelfPeers {
    local as OWNAS;
    source address OWNIP;
    ipv4 {
        next hop self;
        igp table OSPF_table;
        table BGP_table;
        import all;
        export filter {
            if source = RTS_STATIC then reject;
            accept;
        };
    };
    ipv6 {
        import none;
        export none;
    };
}

################ iBGP ################
#protocol bgp <协议名> from SelfPeers {
#    neighbor <本AS内的邻居IP> as OWNAS;
#    rr client;
#}

################ eBGP ################
#protocol bgp <协议名> from OutNet {
#    neighbor <对方的链路本地地址>%<WG接口名> as <对方的ASN>;
#    source address OWNLLA;
#}

0x04 配置文件

/etc/bird/bird.conf

protocol device Device {
    scan time 10;
}

include "/etc/bird/local/own.conf";
include "/etc/bird/local/kernel.conf";
include "/etc/bird/local/table.conf";
include "/etc/bird/local/ospf.conf";
include "/etc/bird/local/bgp.conf";

/etc/wireguard/iGP_xx.conf

[Interface]
PrivateKey = <私钥>
ListenPort = <端口>
MTU = 1420
Table = off
PostUp = sysctl -w net.ipv6.conf.%i.autoconf=0
Address = fe80::3997:xx/64

[Peer]
PublicKey = <Peer-PublicKey>
Endpoint = <IP/NameServer>:<端口>
AllowedIPs = 10.0.0.0/8, 172.20.0.0/14, 172.31.0.0/16, fd00::/8, fe00::/8, ff02::5

/etc/wireguard/eBGP_xx.conf

[Interface]
PrivateKey = # 你的 WireGuard 私钥
ListenPort = # 你的监听端口,一般是对方as后五位
MTU = 1420
Table = off
PostUp = ip addr add fe80::3997/64 dev %i

[Peer]
PublicKey = <对方的公钥>
Endpoint = <对方的公网IP/域名>:<监听端口>
AllowedIPs = 10.0.0.0/8, 172.20.0.0/14, 172.31.0.0/16, fd00::/8, fe80::/64

0x05 Looking Glass

/etc/systemd/system/proxy.service

sudo tee /etc/systemd/system/proxy.service > /dev/null <<EOF
[Unit]
Description=Looking Glass Proxy
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/proxy
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable proxy
systemctl start proxy
systemctl status proxy

0xFF 参考资料

  1. DN42探究日记 - Ep.2 通过OSPF搭建内部网络
  2. 使用 WireGuard + Babald(Bird2) 快速组网