Featured image of post 长沙理工大学:校园网共享指南

长沙理工大学:校园网共享指南

校园网限制一人一终端,但现在的大学生还有几人是有且只有一台上网设备的?指望推动学校在短时间做出改变不太现实,只好另辟蹊径。

2016年11月7日通过的《中华人民共和国网络安全法》第二十四条规定,「网络运营者为用户办理网络接入、域名注册服务,办理固定电话、移动电话等入网手续,或者为用户提供信息发布、即时通讯等服务,在与用户签订协议或者确认提供服务时,应当要求用户提供真实身份信息。用户不提供真实身份信息的,网络运营者不得为其提供相关服务。」

到了教育部这里落实,就变成了校园网一人一号。再到运营商这里,就变成了一人一终端,还不准使用路由器。这显然已经和合规没有任何关系,学生的需求也摆在这里,但限制却还是这个鸟样。好一点的大学,比如上海交大这种坐拥华东教育骨干网的学校可以做到校园网免费,为什么我们甚至不能放开连接设备数量上的限制呢?

2015年以来……目前,我校IPV4/IPV6总出口带宽达到47GB,其中电信25GB、联通10GB、移动10GB、教育网2GB,校园网总注册用户数超过4.34万、活跃用户数超过2.43万。办公账户(免费)带宽由2MB升到36MB。宿舍区基本账户(付费)带宽由2MB升到12MB,网费不变。……

这套数据应该不是最新的,2022年寒假校园网又进行了一次大扩容,具体扩容了多少不得而知。如果按照这套数据计算,总出口 47GB,活跃用户数2.43万,则人均带宽是$ \dfrac{47GB * 1000 * 8}{24300} \approx 15Mbps $。这点可怜的带宽,还要给学校的官网防 DDoS,加上网安等种种因素,就变成了一人一终端这种限制。

现在的大学生还有几人是有且只有一台上网设备的?室友间的一些操作也需要一套局域网环境(文件共享、联机游戏……)指望推动学校在短时间做出这套改变不太现实。但需求总要解决,只能先自己想想办法,从技术上解决这个矛盾了。

Update 2023/10/7:可能是部署了新设备,经测试,在敏行轩,本文措施失效——即使部署所有措施,依旧会频繁被检测。虽然我的脚本可以自动让路由器重新上线,但上网体验会变得很差,游戏更是几乎不可能。那么,敏行轩大概率是部署了新的检测方法,基本只剩加密所有流量这一条路可走。

Update 2023/10/16:现在在敏行轩(其他区块只会更宽松),最有效也最简单的办法就是用 Clash 代理所有流量(即使全局直连也可以),具体方法文章后段有详细说明。

# 硬件

需要一台可以刷入 OpenWRT 的路由器,我采用的是一台 Nano Pi R2S,最好选择这种用户基数大固件多的产品,也最好能自己编译固件。

关于如何为路由器刷入 OpenWRT 请自行在网上搜索对应的路由器型号+教程。不建议购买所谓的「校园网路由器」,这种路由器通常价格比同性能路由器贵非常多,而且卖的人还不一定懂技术。

# 接入路由器

通过一段时间的观察,可以得到我校校园网前端的计费系统采用城市热点的 Dr.COM,这是一套非常常见的计费系统;BRAS 终端是锐捷的设备,采用 POE 方式连接锐捷的 AP,似乎没有参与认证。

1
daemon.info pppd[8599]: CHAP authentication succeeded: Welcome to Drcom System:

我将校园网分为三大类接入方式,无线,办公区有线,学生公寓有线。

前两者都是 DHCP+Portal 验证,网页表单提交账号即可完成验证。学生公寓区域的有线设备通过 PPPoE 认证,账号信息就是校园网账号本身。

因此路由的接入方式便确定了。宿舍的有线直接 PPPoE 认证就可以正常上网了。对于 Portal 的要麻烦一些,若无法连接外网则判断 Portal 能否访问,能访问的话提交一个构造好的 POST 包登录即可。

Portal 认证的脚本校友已经写过不少:

https://github.com/linfangzhi/CSUST_network_auto_login

https://github.com/eigeen/csust-cn-login

https://github.com/colawithsauce/csust-network-login

