背景

我的路由器 7x24 开机无密码,当耳机受影响时我会暂时关闭无线网。2015 年 11 月我的路由器坏了,朋友给我推荐小米 mini 路由器。这人自己有个小米路由器,经常不能正常启动(那个灯是桔黄色的,不会变蓝),我问他为什么还推荐小米,他说便宜功能多、不好用随时换。我本来就没有认定的路由器,所以就听他的没买 300 - 1 的极路由,买了个 130 - 1 的小米 mini。

设置好之后,用浏览器访问 192.168.31.1,输入密码登录管理页面,第一感觉就是慢。

想关闭无线网

  • 常用设置,这会显示 Wi-Fi 设置标签 > 点击相应 ssid 旁边的“关闭”单选按钮 > 保存 > 确认重启

想启用 mac 白名单/黑名单

  • 常用设置 > 安全中心 > 等待“无线访问控制”出现 > 点击它旁边的开关 > 一条一条添加设备(若选择“从在线列表添加”则无法修改设备名字) > 保存并生效

登录之后显示的页面是 路由状态 > (你的路由器名字),这里可以查看连接到路由器上的设备,界面类似下面

图很直观,文字几乎没用,一堆 android-

路由状态 > 终端设备 页面可以禁用设备访问 wan,界面类似下面

这里显示的名字较长,但看不到各位的流量状况,也就无法确定该禁止谁访问 wan。所以我想做一个列表页面,显示设备的完整名字和流量并控制它能否访问 wan

工具

小米路由器 mini

google chrome 45

正文

我打算就把它显示在 路由状态 > (你的路由器名字),这是登录后进入的页面,下面称其为首页。

要修改首页,可以修改保存在服务器上的文件,也可以在页面加载之后运行一段脚本。我选择后者因为它在浏览器中就能完成,缺点是每次打开首页都要手动执行脚本。

本文不使用 fiddler 等反向代理。

snippets

chrome 的 f12 工具的 source 标签有个保存代码段的地方,如下

你可以把一大段脚本保存为代码段文件,右键该文件选择 run,这就省得每次都往控制台粘贴并执行代码。本文的脚本保存在代码段文件 miwifi 中。

位置

用 chrome 访问 192.168.31.1,输入密码,会进入首页,url 类似下面

http://192.168.31.1/cgi-bin/luci/;stok=98a00862e50a7f688cf8868869a7068f/web/home#router

要往这个页面添加一个详细列表,首先选取一个位置放置列表,我打算把它放在“路由器信息”下面

这意味着放在路由器信息那个 dom 元素之下,用 f12 查看他的位置

因此列表将放在 div.routerinfo 下面。在控制台执行 $(".routerinfo") 发现只有 1 个元素,所以不必担心插入多于 1 个列表。

行为

希望构造这样一个列表,它显示设备的完整名字、mac、流量信息,并可以控制某个设备能否访问 wan。这就需要大约两个 ajax,一个获取设备列表,另一个控制 wan 访问。

观察

刚才打开了控制台,应该能看到控制台有一堆输出,由 class.pie.js:1 产生。输出每隔一定时间产生一坨,饼图、列表会跟着刷新,点击 f12 的 network 标签会发现每个成功的 xhr 调用后跟一坨输出,xhr 是

get http://192.168.31.1/cgi-bin/luci/;stok=98a00862e50a7f688cf8868869a7068f/api/misystem/status

没有参数

这个 console.log 为我省了不少时间,不用去查找绘制函数了。接下来要修改这个绘制函数,让其更新前面设计的列表。

点击控制台输出右边的 class.pie.js:1,这会在代码窗格打开 class.pie.js,这是个最小化后的文件不容易阅读,点击打开的代码左下角的大括号格式化它,这会在代码窗格打开 class.pie.js:formatted,光标已经定位到 console.log 处了,在那里加一个断点。

过一会一个新的 ajax 成功了,将调用这里的 console.log,然后会中断在这里,查看其调用堆栈发现比较长,一堆我不关心的 jquery 代码

blackbox

如果不想在调用堆栈里看到无关的代码比如 jquery,可以将 jquery 添加到黑盒,这样调用堆栈就没有那么多噪音了。

