更新:在参考了我派的 这篇文章 后,咱也用 Shortcuts 实现了 iOS 设备上的自动认证,你可以 点这里 安装这个 Shortcut。但是 iOS Shortcuts 做不到抓取NextURL也没法直接获得 MAC 地址,所以实现上不是很完美。
背景及需求
我校的电信有线网络并不会限制路由器的使用。然而,有线网络的认证方式是动态 IP + Web 认证。在每次重启路由器后,访问任意非 HTTPS 页面就会被劫持到电信的认证网页,在该网页上输入账号密码后,才能联网。
虽说不算太麻烦,但每次都要手动输入账号密码,还是让人有些不爽。正好前段时间购买了一台 newwifi 3 路由器并刷入了 Padavan 系统,因此探索一下使用路由器实现校园网自动认证的方法。
原理
我校有线网络 Web 认证的本质,就是发送一个 HTTP-POST 请求到认证服务器。因此,我们只需要用 curl 构造一个 POST 请求,并且在每次路由器重启后都发送一遍即可实现自动认证。
尽管不同学校的 POST 请求可能会有一些差别,但只要使用了 Web 认证,其原理和实现方法都是相同的。
抓取登录所用的 HTTP-POST 请求
这里,我们使用 Chrome 的开发者工具来抓取请求。重启路由器后打开认证页面,按 command - option - I 调出开发者工具,切换到 Network 选项卡并勾选 Preserve log。
随后,我们正常输入用户名和密码登录。此时,开发者工具中会出现一些 HTTP 请求。我们需要在请求中寻找登录所需的项。一般来说,该项的 Request URL 会含有 login 等字段,且 Request Method 为 POST。登录网络的 HTTP-POST 请求
在找到这个请求后,我们在请求上单击右键,选择 Copy > Copy as cURL。将请求复制为 cURL
将复制到的 cURL 粘贴到任意文本编辑器中,以待进一步的处理。待处理的 cURL
修改 cURL 使其永久可用
以我校为例,在上一步中我们获得的 cURL 如下:curl 'http://172.25.249.8/eportal/InterFace.do?method=login' -H 'Connection: keep-alive' -H 'Origin: http://172.25.249.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36' -H 'DNT: 1' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Accept: */*' -H 'Referer: http://172.25.249.8/eportal/index.jsp?userip=100.66.137.149&wlanacname=&nasip=171.88.130.251&wlanparameter=78-4f-43-4c-f0-01&url=http://123.123.123.123/&userlocation=ethtrunk/3:691.3201' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en;q=0.7' -H 'Cookie: EPORTAL_COOKIE_OPERATORPWD=; EPORTAL_COOKIE_SERVER=; EPORTAL_COOKIE_SERVER_NAME=; EPORTAL_COOKIE_USERNAME=; EPORTAL_COOKIE_PASSWORD=; EPORTAL_AUTO_LAND=; EPORTAL_USER_GROUP=null; JSESSIONID=684400A38AA6F9CAF582BD43C001BDE3' --data 'userId=&password=&service=&queryString=userip%253D100.66.137.149%2526wlanacname%253D%2526nasip%253D171.88.130.251%2526wlanparameter%253D78-4f-43-4c-f0-01%2526url%253Dhttp%253A%252F%252F123.123.123.123%252F%2526userlocation%253Dethtrunk%252F3%253A691.3201&operatorPwd=&operatorUserId=&validcode=&passwordEncrypt=false' --compressed --insecure
首先将末尾的 --compressed --insecure 去除。分析 cURL,前大半部分都是 HTTP 请求的标头(-H 后的内容),你可以酌情作一些修改或删除。比如把 -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36' 改为 -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36" 就能伪装成 Windows 的 User-Agent 等等,在此不多赘述。
最后的 --data 部分,才是我们要关注的重点。根据抓到的请求,userId= 后是我们的宽带账号,password= 后是我们的宽带密码。同时,后面的 userip%253D1 后是我们获得的内网 IP,wlanparameter%253D 后是我们设备的 MAC 地址。
为了构造可永久使用的 cURL,首先要确保宽带账号、宽带密码是正确的。最后需要处理的,就是内网 IP 和设备 MAC 地址的问题。在 Padavan 的 Linux 环境下,你可以使用以下命令获取当前的内网 IP:ifconfig | grep inet | grep -v inet6 | grep -v 127 | grep -v 192 | awk '{print $(NF-2)}' | cut -d ':' -f2
使用以下命令获取设备 MAC 地址:ifconfig ra0 | grep HWaddr | awk '{print $NF}' | tr '[:upper:]' '[:lower:]' | tr ':' '-'
这时,我们就可以构造出一个永久可用的 cURL,如下:CURRENT_IP=$(ifconfig | grep inet | grep -v inet6 | grep -v 127 | grep -v 192 | awk '{print $(NF-2)}' | cut -d ':' -f2)
MAC_ADDRESS=$(ifconfig ra0 | grep HWaddr | awk '{print $NF}' | tr '[:upper:]' '[:lower:]' | tr ':' '-')
curl -X POST "http://172.25.249.8/eportal/InterFace.do?method=login" -H "Connection: keep-alive" -H "Origin: http://172.25.249.8" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36" -H "DNT: 1" -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "Accept: */*" -H "Referer: http://172.25.249.8/eportal/index.jsp?userip=${CURRENT_IP}&wlanacname=&nasip=171.88.130.251&wlanparameter=${MAC_ADDRESS}&url=http://baidu.com/&userlocation=ethtrunk/3:691.3201" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: zh-CN,zh;q=0.9,zh;q=0.8,en;q=0.7" -H "Cookie: EPORTAL_COOKIE_OPERATORPWD=; EPORTAL_COOKIE_USERNAME=; EPORTAL_COOKIE_PASSWORD=; EPORTAL_COOKIE_SERVER=; EPORTAL_COOKIE_SERVER_NAME=; EPORTAL_AUTO_LAND=; EPORTAL_USER_GROUP=null; JSESSIONID=2B36EA2F20A0CE7361D592CE7DBDFED3" --data "userId=&password=&service=&queryString=userip%253D${CURRENT_IP}%2526wlanacname%253D%2526nasip%253D171.88.130.251%2526wlanparameter%253D${MAC_ADDRESS}%2526url%253Dhttp%253A%252F%252Fbaidu.com%252F%2526userlocation%253Dethtrunk%252F3%253A691.3201&operatorPwd=&operatorUserId=&validcode=&passwordEncrypt=false"
# 记得修改宽带账号、宽带密码
在这里,我们用变量 CURRENT_IP 存储获得的内网 IP,用变量 MAC_ADDRESS 存储获得的 MAC 地址,并在 curl 命令中进行了替换。需要注意的是,要在 bash 命令的引号中使用变量的话,引号必须为双引号,而不能采用由 Chrome 复制得来的单引号。
测试 cURL
重启路由器或在认证页面上登出,打开 macOS 的终端,运行以下三行命令:CURRENT_IP=$(ifconfig | grep inet | grep -v inet6 | grep -v 127 | cut -d ' ' -f2)
MAC_ADDRESS=$(ifconfig en0 | grep ether | awk '{print $NF}' | tr ':' '-')
curl -X POST "http://172.25.249.8/eportal/InterFace.do?method=login" -H "Connection: keep-alive" -H "Origin: http://172.25.249.8" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36" -H "DNT: 1" -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "Accept: */*" -H "Referer: http://172.25.249.8/eportal/index.jsp?userip=${CURRENT_IP}&wlanacname=&nasip=171.88.130.251&wlanparameter=${MAC_ADDRESS}&url=http://baidu.com/&userlocation=ethtrunk/3:691.3201" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: zh-CN,zh;q=0.9,zh;q=0.8,en;q=0.7" -H "Cookie: EPORTAL_COOKIE_OPERATORPWD=; EPORTAL_COOKIE_USERNAME=; EPORTAL_COOKIE_PASSWORD=; EPORTAL_COOKIE_SERVER=; EPORTAL_COOKIE_SERVER_NAME=; EPORTAL_AUTO_LAND=; EPORTAL_USER_GROUP=null; JSESSIONID=2B36EA2F20A0CE7361D592CE7DBDFED3" --data "userId=&password=&service=&queryString=userip%253D${CURRENT_IP}%2526wlanacname%253D%2526nasip%253D171.88.130.251%2526wlanparameter%253D${MAC_ADDRESS}%2526url%253Dhttp%253A%252F%252Fbaidu.com%252F%2526userlocation%253Dethtrunk%252F3%253A691.3201&operatorPwd=&operatorUserId=&validcode=&passwordEncrypt=false"
# 记得修改宽带账号、宽带密码
这里 CURRENT_IP 和 MAC_ADDRESS 后的命令与上面的略有不同,是因为 macOS 下获取内网 IP 与 MAC 地址的命令与 Padavan 有一些区别。稍等后,结果中出现了 success 的提示,并且网络可以正常连接了,就说明我们构造的 cURL 是可用的。测试表明 cURL 可用
编写脚本
为了自动化完成 curl 认证的过程,我们需要编写一个简单的 shell 脚本,以下是一份参考:#!/bin/sh
logger "开始检测网络认证状态"
KEYWORD=$(curl -s http://baidu.com | grep "NextURL")
if [[ ${KEYWORD} != "" ]]; then
logger "检测到尚未认证,尝试自动认证"
CURRENT_IP=$(ifconfig | grep inet | grep -v inet6 | grep -v 127 | grep -v 192 | awk '{print $(NF-2)}' | cut -d ':' -f2)
MAC_ADDRESS=$(ifconfig ra0 | grep HWaddr | awk '{print $NF}' | tr '[:upper:]' '[:lower:]' | tr ':' '-')
LOGIN_STATUS=$(curl -s -X POST "http://172.25.249.8/eportal/InterFace.do?method=login" -H "Connection: keep-alive" -H "Origin: http://172.25.249.8" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36" -H "DNT: 1" -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "Accept: */*" -H "Referer: http://172.25.249.8/eportal/index.jsp?userip=${CURRENT_IP}&wlanacname=&nasip=171.88.130.251&wlanparameter=${MAC_ADDRESS}&url=http://baidu.com/&userlocation=ethtrunk/3:691.3201" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: zh-CN,zh;q=0.9,zh;q=0.8,en;q=0.7" -H "Cookie: EPORTAL_COOKIE_OPERATORPWD=; EPORTAL_COOKIE_USERNAME=; EPORTAL_COOKIE_PASSWORD=; EPORTAL_COOKIE_SERVER=; EPORTAL_COOKIE_SERVER_NAME=; EPORTAL_AUTO_LAND=; EPORTAL_USER_GROUP=null; JSESSIONID=2B36EA2F20A0CE7361D592CE7DBDFED3" --data "userId=&password=&service=&queryString=userip%253D${CURRENT_IP}%2526wlanacname%253D%2526nasip%253D171.88.130.251%2526wlanparameter%253D${MAC_ADDRESS}%2526url%253Dhttp%253A%252F%252Fbaidu.com%252F%2526userlocation%253Dethtrunk%252F3%253A691.3201&operatorPwd=&operatorUserId=&validcode=&passwordEncrypt=false") # 含有变量时只能使用双引号
SUCCESS=$(echo ${LOGIN_STATUS} | grep success)
if [[ ${SUCCESS} != "" ]]; then
logger "自动认证成功"
else
LOGIN_STATUS=$(echo ${LOGIN_STATUS} | cut -d ',' -f3 | cut -d '"' -f4)
logger "自动认证失败: ${LOGIN_STATUS}"
fi
else
logger "检测到已经认证"
fi
# 记得修改宽带账号、宽带密码
在脚本开始的时候,我们通过 curl -s http://baidu.com 来检测是否已经通过认证。如果尚未认证,curl 返回的结果如下:$ curl -s http://baidu.com # -s, 不输出任务进度
如果已经认证,curl 返回的结果如下:$ curl -s http://baidu.com
我们可以观察到,在尚未认证时,返回的结果中含有关键词 NextURL(当然,其他与已认证时返回结果不同的内容都可以)。因此,我们使用 KEYWORD 变量来判断认证状态,如果尚未认证,KEYWORD 就不为空,反之 KEYWORD 就为空。
因此,你可以在认证前、认证后分别执行 curl http://baidu.com,找到前者含有而后者没有的特征性内容,将其放在 grep 命令后。
如果尚未认证,脚本就会使用 curl 发送 HTTP-POST 请求进行认证,并检查返回的结果中是否有 success 字样。如果有,则代表认证成功;如果没有,脚本则会记录下返回的提示信息。
将脚本上传到路由器
打开 macOS 终端,使用 ssh 连接到路由器:ssh [email protected] # Padavan 的默认网关 IP 为 192.168.123.1,用户名为 admin
输入默认密码 admin 即可 ssh 登录到路由器。随后执行以下命令:cd /etc/storage # 进入存储脚本的目录
vi auto_login.sh # 新建并编辑自动登录脚本
在 vi 编辑器下,按 i 进入编辑模式,将之前准备好的脚本粘贴上去,然后按 esc 退出编辑模式,随后输入 :wq 并回车即可保存。再执行以下命令赋予脚本执行权限:chmod +x auto_login.sh
完成后,执行 exit 即可断开 ssh 连接。
登录到路由器后台,在 系统管理 > 恢复/导出/上传设置 > 保存 /etc/storage/ 内容到闪存 后点击 提交。保存脚本到路由器闪存
最后,在 自定义设置 > 脚本 > 在 WAN 上行/下行启动后执行 的内容后添加一行:/etc/storage/auto_login.sh,并点击页面最下方的 应用本页面设置 即可。设置 WAN 启动后自动认证
如果你还不放心,那么还可以借助 Crontab 每隔一段时间检查认证状态并自动认证,只需要打开 系统管理 > 服务 > Cron 守护程序,然后在 计划任务 中填入 crontab 命令并应用设置即可:*/20 * * * * /etc/storage/auto_login.sh
# 此处是每 20 分钟运行一次自动认证脚本
# Crontab 格式可参考 https://crontab.guru配置 Crontab
小结
此时,你的路由器应该已经可以自动完成校园有线网的认证过程了。对于晚上要断电的学校( 比如我校),再购买一个路由器 UPS 即可真正实现 24*7 不间断 WiFi 供应。
然而,如果你的寝室断电后有线网络信号也会被切断,那么你可以利用 Padavan 的 crontab 在断电时切换到无线中继模式,并中继开放的校园 WiFi。对于我校而言,中继电信校园 WiFi 时,上述自动认证脚本一样可用。具体的实现过程,此处就不再赘述。
什么?你说校园 WiFi 也会被关闭?那你为什么不老老实实用流量呢?
一点小改进
得益于上面提到的 NextURL 字段,其实获取内网 IP 与 MAC 地址也可以这么写,这样 macOS 和 Padavan 都能用:CURRENT_IP=$(curl -s http://baidu.com | grep NextURL | cut -d '/' -f5 | cut -d '&' -f1 | cut -d '?' -f2 | cut -d '=' -f2)
MAC_ADDRESS=$(curl -s http://baidu.com | grep NextURL | cut -d '/' -f5 | cut -d '&' -f4 | cut -d '=' -f2 | tr -d '
另外还有一点,把 queryString 中两次 URL encode 过的字段再 decode 回来其实也是能成功的,而且如果要用 iOS Shortcuts 来完成自动化认证的话还必须先 decode 回来。
参考及感谢