博主头像

人間になりたい!!!!!


皖ICP备2025096275号

整活向:使用 OSPFv3 + WireGuard 隧道让一个没有 IPv6 的网络环境也能使用 IPv6 上网

前言

博主大学的校园网环境中没有公网 IPv6 出口. 对于博主这种玩网络的人来说十分的不便. 但是博主在学校和在家的主路由都是 OpenWrt, 且之间有一条 VPN 骨干网可以互相通信. 于是乎博主想到了一个方法: 使用类似 Overlay Network 的方式, 通过 OSPFv3 将学校主路由的 IPv6 默认路由下一跳改为家里的主路由, 将家里的 IPv6 网络给校园网用.

配置需求

  • 对端网关可以互相通信 (可通过 EasyTier, ZeroTier, TailScale 等 VPN)
  • 双方网关为软路由系统或可玩性较高的硬路由

基础配置思路

由于没有 IPv6 环境, 但是 OSPFv3 又需要使用 IPv6 来进行通信, 所以这里我们借助 WireGuard 来建立一条 6in4 通道. 然后使用 Bird v2 来运行 OSPFv3, 将家庭宽带的 ::/0 路由引入该 OSPF 会话, 从而达到校园网网关使用这条线路进行 IPv6 上网的目的.

由于该文章编写于暑期阶段, 因此这里将使用 Debian 13 虚拟机作为校园网网关. 该虚拟机已经在内网接口关闭了 IPv6 功能, 因此无法直接通过内网连接公网 IPv6 业务.

开整

1. 安装并配置 Bird v2

由于新版 OpenWrt 系统内置 WireGuard, 因此我们这里只需要另外安装 Bird 即可.

  • 进入 WebUI, 打开 System -> Software 页面, 搜索 Bird 并安装 bird2, bird2c
  • 安装完成后打开 SSH, 查询 Bird 安装状态

    root@X-wrt-Home:~# bird --version
    BIRD version 2.19.1
  • 移动配置文件位置并更改配置文件存储位置
    随着配置愈发复杂, 单个配置文件是无法满足我们的配置要求的. 所以这里我们使用 /etc/bird 来作为配置文件的存储文件夹.

    实际上, 除了 OpenWrt, 常规 Linux 安装 Bird 时都是采用 /etc/bird 作为配置文件目录
    mkdir /etc/bird
    mv /etc/bird.conf /etc/bird/bird.conf
    vim /etc/init.d/bird

    将其中的 BIRD_CONF 赋值为 /etc/bird/bird.conf

  • 更改完后保存并重启 Bird 进程

    /etc/init.d/bird restart

2. 配置 WireGuard 接口

OpenWrt 默认安装 WireGuard, 但没有默认的私钥和公钥, 所以这里我们自己生成

  • 进入 SSH, 生成公钥和私钥

    cd /etc/wireguard
    wg genkey | tee privatekey | wg pubkey > publickey

OpenWrt 原生支持在 WebUI 中配置和管理 WireGuard 接口, 所以我们这里直接在 WebUI 上进行配置.

  • 打开 WebUI, 切换至 Network -> Interfaces, 单击 Add new interface...

    • 在 Name 中输入该 WireGuard 接口的名称, 注意不要太长. 然后将 Protocol 切换至 WireGuard VPN
    • Private KeyPublic Key 中填入我们刚刚生成的密钥
    • Listen Port 中填入可供 WireGuard 监听的空闲端口
    • IP Addresses 中填入一个CIDR 格式的链路本地 IPv6 地址和一个符合 ULA 规范的 IPv6 地址

      我们这里因为接入的设备不多, 所以即使在考虑冗余的情况下, 给一个 /112 的网段也是绰绰有余了.
    示例配置
  • 切换至 Peers 页面, 点击 Add peer

    • Description 中填入对端设备名称
    • Public Key 中填入对端设备公钥
    • Allowed IPs 中填入对端 WireGuard 内网 IPv6 地址和 ::/0
    • Endpoint Host 中填入校园网网关的 VPN 内网地址
    • Endpoint Port 中填入校园网网关的 WireGuard 监听地址

      因为我们还未配置校园网网关接口, 所以这里直接随便写一个端口即可.
    • Persistent Keep Alive 中填入 25
    示例配置
  • 配置完成后保存提交

    相同的配置需要在校园网网关上也配置一遍
  • 双方都配置好后, 检查接口状态. 如果接口的 TXRX 都有流量, 那就证明配置成功了. 此时可以进行测试.
