作为一个大学生,在宿舍上网是一件非常平常的事情,而又因为移动网络的不稳定性,其实我没有把握它能够在高峰期一直以比较符合心意的速度发送喝接收数据,因此一条相对而言比较稳定的宽带就成了大学上网的首选

恰好,UIC的T5和二期D3附近都有三大运营商在摆摊销售校园专属套餐,于是我便凑上去看了一下……

混乱的信息

在我了解信息的过程中,三大运营商都有人跟我说二期的一条宽带只能连接三个设备,让我们多办一条,虽然在这个智能穿戴设备丰富的年代,拥有超过三个智能设备的人应该不在少数,因此我一开始就在怀疑它的真实性

不过这个信息对我宽带的选购其实影响还挺大的,它触及到了我的核心问题:到底要办多少个的问题

但作为一个爱折腾的人,我当然要想研究一下,这背后的原理到底是什么?看有没有办法解决啦

不过可惜的是,因为刚刚开学还并没有很多人办理了宽带,有些办了的同学也没有说出具体的操作流程让我去判断,所以我并没有方法去实际测试

就算问运营商的工作人员,他们很多也不愿意说(会影响销量,谁干啊),即使有些说了的感觉说法也不一样,导致我没有足够的信息判断

此时,我已经做好了最坏的打算:花上半天自行学习路由器刷写 Openwrt 并自行编写相关的插件

疯狂的打折

在我刚到学校的那一天,三个运营商宽带的价格其实是不一样的,电信是570,联通和移动是720一年(300M带宽)

而到了第2天,移动改成了520,联通说720还能送一个路由器(大概市场价就70左右)或者再送一个套餐

来到了第3天,联通甚至变成了360一个套餐,还加上送路由器

经过以上比较之后,我最终选择了买联通的宽带,理论上套餐包含300M下行宽带,手机卡流量200G区域、40G定向、30G通用(反正都用不完),送了个小米 R4CM 路由器,看起来在买宽带这件事情上,真的会早买早吃亏啊

到手的流量

另外再补充下,经过我并不严谨的调查,其实运营商送的这个小米 R4CM 只是无线速率能到300M,WAN 口速率应该并不能达到300M,实际测试下来也只能到100M左右,建议办理了300M宽带的同学自己买个200价位左右的千兆路由器,才有更好的上网速度

实测网速

后面换了个 Tplink 的 AX3000,下载能跑满300M了,但是上传依然也只有30M左右,可能是上下行不对等吧

忙碌的安装师傅

在最后一天经过这么多的打折之后,买宽带的人明显增多了很多,我等到了第二天,安装的师傅都还没有来,即使打电话也一直说在通话中

这时,我看到了联通客服朋友圈里发了个自主安装流程,于是就找舍友去楼下摊位嫖了根网线,自己安装起了宽带

宽带接口

事实上,安装的方式并不复杂,甚至不需要看他们给的安装教程(反而看了的会发现很多不一样的地方)

简单来说就是:

  1. 插好路由器电源,网线接入WAN口(有的标为Internet,或者高端的可以随便插自适应)
  2. 连接WIFI进入路由器后台,设置好名称和密码
  3. 上网模式调为DHCP(或自动获取)
  4. 断开WIFI连接,再连上之后点击弹出的登录页面,登录UIC账号
  5. 再次断开WIFI,连上弹出第二种登录页面,输入宽带账号密码(一般为vip+学号,密码可以在联通APP修改)

经历这几个步骤,其实就能上网了

不过,不知道什么原因,我在半夜又被断了网,自己折腾了快半个小时还是发现会在登录页面报错500,最后实在搞不懂去询问客服并给了个学号之后重复步骤4、5又可以上网了(我也不知道他后台配置了什么才恢复的)

设备限制原理猜想

根据大家都反馈及自己的观察,我有了以下猜想

运营商给的教程,其实本来是希望把路由器当成一个AP,中继网线的信号,由楼层交换机使用DHCP进行每个设备的IP分配,并在设备端进行登录,限制登录数为3

但是网线插WAN再分局域网的用法,其实是大部分人最正常的安装方式,这样楼层交换机只会识别到路由器一个设备的Mac地址,并且只需要一次登录即可

看起来,运营商是专门用小众的偏门方法让不懂相关知识的同学们以为是真的有限制设备从而卖多点呢?⊙﹏⊙∥

自动化脚本

据他们所说,以上步骤4、5的登录过期时间是30天,此后有可能需要手动重新登录

而作为大学生,平时课业也十分繁忙,至少有半天都会不在宿舍内,需要手动登录的话就非常麻烦,出去了没法登录还会给在宿舍的舍友造成困扰

因此,我打开浏览器F12,稍微分析了下数据包(因为是http所以能直接读取),看见了以下流程

第一部分:UIC登录