调用堆栈显示 PieChart.prototype.update > PieChart.prototype.drawPie > process > sector,阅读代码后知道 PieChart.prototype.drawPie 负责更新饼图和列表,主要工作由 process 来做。那么只要替换 PieChart.prototype.drawPie,让它照常更新饼图,但更新新的列表,本文的目的就达到了。

收集

开始行动之前要找几个可用的 ajax 以获取设备列表及控制 wan 访问。开着 f12 的 network 标签四处点击,几个小时之后找到下面两个 ajax,路径相对于首页

get ../api/xqnetwork/wifi_macfilter_info?model=

model 取值 0 - 黑名单和 1 - 白名单。该参数不重要,重要的是该 ajax 一定返回一个数组 flist,里面似乎是路由重置以来所有通过 wifi 连接的设备,不知道重置路由会不会清除 flist。这一下子就改变了我的思路,本来打算只在列表中显示连接的设备,现在打算显示这个完整列表,然后仅更新连接的设备了。

get ../api/xqsystem/set_mac_filter?mac=&wan=

控制 mac 访问 wan,wan 取值 0 - 关闭和 1 - 开启

drawPie

既然前面中断到了 sector,咱们看看调用 sector 的 drawPie 函数有什么信息可用。drawPie 用到的信息不是通过函数参数而是通过 this 传递的。数组 this.datas 是设备列表,每个数组元素代表一个接入设备。数组元素包含的信息少的可怜、没有 mac,没有 mac 也就无法使用前面找到的 ajax set_mac_filter。为了使用 set_mac_filter 要先搞明白是调用 drawPie 的函数就没有详细信息还是信息没有传进来,然后分别采取对策。

前面知道是那个定时发起的 ajax status 调用的 drawPie,在 network 标签查看 status 发现返回值比较详细,包含 mac

换句话说调用 drawPie 的函数有足够的信息,只是没有传进来。所以接下来不仅要修改 drawPie,还要修改 drawPie 的上游函数,让它们给 drawPie 传入更详细的信息,至少要包含设备 mac。顺着前面的调用堆栈往上找,除去不关心的加入黑盒的函数外就 4 个函数,按离 drawPie 从近到远分别是

  • PieChart.prototype.update
  • 匿名函数,该函数响应消息 chart:pie_update
  • $.pub,该函数发布包括 chart:pie_update 的一些自定义消息
  • 匿名函数,ajax status 成功后进入该函数

PieChart.prototype.update

PieChart.prototype.update = function(datas, count) {this.datas = datas;this.count = count;this.loaddone();this.getTotal();this.drawPie();this.drawCount()
}

只是把传入的 datas 加到 this 上,和 drawPie 相比没有什么有用的信息,前面知道 datas 信息太少,还得往上找

匿名函数 $.sub("chart:pie_update", function(evt, data){ ... });

这个函数信息很全,data 是 ajax status 返回的 json 对象的 dev 属性的原始内容,问题是如何修改它?

通过阅读 $.sub 的源代码

(function ($) {var o = $({});$.sub = function () { o.on.apply(o, arguments); };$.unsub = function () { o.off.apply(o, arguments); };$.pub = function () { o.trigger.apply(o, arguments); };
}(jQuery));

知道 \(.sub 通过 `\)({}).on把监听函数保存到了 sub、unsub、pub 共同捕获的局部变量 $({}) 中,外部无法访问这个局部变量也就无法替换它保存的监听函数;另一方面,调用$.sub时传入的是匿名函数,外部取不到这个函数就没法用 $.unsub 取消监听(然后用$.sub` 挂接修改后的监听函数)。所以从代码目前编写的方式看,无法修改这个匿名函数的行为,还得往上找

$.pub

这个代码其实是库代码,但既然它直接写在首页的 html 里,我们可以视情况修改它。

