编辑
2025-10-16
C#
00

目录

功能概述
技术实现
所需依赖
基础配置
主程序结构
HTTP客户端初始化
定时器设置
路由器重启流程
登录路由器
执行重启命令
完整代码示例
实现原理详解
HTTP请求模拟
登录过程分析
重启命令执行
定时执行机制
适配不同路由器
路由器地址和登录凭据
登录流程
重启命令路径
总结

在本篇文章中,我们将介绍一个使用 C# 编写的程序,该程序可以自动登录到路由器并定时重启它。程序利用 HttpClient 和异步编程来执行网络请求,确保高效性。下面将详细分析程序的各个部分及其功能。

其实用telnet来实现更简单,问题是一般的路由器没有提供这个功能。

功能概述

我们将开发一个控制台应用程序,具有以下功能:

  • 自动登录路由器管理界面
  • 定时执行路由器重启命令(默认1小时一次)
  • 程序启动时立即执行一次重启
  • 完整的错误处理和日志记录

技术实现

所需依赖

C#
using System; using System.Net; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using System.Text.RegularExpressions;

基础配置

首先,我们需要设置路由器的基本信息:

C#
private static string routerAddress = "http://192.168.18.1"; private static string username = "user"; // 根据路由器设置修改 private static string password = "yourpassword"; // 替换为您的路由器密码 private static CookieContainer cookieContainer = new CookieContainer(); private static HttpClientHandler handler; private static HttpClient client;

主程序结构