Windows登录后会打开 http://www.msftconnecttest.com/redirect的页面,自动跳转到 http://172.29.250.5:30004/byod/byodrs/login/defaultLogin,以POST的方式发送了以下数据(为了保护隐私,部分信息已用*代替),不同楼层IP可能会有所不同,需要自己修改下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"userName": "t33******3",
"userPassword": "一个base64",
"serviceSuffixId": "-1",
"dynamicPwdAuth": false,
"code": "",
"codeTime": "",
"validateCode": "",
"licenseCode": "",
"userGroupId": 0,
"validationType": 0,
"guestManagerId": 0,
"shopIdE": null,
"wlannasid": null
}

我们需要修改的就是学号和密码(密码以base64编码发送),发完这串,认证就基本上完成了,然后就进入了前文说的第5步

第二部分:联通登录

获取登录页面

在连接到一个新网络的时候,我们是什么也不知道的,根据系统默认的操作,会弹出登录框,点开便会在浏览器打开 http://www.msftconnecttest.com/redirect
发送 GET 请求后就会得到 302 的回复,获得新的地址
在这里,我们可以看见新地址是 http://portal.gd165.com/?wlanuserip=172.29.105.168&wlanacname=&basname=120.80.200.50&ssid=uiczh.edu&vlanid=ethtrunk/10:4001.0

向该地址发送 GET 请求,得到以下回复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="http://portal.gd165.com:80/">

<title>main</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="w" type="text/css" href="styles.css">
-->
</head>

<script type="text/javascript">
function getBasInfo() {
var url = window.parent.location.href;
document.getElementById("basPushUrl").value = url;
document.forms[0].submit();
}
</script>
<html>
<body onload="getBasInfo()">
<form action="http://portal.gd165.com:80/index.do" method="post">
<input name="basPushUrl" id="basPushUrl" type="hidden">
<input type="hidden" name="debugua" value="">
<input type="hidden" name="testmacauth" value="false">
</form>
</body>
</html>

引导我们前往 http://portal.gd165.com:80/index.do

接着可以观察到,浏览器以 POST 发送了以下内容到 http://portal.gd165.com/index.do

1
basPushUrl=http%3A%2F%2Fportal.gd165.com%2F%3Fwlanuserip%3D172.29.104.170%26wlanacname%3D%26basname%3D120.80.200.50%26ssid%3Duiczh.edu%26vlanid%3Dethtrunk%2F10%3A4001.0&debugua=&testmacauth=false

此外值得一提的是,我尝试使用 Python 的 requests 模块去重现该操作,但是得到的结果都是500错误
后面我再研究了下,发现除了 POST 了数据之外,客户端还向服务器发送了如下 headers

1
2
3
4
5
6
7
8
9
10
11
12
13
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: max-age=0
Connection: keep-alive
Content-Length: 195
Content-Type: application/x-www-form-urlencoded
DNT: 1
Host: portal.gd165.com
Origin: http://portal.gd165.com
Referer: http://portal.gd165.com/?wlanuserip=172.29.105.168&wlanacname=&basname=120.80.200.50&ssid=uiczh.edu&vlanid=ethtrunk/10:4001.0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69

经过多次尝试,最终发现必要的 headers 为 Content-TypeUser-Agent

将上述 headers 加入脚本后便正常返回了200,解析后是一个 html 文件,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<base href="http://portal.gd165.com:80/">
<meta charset="UTF-8" />
<title>联合国际学院</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="description" content="gd zhbsd wlan login">
<link rel="stylesheet" type="text/css" href="/gd/zhbsd/css/common.css" />
<link rel="stylesheet" type="text/css" href="/gd/zhbsd/css/index.css" />
<script type="text/javascript" src="/common/js/jquery.min.js" ></script>
<script type="text/javascript" src="/gd/zhbsd/js/login.js" ></script>
<script type="text/javascript" src="/gd/zhbsd/js/flexible.js"></script>
</head>
<body>
<div class="page flex-col justify-between">
<div class="image-wrapper_1 flex-col">
<img
class="image_1"
referrerpolicy="no-referrer"
src="/gd/zhbsd/img/SketchPng7906f93c7a579face959d64fa751a15cab98bc5b16741bf5dd27df658c565449.png"
/>
</div>
<div class="section_2 flex-col">
<div class="text-wrapper_2 flex-col">
<span class="text_5">
使用过程中如有疑问,请联系校网内网络运营商客服156 0286 3828(微信同号)
</span>
</div>
<form action="/login.do" id="loginform" method="post">

