锐捷校园网解限探索记录

https://linux.do/t/topic/2521942
在假期前,我测试了校园网对单线多拨没有限制(端口mac绑定),假期购买了一台瑞芯微rk3588的妖板BDY-G98 给rk3588小主机超频失败 ,如今回到学校使用就是个很大的问题。于是来研究这个。

可能你能看到的最全的(

0x00 前期梳理

梳理一下要求。

  1. 解除设备数限制 这个是最基本的要求了。

  2. 透明代理 我已经不想在每一天设备上安装mihomo,配置节点了,麻烦不说有些应用还不会遵循设置。

  3. 单线多拨 20M的宽带也是没谁了,不解限速太难受。虽然在AI下我们或许能对锐捷这套校园网管理系统做些攻击尝试,但是挨处分这些就免了,本人恰巧在网管中心工作,能接触一部分功能,恰巧有些账号是很久没人登录的,而且密码有规律进行了一波弱密码尝试(

  4. 宿舍使用 紧凑 耗电小 纯被动散热 满足上面要求所需的性能 当然价格也不能太高 100 出头最好。

综上所述,能做到上面要求的也就是能刷OpenWRT的硬路由了。从最后跑完整个流程得到的最低配置是要闪存256M 内存384M。如果你不需要上面的一些功能,可以继续往低选。

推荐首先选择联发科的设备,生态比高通好得多。

我最初的选择是RAX3000M的64G emmc 版本,但是价格就比较高了199元,我也没有在路由器跑docker的想法,纯被动散热下MT7981这颗芯片发热量是比较大的,不是很划算,观望了几天,恰巧之前玩过BDY-G98,从群友得知有 BDY-G56 这个硬件配置和RAX3000M一模一样,甚至有1G内存8G emmc,让老哥给我改改散热和外壳,得到了一个非常紧凑的大小,比RAX3000M优惠多的价格拿到,物有所值了。

缺点是这台设备存世量很少,不在openwrt的硬件列表上,虽然上面的老哥也给了一份可用的固件,但是还是需要自己编译固件,因为后面发现像单线多拨和其他的一些依赖需要自己增加内核模块,不过mt798x的生态比较完善,难度没有这么高,特别是现在有ai的支持之下。

如果你没有编译固件的能力,我更推荐你使用RAX3000M,可以在ImmortalWrt使用image builder在线构建固件,当然我更推荐你自行编译,自由度更高。

0x01 编译/刷入固件

推荐24.10版本,这个版本工具比较全,虽然像mwan3这种需要兼容层工作,而到了25.12上就需要使用重写的版本,而且不一定有mtk的闭源驱动。

采用 GitHub - padavanonly/immortalwrt-mt798x-6.6: An opensource OpenWrt variant for mainland China users. · GitHub 的源码。
如何进行固件编译/刷入,Uboot等就不多赘述,这部分openwrt社区教程已经非常丰富,主要说明一些注意点。源码大小30GB+,留意硬盘大小。

bdy-g56 需要自行修改源码支持,作为一个希望较为通用的教程这里就不说明了。

注意勾选一下软件包,依赖会自动勾选。

# 基础部分
kmod-nft-queue luci-app-mtwifi-cfg luci-app-eqos-mtk
# 单线多拨
kobs kmod-macvlan ip-full mwan3 luci-app-mwan3 iptables-nft 
#工具
curl ethtool

由于我是在BDY-G98上进行的编译,在arm64上多线程编译时会有一些问题。如果是x86交叉编译则不需要。

  1. perl 需要单线程编译,否则会遇到依赖未被编译而报错终止。
  2. golong编译会遇到不支持arm64的问题,需要手动安装go 1.26 修改文件使用环境中的go来编译。
user@armbian:~/immortalwrt-mt798x-6.6/feeds/packages$ git diff lang/golang/golang/Makefile
diff --git a/lang/golang/golang/Makefile b/lang/golang/golang/Makefile
index c1eb93f..b26c8e9 100644
--- a/lang/golang/golang/Makefile
+++ b/lang/golang/golang/Makefile
@@ -83,7 +83,7 @@ BOOTSTRAP_GO_VALID_OS_ARCH:= \
   darwin_386     darwin_amd64 \
   dragonfly_386  dragonfly_amd64 \
   freebsd_386    freebsd_amd64    freebsd_arm \
-  linux_386      linux_amd64      linux_arm \
+  linux_386      linux_amd64      linux_arm     linux_arm64 \
   netbsd_386     netbsd_amd64     netbsd_arm \
   openbsd_386    openbsd_amd64 \
   plan9_386      plan9_amd64 \
@@ -266,26 +266,33 @@ define Host/Configure
 endef
 
 define Host/Compile
-       $(call GoCompiler/Bootstrap/Make, \
-               $(HOST_GO_VARS) \
-               CC="$(HOSTCC_NOCACHE) -std=gnu17" \
-       )
-
-       $(call GoCompiler/Bootstrap-1.17/Make, \
-               GOROOT_BOOTSTRAP="$(BOOTSTRAP_ROOT_DIR)" \
-               $(HOST_GO_VARS) \
-       )
-
-       $(call GoCompiler/Bootstrap-1.20/Make, \
-               GOROOT_BOOTSTRAP="$(BOOTSTRAP_1_17_BUILD_DIR)" \
-               $(HOST_GO_VARS) \
-       )
+#      $(call GoCompiler/Bootstrap/Make, \
+#              $(HOST_GO_VARS) \
+#              CC="$(HOSTCC_NOCACHE) -std=gnu17" \
+#      )
+#
+#      $(call GoCompiler/Bootstrap-1.17/Make, \
+#              GOROOT_BOOTSTRAP="$(BOOTSTRAP_ROOT_DIR)" \
+#              $(HOST_GO_VARS) \
+#      )
+#
+#      $(call GoCompiler/Bootstrap-1.20/Make, \

0x02 解除设备数限制

大多数学校采用检查 TTL 和 追踪 HTTP UA 的方式,UA3F 是一个 HTTP(S) 重写代理,可用于透明改写请求/响应 Header、Body,也可按规则执行 URL 重定向、拒绝或丢弃请求。

如果不需要透明代理,可以直接参照此教程(依赖 kmod-nft-queue ):

我更推荐使用二进制版本,通过eBPF卸载来改写L3层数据(TTL等)性能会更好,同时不占用透明代理,可配合其本身的TPROXY透明代理http,或者其他代理核心透明代理模式进行分流给UA3F。配置方式可以直接参考UA3F文档。

可以先尝试只修改TTL,如果检查不严格可以直接使用nftables只改写ttl,就无需UA3F了。

root@ImmortalWrt:/etc/nftables.d# cat 12-mangle-ttl-64.nft 
# 1. 发出的包固定为 64(Android/Linux/macOS 标准初始值,如果偏好 Windows 可改 128)
chain mangle_postrouting_ttl64 {
    type filter hook postrouting priority 300; policy accept;
    counter ip ttl set 64
}
chain mangle_prerouting_ttl64 {
    type filter hook prerouting priority 300; policy accept;
    counter ip ttl set 64
}
# 2. 从 WAN 口进入的包:将 TTL 设为 2(防止外层探测穿透至局域网终端)
# 注意:wan替换为你实际的接口名(如 wan、eth0)
chain mangle_prerouting_ttl2 {
    type filter hook prerouting priority 300; policy accept;
    iifname "wan" counter ip ttl set 2
}
# 3. 防路由跟踪:直接丢弃发给路由及经路由转发的 TTL=1 探测包
chain filter_input_ttl {
    type filter hook input priority 0; policy accept;
    ip ttl 1 counter drop
}
chain filter_forward_ttl {
    type filter hook forward priority 0; policy accept;
    ip ttl 1 counter drop
}

sing-box可以根据协议类型分流http给UA3F(SOCKS5模式),降低UA3F处理压力。但是用mihomo的就比较难受了,总所周知sing-box的配置文件难写的很,而且大版本会引入破坏性修改,加之习惯了mihomo,只能牺牲一些性能让UA3F用REDIRECT模式在流量进入 Mihomo 之前先由防火墙截获 HTTP 流量修改 UA。

实话说UA检测在26年已经式微了。

0x03 单线多拨

在 ImmortalWrt 中,将 Macvlan 单线多拨、源进源出 PBR(保障认证心跳)、mwan3 负载均衡 结合,能够实现校园网多账号带宽链路聚合。

网络基础配置

进入系统后台 网络 → 接口 进行配置:

  1. 创建 Macvlan 设备:

    • 进入 网络 → 接口 → 设备,添加设备类型为 MAC VLAN。
    • 基础设备选择物理上行网口(如 eth0),命名为 wanmac0、wanmac1 等。
  2. 创建逻辑接口:

    • 在接口页面添加新接口,协议选择DHCP。
    • 接口命名必须使用标准数字后缀:vwan0、vwan1…
    • 分别绑定对应的 wanmac0、wanmac1 设备。

    推荐关闭ipv6

  3. 配置网关与跃点数(Metric):

    • 点击每个 vwan 接口的 修改 → 高级设置。
    • 确保勾选 「使用默认网关」。
    • 为每个接口设置不同的 「网关跃点」(如 vwan0 为 10,vwan1 为 20),防止主表路由冲突。
    • 将所有虚拟 WAN 接口划入同一防火墙区域(通常为 wan 区域)。

部署源进源出 Hotplug 脚本

由于 mwan3 会在内核中插入基于数据包标记(fwmark)的策略路由(规则优先级通常在 2000 后),为了确保各认证客户端的心跳包绝对原路返回,必须将自定义的 PBR 优先级提升至 500 + num。

在终端执行以下命令写入脚本:

Bash

cat << 'EOF' > /etc/hotplug.d/iface/95-wan-source-routing
#!/bin/sh
# 监听网络接口启动 (ifup)、重租 (ifupdate) 和关闭 (ifdown)
[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifupdate" ] || [ "$ACTION" = "ifdown" ] || exit 0

case "$INTERFACE" in
    vwan*)
        suffix="${INTERFACE#vwan}"
        if [ -z "$suffix" ]; then
            num=0
        else
            num=$((suffix + 1))
        fi
        table=$((200 + num))
        # 优先级设为 500+,确保高于 mwan3 的默认捕获规则
        pref=$((500 + num))

        if [ "$ACTION" = "ifdown" ]; then
            ip rule del pref "$pref" 2>/dev/null
            ip route flush table "$table" 2>/dev/null
            exit 0
        fi

        IP=$(ip -4 -o addr show dev "$DEVICE" 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -n1)
        GW=$(ip -4 route show dev "$DEVICE" 2>/dev/null | awk '/default/ {print $3}' | head -n1)

        if [ -n "$IP" ] && [ -n "$GW" ]; then
            ip route replace default via "$GW" dev "$DEVICE" table "$table" 2>/dev/null
            ip rule del pref "$pref" 2>/dev/null
            ip rule add from "$IP" lookup "$table" pref "$pref"
        fi
        ;;
esac
EOF

chmod +x /etc/hotplug.d/iface/95-wan-source-routing

路由规则碰撞警告

如果自定义的 pref 数值大于 mwan3 规则(如 2000 以上),认证心跳包将被 mwan3 的负载均衡规则强制劫持,造成心跳超时掉线。务必保持 pref 小于mwan3。

配置 mwan3 负载均衡

在 LuCI 界面进入 网络 → 负载均衡(mwan3)

  1. 配置接口(Interfaces):

    • 删除默认的 wan,添加 vwan0、vwan1。
    • 跟踪方式:勾选启用,跟踪的目标 IP 设置为公网通用 DNS(如 223.5.5.5、119.29.29.29)。
    • 可靠度设为 2。

    注意ipv6对应的wan6也要添加

  2. 配置成员(Members):

    • 创建 vwan0_m1_w1:接口绑定 vwan0,跃点数(Metric)填 1,权重(Weight)填 1。
    • 创建 vwan1_m1_w1:接口绑定 vwan1,跃点数(Metric)填 1,权重(Weight)填 1。
  3. 配置策略(Policies):

    • 创建策略 balanced:将上述成员(vwan0_m1_w1、vwan1_m1_w1)全部加入,形成等权聚合。
  4. 配置规则(Rules):

    • 修改默认规则 default_rule:将目标策略设为 balanced,分配所有普通上网流量走聚合。

最终效果

Interface status:
 interface wan is online and tracking is active (online 28h:44m:57s, uptime 31h:08m:46s)
 interface wan6 is online and tracking is active (online 25h:24m:23s, uptime 50h:06m:19s)
 interface vwan0 is online and tracking is active (online 28h:44m:57s, uptime 33h:45m:26s)
 interface vwan1 is online and tracking is active (online 28h:44m:57s, uptime 31h:05m:30s)
 interface vwan2 is online and tracking is active (online 28h:44m:57s, uptime 31h:05m:36s)

Current ipv4 policies:
load_blance:
 vwan2 (25%)
 vwan1 (25%)
 vwan0 (25%)
 wan (25%)

Current ipv6 policies:
load_blance:
 unreachable

Directly connected ipv4 networks:
x.x.x.x

Directly connected ipv6 networks:
xxxx:xxxx:xxxx::/64
xxxx:xxxx:xxxx:xxxx::/64
xxxx::/64

Active ipv4 user rules:
  224 14472 MARK       0    --  *      *       0.0.0.0/0            172.16.0.0/12        
   10   670 MARK       0    --  *      *       0.0.0.0/0            10.0.0.0/8           
 418K   35M - load_blance  0    --  *      *       0.0.0.0/0            0.0.0.0/0            
    0     0 - load_blance  0    --  *      *       0.0.0.0/0            0.0.0.0/0            

Active ipv6 user rules:
 175K   16M MARK       0    --  *      *       ::/0                 ::/0                 
    0     0 - load_blance  0    --  *      *       ::/0                 ::/0     

mihomo 配置

当 mwan3 重新加载策略或检测到某个接口掉线/重连时,会重构防火墙 mangle 链并刷新路由标记,这会导致 mihomo 的透明代理(Tproxy / Tun)连接中断或丢包。

校园网ipv6多不下发PD前缀,建议dns模块关闭ipv6,仅支持ipv6路由(可ping通ipv6),这样既可以用ipv6连接到HKIX的节点也不至于因为NAT6或多拨v6导致的问题。

放宽内核反向过滤(rp_filter)

多拨与负载均衡场景下,必须开启宽松模式,防止内核因非对称路由直接丢弃回包:

Bash

# 写入持久化配置
cat << 'EOF' > /etc/sysctl.d/99-multihoming.conf
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
EOF

# 立即应用配置
sysctl -p /etc/sysctl.d/99-multihoming.conf

系统验证与状态排查

按照顺序执行以下测试:

  1. 验证策略路由优先级与表项:

    ip rule show
    

    确认 pref 位于 mwan3 规则之前,格式如下:

    1002:   from 10.90.80.61 lookup 201
    2001:   from all fwmark 0x100/0xff00 lookup 100
    
  2. 验证源进源出可用性(单网卡绑定):

    curl --interface <vwan0分配的IP> http://ip.im -4
    curl --interface <vwan1分配的IP> http://ip.im -4
    

    两者均应成功返回公网响应,且即使网关不同也不会超时。

需要关闭硬件卸载/硬件加速吗?

实测无论是 HNAT / 全锥形 NAT / 防火墙硬件流量卸载都不需要关闭,很多教程都指出要关闭实测是没有影响的。

0x04 登录校园网

在GitHub上登录校园网的项目有很多,语言有python/bash/go/C++,但是没有对单线多拨这种情况的登录做的项目。
参考了以下下项目:

Iamtianyuyang/UPCnetworklogin: 这是一个基于c语言用于linux命令行登录中国石油大学(华东)校园网的代码。 | https://github.com/Iamtianyuyang/UPCnetworklogin
fjd2004711/ruijie_nxu: 对于宁夏大学(NXU)校园网锐捷认证的 Linux 通用登录脚本 | https://github.com/fjd2004711/ruijie_nxu
mapkkkk/single_login: 校园网自动登录 | https://github.com/mapkkkk/single_login
here200/Connect-School-Net: 一键登录校园网,针对网页认证 | https://github.com/here200/Connect-School-Net/tree/master
PengweeWang/campusnet_login | https://github.com/PengweeWang/campusnet_login
its-david-li/Ruijie-Campus-Auth: 帮你在路由器或 Linux 电脑上自动登录锐捷校园网的实用小脚本。配好之后扔在定时任务里就行,断网秒连。告别弹窗,让你的设备安安静静、稳稳当当地保持在线。 | https://github.com/its-david-li/Ruijie-Campus-Auth/tree/main
a76yyyy/HustWebAuth: HustWebAuth is a program used to implement Ruijie web authentication. | https://github.com/a76yyyy/HustWebAuth
Jun-maxs/CampusNetLogin: 校园网登录工具 + 远程控制系统 (ePortal认证/移动端Web/远程Agent) | https://github.com/Jun-maxs/CampusNetLogin
Redlnn/Ruijie-ePorta-Tool: 一个基于Python的自动登录锐捷ePorta网页认证的工具 | https://github.com/Redlnn/Ruijie-ePorta-Tool
huantuoshen-prog/ruijie-gdstvc-autologin: 锐捷Web认证自动登录 | OpenWrt路由器脚本 | 广科院校园网 | 支持电信联通 | Shell | https://github.com/huantuoshen-prog/ruijie-gdstvc-autologin#%E8%B7%AF%E7%94%B1%E5%99%A8%E9%83%A8%E7%BD%B2
Gloridust/RuijieWIFI-AutoLogin: 自动登录宜宾学院锐捷校园WiFi认证系统,防止意外掉线。理论上支持所有锐捷系统校园网。 | https://github.com/Gloridust/RuijieWIFI-AutoLogin

选择在a76yyyy/HustWebAuth的基础上fork增加支持单线多拨下指定接口,go语言编写占用低,性能好,二进制便于跨平台部署。

0x05 透明代理

推荐使用ShellCrash 相比openclash更原生,性能更好占用更低,缺点是没这么即开即用,推荐关闭本地配置文件覆写,会破坏你的配置文件中的规则。自己参考内置的配置文件去写适合路由器的配置。

这部分代理社区的教程也很多,在此就不赘述了。

0x06 总结

这篇只讲述了校园网相关,其实很多地方是研究了ImmortalWrt源码和mtk相关闭源驱动才得出相关的结论,像自编译后WiFi配置缩水,ipv6路由不可达,UA3F失效等等。放假之前在win上虚拟网口的操作我本以为实际上难度一般,但是最终难度超乎我的想象,花费了10天时间才完成整个流程。

考虑到学校内网不限速,下一步试试把这个通过内网shadowsocks共享给其他同学用。(二包运营商)

76 个赞

强啊佬,写的很细

1 个赞

之前用爱快测试了多拨绝对不是嫌mwan麻烦,学校的限制是每账号百兆,但是实测12拨只有五百多,有点奇怪

佬,除了这个TTL=64,如果检测更严格,它还有什么可以检测?我热点改TTL可以用,但是我比较好奇 :smiley:

基本就是ttl,nat后面的设备除了ttl有明显的特征,再就是行为特征了,不过鬼才检测行为特征

检测方法还有很多,看相关章节的参考链接。

1 个赞

我们学校是免费的 50m 校园网 目前接的万兆电信宽带 路由器似乎是h3c 这个有现成的项目吗

还好我们学校不检测登录设备数量,中间跨一个路由器就行。流量直接ss到另一个服务器里,服务器是老师的流量随便花。

我测下来多拨是会有一个软上限,这个原因是连接分配和线程数量上限导致的。因为在路由器负载均衡,等比例分配所有局域网连接,有可能会导致有两个下载线程分配到了同一个接口。然后比如你12拨,但是下载只分配8线程最佳也只能合并8个接口的速度。

解决方法就是利用队列控制和QoS有选择的去分配而不是公平分配。

我们学校是旧的锐捷认证(客户端),限制三台设备,是否有破限的办法?

有对锐捷协议逆向的开源客户端Mentohust,原理大同小异。

1 个赞

想问一下为什么这样就能破解设备数量限制?没理解原理?

我的理解是大量的篇幅是在绕过路由器限制和多拨上?在我的学校没这个情况

深澜这个有嘛 :grin:

这只是登录,解限制还是看相关章节。

1 个赞

原理都差不多,应该能通用,不过登录需要改改。

补充一点是每个校园的锐捷登录中service字段不一样需要注意。

哦,我明白了。你说的设备数量限制指的是禁止挂路由器。

我以为是一个账户可以直接同时登录更多的设备。。。我们学校目前是可以挂路由器的。

:joy:

20M的宽带是免费使用的吗? 如果不是那学校也太坑了啊。

方法挺多的,最硬核的应该是DPI深度包检测,但是这玩意比较消耗资源,很多学校设备有这个但是没开。

1 个赞

20M还要花钱……
今年新生是50M……
被背刺死了