C#
static async Task Main(string[] args) { Console.WriteLine("路由器定时重启程序已启动"); // 初始化HTTP客户端 InitializeHttpClient(); // 设置定时器 - 24小时执行一次 SetupTimer(); // 初次启动也执行一次 await RebootRouter(); Console.WriteLine("按任意键退出..."); Console.ReadKey(); }

HTTP客户端初始化

C#
private static void InitializeHttpClient() { handler = new HttpClientHandler { CookieContainer = cookieContainer, UseCookies = true }; client = new HttpClient(handler) { BaseAddress = new Uri(routerAddress), Timeout = TimeSpan.FromSeconds(30) }; // 设置默认的User-Agent和其他请求头 client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"); client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); client.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7"); }

定时器设置

C#
private static void SetupTimer() { var timer = new System.Timers.Timer(1* 60 * 60 * 1000); // 1小时 timer.Elapsed += async (sender, e) => { try { await RebootRouter(); } catch (Exception ex) { Console.WriteLine($"[{DateTime.Now}] 定时重启出错: {ex.Message}"); } }; timer.AutoReset = true; timer.Start(); }

路由器重启流程

重启路由器的过程分为两个主要步骤:登录路由器和执行重启命令。

C#
private static async Task RebootRouter() { try { Console.WriteLine($"[{DateTime.Now}] 开始重启路由器..."); // 第1步:登录到路由器 bool loginSuccess = await LoginToRouter(); if (loginSuccess) { // 第2步:执行重启命令 bool rebootSuccess = await ExecuteReboot(); if (rebootSuccess) { Console.WriteLine($"[{DateTime.Now}] 路由器重启命令已发送成功!"); } else { Console.WriteLine($"[{DateTime.Now}] 路由器重启命令发送失败!"); } } else { Console.WriteLine($"[{DateTime.Now}] 登录路由器失败!"); } } catch (Exception ex) { Console.WriteLine($"[{DateTime.Now}] 错误: {ex.Message}"); } }

登录路由器

登录过程模拟了浏览器的行为,包括获取随机计数值、设置Cookie、发送登录请求等步骤:

C#
private static async Task<bool> LoginToRouter() { try { // 首先访问登录页面获取初始Cookie var initialResponse = await client.GetAsync("/"); // 获取随机计数值(用于安全验证) var randCountResponse = await client.PostAsync("/asp/GetRandCount.asp", null); string randCount = await randCountResponse.Content.ReadAsStringAsync(); Console.WriteLine($"获取到的随机计数: {randCount}"); // 设置初始Cookie cookieContainer.Add(new Uri(routerAddress), new Cookie("Cookie", "body:Language:chinese:id=-1")); cookieContainer.Add(new Uri(routerAddress), new Cookie("MenuJumpIndex", "0")); // 准备登录参数 var loginParams = new Dictionary<string, string> { { "UserName", username }, { "PassWord", Convert.ToBase64String(Encoding.UTF8.GetBytes(password)) }, { "Language", "chinese" }, { "x.X_HW_Token", randCount } }; // 创建表单内容 var loginContent = new FormUrlEncodedContent(loginParams); // 添加引用页头 client.DefaultRequestHeaders.Referrer = new Uri(routerAddress); // 发送登录请求 var loginResponse = await client.PostAsync("/login.cgi", loginContent); // 检查登录结果 if (loginResponse.IsSuccessStatusCode) { // 获取登录后的页面内容 string responseContent = await loginResponse.Content.ReadAsStringAsync(); // 登录后应该被重定向到index.asp var indexResponse = await client.GetAsync("/index.asp"); if (indexResponse.IsSuccessStatusCode) { Console.WriteLine("登录成功!"); return true; } } return false; } catch (Exception ex) { Console.WriteLine($"登录过程中出错: {ex.Message}"); return false; } }

执行重启命令

执行重启命令需要先获取页面中的安全令牌(onttoken),然后发送重启请求:

C#
private static async Task<bool> ExecuteReboot() { try { // 重启功能在 resetfactory.asp 页面 Console.WriteLine("访问重启页面..."); var resetPageUrl = "/html/ssmp/restore/resetfactory.asp"; var resetPageResponse = await client.GetAsync(resetPageUrl); if (!resetPageResponse.IsSuccessStatusCode) { Console.WriteLine($"访问重启页面失败,状态码: {resetPageResponse.StatusCode}"); return false; } // 获取页面内容以提取 onttoken var pageContent = await resetPageResponse.Content.ReadAsStringAsync(); // 匹配模式 <input type="hidden" name="onttoken" id="hwonttoken" value="..."> var tokenMatch = Regex.Match(pageContent, @"<input\s+type=""hidden""\s+name=""onttoken""\s+id=""hwonttoken""\s+value=""([^""]+)""", RegexOptions.IgnoreCase); if (!tokenMatch.Success) { Console.WriteLine("无法找到onttoken值"); return false; } string tokenValue = tokenMatch.Groups[1].Value; Console.WriteLine($"获取到的onttoken值: {tokenValue}"); // 设置重启请求的引用页 client.DefaultRequestHeaders.Referrer = new Uri($"{routerAddress}{resetPageUrl}"); // 准备重启请求参数 var rebootParams = new Dictionary<string, string> { { "x.X_HW_Token", tokenValue } }; // 创建重启请求内容 var rebootContent = new FormUrlEncodedContent(rebootParams); // 发送重启请求 var rebootUrl = "set.cgi?x=InternetGatewayDevice.X_HW_DEBUG.SMP.DM.ResetBoard&RequestFile=html/ssmp/restore/resetfactory.asp"; var rebootResponse = await client.PostAsync(rebootUrl, rebootContent); if (rebootResponse.IsSuccessStatusCode) { Console.WriteLine("重启命令已成功发送"); return true; } else { Console.WriteLine($"重启命令发送失败,状态码: {rebootResponse.StatusCode}"); var responseContent = await rebootResponse.Content.ReadAsStringAsync(); Console.WriteLine($"响应内容: {responseContent}"); return false; } } catch (Exception ex) { Console.WriteLine($"执行重启时出错: {ex.Message}"); return false; } }

完整代码示例

下面是完整的定时重启路由器程序代码:

C#
using System; using System.Net; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using System.Text.RegularExpressions; namespace AppRebootRouter { class Program { private static string routerAddress = "http://192.168.18.1"; private static string username = "user"; // 根据路由器设置修改 private static string password = "yqv2psyy"; // 替换为您的路由器密码 private static CookieContainer cookieContainer = new CookieContainer(); private static HttpClientHandler handler; private static HttpClient client; static async Task Main(string[] args) { Console.WriteLine("路由器定时重启程序已启动"); // 创建一个HttpClient实例,这个一直会用的 handler = new HttpClientHandler { CookieContainer = cookieContainer, UseCookies = true }; client = new HttpClient(handler) { BaseAddress = new Uri(routerAddress), Timeout = TimeSpan.FromSeconds(30) }; // 设置默认的User-Agent client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"); client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); client.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7"); // 设置定时器 - 使用更可靠的方式实现定时功能 var timer = new System.Timers.Timer(24 * 60 * 60 * 1000); // 24小时 timer.Elapsed += async (sender, e) => { try { await RebootRouter(); } catch (Exception ex) { Console.WriteLine($"[{DateTime.Now}] 定时重启出错: {ex.Message}"); } }; timer.AutoReset = true; timer.Start(); // 初次启动也执行一次 await RebootRouter(); Console.WriteLine("按任意键退出..."); Console.ReadKey(); } private static async Task RebootRouter() { try { Console.WriteLine($"[{DateTime.Now}] 开始重启路由器..."); // 第1步:登录到路由器 bool loginSuccess = await LoginToRouter(); if (loginSuccess) { // 第2步:执行重启命令 bool rebootSuccess = await ExecuteReboot(); if (rebootSuccess) { Console.WriteLine($"[{DateTime.Now}] 路由器重启命令已发送成功!"); } else { Console.WriteLine($"[{DateTime.Now}] 路由器重启命令发送失败!"); } } else { Console.WriteLine($"[{DateTime.Now}] 登录路由器失败!"); } } catch (Exception ex) { Console.WriteLine($"[{DateTime.Now}] 错误: {ex.Message}"); } } private static async Task<bool> LoginToRouter() { try { // 首先访问登录页面获取一些初始Cookie var initialResponse = await client.GetAsync("/"); // 获取随机计数值 var randCountResponse = await client.PostAsync("/asp/GetRandCount.asp", null); string randCount = await randCountResponse.Content.ReadAsStringAsync(); Console.WriteLine($"获取到的随机计数: {randCount}"); // 设置初始Cookie cookieContainer.Add(new Uri(routerAddress), new Cookie("Cookie", "body:Language:chinese:id=-1")); cookieContainer.Add(new Uri(routerAddress), new Cookie("MenuJumpIndex", "0")); // 准备登录参数 var loginParams = new Dictionary<string, string> { { "UserName", username }, { "PassWord", Convert.ToBase64String(Encoding.UTF8.GetBytes(password)) }, { "Language", "chinese" }, { "x.X_HW_Token", randCount } }; // 创建表单内容 var loginContent = new FormUrlEncodedContent(loginParams); // 添加引用页头 client.DefaultRequestHeaders.Referrer = new Uri(routerAddress); // 发送登录请求 var loginResponse = await client.PostAsync("/login.cgi", loginContent); // 检查登录结果 if (loginResponse.IsSuccessStatusCode) { // 获取登录后的页面内容 string responseContent = await loginResponse.Content.ReadAsStringAsync(); // 登录后应该被重定向到index.asp var indexResponse = await client.GetAsync("/index.asp"); if (indexResponse.IsSuccessStatusCode) { Console.WriteLine("登录成功!"); return true; } } return false; } catch (Exception ex) { Console.WriteLine($"登录过程中出错: {ex.Message}"); return false; } } private static async Task<bool> ExecuteReboot() { try { // 重启功能在 resetfactory.asp 页面 Console.WriteLine("访问重启页面..."); var resetPageUrl = "/html/ssmp/restore/resetfactory.asp"; var resetPageResponse = await client.GetAsync(resetPageUrl); if (!resetPageResponse.IsSuccessStatusCode) { Console.WriteLine($"访问重启页面失败,状态码: {resetPageResponse.StatusCode}"); return false; } // 获取页面内容以提取 onttoken var pageContent = await resetPageResponse.Content.ReadAsStringAsync(); // 匹配模式 <input type="hidden" name="onttoken" id="hwonttoken" value="..."> var tokenMatch = Regex.Match(pageContent, @"<input\s+type=""hidden""\s+name=""onttoken""\s+id=""hwonttoken""\s+value=""([^""]+)""", RegexOptions.IgnoreCase); if (!tokenMatch.Success) { Console.WriteLine("无法找到onttoken值"); return false; } string tokenValue = tokenMatch.Groups[1].Value; Console.WriteLine($"获取到的onttoken值: {tokenValue}"); // 设置重启请求的引用页 client.DefaultRequestHeaders.Referrer = new Uri($"{routerAddress}{resetPageUrl}"); // 准备重启请求参数 var rebootParams = new Dictionary<string, string> { { "x.X_HW_Token", tokenValue } }; // 创建重启请求内容 var rebootContent = new FormUrlEncodedContent(rebootParams); // 发送重启请求 var rebootUrl = "set.cgi?x=InternetGatewayDevice.X_HW_DEBUG.SMP.DM.ResetBoard&RequestFile=html/ssmp/restore/resetfactory.asp"; var rebootResponse = await client.PostAsync(rebootUrl, rebootContent); if (rebootResponse.IsSuccessStatusCode) { Console.WriteLine("重启命令已成功发送"); return true; } else { Console.WriteLine($"重启命令发送失败,状态码: {rebootResponse.StatusCode}"); var responseContent = await rebootResponse.Content.ReadAsStringAsync(); Console.WriteLine($"响应内容: {responseContent}"); return false; } } catch (Exception ex) { Console.WriteLine($"执行重启时出错: {ex.Message}"); return false; } } } }

image.png

实现原理详解

HTTP请求模拟

本程序本质上是通过模拟浏览器行为来访问路由器的管理界面。我们使用HttpClient类来发送HTTP请求,并使用CookieContainer来管理会话状态。这种方式无需使用浏览器自动化工具(如Selenium),效率更高,资源占用更少。

登录过程分析

登录一个路由器管理界面通常涉及以下几个步骤:

  1. 获取初始Cookie:访问首页以获取初始会话Cookie
  2. 获取安全令牌:许多路由器会生成一个随机令牌用于防止CSRF攻击
  3. 处理凭据:通常密码会进行某种形式的编码(如Base64)
  4. 发送POST请求:将用户名、密码和安全令牌作为表单数据提交
  5. 验证登录成功:通常通过访问只有登录后才能访问的页面来验证

在我们的实现中,通过访问/asp/GetRandCount.asp获取随机计数值,并使用它作为安全令牌。密码使用Base64编码后发送,这是许多路由器常见的做法。

重启命令执行

执行重启命令同样需要先获取安全令牌,这通常包含在页面的隐藏表单字段中。在这个例子中,我们使用正则表达式从重启页面的HTML内容中提取onttoken值:

C#
var tokenMatch = Regex.Match(pageContent, @"<input\s+type=""hidden""\s+name=""onttoken""\s+id=""hwonttoken""\s+value=""([^""]+)""", RegexOptions.IgnoreCase);

获取到令牌后,我们将其作为参数发送到路由器的重启API端点:

C#
var rebootUrl = "set.cgi?x=InternetGatewayDevice.X_HW_DEBUG.SMP.DM.ResetBoard&RequestFile=html/ssmp/restore/resetfactory.asp";

定时执行机制

我们使用System.Timers.Timer类来实现定时功能,设置为每1小时执行一次重启操作:

C#
var timer = new System.Timers.Timer(1* 60 * 60 * 1000); // 1小时 timer.Elapsed += async (sender, e) => { try { await RebootRouter(); } catch (Exception ex) { Console.WriteLine($"[{DateTime.Now}] 定时重启出错: {ex.Message}"); } }; timer.AutoReset = true; timer.Start();

AutoReset = true确保定时器会重复触发,而不是只执行一次。

适配不同路由器

本程序专为特定型号的路由器编写,如果要适配其他品牌或型号的路由器,需要根据实际情况修改以下几个方面:

路由器地址和登录凭据

C#
private static string routerAddress = "http://192.168.18.1"; // 路由器IP地址 private static string username = "user"; // 用户名 private static string password = "yourpassword"; // 密码

登录流程

不同路由器有不同的登录API和安全机制。需要分析目标路由器的登录请求,包括:

  • 登录API端点(如本例中的/login.cgi
  • 安全令牌获取方式
  • 密码编码方式(有些路由器可能使用MD5而非Base64)
  • 登录参数的名称和格式

重启命令路径

路由器重启命令的API端点和参数也各不相同:

  • 重启页面的URL(如本例中的/html/ssmp/restore/resetfactory.asp
  • 重启API端点(如本例中的set.cgi?x=...
  • 安全令牌的获取和传递方式

总结

定时重启路由器是一个简单但实用的网络维护工具,通过模拟HTTP请求和自动化交互实现了路由器管理界面的操作自动化。本程序提供了一个完整的实现示例,包括登录验证、指令执行和定时触发功能,可以根据具体路由器型号和需求进行调整和扩展。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!