<input type="hidden" name="loginpage" id="loginpage" value="gd/zhbsd/login.jsp"/>
<input type="hidden" name="onlinepage" id="onlinepage" value="gd/zhbsd/online.jsp"/>
<input type="hidden" name="logoutpage" id="logoutpage" value="" />
<input type="hidden" name="accountprefixname" id="accountprefixname" value=""/>
<input type="hidden" name="accountsuffixname" id="accountsuffixname" value=""/>
<input type="hidden" name="pagetype" id="pagetype" value="0"/>
<input type="hidden" name="macauth" id="macauth" value="0"/>
<input type="hidden" name="accountvalid" id="accountvalid" value="1800"/>
<input type="hidden" name="customerId" id="customerId" value="001"/>
<input type="hidden" name="customerName" id="customerName" value="campus"/>
<input type="hidden" name="basName" id="basName" value="120.80.200.50" />
<input type="hidden" name="basPushUrl" id="basPushUrl" value="http://portal.gd165.com/?wlanuserip=172.29.104.170&wlanacname=&basname=120.80.200.50&ssid=uiczh.edu&vlanid=ethtrunk/10:4001.0" />
<input type="hidden" name="accountName" id="accountName" value="" />
<input type="hidden" name="sendSMS" id="sendSMS" value="" />
<input type="hidden" name="attrName" id="attrName" value="ssid" />
<input type="hidden" name="attrValue" id="attrValue" value="[uiczh.edu]" />
<input type="hidden" name="realmName" id="realmName" value="" />
<input type="hidden" name="fixedAccountPrefixName" id="fixedAccountPrefixName" value="" />
<input type="hidden" name="errormessage" id="errormessage" value="" />
<input type="hidden" name="keepAliveTime" id="keepAliveTime" value="" />
<input type="hidden" name="wlanuserip" id="wlanuserip" value="172.29.104.170"/>
<input type="hidden" name="client_type" id="client_type" value="pz"/>
<input type="hidden" name="basname" id="basname" value="120.80.200.50" />
<input type="hidden" name="setUserOnline" id="setUserOnline" value="" />
<input type="hidden" name="userOpenAddress" id="userOpenAddress" value="">
<input type="hidden" name="accountType" id="accountType" value="">
<input type="hidden" name="token" id="token" value="1a616f38622f1cbd94d4d276f666c9aa"/>
<input type="hidden" name="checkbox" id="checkbox" value="0"/>
<div class="section_1 flex-col">
<div class="section_3 flex-row justify-between">
<span class="text_1">宽带账号</span>
<input type="text" class="box_1 flex-col" id="username" name="username">
</div>
<div class="section_4 flex-row justify-between">
<span class="text_2">密码登陆</span>
<input type="password" class="group_1 flex-col" id="password" name="password">
</div>
<div class="section_5 flex-row">

<div id="errorbox" class="errorbox">
<div class="errormsg">
<img src="/gd/zhbsd/img/errorpng.png" />
登录失败,请检查 用户名或密码
</div>
</div>
</div>
<div class="section_6 flex-row">
<div class="text-wrapper_1 flex-col">
<span class="text_4" onclick="login()">点击登陆</span>
</div>
</div>
</div>
</form>
</div>
</div>
</body>
</html>

在这个文件中,我们可以看见我们在下一步要用到的 token
这样,我们第一步获取 token 就完成了

发送登录信息

取其中的token,再次POST以下数据到 http://portal.gd165.com/login.do ,同样不要忘记了前面的 headers

1
loginpage=gd%2Fzhbsd%2Flogin.jsp&onlinepage=gd%2Fzhbsd%2Fonline.jsp&logoutpage=&accountprefixname=&accountsuffixname=&pagetype=0&macauth=0&accountvalid=1800&customerId=001&customerName=campus&basName=120.80.200.50&basPushUrl=http%3A%2F%2Fportal.gd165.com%2F%3Fwlanuserip%3D172.29.104.170%26wlanacname%3D%26basname%3D120.80.200.50%26ssid%3Duiczh.edu%26vlanid%3Dethtrunk%2F10%3A4001.0&accountName=&sendSMS=&attrName=ssid&attrValue=%5Buiczh.edu%5D&realmName=&fixedAccountPrefixName=&errormessage=&keepAliveTime=&wlanuserip=172.29.104.170&client_type=pz&basname=120.80.200.50&setUserOnline=&userOpenAddress=&accountType=&token=1a616f38622f1cbd94d4d276f666c9aa&checkbox=0&username=vip233******3&password=Q********

观察可得,我们需要修改的仅有以下内容:

  • wlanuserip=172.29.104.170 从路由器看
  • username= “vip”+学号
  • token=前面拿的
  • password=宽带密码,自己营业厅查

这样理论上就登录完成了

对此,我写出的自动化脚本如下(仅针对联通,其他运营商前半部分应该能用,后半部分得自己改改)

如果看不见的话点这里

但是貌似我请求回来的都会是500,为什么呢……

当然,由于各种原因,我无法去反复测试,这仅仅只是一次抓包的结果,建议在动手前自己在抓包一次对比我的数据以确保无差异

延申阅读-UIC的非正常用法系列

宁盾令牌自定义

课表导入日历