引言

邮专每个工作日晚上0点就会断网。xdm每天0点急急忙忙切换手机热点,要是忘了的话便会痛失一局CS:GO,然后开始口吐芬芳。

虽然3g的含金量摆在那里,但是学校晚上断网实在不能阻止同学们的夜生活,只会拉仇恨而已。鉴于此我找出了绕过校园网认证系统直接上网的方法。

这个文章的目的是突破校园网晚上断网,理论上用这种方法也可以免费上网,emmm……
此文章仅供技术交流之用,出现问题作者概不负责。

原理

学校内外网满足以下条件:

  • 晚上断网之后,连接了校园网的设备不能通过认证系统,不能访问公网,但可以进行正常内网访问。
  • 学校提供了VPN服务,从公网登录后可以作为内网设备访问到内网。

自然地,我们只要使用一台公网电脑,用它登录学校VPN,获得学校内网IP,作为代理服务器。然后我们用我们的内网设备直接设置代理到这个IP,就可以由此进行代理上网。

然而经过测试发现我在寝室的设备并不能直接建立连接到这个IP,ping也ping不通,看来是防火墙策略不允许。不过经过反向测试,通过公网设备访问我寝室的设备,成功了。

那么我们要想让公网设备作为代理服务器,可以使用FRP搭建反向代理隧道来穿透防火墙,然后通过此隧道通信。
file

FRP简介

Github项目地址
frp 是一种快速反向代理,是一个隧道工具,可帮助您将 NAT 或防火墙后面的本地服务器暴露给 Internet。 截至目前,它支持 TCP 和 UDP ,以及 HTTP 和 HTTPS 协议,其中请求可以通过域名转发到内部服务。
file
通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:

  • 客户端服务端通信支持 TCP、KCP 以及 Websocket 等多种协议。
  • 采用 TCP 连接流式复用,在单个连接间承载更多请求,节省连接建立时间。
  • 代理组间的负载均衡。
  • 端口复用,多个服务通过同一个服务端端口暴露。
  • 多个原生支持的客户端插件(静态文件查看,HTTP、SOCK5 代理等),便于独立使用 frp 客户端完成某些工作。
  • 高度扩展性的服务端插件系统,方便结合自身需求进行功能扩展。
  • 服务端和客户端 UI 页面。

FRP完整使用文档


因为公网设备只能单向访问到内网设备,这样的场景很像NAT穿透场景(此处的内网设备可类比为NAT穿透时的公网设备,公网设备可类比为NAT穿透时的局域网设备),所以我们将frps(服务端)部署在内网设备上,将frpc(客户端)部署在公网设备上。
之后按照FRP官方文档编辑好配置文件,开启之后就可以建立隧道。

我为了保证稳定性、可拓展性、实现多设备上网以及实现魔法上网,使用了腾讯云服务器(Ubuntu 20.04)作为公网代理服务器,并配置了Clash,开了代理端口,在寝室安装了树莓派充当内网服务器。这样不管我在内网有多少设备,只要把代理服务器设置为内网服务器就可以绕过认证系统直接上网,同时支持魔法上网。以下步骤均按照此方法配置。

步骤

1. 在公网设备上登录学校VPN

如果你的公网设备有图形化界面,那么直接安装Easyconnect,登录即可,然后可以跳过这一部分。

深信服的Easyconnect的Linux版本不能通过命令行登录,只能通过图形界面操作。然而一般Linux服务器并没有图形界面。

网上找到的一个方法是把图形发送到Windows中显示,略显繁琐。这里我使用了开源项目docker-easyconnect,作者已经配置好了镜像,只需在启动Docker容器时使用参数传入账号密码即可。若命令行登录存在问题,也可以使用项目中带VNC服务的镜像,使用VNC连接图形界面登录。