root@Debian:/etc/wireguard# ping fe80:1::1%tunnel_ipip6
PING fe80::1%tunnel_ipip6 (fe80:1::1%tunnel_ipip6) 56 data bytes
64 bytes from fe80:1::1%tunnel_ipip6: icmp_seq=1 ttl=64 time=0.812 ms
64 bytes from fe80:1::1%tunnel_ipip6: icmp_seq=2 ttl=64 time=0.614 ms
64 bytes from fe80:1::1%tunnel_ipip6: icmp_seq=3 ttl=64 time=0.750 ms
64 bytes from fe80:1::1%tunnel_ipip6: icmp_seq=4 ttl=64 time=1.25 ms
^C
--- fe80:1::1%tunnel_ipip6 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3052ms
rtt min/avg/max/mdev = 0.614/0.857/1.254/0.239 ms

可以看到连接是没有问题的, 至此 WireGuard 侧配置完成.

3. 配置 OSPF

  • 在这两台设备上创建 bird.conf

    vim /etc/bird/bird.conf

    按照该模板填写

    log syslog all;
    
    define ROUTER_ID                = <ROUTER_ID>
    
    protocol device {
      scan time 10;
    };
    
    protocol direct {
      ipv4;
      ipv6;
    };
    
    include "kernel.conf";
    include "ospf.conf";
    • ROUTER_ID 当前路由器的 Router ID. 需要双方不同且唯一. 值形式与 IPv4 类似, 均为 xxx.xxx.xxx.xxx. 这里可以直接填写本机的内网 IPv4 地址.
  • 分别创建 kernel.conf

    protocol kernel kernel_v4{  
      ipv4 {
          import none;
          export filter {
              if source = RTS_STATIC then reject;
              accept;
          };
      };
    }
    
    protocol kernel kernel_v6 {
      ipv6 {
          import none;
          export filter {
              if source = RTS_STATIC then reject;
              accept;
          };
      };
    }
    该配置文件旨在让 Bird 将动态路由协议 (如 BGP, OSPF) 学习到的路由写入系统内核, 但拒绝将自己配置文件中写死的静态路由写入内核.
  • 分别创建 ospf.conf

    • 校园网网关

      protocol ospf v3 ospf_4to6 {
       router id ROUTER_ID;
       ipv6 {
        import all;
        export none;
       };
       include "/etc/bird/ospf/0.conf";
      }
      该配置文件旨在让 Bird 从该 OSPF 会话中引入所有学习到的路由, 但不导出任何路由到该 OSPF 会话中.
    • 家庭网关

      filter export_default {
       if net ~ [ ::/0 ] then {
        accept;
       } else {
        reject;
       }
      }
      
      protocol ospf v3 ospf_4to6_test {
       router id ROUTER_ID;
       ipv6 {
        import none;
        export filter export_default;
       };
       include "/etc/bird/ospf/0.conf";
      }
      该配置文件旨在让 Bird 将 ::/0 的默认路由导入 OSPF 中, 但不导出任何学习到的路由到系统内核中.
  • 分别创建 OSPF 会话配置文件

    • 校园网网关

      mkdir ospf
      vim ospf/0.conf
      • 配置文件

        area 0.0.0.0 {
         interface "tunnel_ipip6" {
         type ptmp;
         ttl security tx only;
         neighbors {
             fd00:1::1;
         };
         };
        };
    • 家庭网关

      mkdir ospf
      vim ospf/0.conf
      • 配置文件

        area 0.0.0.0 {
         interface "tunnel_ipip6" {
         type ptmp;
         ttl security tx only;
         neighbors {
             fd00:1::2;
         };
         };
        };
    Q. 为什么使用 ULA 地址建立连接却还需要 Link-Local 地址?
    A. 因为 OSPFv3 邻居发现依赖链路本地地址 (Link-Local), 协议报文以 Link-Local 为源/目的进行邻接建立; 全局或 ULA 地址可以用于配置, 管理或路由条目. 但不能替代接口上的 Link-Local 地址参与邻接建立, 但是公网会话却需要使用符合 ULA 规范的地址. 因此虽然 OSPF 配置文件中使用 ULA 地址, 但实际连接时 Bird 会检查该接口是否拥有 Link-Local 地址. 如果没有, OSPF 连接则会失败.
  • 分别应用配置

    birdc c
  • 检查会话状态

    birdc s p

    如果 OSPF 已经处于 Running 状态, 则配置完成

    root@Debian:/etc/bird# birdc s p
    BIRD 2.19.1 ready.
    Name       Proto      Table      State  Since         Info
    device1    Device     ---        up     14:40:45.408  
    direct1    Direct     ---        up     14:40:45.408  
    kernel_v4  Kernel     master4    up     14:40:45.408  
    kernel_v6  Kernel     master6    up     14:40:45.408  
    ospf_4to6  OSPF       master6    up     14:46:00.698  Running

3. 配置防火墙