路由器上安好 pythonrequests 库然后运行这些脚本即可。如果因无网络不能安装,重新编译一个固件就行。再不行就写一个 Shell 脚本登录。

# 封锁状况

此时已经可以通过路由器上网了,但依然不能全寝共享。

校园网多设备共享很被检测到会被临时屏蔽,此时会屏蔽所有的网络流量,据说还会强制重定向所有 HTTP 请求到http://1.1.1.3/remind/proxy_remind.htm?tm=8,不过我是没有遇上。

Update: 会强制重定向到以下网页:

校园网共享检测提示

查阅资料发现,检测是否多设备共享有两种思路,一种是通过设备流量特征识别:

  • TTL
  • IPID
  • 时间戳
  • UA

另一种是侵入式流量审计,这个可能看学校,不过我校肯定是有的:

增强网络安全防护能力。……部署出口防火墙、出口行为审计……、IPS(入侵防御)等安全设备系统,加固学校网络和信息系统的整体安全。

通过一次喊人来寝室修网络得知肯定是深信服的设备。

通过路由器裸奔一段时间发现如下规律:

  • 两台不同平台的产品(如 Windows 电脑和 iPad)同时上网会在较短时间内被封锁
  • 封锁时用代理可以连出去,B 站也能看,其他的不行,甚至无法 Ping 通校外 IP
  • 被封锁后重新认证也无法上网,更换 MAC 地址后才能恢复

得出的结论是大概率通过 UA 识别,检测到后封禁当前 MAC 地址一段时间。

# 流量处理

# 统一 TTL

将这行规则加入路由器的「网络」-「防火墙」-「自定义规则」(下同),即可统一 TTL 为 65,其中-o br-lan可以视情况更换,如eth0

1
iptables -t mangle -I POSTROUTING -o br-lan -j TTL --ttl-set 65

这条规则用到了 ipopt 模块,在官方编译的固件或其他一些极简的固件里默认不会安装。这种情况下用opkg安装即可:

1
2
opkg update
opkg install iptables-mod-ipopt

保存规则并重启防火墙,在电脑上随便 Ping 一个网站看 TTL 是否为 65(不要在路由器上 Ping,除非你知道你在干什么)。

# 统一时间戳

接下来先启用 OpenWrt 自带的 NTP 服务器,然后劫持所有局域网内的 NTP 请求到路由器,以达到我们统一时间戳的目的。

这种方法并不完美,因为手机连接基站时会同步到别的 NTP 服务器,最好的办法是直接去除 TCP 包的时间戳,但这种方法暂无成熟的实现,只能先采用劫持 NTP 请求的办法。

只需要在管理页面中修改几个设置就可以了。

  • 点击 System -> System(系统)
  • 勾选 Enable NTP client(启用 NTP 客户端)和 Provide NTP server(作为 NTP 服务器提供服务)。
  • NTP server candidates(候选 NTP 服务器)按需设置,可以使用阿里云的 NTP 服务器:ntp.aliyun.com
  • 点击 Save & Apply 按钮。

向防火墙添加以下规则:

1
2
3
4
5
6
iptables -t nat -N ntp_force_local
iptables -t nat -I PREROUTING -p udp --dport 123 -j ntp_force_local
iptables -t nat -A ntp_force_local -d 0.0.0.0/8 -j RETURN
iptables -t nat -A ntp_force_local -d 127.0.0.0/8 -j RETURN
iptables -t nat -A ntp_force_local -d 192.168.0.0/16 -j RETURN
iptables -t nat -A ntp_force_local -s 192.168.0.0/16 -j DNAT --to-destination 192.168.1.1

其中192.168.1.1需要更改成路由器的地址,视固件而定。

若你的路由器地址不在192.168.0.0/16内,最后两行都要跟着改,一般的家用路由器都在这个范围内。

Windows 下确认效果:

1
w32tm /stripchart /computer:baidu.com /dataonly /samples:5

如果能正常同步就证明配置成功了。

# 统一 UA

网上的解决方案大部分基于代理,比如 Privoxy,甚至 Clash。还有不少是通过XMURP-UA直接在内核层面处理 UA,这几年又有新的插件出来,比如UA2F

# 方案一:UA2F

