北工大校园网 QWRT/OpenWrt IPv6 配置实录:无 DHCPv6-PD 下的 IPv6 Relay、校园认证与 OpenClash 共存
这次折腾的目标并不是简单地“让路由器拿到 IPv6”,而是让接入北工大校园网的 QWRT 路由器能够正常完成校园网认证,并把学校分配在 WAN 侧的 IPv6 /64 网络通过 IPv6 Relay 延伸到 LAN,使电脑等终端获得真实校园网 IPv6 地址。同时还要兼容 OpenClash,实现 IPv4 继续按原有方式使用 OpenClash,而 IPv6 可以直接通过校园网访问公网。
整个过程中实际上遇到了三个相互独立的问题:校园网 IPv6 认证、没有 DHCPv6-PD 时的 LAN IPv6 Relay,以及 OpenClash 对 AAAA DNS 记录的抑制。最开始这三个问题叠在一起,很容易误判成“学校 IPv6 不通”或者“路由器不支持 IPv6”。
下面按照实际排障过程,从头到尾整理。
一、网络环境和最初的问题
使用的路由器是京东云雅典娜 AX6600,刷入 QWRT。WAN 物理接口是 eth4,IPv4 通过 DHCP 获取,IPv6 通过 DHCPv6/RA 获取。
最初查看 WAN6 后发现,路由器本身其实已经获得了学校提供的公网 IPv6:
2001:da8:216:210d:ded8:7cff:fe56:225c/64
同时存在默认路由:
default from 2001:da8:216:210d::/64
via fe80::76ea:cbff:fe5b:d91b
dev eth4
这说明至少从二层和 IPv6 RA 的角度,路由器已经成功加入学校 IPv6 网络。
但 LAN 端当时只有:
fda5:724f:9eec::/64
这样的 ULA 私有 IPv6 地址,Windows 没有获得 2001:da8:216:210d::/64 的公网地址。
这里逐渐确认了一个很关键的事实:
学校给的是 WAN 所在链路上的一个
/64,没有下发 DHCPv6 Prefix Delegation,也就是没有额外给路由器一个可以自由分配给 LAN 的 IPv6 前缀。
因此普通 OpenWrt 家宽环境中常见的:
WAN 获得 /56 或 /60
→ 路由器拆一个 /64 给 LAN
在这里行不通。
只能采用:
WAN /64
↓
RA Relay
DHCPv6 Relay
NDP Relay
↓
LAN 继续使用同一个 /64
也就是说,需要把校园网这一条 IPv6 链路“延伸”到 LAN。
二、先确认校园网 IPv6 门户本身是否可达
校园网认证相关域名经过学校 DNS 可以解析。
例如:
lgn6.bjut.edu.cn
可以得到 IPv6 地址:
2001:da8:216:30c9::a
2001:da8:216:30c9::2
直接从路由器访问:
curl -6 \
-H 'Host: lgn6.bjut.edu.cn' \
'http://[2001:da8:216:30c9::a]/'
可以收到 Dr.COM 门户响应。
因此,路由器到校园认证系统的 IPv6 链路没有问题。
同时还发现学校提供两个很有用的接口。
IPv4 映射:
curl -4 \
'http://lgn.bjut.edu.cn/drcom/getipv4?callback=x'
会返回类似:
x({"result":1,"ip":"172.21.13.69"})
IPv6 地址:
curl -6 \
-H 'Host: lgn6.bjut.edu.cn' \
'http://[2001:da8:216:30c9::a]/drcom/getipv6?callback=x'
返回:
x({"result":1,"ip":"2001:da8:216:210d:...."})
这两个接口后来对认证过程非常有帮助。
三、分析校园网 Portal 的认证逻辑
最开始直接按照传统 Dr.COM 的参数去请求登录接口,会遇到:
认证操作非本机终端
或者请求并不能正确完成认证。
后来对门户页面加载的 JavaScript,特别是 a41.js 和相关逻辑进行了分析。
Portal 当前使用:
/eportal/portal/login
同时配置中可以看到:
page_data_encrypt = 1
encryption_type = 1
secret_key = test
关键问题就在这里。
网页并不是把登录参数直接明文发送到 /eportal/portal/login,而是先进行一个非常简单的编码。
相关 JavaScript 的逻辑本质上是:
每个字符 ASCII 值
XOR 22
↓
转成两位十六进制
例如:
'1'
ASCII = 49
49 XOR 22 = 39
39 = 0x27
所以:
enc("1") = "27"
在 QWRT 中由于系统没有完整 GNU 工具,最后使用 BusyBox hexdump 实现:
enc() {
printf '%s' "$1" |
hexdump -v -e '1/1 "%02x\n"' |
while read h; do
[ -n "$h" ] && printf '%02x' "$((0x$h ^ 22))"
done
}
这里还有一个很容易搞错的地方。
/drcom/chkstatus、/drcom/getipv6 等 Dr.COM 接口本身不需要进行这种参数编码;但:
/eportal/portal/login
需要。
之前一直失败的重要原因之一,就是把这两套接口的参数处理方式混在了一起。
四、确定认证参数和 MAC 行为
Portal 前端初始化终端参数时,会从:
ss4
olmac
获取 MAC。
实际 /drcom/chkstatus 返回的是:
ss4 = 000000000000
后面在线状态中:
olmac = 000000000000
所以本次 IPv6 Portal 场景中,网页实际上并没有使用路由器物理 MAC:
dc:d8:7c:56:22:5c
而是使用:
000000000000
这也是为什么之前直接把路由器真实 MAC 塞进去,反而会得到:
认证操作非本机终端
前端还会给普通 PC 账号添加:
,0,
前缀,因此实际 user_account 类似:
,0,用户名
同时门户支持:
login_ip_type = 0
表示 IPv4 + IPv6 统一认证,
以及:
login_ip_type = 2
表示 IPv6 认证。
经过参数编码后,从 QWRT 发起请求,终于得到:
Portal协议认证成功!
随后访问:
/drcom/chkstatus
返回:
"result":1
并显示当前 IPv6 地址。
这就证明路由器 WAN IPv6 已经真正进入在线状态。
五、为什么认证成功以后 ping6 还是全部超时
这里出现了整个过程中一个比较容易误导判断的现象。
认证成功后:
ping6 2400:3200::1
仍然:
100% packet loss
对 Cloudflare:
2606:4700:4700::1111
同样没有 Echo Reply。
一开始很容易认为:
“认证虽然显示成功,但公网 IPv6 还是没通。”
后来改用真正的应用层协议测试。
首先直接用公网 IPv6 DNS:
nslookup www.cloudflare.com 2400:3200::1
成功获得结果。
这已经证明:
IPv6 UDP/53
可以访问公网。
然后绕过 DNS,直接指定 Cloudflare 的真实 AAAA:
curl -6 -I \
--resolve 'www.cloudflare.com:443:[2606:4700::6810:7c60]' \
https://www.cloudflare.com/
返回:
HTTP/2 200
至此可以确定:
QWRT 路由器本身的公网 IPv6 完全正常。
所以这次排障得到一个重要经验:
ping6 不通 ≠ IPv6 不通
校园网或中间设备完全可能过滤 ICMPv6 Echo Request/Reply,但 TCP、UDP 仍正常工作。
六、配置 IPv6 Relay
确认路由器 WAN IPv6 正常后,开始处理 LAN。
修改前首先备份:
TS="$(date +%Y%m%d-%H%M%S)"
cp /etc/config/network "/etc/config/network.bak.$TS"
cp /etc/config/dhcp "/etc/config/dhcp.bak.$TS"
cp /etc/config/firewall "/etc/config/firewall.bak.$TS"
然后配置 WAN6 为 Relay Master:
uci -q delete dhcp.wan6
uci set dhcp.wan6='dhcp'
uci set dhcp.wan6.interface='wan6'
uci set dhcp.wan6.ra='relay'
uci set dhcp.wan6.dhcpv6='relay'
uci set dhcp.wan6.ndp='relay'
uci set dhcp.wan6.master='1'
LAN 同样使用 Relay:
uci set dhcp.lan.ra='relay'
uci set dhcp.lan.dhcpv6='relay'
uci set dhcp.lan.ndp='relay'
由于不再使用 OpenWrt 自己分配 IPv6 子网,因此去掉:
uci -q delete network.lan.ip6assign
保存:
uci commit dhcp
uci commit network
重启:
/etc/init.d/odhcpd restart
最开始还执行了一次:
/etc/init.d/network reload
结果 QWRT 的 Qualcomm/QSDK 网络脚本输出了大量:
unknown operand
Permission denied
以及 Wi-Fi 重新初始化日志。
不过后面证明这些主要是 QWRT/QSDK 脚本本身比较混乱,与 IPv6 Relay 的核心功能无关。
后面的调试中就不再频繁 reload 整个 network,而是只重启:
/etc/init.d/odhcpd restart
七、Windows 成功获得校园公网 IPv6
Relay 生效后,Windows 的 ipconfig 中终于出现:
2001:da8:216:210d:940d:a7b4:f526:6566
以及临时地址:
2001:da8:216:210d:c06e:3c23:bd4a:4435
默认网关为 QWRT:
fe80::ded8:7bff:fe56:225b
IPv6 路由表也出现:
::/0
→ fe80::ded8:7bff:fe56:225b
2001:da8:216:210d::/64
→ On-link
因此 RA Relay 已经成功。
这里虽然:
ipconfig /renew6
会出现:
信号灯超时时间已到
但这并不代表 IPv6 获取失败。
因为公网 IPv6 地址主要已经通过 RA/SLAAC 获得,而不是必须依赖 DHCPv6 Stateful Address。
八、LAN 客户端为什么仍然不能访问公网 IPv6
Windows 虽然已经获得真实公网 IPv6,但最开始:
curl.exe -6 ...
仍然超时。
于是开始检查 NDP。
当时:
ip -6 route get Windows_IPv6
错误地显示:
dev eth4
也就是说内核认为 Windows 的 IPv6 地址就在 WAN 上。
而:
ip -6 neigh show proxy dev eth4
也没有 Windows 的公网 IPv6。
因此进行了临时验证:
ip -6 route replace "$WIN6/128" dev br-lan
ip -6 neigh replace proxy "$WIN6" dev eth4
此后:
ip -6 route get "$WIN6"
变成:
dev br-lan
Proxy NDP 中也能看到该地址。
这一步证明 NDP Relay 的方向判断是正确的。
但即使这样,Windows 访问公网仍然失败。
说明还有另一层问题。
九、发现校园网认证是按客户端 IPv6 地址进行的
接下来直接从 Windows 访问:
http://[2001:da8:216:30c9::a]/drcom/chkstatus
返回:
"result":0
并且 myv6ip 正是 Windows 自己当前使用的:
2001:da8:216:210d:c06e:3c23:bd4a:4435
这时问题彻底明确:
IPv6 Relay 已经把 Windows 接入校园 IPv6 网络,但学校 Portal 认为这个新的 IPv6 地址是另外一个未认证终端。
当时校园网官网在线终端中只有路由器 WAN IPv6:
2001:da8:216:210d:ded8:7cff:fe56:225c
而没有 Windows 的临时 IPv6。
因此不是 Relay 转发失败,而是:
Windows IPv6 → 校园网络可达
Windows IPv6 → 尚未通过 Portal 公网认证
十、Windows IPv6 完成校园认证
Windows 通过自己的 IPv6 地址访问 Portal。
期间曾经手动构造 /eportal/portal/login 请求,服务端返回了一个 ThinkPHP:
Fatal error:
Call to a member function toArray() on null
这个页面甚至包含了请求调试信息。
需要注意,这种错误页中的认证字段虽然不是明文密码,但其编码只是前面提到的简单 XOR,因此不应该把完整错误页面上传到公开论坛、GitHub 或公开日志中。
更重要的是,之后再次检查:
/drcom/chkstatus
发现:
"result":1
而:
v6ip
已经变成 Windows 当前 IPv6:
2001:da8:216:210d:c06e:3c23:bd4a:4435
说明 Windows IPv6 会话已经建立。
再次测试:
curl.exe -6 -I `
--resolve "www.cloudflare.com:443:[2606:4700::6810:7c60]" `
https://www.cloudflare.com/
终于得到:
HTTP/1.1 200 OK
至此 LAN 客户端的公网 IPv6 数据面也完全打通。
十一、最后一个问题:OpenClash 把 AAAA 记录屏蔽了
虽然指定 IPv6 地址访问成功,但普通执行:
curl.exe -6 https://www.cloudflare.com/
却得到:
Could not resolve host
检查 DNS:
nslookup www.cloudflare.com 192.168.100.1
只返回:
198.18.x.x
这是典型的 OpenClash Fake-IP。
进一步查看 OpenClash:
uci show openclash | grep -Ei 'ipv6|dns'
发现:
openclash.config.ipv6_enable='0'
openclash.config.ipv6_dns='0'
Clash YAML 中也是:
dns:
ipv6: false
enhanced-mode: fake-ip
所以问题不是 Windows IPv6,而是:
OpenClash DNS 主动把 AAAA 查询结果屏蔽了。
十二、调整 OpenClash:IPv4 使用代理,IPv6 保持直连
最终目标是:
IPv4 → OpenClash
IPv6 → 校园网直连
DNS → 同时返回 A 和 AAAA
因此不需要开启 OpenClash 的 IPv6 流量接管,只需要允许 DNS 返回 IPv6。
先设置:
uci set openclash.config.ipv6_dns='1'
uci commit openclash
随后又将增强模式由:
fake-ip
改成:
redir-host
最终配置:
uci set openclash.config.en_mode='redir-host'
uci set openclash.config.ipv6_enable='0'
uci set openclash.config.ipv6_dns='1'
uci commit openclash
重启:
/etc/init.d/openclash restart
然后:
/etc/init.d/dnsmasq restart
最终 UCI:
en_mode = redir-host
ipv6_enable = 0
ipv6_dns = 1
Windows 清空 DNS:
ipconfig /flushdns
重新查询:
nslookup www.cloudflare.com 192.168.100.1
此时已经能同时得到真实 IPv4:
104.16.124.96
104.16.123.96
以及真实 IPv6:
2606:4700::6810:7b60
2606:4700::6810:7c60
再查询:
Resolve-DnsName www.cloudflare.com `
-Type AAAA `
-Server 192.168.100.1
也能正常返回 AAAA。
最终:
curl.exe -6 -I https://www.cloudflare.com/
直接:
HTTP/1.1 200 OK
到这里,DNS 问题也解决。
十三、验证 NDP Relay 是否真的可以动态工作
前面为了诊断曾经手工添加过:
ip -6 route replace "$WIN6/128" dev br-lan
ip -6 neigh replace proxy "$WIN6" dev eth4
这些命令不能作为最终方案。
因为 Windows 使用 IPv6 Privacy Extension 后,临时 IPv6 地址会变化。
如果每换一个 IPv6 都要手动加 /128,显然没有意义。
因此最后专门测试 odhcpd 是否能够自动学习。
先删除针对 Windows 当前地址的手工规则:
ip -6 route del "$WIN6/128" dev br-lan
ip -6 neigh del proxy "$WIN6" dev eth4
然后把 odhcpd 日志提高到 Debug:
uci set dhcp.odhcpd.loglevel='7'
uci commit dhcp
/etc/init.d/odhcpd restart
重启后再次查看,发现 /128 路由已经自动出现:
2001:da8:216:210d:c06e:3c23:bd4a:4435
dev br-lan
proto static
Proxy NDP 也自动出现:
2001:da8:216:210d:c06e:3c23:bd4a:4435 proxy
更关键的是日志明确显示:
Netlink newneigh ... on lan
Added proxy neighbour entry ... on wan6
Learning about proxy routing for ... on lan
还可以看到:
Got a RA on wan6
Forward a RA on lan
以及:
Got a DHCPv6-request on lan
Sending a DHCPv6-relay-forward on wan6
这说明三部分全部正常:
RA Relay
DHCPv6 Relay
NDP Relay
随后 Windows 再次强制使用这个 IPv6:
curl.exe -6 -v `
--interface "2001:da8:216:210d:c06e:3c23:bd4a:4435" `
--resolve "www.cloudflare.com:443:[2606:4700::6810:7c60]" `
https://www.cloudflare.com/
成功:
Established connection
HTTP/1.1 200 OK
因此可以确认:
最终工作状态完全依赖 odhcpd 的动态 NDP Relay,而不是我们之前临时添加的静态
/128。
测试完成后恢复正常日志等级:
uci set dhcp.odhcpd.loglevel='4'
uci commit dhcp
/etc/init.d/odhcpd restart
十四、最终配置
最终 odhcpd 为:
dhcp.wan6.interface='wan6'
dhcp.wan6.ra='relay'
dhcp.wan6.dhcpv6='relay'
dhcp.wan6.ndp='relay'
dhcp.wan6.master='1'
dhcp.lan.ra='relay'
dhcp.lan.dhcpv6='relay'
dhcp.lan.ndp='relay'
最终 OpenClash:
en_mode='redir-host'
ipv6_enable='0'
ipv6_dns='1'
整个网络现在的逻辑变成:
┌── IPv4 ── OpenClash
Windows ─ QWRT ───┤
└── IPv6 ── BJUT IPv6 ── Internet
IPv6 这一侧进一步展开就是:
Windows
│
│ 2001:da8:216:210d::/64
↓
br-lan
│
│ RA / DHCPv6 / NDP Relay
↓
QWRT odhcpd
│
↓
eth4 / wan6
│
↓
北工大校园 IPv6
│
↓
Internet
十五、几个最容易误判的地方
这次最大的几个坑其实都非常典型。
首先是没有 DHCPv6-PD。WAN 拿到 /64 并不意味着 LAN 能直接通过 ip6assign 获得一个公网子网。这种情况下需要的是 Relay,而不是继续尝试 Prefix Delegation。
其次是 ping6。这次无论路由器还是 Windows,都出现过:
ping6 100% 丢包
但 HTTPS、UDP DNS 全部正常。因此实际网络诊断应该至少使用:
DNS
TCP
HTTPS
而不能只依赖 ICMP Echo。
第三是 OpenClash。最初 IPv6 数据面已经通了,但由于:
dns.ipv6 = false
导致应用根本得不到 AAAA,所以表面现象仍然是“IPv6 上不了网”。
第四是 Fake-IP。Fake-IP 对纯 IPv4 代理环境很方便,但在这次:
IPv4 代理
IPv6 直连
的混合环境里,redir-host + AAAA 更容易保持真实 IPv6 地址解析。
第五是校园认证。Relay 解决的是网络连通问题,并不会自动让 LAN 中新出现的 IPv6 地址继承另一个 IPv6 地址的认证状态。实际测试说明校园 Portal 会识别客户端 IPv6,因此客户端地址变化以后可能需要按校园网正常流程重新认证。
十六、最终验证方法
以后如果怀疑配置失效,不需要重新走整套排查。
先在 Windows 看:
ipconfig
应该存在:
2001:da8:216:210d:xxxx:xxxx:xxxx:xxxx
然后:
Resolve-DnsName www.cloudflare.com `
-Type AAAA `
-Server 192.168.100.1
应该得到真实:
2606:4700::...
最后:
curl.exe -6 -I https://www.cloudflare.com/
出现:
HTTP/1.1 200
即可说明:
IPv6 地址获取正常
DNS AAAA 正常
NDP Relay 正常
公网 IPv6 正常
如果突然只能访问校园门户,公网 IPv6 不通,则优先检查:
/drcom/chkstatus
中的:
result
是否仍为:
1
如果变成 0,很可能只是终端换了新的临时 IPv6,需要重新完成正常校园网认证,而不是路由器 Relay 配置坏了。
结论
这次最终解决方案的本质并不是“给 OpenWrt 开个 IPv6 开关”,而是把三个层面分别处理:
第一层:校园 IPv6 认证
↓
确认 WAN IPv6 真正拥有公网访问权限
第二层:IPv6 Relay
↓
利用 odhcpd 将学校同一个 /64
通过 RA / DHCPv6 / NDP Relay 延伸至 LAN
第三层:OpenClash DNS
↓
允许 AAAA 返回
同时保持 IPv6 不由 OpenClash 接管
最终不需要 NAT66,也不需要给每台电脑写死 IPv6 /128 路由,更不需要长期维护静态 Proxy NDP。
正常情况下 odhcpd 会根据 LAN 邻居自动创建对应的客户端 /128 路由和 WAN Proxy NDP。
现在的最终状态就是:
路由器 WAN IPv6:正常
校园 IPv6 认证:正常
LAN 公网 IPv6:正常
RA Relay:正常
DHCPv6 Relay:正常
NDP Relay:正常
OpenClash IPv4:正常
AAAA DNS:正常
Windows IPv6 HTTPS:正常
文章由AI生成