前面知道匿名函数 \(.sub("chart:pie_update", function(evt, data){ ... }); 的 data 参数信息很全,而该函数由 `\).pub调用,所以 $.pub 的信息也很全。当$.pub发送事件 chart:pie_update 时会调用所有用 $.sub 监听该事件的函数。查看源代码发现只有一个函数处理 chart:pie_update 事件,就是上面那个匿名函数。所以可以修改$.pub` 让它遇到 chart:pie_update 时直接调用基于上面的匿名函数修改的函数,遇到其它事件照常发送。

var oldPub = $.pub;$.pub = newPub;function newPub(type, arg) {if (type == "chart:pie_update") {// 基本上复制上面那匿名函数的内容} elseoldPub.apply(null, arguments);
}

代码段 miwifi 概述

定义一个全局变量 wifi,它里面有两个属性 get 和 post,分别代表 ajax get 和 ajax post,每个属性又有一堆方法用来发起具体的 ajax;然后运行一个匿名函数绘制前面设计的列表,具体工作是

  • 用前面收集到的 ajax 填充 wifi.get 和 wifi.post
  • 保存 $.pub
  • 使用 wifi.get.wifi_macfilter_info 获取所有通过 wifi 连接到路由器的设备列表,成功时执行另一个匿名函数

这另一个匿名函数的具体工作是

  • 在 div.routerinfo 下面添加一个 div 作为列表的容器
  • 往 document.head 追加一个 <style> 用于设置前面 div 的样式
  • 修改 PieChart.prototype.drawPie 和 $.pub,PieChart.prototype.drawPie = newDrawPie; $.pub = newPub;
  • 把从 ajax wifi_macfilter_info 得到的 flist 的所有条目逐一添加到列表
  • 监听列表条目的点击事件,点击时翻转该条目的 wan 访问能力

newPub 的大体工作前面已经说了,newDrawPie 要做两件事情

  • 像以前一样绘制饼图
  • 修改 $.pub 之后现在的 datas 里面已经包含了设备的 mac,通过 mac 查找列表中相应的条目,给找到的条目添加流量信息。从 ajax wifi_macfilter_info 生成的列表仅包含通过 wifi 连接的设备,newDrawPie 是 ajax status 成功后调用的,该调用还包含通过网线连接的设备和一个叫 other 的流量微不足道的设备的合计,需要加以处理。

效果

修改间距,添加连接时长

代码

本文代码编辑于 microsoft visual studio 2015

//
// 假设当前 url 是
// http://192.168.31.1/cgi-bin/luci/;stok=bcdeb10c02009edccb478e16585b4775/web/home
//
// get
// ../api/misystem/status                   路由状态 - 绘制饼图时
// ../api/misystem/devicelist               路由状态 - 查看终端设备时
// ../api/misystem/qos_info                 高级设置 > qos 智能限速 > 设备列表
// ../api/xqnetwork/wifi_macfilter_info     常用设置 > 安全中心 > 无线访问控制
//  model - 0,默认值,黑名单列表;1,白名单列表
// ../api/xqsystem/reboot                   重启路由器
//  client - web
// ../api/xqsystem/set_mac_filter           禁止指定的 mac 访问 wan
//  mac - encodeURIComponent(mac)
//  wan - 0,关闭 wan;1 - 开启 wan
//
// post
// ../api/xqnetwork/set_wifi
//  wifiIndex - 1,2.4G Wi-Fi;2,5G Wi-Fi;3,访客 Wi-Fi
//  on - 0,关;1,开
//  ssid - ssid,比如 wangzimei
//  pwd - 该 ssid 的密码
//  encryption - none,不使用密码
//  channel - 0,自动
//  bandwidth - 0
//  hidden - 0
//  txpwr - max
//
// http://192.168.31.1/cn/device_list_samsung.png
//
// wifi.get.wifi_macfilter_info(0, o => { o.flist.forEach(o => { console.log(o.name, o); }); });var wifi;!function () {var oldPub = $.pub,template ='<div data-mac="{$mac}" class="{$wan}" style="background-image: url({$icon});">' +"    <div>{$name}</div>" +"    <div>{$mac}</div>" +"    <div class=online></div>" +"    <div class=download-percentage></div>" +"    <div class=traffic><div class=up></div><div class=down></div></div>" +"</div>",lastPicked = $([]),deviceList;wifi = {get: {devicelist: function (f) { $.getJSON("../api/misystem/devicelist", typeof f == "function" ? f : logJson); },qos_info: function (f) { $.getJSON("../api/misystem/qos_info", typeof f == "function" ? f : logJson); },reboot: function () { $.getJSON("../api/xqsystem/reboot"); },status: function (f) { $.getJSON("../api/misystem/status", typeof f == "function" ? f : logJson); },wifi_macfilter_info: function (model, f) { $.getJSON("../api/xqnetwork/wifi_macfilter_info", { model: model }, typeof f == "function" ? f : logJson); }},post: {set_wifi: function (on, i, ssid) {$.post("../api/xqnetwork/set_wifi", {on: on ? 1 : 0,wifiIndex: i || 1,ssid: ssid || "wangzimei",encryption: "none"});}}};wifi.get.wifi_macfilter_info(0, function (o) {var flist = o.flist,s = "",i, len;PieChart.prototype.drawPie = newDrawPie;$.pub = newPub;$("#piecharttable").html("");$(".new-device-list-css").length || $(document.head).append("<style class=new-device-list-css>" +"    .new-device-list .busy { background-color: salmon; }\n" +"    .new-device-list .download-percentage { width: 5em; }\n" +"    .new-device-list .no-wan { text-decoration: line-through; }\n" +"    .new-device-list .online { width: 10em; }\n" +"    .new-device-list .traffic { width: 15em; }\n" +"    .new-device-list .traffic > div { line-height: 40px; }\n" +"    .new-device-list > div { background-position: left center; background-repeat: no-repeat; background-size: 60px; display: flex; line-height: 80px; text-align: right; transition: background-color 0.5s ease; }\n" +"    .new-device-list > div > :nth-child(1) { width: 20em; }\n" +"    .new-device-list > div > :nth-child(2) { width: 10em; }\n" +"</style>");$(".new-device-list").remove();$("<div class=new-device-list></div>").insertAfter(".routerinfo");deviceList = $(".new-device-list");for (i = 0, len = flist.length; i < len; ++i)s += StringH.tmpl(template, {mac: flist[i].mac,wan: flist[i].authority.wan ? "" : "no-wan",name: escapeHtml(flist[i].name),icon: flist[i].company.icon ? "/cn/" + flist[i].company.icon : "/img/device_list_unknow.png"});deviceList.html(s);deviceList.on("click", "[data-mac]", onClickDevice);});function logJson(json) { console.log(json); }function onClickDevice() {var t = $(this);if (!t.hasClass("busy")) {t.addClass("busy");$.getJSON("../api/xqsystem/set_mac_filter", { mac: t.attr("data-mac"), wan: t.hasClass("no-wan") ? 1 : 0 }).done(function (json) { json.code || t.toggleClass("no-wan"); }).always(function () { t.removeClass("busy"); });}}function newPub(type, arg) {var dev, colorMap, total, i, len, value, bf;if (type == "chart:pie_update") {dev = arg.devStatistics;colorMap = ["#33cc33", "#2673bf", "#ffaa00", "#ff6600", "#d96cb5", "#00baff", "#ff4060", "#00d990", "#d96cca", "#ff4400"];total = 0;for (i = 0, len = dev.length; i < len; ++i) {value = parseInt(dev[i].download, 10);dev[i].value = value;dev[i].value2 = parseInt(dev[i].downspeed, 10);dev[i].color = colorMap[i];total += value;}bf = byteFormat(total, 10, true);$.pieChart.update(dev, {value: bf[0],label: bf[1]});} elseoldPub.apply(null, arguments);}function newDrawPie() {var r = this.r - 2,angle = 0,start = 0,currentPicked = [],i, len, angleplus, pie, o, div;lastPicked.css("color", "");lastPicked.find(".online").text("");lastPicked.find(".download-percentage").text("");lastPicked.find(".up").text("");lastPicked.find(".down").text("");for (i = 0, len = this.datas.length; i < len; ++i) {o = this.datas[i];o.color || (o.color = Raphael.hsb(start, 0.8, 0.9)),angleplus = 360 * o.value / this.total,pie = sector(this.paper, this.rad, this.cx, this.cy, r, angle, angle + angleplus, {fill: o.color,stroke: this.stroke,"stroke-width": 0});angle += angleplus;start += 0.1;pie.id = "pie_" + i;this.chart.push(pie);div = deviceList.find('[data-mac="' + o.mac + '"]');if (!div.length) {o.icon = "/img/device_list_unknow.png";div = $(StringH.tmpl(template, o));div.children(":first-child").text(o.devname);}div.css("color", o.color);div.find(".online").text($.secondToDate(o.online));div.find(".download-percentage").text((this.total ? (o.value / this.total * 100).toFixed(1) : 0) + "%");div.find(".up").text(byteFormat(o.upspeed) + "/S - " + byteFormat(o.upload));div.find(".down").text(byteFormat(o.downspeed) + "/S - " + byteFormat(o.download));currentPicked.push(div[0]);}lastPicked = $(currentPicked);deviceList.prepend(lastPicked);}function sector(paper, rad, cx, cy, r, startAngle, endAngle, params) {var x1 = cx + r * Math.cos(-startAngle * rad),x2 = cx + r * Math.cos(-endAngle * rad),y1 = cy + r * Math.sin(-startAngle * rad),y2 = cy + r * Math.sin(-endAngle * rad);return endAngle - startAngle == 360 ?paper.circle(cx, cy, r).attr(params) :paper.path(["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2, "z"]).attr(params);}// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jqueryfunction escapeHtml(s) {var entityMap = {"&": "&amp;","<": "&lt;",">": "&gt;",'"': "&quot;","'": "'","/": "/"};return s.replace(/[&<>"'\/]/g, function (str) {return entityMap[str];});}
}();// 关于路由器密码
// 路由器密码和 mac 地址差不多,都是客户向路由器提交一个字符串,路由器查表以确定是否接受连接,密码可以泄露,mac 也可以伪造。
//
// 关于小米路由器
// 优点:
//  便宜
//  可以禁止设备访问外网
//  获取设备型号
// 缺点:
//  ajax 速度很慢
//  动不动就要重启路由器,重启路由器尤其慢
//  很难找在哪设置某项内容
//  mac 地址只能用冒号分隔
//  不知道在哪看日志,只看到有个上传日志的按钮
//  即使从白名单删除了设备,设备列表里面仍然是以前自己指定的名字,无法查看设备原来的名字
//  /img/device_list_err.png、/img/device_list_unknow.png 和其它设备图标路径不一样,并缺少下列图片
//      /cn/device_list_google.png
//      /cn/device_list_vivo.png
//      /cn/device_list_windows.png
// 不明觉厉的功能:
//  我 1 个朋友 1 年多前来我家,此后再没来过。当时我把他苹果手机的 mac 加入以前的路由器白名单了。前段时间换路由,
//  把白名单拷贝到这个小米中,当时没注意,过两天发现这个白名单条目关联的图标是苹果。小米能根据 mac 判断手机型号?
//
// 360免费wifi的原理是什么?有无窃取手机记录的wifi数据?
// http://www.zhihu.com/question/27065773/answer/35111715
//
// 如何看待小米路由进行 404 网页劫持?
// http://www.zhihu.com/question/30358197
//
// 小米路由器劫持用户浏览器事件回顾
// http://drops.wooyun.org/tips/6820
//
// 小米路由器先劫持 http 错误码, 现在又在部分网站添加小尾巴, 什么节奏?
// https://www.v2ex.com/t/199701

使用

打开 192.168.31.1 登录 > 按 f12 > 转到 sources 标签 > 选 snippets > 右键 new > 输入文件名比如 miwifi > 把上面的代码粘贴到打开的文件内 > 保存 > 右键文件名 > run

转载于:https://www.cnblogs.com/w-zm/p/customize-miwifi-admin-page.html

自定义小米路由器管理页面相关推荐

  1. 小米云服务器怎么管理员密码,小米路由器管理密码怎么设置 小米路由器管理密码设置介绍【图文】...

    路由器产品已经成为我们的实际生活中必不可缺的重要工具之一了,而且针对旗下林林总总的产品,包括品牌以及具体的型号板块都为消费者提供了多种多样的选择,那么对于我们自己而言,就比较倾向于选择知名的大品牌旗下 ...

  2. 路由器管理页面html,196.168.1.1登陆页面网址

    196.168.1.1手机怎么登陆? 解决方法如下: 1.路由器设置网址是192.168.1.1,而非196.168.1.1,故此无法登陆原因是网址输入错误. 2.在手机端浏览器输入网址192.168 ...

  3. 热点登陆打不开网页 服务器已关闭,手机登录路由器管理页面打不开怎么办?...

    问:由于我家里没有电脑,因此我想手机来设置我的路由器,但是我在手机上打不开路由器的管理页面,我应该怎么办? 答:手机设置路由器的时候,如果打不开路由器的管理页面,请按照下面的步骤进行操作. 解决办法: ...

  4. 水星路由器登录界面找不到服务器,水星路由器管理页面怎么登陆不进去? | 192路由网...

    正在情况下,在浏览器中输入melogin.cn,就可以进入水星路由器的管理页面.如果在浏览器中输入melogin.cn后,无法进入水星路由器的管理页面,请按照下面的步骤进行操作. 注意: 如果你在浏览 ...

  5. dvwa页面打不开的原因_路由器管理页面打不开怎么办? | 192路由网

    如果打不开路由器的管理页面,就无法对路由器进行设置,这非常的糟糕. 为了帮助大家解决这个问题,鸿哥特意整理了这篇文章,来详细的介绍路由器管理页面打不开的解决办法,请按照下面的步骤进行操作. 1. 你的 ...

  6. 网站荣耀服务器ip,华为荣耀路由器管理页面IP地址是多少

    华为路由器还有荣耀路由器都是华为旗下的产品,Web管理页面网址都是192.168.3.1 当手机.或者电脑成功连上路由器Wi-Fi或有线网络时,在浏览器输入此网址就可以进入管理页面. Web管理页面主 ...

  7. 网站荣耀服务器ip,华为荣耀路由器管理页面IP地址是多少(2)

    1.确认电脑正确连接路由LAN口. 2.打开电脑 本地网络和共享中心 > 本地连接 >属性 > Internet协议版本4(TCP/IPv4)> 属性 >自动获取IP地址 ...

  8. 使用FRP远程访问TP-LINK路由器管理页面

    文章目录 1. 问题发现 2. 解决方案 3. 参考文章 1. 问题发现 FRP 客户端使用如下配置 [TP-LINK-login] type = tcp local_ip = tplogin.cn ...

  9. 解决无法登录路由器管理页面的问题

    之前保存了登录路由器的网站,后来修改了ip地址后没有办法登录了,按照百度的教成把ip地址修改成了动态获取,但是依然没有解决. 后来尝试直接百度ip, 有那种可以查询ip地址的网站,然后复制ip地址后搜 ...

最新文章

  1. 利用 VMWare 搭建随机拓扑网络
  2. 触手可得的云原生 | 阿里云中间件发布多项新功能
  3. 第44节:Java当中的JVM
  4. (转载)简单linux C++内存池
  5. AutoCAD VBA对齐对象
  6. 深入体验JavaWeb开发内幕——简述JSP中的自定义标签叫你快速学会
  7. OK335x mksd.sh hacking
  8. UIWebView 无缝切换到 WKWebView
  9. 结巴分词代码java_java版结巴分词工具
  10. modelica语言学习心得
  11. PVR个人视频录像机 - XBMC 12.0(Frodo)新功能
  12. wps怎么把xlsx转成html,怎样把wps转换成excel
  13. 微信小程序 保存图片 wx.saveImageToPhotosAlbum
  14. 【开源库分享】雷电模拟器自动化操作库 C#版本
  15. JavaSwing_2.8: JTextArea(文本区域)
  16. 先行一步,7大技术创新和突破,阿里云把 Serverless 领域的这些难题都给解了
  17. 逆向笔记 | 破解极域学生端密码并实现窗口化屏幕广播
  18. 5G-NR通信标准介绍
  19. 手机看家监控摄像头怎么连接手机
  20. 不思量,自难忘:我的10年程序生涯

热门文章

  1. 计算机组成原理之控制器
  2. 使用ADB命令抓取手机日志——crash等无响应操作(adb bugreport > bugreport.txt 或 adb logcat -> F:/logcat.txt)
  3. i9-10885H 怎么样 相当于什么水平
  4. 国产NTFS 磁盘读写工具 - Omi NTFS磁盘专家 for Mac
  5. 关于verilog实例化的介绍
  6. 大佬说:怎么手写一个Tomcat然后给这个Tomcat 部署项目并且成功处理请求 ? 我TM当时就吓尿了!
  7. 阿里程序员:入职才两个月,我决定离职
  8. 一本好的PHP自学书籍-和我一起轻松学习PHP,推荐给你
  9. vue项目如何在data里调用methods中的方法
  10. 用ImageBuilder定制自己的openwrt路由器