编译固件时自定义加入ua2fluci-app-ua2f,R2S 可以在这里下载编译好的。UA2F 与 Turbo ACC 冲突,即使没有使用 Turbo ACC 也记得要关掉「全雏形 NAT」和「软件流量分载」这两个功能。

完成后启动 UA2F 再打开ua.233996.xyz就会发现自己的 UA 已经被修改了。

# 方案二:Privoxy

安装好 Privoxy 并正确配置,然后将所有 HTTP 流量转发给 Privoxy 代理,并在 Privoxy 中替换 UA。

# 安装 Privoxy
1
2
3
opkg update
opkg install luci-app-privoxy
opkg install luci-app-privoxy-zh-cn
# 配置 Privoxy

点击 Services -> Privoxy WEB proxy。

  • Files and Directories(文件和目录):Action Files 删除到只剩一个框,填入 match-all.action。Filter files 和 Trust files 均留空。
  • Access Control(访问控制):Listen addresses 填写 0.0.0.0:8118,Permit access 填写 192.168.0.0/16。Enable action file editor 勾选。
  • Miscellaneous(杂项):Accept intercepted requests 勾选。
  • Logging(日志):全部取消勾选。

点击 Save & Apply。

# 配置防火墙转发

向路由器防火墙添加以下规则:

1
2
3
4
5
6
iptables -t nat -N http_ua_drop
iptables -t nat -I PREROUTING -p tcp --dport 80 -j http_ua_drop
iptables -t nat -A http_ua_drop -d 0.0.0.0/8 -j RETURN
iptables -t nat -A http_ua_drop -d 127.0.0.0/8 -j RETURN
iptables -t nat -A http_ua_drop -d 192.168.0.0/16 -j RETURN
iptables -t nat -A http_ua_drop -p tcp -j REDIRECT --to-port 8118

在路由器的局域网中打开 http://config.privoxy.org/edit-actions-list?f=0,点击 Edit 按钮。Action 那一列中,hide-user-agent 改选为 Enable(绿色),在右侧 User Agent string to send 框中填写 Privoxy/1.0或任意 UA;其它全部选择为 No Change (紫色)。点击 Submit 按钮。

如果打不开这个页面,说明之前某个地方配置有误。

# 确认效果

本地浏览器调试是看不到效果的,因为经过路由器之前 UA 会保持原样。

访问 ua.chn.moe 以查看 UA 是否修改成功。

# 方案三:Clash

这种方法的思路是使用 Clash 代理/阻止所有发往 80 端口的流量。同时 Clash 也直接接管所有流量,这就意味着无需处理 IPID 和时间戳。

假设你使用的是 OpenClash,方法如下:

OpenClash设置

打开 OpenClash 插件面板,进入 覆写设置 -> 规则设置,勾选自定义规则,将以下规则插入配置:

1
- DST-PORT,80,Proxy

其中Proxy需要视配置文件的不同而更改,例如我的代理组叫做 HK,也可以直接使用节点名称。

对于没有能力加密的同学,则使用以下规则1

1
- DST-PORT,80,REJECT

Update 2023/10/31:经测试,即使不加入这条自定义规则,也足以防止检测。但必须启用 Clash,至少设置全局直连。

# 防止通过 IPID 检测

各设备的 IPID 起始值不同,并随着包数量的上升而上升,接近一条直线,若有多个设备长时间使用后会呈现出多条上升序列。这可以用来探测是否是多个设备。23

由于需要kmod-rkp-ipid,这一步也需要编译固件。

编译好固件后向防火墙添加以下规则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
iptables -t mangle -N IPID_MOD
iptables -t mangle -A FORWARD -j IPID_MOD
iptables -t mangle -A OUTPUT -j IPID_MOD
iptables -t mangle -A IPID_MOD -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A IPID_MOD -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A IPID_MOD -d 255.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -j MARK --set-xmark 0x10/0x10

即可修改所有包的 IPID 为单一递增曲线。

# 老办法

设置如下 crontab 即可在每天凌晨三点重新拨号以打断检测过程:

1
0 3 * * * ( ifdown wan; sleep 5; ifup wan )

# 侵入式流量屏蔽

向路由器防火墙添加以下规则:

1
2
3
4
5
6
iptables -I FORWARD -p tcp -m tcp --sport 80 -m u32 --u32 "5&0xFF=0x7F" -j DROP
iptables -I FORWARD -p tcp -m tcp --sport 8000 -m u32 --u32 "5&0xFF=0x7F" -j DROP
iptables -I FORWARD -p tcp -m tcp --sport 8080 -m u32 --u32 "5&0xFF=0x7F" -j DROP
iptables -I FORWARD -p tcp -m tcp --sport 80 -m u32 --u32 "5&0xFF=0x80" -j DROP
iptables -I FORWARD -p tcp -m tcp --sport 8000 -m u32 --u32 "5&0xFF=0x80" -j DROP
iptables -I FORWARD -p tcp -m tcp --sport 8080 -m u32 --u32 "5&0xFF=0x80" -j DROP

以屏蔽侵入式流量,以上规则来自 V2EX 网友。

这些规则用到了iptablesu32模块,大多数固件都不会默认安装,亦需要通过opkg安装:

1
2
opkg update
opkg install iptables-mod-u32

随后屏蔽学校的「共享提示」页面:

1
2
iptables -I FORWARD -p tcp --sport 80 --tcp-flags ACK ACK -m string --algo bm --string "src=\"http://1.1.1." -j DROP
iptables -I FORWARD -p tcp --sport 80 --tcp-flags ACK ACK -m string --algo bm --string "value=\"http://18.20.18." -j DROP

在Openwrt防火墙的流量规则设置如下规则:

  • 源区域WAN,源地址1.1.1.3,目标区域设备,动作拒绝

  • 源区域WAN,源地址1.1.1.1,目标区域设备,动作拒绝

这些规则来源于校友的博客(找不到来源,可能已经关闭了)

# 意外封锁处理

前面提到学校会封一段时间的 MAC,想要重新上线就需要更换 MAC 地址重新上线。为此我写了一个 Shell 脚本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/sh
DATE=$(date +%Y-%m-%d-%H:%M:%S)
interface=eth0
current_mac=$(ifconfig ${interface} | grep "HWaddr" | awk '{print$5}')
new_mac=$(dd if=/dev/random bs=1 count=3 2>/dev/null | hexdump -C | head -1 | cut -d' ' -f2- | awk '{ print "34:36:3b:"$1":"$2":"$3 }')
tries=0
while [[ $tries -lt 3 ]]; do
    if /bin/ping -c 1 223.5.5.5 >/dev/null; then
        echo --- exit ---
        exit 0
    fi
    tries=$((tries + 1))
done
echo ${DATE} block detected, replacing mac address >>watchdog.log
ifconfig down ${interface}
sleep 1
ifconfig ${interface} hw ether ${new_mac}
sleep 1
ifconfig up ${interface} 
echo ${DATE} old address ${current_mac} has been replaced with ${new_mac} >>watchdog.log

将这个脚本保存到路由器的 home 目录下(用vim粘贴保存以下就可以了),设置如下 Crontab 每分钟执行一次:

1
* * * * * sh /root/net_watchdog.sh

路由器就会自每隔一分钟检测是否在线,如果掉线,则随机更换 MAC 地址并重新上线,日志将会记录在同目录下的watchdog.log中。

Shell自动检测是否掉线

# DNS 内网解析处理

接上路由器之后,校外资源可以正常访问,反倒是校内资源全都无法访问了。经排查发现是路由器下的设备无法解析出正确的 IP 地址,但路由器本身又没有问题。

暂时不清楚是什么原因导致的,但解决起来很简单,可以直接把已知的内网地址 dnsmasq,但我推荐安装 SmartDNS 来解决。

SmartDNS 的安装可以参考官方教程

  • 开启 SmartDNS 并让其接管路由器的主 DNS
  • 设置 SmartDNS 上游为学校内网提供的 DNS,我校是10.255.255.2510.255.255.26
  • 设置别的上游,可以参考这篇博客

这样设置下来,内网资源就可以正常访问了。

# 参考


  1. 这个配置会自动拒绝所有发往 80 端口的连接,对上网体验影响很大。 ↩︎

  2. 具体可以参考这篇论文 ↩︎

  3. 这个方法可行性比较低,没有已知的部署案例。 ↩︎

Built with Hugo
Theme Stack designed by Jimmy