配置并启用docker-easyconnect

  1. 首先保证服务器上Docker可以正常使用。
  2. 启动容器。
    docker run --device /dev/net/tun --cap-add NET_ADMIN -ti -p 127.0.0.1:1080:1080 -p 127.0.0.1:8888:8888 -e EC_VER=7.6.3 -e CLI_OPTS="-d vpnaddress -u username -p password" hagb/docker-easyconnect:cli

    其中 -e EC_VER=7.6.3 表示使用 7.6.3 版本的 EasyConnect,可根据实际情况修改版本号,重邮无需更改即可使用。-e CLI_OPTS="-d vpnaddress -u username -p password"中的vpnaddress是学校VPN服务器(重邮是vpn.cqupt.edu.cn),username是用户名,即统一认证号,password是统一认证密码。

socks5代理地址 127.0.0.1, 端口 1080;也可以使用 http 代理,地址 127.0.0.1, 端口 8888。公网服务器通过这两个代理端口通信即可通过容器内的Easyconnect VPN穿透至校园网内网VPN设备池。Easyconnect VPN只能在一处登录,所以我们之后在公网连接内网用到VPN的时候,设置代理到公网服务器的这两个端口就可以了。

如果命令行登录出现问题,可以使用VNC图形界面版本:

  1. 启动容器

    docker run --device /dev/net/tun --cap-add NET_ADMIN -ti -e PASSWORD=xxxx -v $HOME/.ecdata:/root -p 127.0.0.1:5901:5901 -p 127.0.0.1:1080:1080 -p 127.0.0.1:8888:8888 hagb/docker-easyconnect:7.6.3

    docker-easyconnect:7.6.3中的版本根据需要自行更改,重邮无需更改。-e PASSWORD=xxxx是VNC的连接密码,自行更改。

  2. 使用VNC客户端连接VNC, 地址:127.0.0.1, 端口: 5901, 密码 xxxx (上面自行改的那个)。

  3. 成功连上后你应该能看到Easyconnect的登录窗口,填写并登录easyconnect。

代理端口同上。

2. 配置Clash代理实现魔法上网

Clash是一个 Go 语言开发的多平台代理客户端。GitHub项目地址
能方便地实现魔法上网,具体配置不好多说,请自行解决。
记得开启允许局域网连接。

注意:Clash不仅能魔法上网,还有代理服务器的功能,使用Clash免去了再次配置代理服务器的麻烦。所以如果你不采用Clash的话,需要用其他方法把外网设备配置成代理服务器。

file

理论上来说,只要在服务器上配置好Clash,然后把Clash的代理端口映射到容器就可以了。看起来可行,不过我没测试,因为我搭的时候没想清楚,直接把Clash搭到容器里面了。。。总之搭到容器里面也可以用。

不管用哪种方法,都要保证容器内能通过代理端口上网。我们假定这个端口是7890。

3. 配置FRP

我们把公网服务器反向代理到内网服务器,使内网中的任何设备设置代理到内网服务器就可以通过公网服务器上网,而不需要直接连接到公网服务器。
公网服务器可以单向建立连接到内网服务器。将frps配置到内网服务器上,等待公网服务器建立连接。将frpc配置到公网服务器上,使其反复尝试与内网服务器建立连接。

为了简化过程,将frpc直接配置在Docker容器内部。

编辑并保存以下配置文件:

frps的配置文件 frps.ini

[common]
bind_addr = 0.0.0.0
bind_port = 7000
dashboard_port = 7001
token = xxx

其中bind_addr是绑定地址,bind_port是FRP的通信端口,dashboard_port是FRP的Web管理面板端口,可选,token是验证口令,frpc只有配置了匹配的token才能被frps允许建立连接,可选。

frpc的配置文件 frpc.ini

[common]
server_addr = 10.16.x.x
server_port = 7000
token = xxx

[LAN_VPN]
type = tcp
local_ip = 127.0.0.1
local_port = 7890
remote_port = 7891

