首页
统计
推荐
青柠网盘
Search
1
2.2 导数与微分的求法
523 阅读
2
一、函数 极限与连续性 笔记
380 阅读
3
2.4 微分中值定理
256 阅读
4
8.7.1 线性代数 练习题 答案
219 阅读
5
5.4 多元函数微分学 练习题
207 阅读
黄诗扶
心上诗扶
行程预告
演出信息
入梦记录
物料归档
黄六六喵
目录
日常学习
其他
阿里视觉SDK
时政
高数专业课
高数
电路
模电
数电
实操
笔记
登录
Search
标签搜索
练习题
触发器与时序电路
电子元器件的识别与检测
笔记
电路等效与电路基本定理
答案
三极管电路
组合逻辑电路
DAC与ADC
导数及其应用
一元函数积分学
线性代数
集成运放
微分方程
交流稳态电路的分析及计算
电路分析知识点总结
函数 极限与连续性
电路基本分析方法
交流电路基本概念
二重积分
栋栋
累计撰写
226
篇文章
累计收到
0
条评论
首页
栏目
黄诗扶
心上诗扶
行程预告
演出信息
入梦记录
物料归档
黄六六喵
目录
日常学习
其他
阿里视觉SDK
时政
高数专业课
高数
电路
模电
数电
实操
笔记
页面
统计
推荐
青柠网盘
搜索到
2
篇与
的结果
2025-09-07
小米R4A V2刷入openwrt 实现校园网自动认证
一、路由器刷入openwrt系统{callout color="#ff0f0f"}区分v1与v2版本小米路由器4A千兆版分为了v1和v2打开小米路由器后台,进入系统信息查看当前固件版本新购买的路由器版本号可能为 2.30.28 ,如果你是23年前购买的老机型大概率是V1版本。 2.30.为v2,2.28.为v1 v1版本与v2版本是有区别的,不能刷相同的固件,因此这里我们以v2作为教程版本。{/callout}1.开Telnet双击运行 1.V2版开Telnet.bat程序 第一个为路由器ip第二个为当前设备的ip密码为路由器管理员密码2.连接路由器,备份固件{alert type="warning"}这步很重要!如果没成功备份固件后续变砖就无法救了!{/alert}直接打开刷机工具包里的putty工具双击R4A进入即可账户密码均为root备份编程器固件cat /proc/mtd&&dd if=/dev/mtd0 of=/tmp/ALL_backup.bin&&dd if=/dev/mtd4 of=/tmp/eeprom.bin使用FlashFXP 下载备份固件保存tmp目录里的 ALL_backup.bin 和 eeprom.bin 到电脑.同时将breed.bin上传到tmp目录{alert type="warning"}注意看看文件大小!不要没有传成功{/alert}3.刷入breed验证breed.bin的MD5数值md5sum /tmp/breed.binMD5值应当为 24e62762809c15ba3872e610a37451a3 使用命令mtd write /tmp/breed.bin Bootloader刷入breed固件使用命令 reboot 重启路由器重启完成后浏览器192.168.1.1进入管理界面{callout color="#f0ad4e"}以后要进入breed的方法是路由器断电 按住复位键不放 路由器通电 等5到10秒钟 松开复位键 浏览器输入192.168.1.1{/callout}4.刷入openwrt点击 固件更新-常规固件 选择好固件(.bin文件)和EEPROM(之前备份的eeprom.bin) 点击上传即可确认一遍是否正确 点击更新进度条跑完即可等待路由器重启啦!如果路由器一直闪黄灯进入安全模式,可以拔掉电源硬重启一次5.进入系统192.168.31.1进入openwrt管理界面二、无网线接口配置方法网络->无线->扫描选择需要连接的网络默认提交确认为客户端模式,且网络接口为之前创建的三、获取认证接口 构建认证请求通过抓包测试,可知登录 注销等接口1.登录接口http://210.28.39.251:801/eportal/?user_account=<用户名>&wlan_user_ip=<当前设备IP>&login_method=1&user_password=<密码>&c=Portal&a=login Host: 210.28.39.251:801 Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0 Referer: http://210.28.39.251/ Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.62.注销接口http://210.28.39.251:801/eportal/?c=Portal&a=logout&ac_logout=0®ister_mode=1&wlan_user_ip=<当前设备IP>&user_account=drcom Host: 210.28.39.251:801 Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0 Accept: */* Referer: http://210.28.39.251/ Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.63.构造认证请求文件根据个人需求编写auto_login.sh脚本{collapse}{collapse-item label="auto_login.sh" open}#!/bin/sh # 校园网认证脚本 # 首先获取当前WAN口IP,然后使用该IP进行认证 # 设置日志文件路径 LOG_FILE="/tmp/auto_login.log" # 获取WWAN接口的IP地址 # 假设你的无线客户端接口是wwan(根据第一步配置) CURRENT_IP=$(ifconfig wwan 2>/dev/null | awk '/inet addr/{print substr($2,6)}') USERNAME="" PASSWORD="" # 如果没有获取到IP,尝试使用其他方法 if [ -z "$CURRENT_IP" ]; then CURRENT_IP=$(ubus call network.interface.wwan status 2>/dev/null | jsonfilter -e '@["ipv4-address"][0].address') fi # 如果仍然没有IP,记录错误并退出 if [ -z "$CURRENT_IP" ]; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误: 无法获取WAN口IP地址" >> $LOG_FILE exit 1 fi echo "[$(date +'%Y-%m-%d %H:%M:%S')] 获取到IP: $CURRENT_IP" >> $LOG_FILE # 构造认证URL AUTH_URL="http://210.28.39.251:801/eportal/?user_account=${USERNAME}&wlan_user_ip=${CURRENT_IP}&login_method=1&user_password=${PASSWORD}&c=Portal&a=login" # 发送第一次认证请求 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发送第一次认证请求..." >> $LOG_FILE RESPONSE=$(curl -s -X GET \ "$AUTH_URL" \ -H "Host: 210.28.39.251:801" \ -H "Connection: keep-alive" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" \ -H "Referer: http://210.28.39.251/" \ -H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") # 记录第一次响应 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第一次认证响应: $RESPONSE" >> $LOG_FILE # 解析第一次响应结果 if echo "$RESPONSE" | grep -q '"result":"1"'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第一次认证成功" >> $LOG_FILE exit 0 elif echo "$RESPONSE" | grep -q '"result":"0"'; then if echo "$RESPONSE" | grep -q '"ret_code":2'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 已经在线,无需重复认证" >> $LOG_FILE exit 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第一次认证失败,等待2秒后重试..." >> $LOG_FILE sleep 2 # 发送第二次认证请求 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发送第二次认证请求..." >> $LOG_FILE RESPONSE=$(curl -s -X GET \ "$AUTH_URL" \ -H "Host: 210.28.39.251:801" \ -H "Connection: keep-alive" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" \ -H "Referer: http://210.28.39.251/" \ -H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") # 记录第二次响应 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证响应: $RESPONSE" >> $LOG_FILE # 解析第二次响应结果 if echo "$RESPONSE" | grep -q '"result":"1"'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证成功" >> $LOG_FILE exit 0 elif echo "$RESPONSE" | grep -q '"result":"0"' && echo "$RESPONSE" | grep -q '"ret_code":2'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次尝试时已经在线" >> $LOG_FILE exit 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证失败: $RESPONSE" >> $LOG_FILE exit 1 fi fi else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 未知响应,等待2秒后重试..." >> $LOG_FILE sleep 2 # 发送第二次认证请求 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发送第二次认证请求..." >> $LOG_FILE RESPONSE=$(curl -s -X GET \ "$AUTH_URL" \ -H "Host: 210.28.39.251:801" \ -H "Connection: keep-alive" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" \ -H "Referer: http://210.28.39.251/" \ -H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") # 记录第二次响应 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证响应: $RESPONSE" >> $LOG_FILE # 解析第二次响应结果 if echo "$RESPONSE" | grep -q '"result":"1"'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证成功" >> $LOG_FILE exit 0 elif echo "$RESPONSE" | grep -q '"result":"0"' && echo "$RESPONSE" | grep -q '"ret_code":2'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次尝试时已经在线" >> $LOG_FILE exit 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证失败: $RESPONSE" >> $LOG_FILE exit 1 fi fi{/collapse-item}{collapse-item label="9月11更新auto_login.sh"}#!/bin/sh # 校园网认证脚本 # 首先获取当前WAN口IP,然后使用该IP进行认证 # 设置日志文件路径 LOG_FILE="/tmp/auto_login.log" # 获取WWAN接口的IP地址 # 假设你的无线客户端接口是wwan(根据第一步配置) CURRENT_IP=$(ifconfig wwan 2>/dev/null | awk '/inet addr/{print substr($2,6)}') USERNAME="" PASSWORD="" # 如果没有获取到IP,尝试使用其他方法 if [ -z "$CURRENT_IP" ]; then CURRENT_IP=$(ubus call network.interface.wwan status 2>/dev/null | jsonfilter -e '@["ipv4-address"][0].address') fi # 如果仍然没有IP,记录错误并退出 if [ -z "$CURRENT_IP" ]; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误: 无法获取WAN口IP地址" >> $LOG_FILE exit 1 fi echo "[$(date +'%Y-%m-%d %H:%M:%S')] 获取到IP: $CURRENT_IP" >> $LOG_FILE # 构造认证URL AUTH_URL="http://210.28.39.251:801/eportal/?user_account=${USERNAME}&wlan_user_ip=${CURRENT_IP}&login_method=1&user_password=${PASSWORD}&c=Portal&a=login" # 发送第一次认证请求 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发送第一次认证请求..." >> $LOG_FILE RESPONSE=$(curl -s -X GET \ "$AUTH_URL" \ -H "Host: 210.28.39.251:801" \ -H "Connection: keep-alive" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" \ -H "Referer: http://210.28.39.251/" \ -H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") # 记录第一次响应 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第一次认证响应: $RESPONSE" >> $LOG_FILE # 解析第一次响应结果 if echo "$RESPONSE" | grep -q '"result":"1"'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第一次认证成功" >> $LOG_FILE exit 0 elif echo "$RESPONSE" | grep -q '"result":"0"'; then if echo "$RESPONSE" | grep -q '"ret_code":2'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 已经在线,无需重复认证" >> $LOG_FILE exit 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第一次认证失败,等待5秒后重试..." >> $LOG_FILE sleep 5 # 发送第二次认证请求 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发送第二次认证请求..." >> $LOG_FILE RESPONSE=$(curl -s -X GET \ "$AUTH_URL" \ -H "Host: 210.28.39.251:801" \ -H "Connection: keep-alive" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" \ -H "Referer: http://210.28.39.251/" \ -H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") # 记录第二次响应 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证响应: $RESPONSE" >> $LOG_FILE # 解析第二次响应结果 if echo "$RESPONSE" | grep -q '"result":"1"'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证成功" >> $LOG_FILE exit 0 elif echo "$RESPONSE" | grep -q '"result":"0"' && echo "$RESPONSE" | grep -q '"ret_code":2'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次尝试时已经在线" >> $LOG_FILE exit 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证失败: $RESPONSE;当前IP为:$CURRENT_IP" >> $LOG_FILE exit 1 fi fi else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 未知响应,等待5秒后重试...;当前IP为:$CURRENT_IP;URL为:$AUTH_URL" >> $LOG_FILE sleep 5 # 发送第二次认证请求 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发送第二次认证请求..." >> $LOG_FILE RESPONSE=$(curl -s -X GET \ "$AUTH_URL" \ -H "Host: 210.28.39.251:801" \ -H "Connection: keep-alive" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" \ -H "Referer: http://210.28.39.251/" \ -H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") # 记录第二次响应 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证响应: $RESPONSE" >> $LOG_FILE # 解析第二次响应结果 if echo "$RESPONSE" | grep -q '"result":"1"'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证成功" >> $LOG_FILE exit 0 elif echo "$RESPONSE" | grep -q '"result":"0"' && echo "$RESPONSE" | grep -q '"ret_code":2'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次尝试时已经在线" >> $LOG_FILE exit 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第二次认证失败: $RESPONSE;当前IP为:$CURRENT_IP" >> $LOG_FILE exit 1 fi fi{/collapse-item}{collapse-item label="9月14更新auto_login.shIP地址变化导致,构建的URL不正确,更新每次认证前,重新获取一次IP"}#!/bin/sh # 校园网认证脚本 # 首先获取当前WAN口IP,然后使用该IP进行认证 USER_ACCOUNT="" USER_PASSWORD="" AUTH_SERVER="" # HTTP请求头部定义 HOST_HEADER="" REFERER_HEADER="" USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" CONNECTION="keep-alive" ACCEPT_LANGUAGE="zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6" # 设置日志文件路径 LOG_FILE="/tmp/auto_login.log" # 函数:获取当前WWAN接口的IP地址 get_current_ip() { # 尝试多种方法获取IP地址 local ip=$(ifconfig wwan 2>/dev/null | awk '/inet addr/{print substr($2,6)}') # 如果没有获取到IP,尝试使用其他方法 if [ -z "$ip" ]; then ip=$(ubus call network.interface.wwan status 2>/dev/null | jsonfilter -e '@["ipv4-address"][0].address') fi # 如果依然获取不到,尝试使用ip命令 if [ -z "$ip" ]; then ip=$(ip -4 addr show dev wwan 2>/dev/null | grep -oE 'inet [0-9.]+' | cut -d' ' -f2) fi # 如果仍然没有IP,记录错误 if [ -z "$ip" ]; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误: 无法获取WAN口IP地址" >> $LOG_FILE echo "" # 返回空字符串 else echo "$ip" fi } # 函数:发送认证请求 send_auth_request() { local ip=$1 local attempt=$2 local auth_url="http://${AUTH_SERVER}/eportal/?user_account=${USER_ACCOUNT}&wlan_user_ip=${ip}&login_method=1&user_password=${USER_PASSWORD}&c=Portal&a=login" echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发送第${attempt}次认证请求..." >> $LOG_FILE # echo "[$(date +'%Y-%m-%d %H:%M:%S')] 认证URL: $auth_url" >> $LOG_FILE RESPONSE=$(curl -s -X GET \ "$auth_url" \ -H "Host: $HOST_HEADER" \ -H "Connection: $CONNECTION" \ -H "User-Agent: $USER_AGENT" \ -H "Referer: $REFERER_HEADER" \ -H "Accept-Language: $ACCEPT_LANGUAGE") echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第${attempt}次认证响应: $RESPONSE" >> $LOG_FILE # 解析响应结果 if echo "$RESPONSE" | grep -q '"result":"1"'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第${attempt}次认证成功" >> $LOG_FILE return 0 elif echo "$RESPONSE" | grep -q '"result":"0"' && echo "$RESPONSE" | grep -q '"ret_code":2'; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第${attempt}次尝试时已经在线,无需重复认证" >> $LOG_FILE return 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第${attempt}次认证失败;响应:$RESPONSE;认证URL:$auth_url" >> $LOG_FILE return 1 fi } # 获取当前IP CURRENT_IP=$(get_current_ip) if [ -z "$CURRENT_IP" ]; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误: 无法获取WAN口IP地址,退出脚本" >> $LOG_FILE exit 1 fi echo "[$(date +'%Y-%m-%d %H:%M:%S')] 获取到IP: $CURRENT_IP" >> $LOG_FILE # 第一次认证尝试 if send_auth_request "$CURRENT_IP" "一"; then exit 0 fi # 第一次尝试失败,等待5秒后重试 echo "[$(date +'%Y-%m-%d %H:%M:%S')] 第一次认证失败,等待5秒后重试..." >> $LOG_FILE sleep 5 # 第二次尝试前重新获取IP NEW_IP=$(get_current_ip) if [ -z "$NEW_IP" ]; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误: 重试时无法获取WAN口IP地址,退出脚本" >> $LOG_FILE exit 1 fi # 检查IP是否变化 if [ "$NEW_IP" != "$CURRENT_IP" ]; then echo "[$(date +'%Y-%m-%d %H:%M:%S')] 检测到IP地址变化:${CURRENT_IP} -> ${NEW_IP}" >> $LOG_FILE CURRENT_IP="$NEW_IP" fi # 第二次认证尝试 if send_auth_request "$CURRENT_IP" "二"; then exit 0 else echo "[$(date +'%Y-%m-%d %H:%M:%S')] 认证最终失败; 当前IP为: $CURRENT_IP" >> $LOG_FILE exit 1 fi{/collapse-item}{/collapse}4.上传到路由器使用putty软件连接到路由器后面使用vim进行操作1.创建auto_login.sh文件vi /etc/auto_login.sh2.在vi编辑器下,按 i 进入编辑模式,按 Shift+Insert 将准备好的脚本粘贴上去,然后按 esc 退出编辑模式,然后输入 :wq 并回车即可保存。若输入错误,在退出编辑模式后,输入 :q! 不保存退出,如何再重新打开编辑 若要全部删除:按 esc 键后,先按 gg (到达顶部),然后 dG 即可。3.设置权限chmod +x /etc/auto_login.sh4.手动运行一次测试一下/etc/auto_login.sh5.查看日志记录cat /tmp/auto_login.log6.设置计划任务 每30分钟运行一次*/30 * * * * /etc/auto_login.sh5.IP监测1.创建 check_ip_change.sh 文件vi /etc/check_ip_change.sh{collapse}{collapse-item label="check_ip_change.sh 文件" open}#!/bin/sh # 接口名称 INTERFACE="wwan" # 用于存储上次IP的文件 IP_FILE="/tmp/last_ip_${INTERFACE}.txt" # 日志文件 LOG_FILE="/tmp/auto_login.log" # 循环次数 LOOP_COUNT=29 # 循环间隔(秒) LOOP_INTERVAL=60 # 获取当前IP地址 get_current_ip() { # 尝试多种方法获取IP地址 local ip="" ip=$(ifconfig ${INTERFACE} 2>/dev/null | awk '/inet addr/{print substr($2,6)}') # 如果没有获取到IP,尝试使用其他方法 if [ -z "$ip" ]; then ip=$(ubus call network.interface.${INTERFACE} status 2>/dev/null | jsonfilter -e '@["ipv4-address"][0].address') fi # 如果依然获取不到,尝试使用ip命令 if [ -z "$ip" ]; then ip=$(ip -4 addr show dev ${INTERFACE} 2>/dev/null | grep -oE 'inet [0-9.]+' | cut -d' ' -f2) fi echo "$ip" } # 记录日志函数 log() { echo "$(date '+%Y-%m-%d %H:%M:%S') check_ip_change.sh-> $1" >> ${LOG_FILE} # logger -t ip-change-detector "$1" } # 主循环函数 main_loop() { for i in $(seq 1 $LOOP_COUNT); do # log "循环第 $i/$LOOP_COUNT 次" # 获取当前IP current_ip=$(get_current_ip) # 如果无法获取当前IP,记录错误但继续循环 if [ -z "${current_ip}" ]; then log "警告: 无法获取接口 ${INTERFACE} 的IP地址" sleep $LOOP_INTERVAL continue fi # log "当前检测到IP: ${current_ip}" # 检查是否存在存储的上次IP if [ -f "${IP_FILE}" ]; then last_ip=$(cat ${IP_FILE}) log "上次记录的IP: ${last_ip}" # 比较IP是否变化 if [ "${current_ip}" != "${last_ip}" ]; then log "检测到IP变化,当前检测到IP: ${current_ip},上次记录的IP: ${last_ip},执行认证脚本..." # 执行认证脚本 if [ -x "/etc/auto_login.sh" ]; then /etc/auto_login.sh >> ${LOG_FILE} 2>&1 auth_result=$? if [ ${auth_result} -eq 0 ]; then log "认证脚本执行成功" else log "认证脚本执行失败,返回码: ${auth_result}" fi else log "错误: 认证脚本 /etc/auto_login.sh 不存在或不可执行" fi # 更新存储的IP echo "${current_ip}" > ${IP_FILE} log "已更新存储的IP为: ${current_ip}" fi else # 首次运行,创建IP记录文件 echo "${current_ip}" > ${IP_FILE} log "首次运行,记录IP: ${current_ip}" fi # 等待下一次循环 if [ $i -lt $LOOP_COUNT ]; then sleep $LOOP_INTERVAL fi done } # 执行主循环 main_loop log "完成 ${LOOP_COUNT} 次循环检测,脚本退出" {/collapse-item}{/collapse}2.设置权限chmod +x /etc/check_ip_change.sh3.设置计划任务 每分钟运行一次* * * * * /etc/check_ip_change.sh # 丢弃所有输出 不保留任何日志 * * * * * /etc/check_ip_change.sh >/dev/null 2>&16.配置web设置界面1.创建用于读写的脚本vi /www/cgi-bin/read_file.cgi vi /www/cgi-bin/write_file.cgiread_file.cgi文件 {collapse}{collapse-item label="read_file.cgi" open}#!/bin/sh echo "Content-type: text/plain" echo "" # 获取查询字符串中的file参数 FILE=$(echo "$QUERY_STRING" | sed -n 's/^.*file=\([^&]*\).*$/\1/p' | sed "s/%20/ /g") # 将相对路径转换为绝对路径 case "$FILE" in ./etc/auto_login.sh) ABS_PATH="/etc/auto_login.sh" ;; ./tmp/auto_login.log) ABS_PATH="/tmp/auto_login.log" ;; *) echo "错误: 无权访问该文件" exit 1 ;; esac # 改进的安全检查:只防止包含../的路径遍历,允许单个. if echo "$FILE" | grep -q "\.\./"; then echo "错误: 无效的文件路径(包含路径遍历)" exit 1 fi # 检查文件是否存在 if [ ! -f "$ABS_PATH" ]; then echo "错误: 文件不存在: $ABS_PATH" exit 1 fi # 读取文件内容 cat "$ABS_PATH" {/collapse-item}{/collapse}write_file.cgi文件 {collapse}{collapse-item label="write_file.cgi" open}#!/bin/sh echo "Content-type: text/plain" echo "" # 读取POST数据 read -r POST_DATA # 解析POST数据,获取file和content参数 FILE_PARAM=$(echo "$POST_DATA" | sed 's/&.*//' | sed 's/file=//') CONTENT_PARAM=$(echo "$POST_DATA" | sed 's/.*&//' | sed 's/content=//') # 对URL编码进行解码 FILE=$(printf "%b" "$(echo "$FILE_PARAM" | sed 's/+/ /g; s/%/\\x/g')") CONTENT=$(printf "%b" "$(echo "$CONTENT_PARAM" | sed 's/+/ /g; s/%/\\x/g')") # 将相对路径转换为绝对路径 case "$FILE" in "./etc/auto_login.sh") ABS_PATH="/etc/auto_login.sh" ;; *) echo "错误: 只能保存到auto_login.sh文件" exit 1 ;; esac # 安全检查:防止路径遍历攻击 if echo "$ABS_PATH" | grep -q "\.\."; then echo "错误: 无效的文件路径" exit 1 fi # 只允许写入特定文件 if [ "$ABS_PATH" = "/etc/auto_login.sh" ]; then # 检查目录是否存在且可写 if [ ! -w "$(dirname "$ABS_PATH")" ]; then echo "错误: 目录不可写: $(dirname "$ABS_PATH")" exit 1 fi # 写入文件 echo "$CONTENT" > "$ABS_PATH" # 检查是否成功写入 if [ $? -eq 0 ]; then echo "文件保存成功" else echo "错误: 文件保存失败" exit 1 fi else echo "错误: 只能保存到auto_login.sh文件" exit 1 fi{/collapse-item}{collapse-item label="9月11更新write_file.cgi"}#!/bin/sh echo "Content-type: text/plain" echo "" # 读取POST数据 read -r POST_DATA # 解析POST数据,获取file和content参数 FILE_PARAM=$(echo "$POST_DATA" | sed 's/&.*//' | sed 's/file=//') CONTENT_PARAM=$(echo "$POST_DATA" | sed 's/.*&//' | sed 's/content=//') # 对URL编码进行解码 FILE=$(printf "%b" "$(echo "$FILE_PARAM" | sed 's/+/ /g; s/%/\\x/g')") CONTENT=$(printf "%b" "$(echo "$CONTENT_PARAM" | sed 's/+/ /g; s/%/\\x/g')") # 将相对路径转换为绝对路径 case "$FILE" in "./etc/auto_login.sh") ABS_PATH="/etc/auto_login.sh" ;; *) echo "错误: 只能保存到auto_login.sh文件" exit 1 ;; esac # 安全检查:防止路径遍历攻击 if echo "$ABS_PATH" | grep -q "\.\."; then echo "错误: 无效的文件路径" exit 1 fi # 只允许写入特定文件 if [ "$ABS_PATH" = "/etc/auto_login.sh" ]; then # 检查目录是否存在且可写 if [ ! -w "$(dirname "$ABS_PATH")" ]; then echo "错误: 目录不可写: $(dirname "$ABS_PATH")" exit 1 fi # 写入文件 echo "$CONTENT" > "$ABS_PATH" # 检查是否成功写入 if [ $? -eq 0 ]; then echo "文件保存成功" #2025.9.11添加 保存后自动运行一次 # 添加执行权限 chmod +x "$ABS_PATH" # 延迟1秒后执行 # sleep 1 # 执行脚本并捕获输出 OUTPUT=$($ABS_PATH 2>&1) echo "脚本执行结果: $OUTPUT" else echo "错误: 文件保存失败" exit 1 fi else echo "错误: 只能保存到auto_login.sh文件" exit 1 fi{/collapse-item}{/collapse}2.创建网页文件先创建目录和文件mkdir -p www/webconfig/ vi /www/webconfig/index.htmlindex.html文件 {collapse}{collapse-item label="index.html" open}<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>OpenWrt 自动登录配置</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: #333; background-color: #f5f5f5; padding: 20px; max-width: 1200px; margin: 0 auto; } header { background-color: #2c3e50; color: white; padding: 1rem; border-radius: 5px; margin-bottom: 20px; text-align: center; } h1 { font-size: 1.8rem; margin-bottom: 0.5rem; } .description { font-size: 1rem; opacity: 0.9; } .container { display: flex; flex-wrap: wrap; gap: 20px; } .panel { flex: 1; min-width: 300px; background: white; border-radius: 5px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); padding: 20px; } .panel h2 { margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #eaeaea; color: #2c3e50; } .editor { width: 100%; min-height: 300px; font-family: monospace; padding: 10px; border: 1px solid #ddd; border-radius: 4px; resize: vertical; } .log-view { width: 100%; min-height: 300px; max-height: 500px; overflow-y: auto; font-family: monospace; padding: 10px; border: 1px solid #ddd; border-radius: 4px; background-color: #f8f8f8; white-space: pre-wrap; } .buttons { margin-top: 15px; display: flex; gap: 10px; } button { padding: 8px 16px; background-color: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: 500; transition: background-color 0.2s; } button:hover { background-color: #2980b9; } button.save { background-color: #27ae60; } button.save:hover { background-color: #219653; } button.refresh { background-color: #95a5a6; } button.refresh:hover { background-color: #7f8c8d; } .status { margin-top: 10px; padding: 8px; border-radius: 4px; display: none; } .status.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; display: block; } .status.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; display: block; } .loading { color: #7f8c8d; font-style: italic; } @media (max-width: 768px) { .container { flex-direction: column; } } </style> </head> <body> <header> <h1>OpenWrt 自动登录配置</h1> <p class="description">编辑自动登录脚本并查看运行日志</p> </header> <div class="container"> <div class="panel"> <h2>自动登录脚本 (./etc/auto_login.sh)</h2> <textarea id="editor" class="editor" placeholder="加载中..."></textarea> <div class="buttons"> <button id="saveBtn" class="save">保存更改</button> <button id="reloadBtn" class="refresh">重新加载</button> </div> <div id="editorStatus" class="status"></div> </div> <div class="panel"> <h2>运行日志 (./tmp/auto_login.log)</h2> <pre id="logView" class="log-view">加载日志内容...</pre> <div class="buttons"> <button id="refreshLogBtn" class="refresh">刷新日志</button> </div> <div id="logStatus" class="status"></div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const editor = document.getElementById('editor'); const logView = document.getElementById('logView'); const saveBtn = document.getElementById('saveBtn'); const reloadBtn = document.getElementById('reloadBtn'); const refreshLogBtn = document.getElementById('refreshLogBtn'); const editorStatus = document.getElementById('editorStatus'); const logStatus = document.getElementById('logStatus'); // 加载脚本内容 function loadScript() { editor.classList.add('loading'); editor.value = '加载中...'; fetch('/cgi-bin/read_file.cgi?file=./etc/auto_login.sh') .then(response => { if (!response.ok) { throw new Error('无法读取文件'); } return response.text(); }) .then(data => { editor.value = data; editor.classList.remove('loading'); showStatus(editorStatus, '脚本加载成功', 'success'); }) .catch(error => { editor.value = ''; showStatus(editorStatus, '错误: ' + error.message, 'error'); editor.classList.remove('loading'); }); } // 加载日志内容 function loadLog() { logView.textContent = '加载中...'; logView.classList.add('loading'); fetch('/cgi-bin/read_file.cgi?file=./tmp/auto_login.log') .then(response => { if (!response.ok) { throw new Error('无法读取日志文件'); } return response.text(); }) .then(data => { logView.textContent = data || '日志文件为空'; logView.classList.remove('loading'); showStatus(logStatus, '日志加载成功', 'success'); }) .catch(error => { logView.textContent = '加载失败: ' + error.message; showStatus(logStatus, '错误: ' + error.message, 'error'); logView.classList.remove('loading'); }); } // 保存脚本内容 function saveScript() { const content = editor.value; fetch('/cgi-bin/write_file.cgi', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `file=./etc/auto_login.sh&content=${encodeURIComponent(content)}` }) .then(response => { if (!response.ok) { throw new Error('保存失败'); } return response.text(); }) .then(data => { showStatus(editorStatus, '保存成功', 'success'); }) .catch(error => { showStatus(editorStatus, '错误: ' + error.message, 'error'); }); } // 显示状态消息 function showStatus(element, message, type) { element.textContent = message; element.className = 'status ' + type; // 3秒后隐藏状态消息 setTimeout(() => { element.className = 'status'; element.textContent = ''; }, 3000); } // 绑定按钮事件 saveBtn.addEventListener('click', saveScript); reloadBtn.addEventListener('click', loadScript); refreshLogBtn.addEventListener('click', loadLog); // 初始加载内容 loadScript(); loadLog(); }); </script> </body> </html>{/collapse-item}{collapse-item label="9月11更新index.html"}<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>OpenWrt 自动登录配置</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: #333; background-color: #f5f5f5; padding: 20px; max-width: 1200px; margin: 0 auto; } header { background-color: #2c3e50; color: white; padding: 1rem; border-radius: 5px; margin-bottom: 20px; text-align: center; } h1 { font-size: 1.8rem; margin-bottom: 0.5rem; } .description { font-size: 1rem; opacity: 0.9; } .container { display: flex; flex-wrap: wrap; gap: 20px; } .panel { flex: 1; min-width: 300px; background: white; border-radius: 5px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); padding: 20px; } .panel h2 { margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #eaeaea; color: #2c3e50; } .editor { width: 100%; min-height: 300px; font-family: monospace; padding: 10px; border: 1px solid #ddd; border-radius: 4px; resize: vertical; } .log-view { width: 100%; min-height: 300px; max-height: 500px; overflow-y: auto; font-family: monospace; padding: 10px; border: 1px solid #ddd; border-radius: 4px; background-color: #f8f8f8; white-space: pre-wrap; } .buttons { margin-top: 15px; display: flex; gap: 10px; flex-wrap: wrap; } button { padding: 8px 16px; background-color: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: 500; transition: background-color 0.2s; } button:hover { background-color: #2980b9; } button.save { background-color: #27ae60; } button.save:hover { background-color: #219653; } button.refresh { background-color: #95a5a6; } button.refresh:hover { background-color: #7f8c8d; } button.download { background-color: #9b59b6; } button.download:hover { background-color: #8e44ad; } .status { margin-top: 10px; padding: 8px; border-radius: 4px; display: none; } .status.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; display: block; } .status.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; display: block; } .loading { color: #7f8c8d; font-style: italic; } @media (max-width: 768px) { .container { flex-direction: column; } .buttons { flex-direction: column; } button { width: 100%; } } </style> </head> <body> <header> <h1>OpenWrt 自动登录配置</h1> <p class="description">编辑自动登录脚本并查看运行日志</p> </header> <div class="container"> <div class="panel"> <h2>自动登录脚本 (./etc/auto_login.sh)</h2> <textarea id="editor" class="editor" placeholder="加载中..."></textarea> <div class="buttons"> <button id="saveBtn" class="save">保存更改</button> <button id="reloadBtn" class="refresh">重新加载</button> </div> <div id="editorStatus" class="status"></div> </div> <div class="panel"> <h2>运行日志 (./tmp/auto_login.log)</h2> <pre id="logView" class="log-view">加载日志内容...</pre> <div class="buttons"> <button id="refreshLogBtn" class="refresh">刷新日志</button> <button id="downloadLogBtn" class="download">下载日志</button> </div> <div id="logStatus" class="status"></div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const editor = document.getElementById('editor'); const logView = document.getElementById('logView'); const saveBtn = document.getElementById('saveBtn'); const reloadBtn = document.getElementById('reloadBtn'); const refreshLogBtn = document.getElementById('refreshLogBtn'); const downloadLogBtn = document.getElementById('downloadLogBtn'); const editorStatus = document.getElementById('editorStatus'); const logStatus = document.getElementById('logStatus'); // 加载脚本内容 function loadScript() { editor.classList.add('loading'); editor.value = '加载中...'; fetch('/cgi-bin/read_file.cgi?file=./etc/auto_login.sh') .then(response => { if (!response.ok) { throw new Error('无法读取文件'); } return response.text(); }) .then(data => { editor.value = data; editor.classList.remove('loading'); showStatus(editorStatus, '脚本加载成功', 'success'); }) .catch(error => { editor.value = ''; showStatus(editorStatus, '错误: ' + error.message, 'error'); editor.classList.remove('loading'); }); } // 加载日志内容 function loadLog() { logView.textContent = '加载中...'; logView.classList.add('loading'); fetch('/cgi-bin/read_file.cgi?file=./tmp/auto_login.log') .then(response => { if (!response.ok) { throw new Error('无法读取日志文件'); } return response.text(); }) .then(data => { logView.textContent = data || '日志文件为空'; logView.classList.remove('loading'); showStatus(logStatus, '日志加载成功', 'success'); }) .catch(error => { logView.textContent = '加载失败: ' + error.message; showStatus(logStatus, '错误: ' + error.message, 'error'); logView.classList.remove('loading'); }); } // 保存脚本内容 function saveScript() { const content = editor.value; fetch('/cgi-bin/write_file.cgi', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `file=./etc/auto_login.sh&content=${encodeURIComponent(content)}` }) .then(response => { if (!response.ok) { throw new Error('保存失败'); } return response.text(); }) .then(data => { showStatus(editorStatus, '保存成功', 'success'); }) .catch(error => { showStatus(editorStatus, '错误: ' + error.message, 'error'); }); } // 下载日志功能 function downloadLog() { const logContent = logView.textContent; if (!logContent || logContent === '加载中...' || logContent === '加载日志内容...') { showStatus(logStatus, '没有可下载的日志内容', 'error'); return; } try { // 创建Blob对象 const blob = new Blob([logContent], { type: 'text/plain' }); const url = URL.createObjectURL(blob); // 创建下载链接 const a = document.createElement('a'); a.href = url; a.download = 'auto_login.log'; document.body.appendChild(a); a.click(); // 清理 setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); showStatus(logStatus, '日志下载成功', 'success'); }, 100); } catch (error) { showStatus(logStatus, '下载失败: ' + error.message, 'error'); } } // 显示状态消息 function showStatus(element, message, type) { element.textContent = message; element.className = 'status ' + type; // 3秒后隐藏状态消息 setTimeout(() => { element.className = 'status'; element.textContent = ''; }, 3000); } // 绑定按钮事件 saveBtn.addEventListener('click', saveScript); reloadBtn.addEventListener('click', loadScript); refreshLogBtn.addEventListener('click', loadLog); downloadLogBtn.addEventListener('click', downloadLog); // 初始加载内容 loadScript(); loadLog(); }); </script> </body> </html>{/collapse-item}{/collapse}3.设置权限chmod +x /www/cgi-bin/read_file.cgi /www/cgi-bin/write_file.cgi4.管理地址管理地址 所有工具和包隐藏内容,请前往内页查看详情
2025年09月07日
12 阅读
0 评论
0 点赞
2023-06-07
系统安装
提前准备一个8G或者更大的空白U盘(资料注意提前备份,写入系统后U盘会被全部清空,切记!!!){mtitle title="win11"/}选择Create Windows 11 Installation Media下载win11系统制作工具(点击可跳转到下载界面) {mtitle title="win10"/}win10系统制作工具(点击可跳转到下载界面){callout color="#ef4d4d"}制作系统u盘会格式化u盘原有内容,请将u盘内容备份后操作{/callout}{message type="warning" content="制作系统u盘会格式化u盘原有内容,请将u盘内容备份后操作"/}{callout color="#ef4d4d"}制作系统u盘会格式化u盘原有内容,请将u盘内容备份后操作{/callout}win10和win11制作系统u盘步骤相同(以win11为例) 最后就完成啦{callout color="#f0ad4e"}win10不同的地方也给你标出来了版本就选windows 10 不要选家庭版{/callout}u盘插到电脑上开机会显示如下画面(若无显示,看最下面)若无显示先将电脑重启,然后一直按 f2键 进入bios界面设置好后按 F10 确认保存就好了若还是不行还是进入刚刚那个界面按 F7 进入高级设置将启动选项第一个选成u盘就好啦还有其它问题也可以联系我
2023年06月07日
33 阅读
0 评论
0 点赞