到达这一步, 我们已经拥有了 IPv6 默认路由, ULA 地址, Link-Local 地址. 但我们仍然无法上网. 为什么呢? 这是因为在家庭网关侧我们需要启用 nat6 才可以让本地数据包正确的发往公网, 同时公网返回的数据包也可以正确的到达本地设备. 因为 OpenWrt 可以使用 WebUI 配置, 所以这里我们全程使用 WebUI.

  • 打开 Network -> Firewall 页面, 在下方的 Zones 区域点击 wan 区域的编辑按钮
  • Advanced Setting 中勾选 IPv6 Masquerading, 然后保存提交
  • 点击左下角 Add 按钮, 命名为 WireGuard, 将所有规则都选择 accept, Covered networks 选择之前创建的 WireGuard 接口, Allowed forwared to destination zones 和 Allowed forwared to source zones 全部勾选. 之后同样切换到 Advanced Settings 中打开 IPv6 Masquerading, 保存提交
  • 切换到 NAT Rules 选项卡, 点击 Add 按钮新建规则
  • 规则名称命名为 nat6_ipip6Tunnel, Restrict to address family 选择 IPv6 Only. Outbound Zone 选择 WireGuard. Source address 填入 fd00:1::/112 (即为刚才填写的 ULA 地址段), Action 选择 MASQUERADE, 保存提交.

至此, 防火墙配置完成

4. 验证

到了这里, 我们已经完成了所有配置. 现在我们来验证校园网网关是否可以 IPv6 上网.

  • IPv6 地址查询
root@Debian:/etc/bird# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:24:11:41:d0:1c brd ff:ff:ff:ff:ff:ff
    altname enp0s18
    altname enxbc241141d01c
    inet 192.168.1.21/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
3: tun0: <POINTOPOINT,UP,LOWER_UP> mtu 1360 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 10.0.64.21/24 brd 10.0.64.255 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::617b:570b:ef5a:a679/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever
5: tunnel_ipip6: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none 
    inet6 fd00:1::2/112 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80:1::2/112 scope link 
       valid_lft forever preferred_lft forever

可以看到这里 eth0 接口是没有公网 IPv6 地址的

  • 连通性测试
root@Debian:/etc/bird# ping www.baidu.com -6
PING www.baidu.com (2409:8c20:6:123c:0:ff:b0f6:b2d) 56 data bytes
64 bytes from 2409:8c20:6:123c:0:ff:b0f6:b2d: icmp_seq=1 ttl=52 time=14.3 ms
64 bytes from 2409:8c20:6:123c:0:ff:b0f6:b2d: icmp_seq=2 ttl=52 time=13.8 ms
64 bytes from 2409:8c20:6:123c:0:ff:b0f6:b2d: icmp_seq=3 ttl=52 time=13.7 ms
64 bytes from 2409:8c20:6:123c:0:ff:b0f6:b2d: icmp_seq=4 ttl=52 time=14.0 ms
64 bytes from 2409:8c20:6:123c:0:ff:b0f6:b2d: icmp_seq=5 ttl=52 time=14.0 ms
^C
--- www.baidu.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 13.671/13.957/14.308/0.208 ms

可以看到这里成功访问了百度的 IPv6 地址, 连通性正常!

  • 网络路径查询
root@Debian:/etc/bird# traceroute www.baidu.com -6
traceroute to www.baidu.com (2409:8c20:6:123c:0:ff:b0f6:b2d), 30 hops max, 80 byte packets
 1  _gateway (fd00:1::1)  0.873 ms  0.856 ms  0.825 ms
 2  ah-ipv6 (2409:***)  2.385 ms  2.360 ms  2.312 ms
 3  * ah-ipv6 (2409:***)  3.636 ms *
 4  2409:*** (2409:***)  5.922 ms * *
 5  2409:*** (2409:***)  12.053 ms *  12.465 ms
 6  2409:*** (2409:***)  14.650 ms * *
 7  2409:*** (2409:***)  10.908 ms 2409:*** (2409:***)  10.122 ms 2409:*** (2409:***)  8.499 ms
 ...

可以看到, 这里的第一跳就是我们刚才通过 OSPF 配置的 Peer! 至此, 配置全部结束!


后记

本文为整活性质想法, 如果你真的有类似需求, 你或许应该寻找更加体面的方法. 本人非专业人员, 如有错误或疏漏欢迎指出! 感谢阅读.

整活向:使用 OSPFv3 + WireGuard 隧道让一个没有 IPv6 的网络环境也能使用 IPv6 上网
https://blog.nanami.tech/archives/331/
本文作者 Madobi Nanami
发布时间 2026-07-22
许可协议 CC BY-NC-SA 4.0
发表新评论