其中bind_addr是绑定地址,填写内网服务器的地址,bind_port是FRP的通信端口,与frps配置一致,token可选,如果frps有的话必须配置一致。
下方的[LAN_VPN]是隧道名,若有多个frpc连接到同一frps的话,任意两个隧道不能重名。
type填写tcp
local_ip填写frpc端的地址,从这个地址(注意是在容器中)必须能访问到Clash或者其他的代理端口(外部映射到Docker的端口或者直接在Docker内的代理端口)。
local_port填写Docker内能访问到的代理端口,我们假定其为7890
remote_port填写的是希望Docker中的local_port与内网服务器上相通的端口,不能被占用,这里假定为7891,那么建立隧道后访问内网服务器的7891端口就相当于访问了公网服务器的7890端口(local_portremote_port可以相同,这里是为了方便说清楚)。

注:校园网分配给设备的IP地址会经常变动,内网服务器也不例外,会导致frpc.ini里配置的bind_addr发生变化,从而导致隧道失效。为了解决此问题,可以为内网服务器配置DDNS服务,参考我的红岩网校作业DDNS脚本

FRP GitHub页面获取相应平台的二进制文件压缩包,解压得到二进制文件。公网服务器需要frpc,内网服务器需要frps。
将上述配置文件复制到各自的二进制文件同目录下。
注:向Docker容器中复制文件命令为docker cp 宿主机文件路径 容器ID:docker容器路径,而从Docker容器复制文件到宿主机命令为docker cp 容器ID:docker容器路径 宿主机文件路径

启动FRP

# 内网服务器
./frps -c frps.ini
# 公网服务器Docker容器
./frpc -c frpc.ini

启动后应该可以看见类似以下输出:

frps

[root.go:200] frps uses config file: frps.ini
[service.go:194] frps tcp listen on 0.0.0.0:7000
[service.go:293] Dashboard listen on 0.0.0.0:7001
[root.go:209] frps started successfully
[service.go:450] [xxxx] client login info: ip [x.x.x.x:xxxxx] version [0.42.0] hostname [] os [linux]
[tcp.go:64] [xxxx] [LAN_VPN] tcp proxy listen port [7891]
[control.go:465] [xxxx] new proxy [LAN_VPN] type [tcp] successfully

frpc

[service.go:349] [xxxx] login to server success, get run id [xxxx]
[proxy_manager.go:144] [xxxx] proxy added: [LAN_VPN]
[control.go:181] [xxxx] [LAN_VPN] start proxy successfully

可以使用nohup ./frps -c frps.ini &这种写法的命令使FRP后台运行。
FRP同样提供了配置FRP服务的模板,在Github Release压缩包中的systemd文件夹中即可修改并配置,配置后更方便管理。具体方法请阅读官方文档。

其实frpc可以不用配置进Docker容器中,理论上用端口映射也可以实现,不过我没测试。

使用

如果上面的配置没问题,那么就全部配置完毕了。

可以实现校园网内外互穿。

内穿外

使用内网代理服务器成功上网。

为内网的上网设备配置代理,代理服务器地址是内网服务器的地址,端口是frpc.ini中配置的remote_port
如果上网的设备就是搭建了内网服务器的设备,那么把代理服务器地址填成localhost即可。

注:安卓设备设置了代理并不会被全局使用。在root之后可以设置全局代理,但如果没有root就只能使用一些APP通过本地VPN实现全局代理(例如Proxy Manager这款APP),代价是耗电量非常大。如图:
file

外穿内

使用公网设备访问校园网内网服务。

在上面配置Docker容器时已经说过了,socks5代理地址 127.0.0.1 , 端口 1080 ;http代理地址 127.0.0.1 , 端口 8888 。公网服务器通过这两个代理端口即可通过容器内的Easyconnect VPN穿透至校园网内网VPN设备池。

因为Easyconnect VPN只能在一处登录,所以我们之后在公网连接内网需要用到VPN的时候,设置代理到公网服务器的这个端口就可以了。

可以在启动Docker容器的时候修改映射到其他端口。

速度

很遗憾,经过测试此代理隧道的速度并不高。下载基本稳定在8Mbps左右,上载基本在5Mbps左右。看来学校限制了VPN用户的速度,打游戏用用应该还行。
file

不过有没有一种可能,只要宿舍室友同心协力,使用n个统一认证账号,开n个虚拟网卡,控制好路由,就可以有n倍的网速呢?