好好活就是有意义的事,有意义的事就是好好活
华中科技大学校园网自动重连
华中科技大学校园网自动重连

华中科技大学校园网自动重连

前言

寝室安装了一个路由器, 但是不知道什么原因, 每天都会断开连接, 需要手动认证一下才可以, 为了避免不必要的麻烦, 写了这样一个小的python脚本来自动的重连

本文设计的操作有一定的上手难度, 不太适合对计算机完全不懂的同学使用, 如有需求, 可私聊

源码地址: https://github.com/Kingdo777/auto-connect-school-network.git, 或者见文末附录

源码解析

主函数非常的简单:

if __name__ == '__main__':
    while True:
        if pong():
            time.sleep(5)
        else:
            login()
            time.sleep(10)

每个5秒检查自己还能不能上网, 方式就是ping 8.8.8.8, 这是很常见的方法.

如果不能上网, 那么就调用login()函数来自动重连

我们的校园网认证的过程,本质上就是提交一个HTTP请求, 那我们的login()函数, 其实就是实现了这个过程, 因此我们只需要知道,我们的网页端认证是怎么操作的即可,麻烦的是华科的校园网的代码设计的还是很复杂的,所以还是稍微的耗费了一点时间.

校园网认证流程

首先我们进入这个认证的页面, 按F12进入开发者模式

preview

我们会在Source中看到两个重要的JS文件,当我们点击网页中的连接 Login的时候就会调用这个函数.

preview

这个函数会收集你的一系列信息,并最终调用:AuthInterFace.login

preview

AuthInterFace定义在 AuthInterFace.js中.

其中init()用于生成请求的url, login()首先将传入的参数合并成content,最后通过post方法发送请求

preview

因此需要我们做的就是, 获取content的内容, 然后我们就可以用python对指定的url发起post请求

获取content的方法也很简单, 只需要在如图位置打上断点, 然后点击网页中连接的按钮,当js执行到断点后,就可以复制content的值

preview

使用

  1. git clone https://github.com/Kingdo777/auto-connect-school-network.git
  2. 我们将上一过程获取到的content信息存放到main.py的同目录下的名为content的文件中
  3. 然后就可以执行python脚本了
  4. 不过windows下需要安装npcap, 可以点击以下链接下载安装
    https://nmap.org/npcap/dist/npcap-1.60.exe

后记

Notes

1) 在什么情况下, 需要重新获取Content?

如果切换了Wifi, 导致IP地址改变, 那么需要重新获取content的值.

这里很重要的一点需要了解, 只有在校园网内网IP发生改变的情况下才需要重新获取content的值, 而这个IP是你直接连接HUST_WIFI或者连接有线的时候需要的, 但是如果你在校园的基础之上加了一个自己买的路由器, 那么其实此路由器下所有的设备共用了路由器的校园网内网IP, 这个时候既是切换设备, 他们的content都是一样的.

2)在那些情况下可用?

此方法成功的前提之一是, 你已经连接了校园网, 有线或者无线! 如果没有连接, 那么程序有可能会崩溃退出!

此外, 如果你能成功打开浏览器,并跳出了认证了页面, 然后点击连接按钮连接成功, 那么此方法基本上都是成功的!

经过测试, 在以下情况下都可以重连:

  • 在主动下线
  • 被强制下线
  • 被挤占下线

但是不知道你是否遇到过, 有时候认证的网页打不开! 这个时候程序会提示一条错误信息:

认证设备响应超时,请稍后再试!

我目前还没有找到解决此问题的方法!

官方脚本 mentohust

其实在Linux下有一个10年前的脚本文件, 名字叫mentohust, 其github地址是:HustLion/mentohust: 接续HustMoon开发的Mentohust,继续更新 (github.com)​github.com/HustLion/mentohust

下载地址Long-term storage for Google Code Project Hosting.​code.google.com/archive/p/mentohust/downloads

但是这个东西问题挺多的, 比如在WSL2中运行就会失败, 我怀疑她只能在直接连接校园网的设备上使用, 有兴趣大家自己玩玩吧:

更新一 简化ping操作

之前的ping操作过于臃肿, 当时是我随手百度的, 今天我又随手百度了一下, 看到了更好的方法:Python Function to test ping​stackoverflow.com/questions/26468640/python-function-to-test-ping/39563638

