公众号第一次发文,分享一个小案例,所有样本在:
https://github.com/suchocolate/test/tree/master/autowifi
最近把树莓派留在了机房想远程登录,但似乎每到夜里机房WIFI就会断网,导致无法远程树莓派(如何远程下回有机会再讲)。然而早上到机房后看树莓派的无线连接并没有断,只需要登陆认证网页认证一下就可以再次上网。所以基本判断不是无线网卡或WIFI信号的问题,可能是WIFI设置了认证租期,那么只要让树莓派能够在断网时自动重新认证应该就可以保持上网了。
图1.1 树莓派4B
为了让树莓派能够自动重认证,我们先看一下认证的页面。首先用自己的电脑接入WIFI,然后用浏览器F12打开元素查看器-网络,登陆认证页面看看。
图2.1
可以看到这个网页加载了1个JavaScript和2个图片。
网页一般由3种元素HTML(构架)+CSS(外观)+JavaScript(行为)组成,我们先来看下基础的HTML。
图2.2
第60行表示需要加载外部JavaScript,就是上面图中的loginscript.js。
第80行表示页面中有一个表单,当提交表单时使用HTTP 的POST方法,并向https://192.0.2.100/login.html提交。
其实登陆页面中整个有文字的部分都是这个表单。
图2.3
第132和138行是实际提交信息的输入框username和password。
第144行是一个获取按钮的函数,这个函数定义在loginscript.js中,让我们看下这个脚本。
图2.4
图2.5
这个函数的功能是向HTML主体写入一个button,当点击这个按钮时调用函数onClickFn形参指向的实参,就是调用时输入的submitAction()。
让我们看一下这个函数:
图2.6
虽然不知道函数具体执行的内容,但最后都会调用form的submit方法来提交数据,所以这个按钮就是指导浏览器发送POST提交账号密码的方法,那我们就用浏览器点击一下按钮看看效果。
填写账号密码,点击按钮后,浏览器向https://192.0.2.100/login.htmlPOST了消息。
图3.1
点击响应看看效果,LoginSuccessful。
图3.2
点击预览的倒三角收起预览,可以看到网页的代码:
图3.3
点击参数查看提交的信息,原来实际提交的表单就在这里。
图3.4
十分不推荐这种明文发送账号密码的认证机制。
现在知道了要提交的数据,那么就可以准备脚本让树莓派认证了。
树莓派默认安装了python,并且默认有requests模块,就用requests模块实现认证。
import requests
在准备post消息之前还需要准备http的头部消息。
头部数据从图3.1中复制获得,表单数据从图3.4中复制获得,把他们转成字典,供requests使用。
headers={
"Host": "192.0.2.100",
"User-Agent": "Mozilla/5.0",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding": "gzip, deflate, br",
"Content-Type":"application/x-www-form-urlencoded",
"Content-Length": "156",
"Origin": "https://192.0.2.100",
"Connection": "keep-alive",
"Referer":"https://192.0.2.100/login.html?redirect=192.0.2.100/",
"Upgrade-Insecure-Requests": "1"
}
data={
"buttonClicked":"4",
"err_flag":"0",
"err_msg":"",
"info_flag":"0",
"info_msg":"",
"redirect_url":"http%3A%2F%2F192.0.2.100%2F",
"network_name":"Guest+Network",
"username":"VIP12",
"password":"123456"
}
#最后用requests登陆即可
requests.post('https://192.0.2.100/login.html',data=data,headers=headers,verify=False)
# 'https://192.0.2.100/login.html 就是认证的网页。
# data是提交的表单。
# headers是http头部。
# verify=False是关闭SSL检查,因为这个网站的证书没有在公网注册。
现在解决了重认证的问题,那么接下来解决如何检测断网:
# 引入os用以使用系统命令,引入time用以延时和打印时间
import os
import time
# 定义子函数,循环检测是否断网
def autowifi():
while (True):
# ping外网地址3次,每次等5秒
result =os.system(u"ping 1.2.4.8 -c 3 -W 5")
# 如果ping失败
if result !=0:
try:
# iw是无线网卡的操控命令
os.system(u"iw wlan0 disconnect")
# sleep让程序暂停,目的是留给前一个命令充分的时间执行
time.sleep(5)
# wifi名称需要根据实际情况替换
os.system(u"iw wlan0 connect wifiname")
time.sleep(5)
# 重新获取IP
os.system(u"dhclient wlan0")
time.sleep(10)
r=requests.post('https://192.0.2.100/login.html',data=data,headers=headers,verify=False)
time.sleep(5)
# 打印post的时间和结果,status_code是requests对象自带属性
print(time.asctime(time.localtime(time.time())),r.status_code)
exceptException as e:
# 如果有报错,打印报错,不退出程序
print(e)
else:
# 如果ping 正常说明没有断网,打印时间
print(time.asctime(time.localtime(time.time())),"normal")
print("="*50)
# 睡10分钟再测
time.sleep(600)
# 主语句调用子函数
if __name__=='__main__':
autowifi()
为了持续监控需要python脚本保持在后台,那么用nohup运行:
nohup python -u autowifi.py > nohup.out 2>&1 &
# -u:让系统命令直接输出到标准输出
# >nohut.out:输出到log文件
# 2>&1:报错也输出到log文件
# &:后台运行
运行几天后的效果。