其实就是直接调用os.system(“ping 8.8.8.8”), 然后根据返回结果来判断是否能通, 简化后的代码我放在了附录二.

我已经在Github上传了这个更新, 并且新方法不需要安装npcap软件!

更新二 异常处理和Ping优化

异常处理

python的requests.post方法, 并不是总是成功的, 比如此时你Wifi断开, 那么就会导致请求无法达到, 将会触发超时异常, 但是原来的代码中并没有添加异常的处理, 因此这将导致程序的退出, 因此添加了异常的情况的捕获.

此外, 在<后记->Notes>中提到可能会遇到认证设备响应超时,请稍后再试!” , 对于这种情况我们需要延长睡眠的时间, 额外延长了 120秒

Ping优化

现有的方法, 只会ping一次8.8.8.8来验证是否可上网, 好处是速度很快, 缺点是容易误判, 也就是有可能此时网络拥堵, 依然有可能导致无法ping通, 但是其实是可以上网的, 因此我对ping操作进行了修改:

其中 202.114.0.242 是我们校园网的DNS服务器!以上方法可以最大程度的保证不会误判!

但是缺点是判断的流程会很长! 可以自己任意的修改怎么取舍!

(最新的代码已经上传的Github, 或者是附录三)

附录

附录一

import time
import json
from scapy.layers.inet import IP, ICMP
from scapy.packet import Raw
from scapy.sendrecv import sr1
import requests

def login():
    url = 'http://192.168.50.3:8080/eportal/InterFace.do?method=login'
    with open("content", "r") as f:
        data = f.read()
    header = {
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
    }
    response = requests.post(url, data, headers=header)
    content = json.loads(response.text)
    encoding = response.encoding
    if content['result'] == 'fail':
        print(content['message'].encode(encoding).decode('utf-8'))
    else:
        print("login at --> " + time.asctime(time.localtime(time.time())))
    return

def pong():
    ping_pkt = IP(dst="8.8.8.8") / ICMP() / b'welcome!'
    ping_result = sr1(ping_pkt, timeout=2, verbose=False)
    try:
        if ping_result.getlayer(ICMP).fields['type'] == 0 \
                and ping_result.getlayer(Raw).fields['load'] == b'welcome!':
            return True
        else:
            return False
    except Exception:
        return False

if __name__ == '__main__':
    while True:
        if pong():
            time.sleep(5)
        else:
            login()
            time.sleep(10)

附录二

import json
import os
import sys
import time
import requests

def login():
    url = 'http://192.168.50.3:8080/eportal/InterFace.do?method=login'
    with open("content", "r") as f:
        data = f.read()
    header = {
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
    }
    response = requests.post(url, data, headers=header)
    content = json.loads(response.text)
    encoding = response.encoding
    if content['result'] == 'fail':
        print(content['message'].encode(encoding).decode('utf-8'))
    else:
        print("login at --> " + time.asctime(time.localtime(time.time())))
    return

def pong():
    if sys.platform.lower() == "win32":
        response = os.system("ping -n 1 8.8.8.8 > ping.log")
    else:
        response = os.system("ping -c 1 8.8.8.8 > ping.log")
    return response == 0

if __name__ == '__main__':
    while True:
        if pong():
            time.sleep(5)
        else:
            login()
            time.sleep(10)

附录三

import json
import os
import sys
import time
import requests


def login():
    url = 'http://192.168.50.3:8080/eportal/InterFace.do?method=login'
    with open("content", "r") as f:
        data = f.read()
    header = {
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
    }

    try:
        response = requests.post(url, data, headers=header, timeout=10)
        content = json.loads(response.text)
        encoding = response.encoding
        if content['result'] == 'fail':
            msg = content['message'].encode(encoding).decode('utf-8')
            print(msg)
            if msg == "认证设备响应超时,请稍后再试!":
                time.sleep(120)
        else:
            print("login at --> " + time.asctime(time.localtime(time.time())))
        return
    except Exception as info:
        print("login 连接异常:" + str(info))


def ping(host, n):
    cmd = "ping {} {} {} > ping.log".format(
        "-n" if sys.platform.lower() == "win32" else "-c",
        n,
        host,
    )
    return 0 == os.system(cmd)


def pong():
    return ping("202.114.0.242", 4) or ping("8.8.8.8", 4)


if __name__ == '__main__':
    while True:
        if pong():
            time.sleep(5)
        else:
            login()
            time.sleep(10)

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注