From 3fc57f2c6b0e5c003ea3b64a89158624eda96e82 Mon Sep 17 00:00:00 2001 From: CN_SZTL Date: Fri, 19 Feb 2021 17:18:45 +0800 Subject: [PATCH] luci-app-wrtbwmon: rollback to old version Signed-off-by: CN_SZTL --- CONTRIBUTED.md | 4 +- package/ctcgfw/luci-app-wrtbwmon/Makefile | 23 - .../luci-app-wrtbwmon/etc/config/wrtbwmon | 5 - .../etc/hotplug.d/iface/99-wrtbwmon | 9 - .../luci-app-wrtbwmon/etc/init.d/wrtbwmon | 44 -- .../luasrc/controller/wrtbwmon.lua | 20 - .../luasrc/model/cbi/wrtbwmon/config.lua | 48 -- .../luasrc/view/wrtbwmon.htm | 579 ------------------ .../luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po | 152 ----- .../root/etc/uci-defaults/luci-wrtbwmon | 11 - .../luci-app-wrtbwmon/usr/sbin/readDB.awk | 213 ------- .../luci-app-wrtbwmon/usr/sbin/wrtbwmon | 460 -------------- .../usr/share/wrtbwmon/usage.htm1 | 34 - .../usr/share/wrtbwmon/usage.htm2 | 18 - package/lean/luci-app-wrtbwmon/Makefile | 17 + .../htdocs/luci-static/wrtbwmon.js | 562 +++++++++++++++++ .../luasrc/controller/wrtbwmon.lua | 43 ++ .../luasrc/model/cbi/wrtbwmon/config.lua | 18 + .../luasrc/model/cbi/wrtbwmon/custom.lua | 7 +- .../luasrc/view/wrtbwmon.htm | 46 ++ .../luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po | 56 ++ .../root/etc/config/wrtbwmon | 4 + .../root/etc/init.d/wrtbwmon | 22 + .../root/etc/uci-defaults/luci-wrtbwmon | 14 + .../root/etc/wrtbwmon.include | 1 + .../root/usr/sbin/readDB.awk | 157 +++++ .../luci-app-wrtbwmon/root/usr/sbin/wrtbwmon | 301 +++++++++ .../root/usr/share/wrtbwmon/usage.htm1 | 23 + .../root/usr/share/wrtbwmon/usage.htm2 | 14 + 29 files changed, 1281 insertions(+), 1624 deletions(-) delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/Makefile delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/etc/config/wrtbwmon delete mode 100755 package/ctcgfw/luci-app-wrtbwmon/etc/hotplug.d/iface/99-wrtbwmon delete mode 100755 package/ctcgfw/luci-app-wrtbwmon/etc/init.d/wrtbwmon delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po delete mode 100755 package/ctcgfw/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon delete mode 100755 package/ctcgfw/luci-app-wrtbwmon/usr/sbin/readDB.awk delete mode 100755 package/ctcgfw/luci-app-wrtbwmon/usr/sbin/wrtbwmon delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/usr/share/wrtbwmon/usage.htm1 delete mode 100644 package/ctcgfw/luci-app-wrtbwmon/usr/share/wrtbwmon/usage.htm2 create mode 100644 package/lean/luci-app-wrtbwmon/Makefile create mode 100644 package/lean/luci-app-wrtbwmon/htdocs/luci-static/wrtbwmon.js create mode 100644 package/lean/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua create mode 100644 package/lean/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua rename package/{ctcgfw => lean}/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/custom.lua (69%) create mode 100644 package/lean/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm create mode 100644 package/lean/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po create mode 100644 package/lean/luci-app-wrtbwmon/root/etc/config/wrtbwmon create mode 100755 package/lean/luci-app-wrtbwmon/root/etc/init.d/wrtbwmon create mode 100755 package/lean/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon create mode 100755 package/lean/luci-app-wrtbwmon/root/etc/wrtbwmon.include create mode 100755 package/lean/luci-app-wrtbwmon/root/usr/sbin/readDB.awk create mode 100755 package/lean/luci-app-wrtbwmon/root/usr/sbin/wrtbwmon create mode 100644 package/lean/luci-app-wrtbwmon/root/usr/share/wrtbwmon/usage.htm1 create mode 100644 package/lean/luci-app-wrtbwmon/root/usr/share/wrtbwmon/usage.htm2 diff --git a/CONTRIBUTED.md b/CONTRIBUTED.md index 8bd938af44..2af7aa017f 100644 --- a/CONTRIBUTED.md +++ b/CONTRIBUTED.md @@ -60,9 +60,7 @@ luci-app-beardropper source: [NateLol/natelol](https://github.com/NateLol/natelo luci-app-vssr source: [jerrykuku/luci-app-vssr](https://github.com/jerrykuku/luci-app-vssr).
luci-proto-modemmanager source: [nickberry17/luci-proto-modemmanager](https://github.com/nickberry17/luci-proto-modemmanager).
luci-theme-infinityfreedom source: [xiaoqingfengATGH/luci-theme-infinityfreedom](https://github.com/xiaoqingfengATGH/luci-theme-infinityfreedom).
-luci-proto-minieap source: [ysc3839/luci-proto-minieap](https://github.com/ysc3839/luci-proto-minieap).
-wrtbwmon source: [brvphoenix/wrtbwmon](https://github.com/brvphoenix/wrtbwmon).
-luci-app-wrtbwmon source: [brvphoenix/luci-app-wrtbwmon](https://github.com/brvphoenix/luci-app-wrtbwmon). +luci-proto-minieap source: [ysc3839/luci-proto-minieap](https://github.com/ysc3839/luci-proto-minieap). ## License ### Depend on their own License. diff --git a/package/ctcgfw/luci-app-wrtbwmon/Makefile b/package/ctcgfw/luci-app-wrtbwmon/Makefile deleted file mode 100644 index 4f6f2cec83..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (C) 2021 Van Waholtz -# -# This is free software, licensed under the Apache License, Version 2.0. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=luci-app-wrtbwmon -PKG_VERSION:=1.6.3 -PKG_RELEASE:=1 - -PKG_LICENSE:=Apache-2.0 -PKG_MAINTAINER:=Van Waholtz - -LUCI_TITLE:=A Luci module that uses wrtbwmon to track bandwidth usage -LUCI_DEPENDS:=+@BUSYBOX_CONFIG_IP +iptables -LUCI_PKGARCH:=all - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/package/ctcgfw/luci-app-wrtbwmon/etc/config/wrtbwmon b/package/ctcgfw/luci-app-wrtbwmon/etc/config/wrtbwmon deleted file mode 100644 index da9470a111..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/etc/config/wrtbwmon +++ /dev/null @@ -1,5 +0,0 @@ - -config wrtbwmon 'general' - option enabled '1' - option path '/tmp/usage.db' - diff --git a/package/ctcgfw/luci-app-wrtbwmon/etc/hotplug.d/iface/99-wrtbwmon b/package/ctcgfw/luci-app-wrtbwmon/etc/hotplug.d/iface/99-wrtbwmon deleted file mode 100755 index 41b49a4a20..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/etc/hotplug.d/iface/99-wrtbwmon +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -[ "$ACTION" = ifup -o "$ACTION" = ifupdate ] || exit 0 -[ "$ACTION" = ifupdate -a -z "$IFUPDATE_ADDRESSES" -a -z "$IFUPDATE_DATA" ] && exit 0 - -/etc/init.d/wrtbwmon restart - -logger -t wrtbwmon "Restart for $ACTION of $INTERFACE ($DEVICE)" - diff --git a/package/ctcgfw/luci-app-wrtbwmon/etc/init.d/wrtbwmon b/package/ctcgfw/luci-app-wrtbwmon/etc/init.d/wrtbwmon deleted file mode 100755 index 1c3213ee17..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/etc/init.d/wrtbwmon +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2019 OpenWrt.org - -START=99 -USE_PROCD=1 - -NAME=wrtbwmon -PID_FILE=/var/run/wrtbwmon.pid -args=/usr/sbin/wrtbwmon - -create_instance() { - procd_open_instance - procd_set_param command $args - procd_set_param respawn - procd_set_param user root -# procd_set_param pidfile $PID_FILE - procd_close_instance -} - -service_triggers() -{ - procd_add_reload_trigger "$NAME" -} - -start_service() { - local db enabled - config_load $NAME - - config_get db general path - [ -z "$db" ] && db="/tmp/usage.db" - append args " -46" - append args "-f $db" - append args "-p /tmp/usage.htm" - append args "-u /etc/wrtbwmon.user" - append args "-d" - - config_get enabled general enabled - [ "$enabled"0 -eq 0 ] || create_instance -} - -stop_service() { - procd_kill wrtbwmon - kill -CONT $(cat $PID_FILE) -} diff --git a/package/ctcgfw/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua b/package/ctcgfw/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua deleted file mode 100644 index 20f254cae6..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua +++ /dev/null @@ -1,20 +0,0 @@ -module("luci.controller.wrtbwmon", package.seeall) - -function index() - if not nixio.fs.access("/etc/config/wrtbwmon") then - return - end - entry({"admin", "network", "usage"}, - alias("admin", "network", "usage", "details"), - _("Traffic Status"), 60) - entry({"admin", "network", "usage", "details"}, - template("wrtbwmon"), - _("Details"), 10).leaf=true - entry({"admin", "network", "usage", "config"}, - arcombine(cbi("wrtbwmon/config")), - _("Configuration"), 20).leaf=true - entry({"admin", "network", "usage", "custom"}, - form("wrtbwmon/custom"), - _("User file"), 30).leaf=true -end - diff --git a/package/ctcgfw/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua b/package/ctcgfw/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua deleted file mode 100644 index 6b3555e451..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua +++ /dev/null @@ -1,48 +0,0 @@ -local lastvalue -local cursor = luci.model.uci.cursor() -local m, s, o -m = Map("wrtbwmon", translate("Usage - Configuration")) - -s = m:section(NamedSection, "general", "wrtbwmon", translate("General settings")) - -o = s:option(Flag, "enabled", translate("Enabled")) -o.rmempty= true - -o = s:option(Value, "path", translate("Database Path"), - translate("This box is used to select the Database path, " - .. "which is /tmp/usage.db by default.")) -o:value("/tmp/usage.db") -o:value("/etc/usage.db") -o.rmempty= false - -function m.on_parse(self) - lastvalue = cursor:get("wrtbwmon", "general", "path") -end - -function o.write(self,section,value) - local fpath = nixio.fs.dirname(value) .. "/" - - if not nixio.fs.access(fpath) then - if not nixio.fs.mkdirr(fpath) then - return Value.write(self, section, lastvalue) - end - end - - io.popen("/etc/init.d/wrtbwmon stop") - io.popen("mv -f " .. fileRename(lastvalue, "*") .. " ".. fpath) - Value.write(self,section,value) - io.popen("/etc/init.d/wrtbwmon start") - - return true -end - -function fileRename(fileName, tag) - local idx = fileName:match(".+()%.%w+$") - if(idx) then - return fileName:sub(1, idx-1) .. tag .. fileName:sub(idx, -1) - else - return fileName .. tag - end -end - -return m diff --git a/package/ctcgfw/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm b/package/ctcgfw/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm deleted file mode 100644 index b78e0e86fc..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm +++ /dev/null @@ -1,579 +0,0 @@ -<%# - Licensed to the public under the Apache License 2.0. --%> - -<% - local fs = require "nixio.fs" - local stat = require "luci.tools.status" - local dba = luci.model.uci.cursor():get("wrtbwmon", "general", "path") - --- Function to generate table from string. - local function strToTable(str) - local tb = {} - local cmd = nil - setmetatable(tb, {__index = table.insert}) - str:gsub("[^%s,]+", tb) - tb.__index = nil - return tb - end - --- Function to update the mac-hostname table. - local function getmactable(family) - local mactable = {} - local leases = (family == 4 and {stat.dhcp_leases()} or {stat.dhcp6_leases()})[1] - - if fs.access("/etc/wrtbwmon.user") then - for line in io.lines("/etc/wrtbwmon.user") do - local macpair = strToTable(line) - mactable[macpair[1]:lower()] = macpair[2] - end - end - - for _, line in pairs(leases) do - if line.macaddr and not mactable[line.macaddr:lower()] then - mactable[line.macaddr:lower()] = line.hostname - end - end - - return mactable - end - --- Rename the db file for ipv6. - local function fileRename(fn, tag) - local idx = fn:match(".+()%.%w+$") - if(idx) then - return fn:sub(1, idx-1) .. tag .. fn:sub(idx, -1) - else - return fn .. tag - end - end - - local function procressData(db, family) - local dbc = (family == 6 and {fileRename(db, ".6")} or {db})[1] - local cmd_setup = "/etc/init.d/wrtbwmon restart" - local cmd_update = "wrtbwmon -" .. family .. " -f " .. db .. " >>/dev/null 2>&1" - local data, total, mactable, firstline = {}, {0.0, 0.0, 0.0, 0.0, 0.0}, getmactable(family), true - local isshow = luci.http.formvalue("isShow") - --- Setup the background update process. - if not fs.access("/var/run/wrtbwmon.pid") then - io.popen(cmd_setup) - else - io.popen(cmd_update) - end - --- Process the database. - for line in io.lines(dbc) do - if firstline then - firstline = false - else - local tbl = strToTable(line) - if isshow == "1" or tbl[8] ~= "0" then - tbl[1] = tbl[1]:lower() - - if mactable[tbl[1]] then - tbl[3] = mactable[tbl[1]] - else - tbl[3] = tbl[1] - end - - for i = 1,#total do - total[i] = total[i] + (tbl[i+3] .. ".0") - end - - data[#data+1] = {tbl[3], tbl[1], unpack(tbl, 4)} - table.insert(data[#data], tbl[2]) - end - end - end - --- Transfer the database to js. - luci.http.prepare_content("application/json") - luci.http.write_json({data, total}) - return - end - - if luci.http.formvalue("proto") == "ipv4" then - procressData(dba, 4) - return - elseif luci.http.formvalue("proto") == "ipv6" then - procressData(dba, 6) - return - end - - if luci.http.formvalue("reset") == "1" then - os.execute("ip -4 neigh flush dev br-lan && ip -6 neigh flush dev br-lan") - os.execute("rm -f " .. fileRename(dba, "*") .. " && wrtbwmon -46 -f " .. dba .. " >>/dev/null 2>&1") - luci.http.status(200, "OK") - return - end --%> - -<%+header%> - - - -
-

<%:Usage - Details%>

- -
-
-
-
-
- -
-
-
- -
-
- -
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
- -
-
-
-
-
-
-
- - -
-
-
- -
-
<%:downflow:%>
-
<%:upflow:%>
-
- -
-
-
<%:Clients%>
-
<%:MAC%>
-
<%:Download%>
-
<%:Upload%>
-
<%:Total Down%>
-
<%:Total Up%>
-
<%:Total%>
-
<%:First Seen%>
-
<%:Last Seen%>
-
-
-
<%:Collecting data...%>
-
-
-
-
- - - - -<%+footer%> diff --git a/package/ctcgfw/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po b/package/ctcgfw/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po deleted file mode 100644 index 02033745c8..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po +++ /dev/null @@ -1,152 +0,0 @@ -msgid "Traffic Status" -msgstr "流量监控" - -msgid "Usage - Configuration" -msgstr "文件设置" - -msgid "Details" -msgstr "流量信息" - -msgid "Configuration" -msgstr "设置" - -msgid "User file" -msgstr "用户文件" - -msgid "General settings" -msgstr "通用设置" - -msgid "Wrtbwmon is a mointor of the traffic usage." -msgstr "Wrtbwmon是一个流量监控器" - -msgid "This box is used to select the Database path, which is /tmp/usage.db by default." -msgstr "该选项用于选择数据存储路径,默认路径为/tmp/usage.db。" - -msgid "This box is used to set the total bandwidth (Byte/s), which is 1000000Byte/s by default." -msgstr "该选项用于选设置总的带宽(Byte/s),默认带宽值1000000Byte/s。" - -msgid "Usage - Custom User File" -msgstr "用户文件配置" - -msgid "This file is used to match users with MAC addresses. Each line must have the following format: \"00:aa:bb:cc:ee:ff,username\"." -msgstr "该文件用来进行MAC和主机进行匹配。每行必须满足\"00:aa:bb:cc:ee:ff,用户名\"的格式" - -msgid "Usage - Details" -msgstr "流量详情" - -msgid "downflow:" -msgstr "下行:" - -msgid "upflow:" -msgstr "上行:" - -msgid "protocol:" -msgstr "协议:" - -msgid "Reset Database" -msgstr "重置" - -msgid "Auto update every" -msgstr "自动刷新" - -msgid "Database Path" -msgstr "数据存储位置" - -msgid "Show Zeros:" -msgstr "显示0流量:" - -msgid "Show More:" -msgstr "显示更多:" - -msgid "bandwidth:" -msgstr "带宽:" - -msgid "Calculate per host totals" -msgstr "单主机总流量统计" - -msgid "Disabled" -msgstr "禁用" - -msgid "1 second" -msgstr "1秒" - -msgid "2 seconds" -msgstr "2秒" - -msgid "5 seconds" -msgstr "5秒" - -msgid "10 seconds" -msgstr "10秒" - -msgid "20 seconds" -msgstr "20秒" - -msgid "30 seconds" -msgstr "30秒" - -msgid "40 seconds" -msgstr "40秒" - -msgid "50 seconds" -msgstr "50秒" - -msgid "60 seconds" -msgstr "60秒" - -msgid "2 minutes" -msgstr "2分" - -msgid "3 minutes" -msgstr "3分" - -msgid "Loading..." -msgstr "数据载入中" - -msgid "Clients" -msgstr "客户端" - -msgid "MAC Address" -msgstr "MAC地址" - -msgid "Download" -msgstr "下载" - -msgid "Upload" -msgstr "上传" - -msgid "Total Down" -msgstr "总下载" - -msgid "Total Up" -msgstr "总上传" - -msgid "Total" -msgstr "总计" - -msgid "First Seen" -msgstr "初次记录" - -msgid "Last Seen" -msgstr "最后记录" - -msgid "TOTAL" -msgstr "总共" - -msgid "Last updated" -msgstr "最后更新于" - -msgid "This will delete the database file. Are you sure?" -msgstr "该操作将删除数据统计文件,确定执行该操作?" - -msgid "Updating again in" -msgstr "下次更新将于" - -msgid "seconds." -msgstr "秒以后。" - -msgid "wrtbwmon is not installed!" -msgstr "wrtbwmon插件尚未安装" - -msgid "." -msgstr "。" diff --git a/package/ctcgfw/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon b/package/ctcgfw/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon deleted file mode 100755 index 97ada9bccd..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -uci -q batch <<-EOF >/dev/null - delete ucitrack.@wrtbwmon[-1] - add ucitrack wrtbwmon - set ucitrack.@wrtbwmon[-1].init=wrtbwmon - commit ucitrack -EOF - -rm -f /tmp/luci-indexcache -exit 0 diff --git a/package/ctcgfw/luci-app-wrtbwmon/usr/sbin/readDB.awk b/package/ctcgfw/luci-app-wrtbwmon/usr/sbin/readDB.awk deleted file mode 100755 index 2080fe5f79..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/usr/sbin/readDB.awk +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/awk - -function inInterfaces(host) { - return(interfaces ~ "(^| )" host "($| )") -} - -function newRule(arp_ip, ipt_cmd) { - # checking for existing rules shouldn't be necessary if newRule is - # always called after db is read, arp table is read, and existing - # iptables rules are read. - ipt_cmd=iptKey " -t mangle -j RETURN -s " arp_ip - system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD") - ipt_cmd=iptKey " -t mangle -j RETURN -d " arp_ip - system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD") -} - -function delRule(arp_ip, ipt_cmd) { - ipt_cmd=iptKey " -t mangle -D RRDIPT_FORWARD -j RETURN " - system(ipt_cmd "-s " arp_ip " 2>/dev/null") - system(ipt_cmd "-d " arp_ip " 2>/dev/null") -} - -function total(i) { - return(bw[i "/in"] + bw[i "/out"]) -} - -BEGIN { - if (ipv6) { - iptNF = 8 - iptKey = "ip6tables" - } else { - iptNF = 9 - iptKey = "iptables" - } -} - -/^#/ { # get DB filename - FS = "," - dbFile = FILENAME - next -} - -# data from database; first file -ARGIND==1 { #!@todo this doesn't help if the DB file is empty. - lb=$1 - - if (lb !~ "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$") next - - if (!(lb in mac)) { - mac[lb] = $1 - ip[lb] = $2 - inter[lb] = $3 - speed[lb "/in"] = 0 - speed[lb "/out"]= 0 - bw[lb "/in"] = $6 - bw[lb "/out"] = $7 - firstDate[lb] = $9 - lastDate[lb] = $10 - ignore[lb] = 1 - } else { - if ($9 < firstDate[lb]) - firstDate[lb] = $9 - if ($10 > lastDate[lb]) { - ip[lb] = $2 - inter[lb] = $3 - lastDate[lb] = $10 - } - bw[lb "/in"] += $6 - bw[lb "/out"] += $7 - ignore[lb] = 0 - } - next -} - -# not triggered on the first file -FNR==1 { - FS=" " - if(ARGIND == 2) next -} - -# arp: ip hw flags hw_addr mask device -ARGIND==2 { - #!@todo regex match IPs and MACs for sanity - if (ipv6) { - statFlag= ($4 != "FAILED" && $4 != "INCOMPLETE") - macAddr = $5 - hwIF = $3 - } else { - statFlag= ($3 != "0x0") - macAddr = $4 - hwIF = $6 - } - - lb=$1 - if (hwIF != wanIF && statFlag && macAddr ~ "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$") { - hosts[lb] = 1 - arp_mac[lb] = macAddr - arp_ip[lb] = $1 - arp_inter[lb] = hwIF - arp_bw[lb "/in"] = 0 - arp_bw[lb "/out"] = 0 - arp_firstDate[lb] = systime() - arp_lastDate[lb] = arp_firstDate[lb] - arp_ignore[lb] = 1 - } - next -} - -#!@todo could use mangle chain totals or tailing "unnact" rules to -# account for data for new hosts from their first presence on the -# network to rule creation. The "unnact" rules would have to be -# maintained at the end of the list, and new rules would be inserted -# at the top. -ARGIND==3 && NF==iptNF && $1!="pkts" { # iptables input - if (ipv6) { - lfn = 5 - tag = "::/0" - } else { - lfn = 6 - tag = "0.0.0.0/0" - } - - if ($(lfn) != "*") { - m = $(lfn) - n = m "/in" - } else if ($(++lfn) != "*") { - m = $(lfn) - n = m "/out" - } else if ($(++lfn) != tag) { - m = $(lfn) - n = m "/out" - } else { # $(++lfn) != tag - m = $(++lfn) - n = m "/in" - } - - if (mode == "diff" || mode == "noUpdate") print n, $2 - if (mode != "noUpdate") { - if (inInterfaces(m)) { # if label is an interface - if (!(m in arp_mac)) { - cmd = "cat /sys/class/net/" m "/address" - cmd | getline arp_mac[m] - close(cmd) - - if (length(arp_mac[m]) == 0) arp_mac[m] = "00:00:00:00:00:00" - - arp_ip[m] = "NA" - arp_inter[m] = m - arp_bw[m "/in"] = 0 - arp_bw[m "/out"] = 0 - arp_firstDate[m] = systime() - arp_lastDate[m] = arp_firstDate[m] - arp_ignore[lb] = 1 - } - } else { - if (!(m in arp_mac)) hosts[m] = 0 - else delete hosts[m] - } - - if ($2 > 0) { - arp_bw[n] = $2 - arp_lastDate[m] = systime() - arp_ignore[m] = 0 - } - } -} - -END { - if (mode == "noUpdate") exit - - for (i in arp_ip) { - lb = arp_mac[i] - if (!arp_ignore[i] || !(lb in mac)) { - ignore[lb] = 0 - - if (lb in mac) { - bw[lb "/in"] += arp_bw[i "/in"] - bw[lb "/out"] += arp_bw[i "/out"] - lastDate[lb] = arp_lastDate[i] - } else { - bw[lb "/in"] = arp_bw[i "/in"] - bw[lb "/out"] = arp_bw[i "/out"] - firstDate[lb] = arp_firstDate[i] - lastDate[lb] = arp_lastDate[i] - } - mac[lb] = arp_mac[i] - ip[lb] = arp_ip[i] - inter[lb] = arp_inter[i] - - if (interval != 0) { - speed[lb "/in"] = int(arp_bw[i "/in"] / interval) - speed[lb "/out"]= int(arp_bw[i "/out"] / interval) - } - } - } - - close(dbFile) - for (i in mac) { - if (!ignore[i]) { - print "#mac,ip,iface,speed_in,speed_out,in,out,total,first_date,last_date" > dbFile - OFS="," - for (i in mac) - print mac[i], ip[i], inter[i], speed[i "/in"], speed[i "/out"], bw[i "/in"], bw[i "/out"], total(i), firstDate[i], lastDate[i] > dbFile - close(dbFile) - break - } - } - - # for hosts without rules - for (i in hosts) - if (hosts[i]) newRule(i) - else delRule(i) -} diff --git a/package/ctcgfw/luci-app-wrtbwmon/usr/sbin/wrtbwmon b/package/ctcgfw/luci-app-wrtbwmon/usr/sbin/wrtbwmon deleted file mode 100755 index 91089a1eee..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/usr/sbin/wrtbwmon +++ /dev/null @@ -1,460 +0,0 @@ -#!/bin/sh -# - -# Default input parameters for wrtbwmon. -runMode=0 -Monitor46=4 - -# Some parameters for monitor process. -for46= -updatePID= -logFile=/var/log/wrtbwmon.log -lockFile=/var/lock/wrtbwmon.lock -pidFile=/var/run/wrtbwmon.pid -tmpDir=/var/tmp/wrtbwmon -interval4=0 -interval6=0 - -# Debug parameters for readDB.awk. -mode= -DEBUG= - -# Constant parameter for wrtbwmon. -binDir=/usr/sbin -dataDir=/usr/share/wrtbwmon - -networkFuncs=/lib/functions/network.sh -uci=`which uci 2>/dev/null` -nslookup=`which nslookup 2>/dev/null` -nvram=`which nvram 2>/dev/null` - -chains='INPUT OUTPUT FORWARD' -interfaces='eth0 tun0 br-lan' # in addition to detected WAN - -# DNS server for reverse lookups provided in "DNS". -# don't perform reverse DNS lookups by default -DO_RDNS=${DNS-} - -header="#mac,ip,iface,speed_in,speed_out,in,out,total,first_date,last_date" - -createDbIfMissing() { - [ ! -f "$DB" ] && echo $header > "$DB" - [ ! -f "$DB6" ] && echo $header > "$DB6" -} - -checkDbArg() { - [ -z "$DB" ] && echo "ERROR: Missing argument 2 (database file)" && exit 1 -} - -checkDB() { - [ ! -f "$DB" ] && echo "ERROR: $DB does not exist" && exit 1 - [ ! -w "$DB" ] && echo "ERROR: $DB is not writable" && exit 1 - [ ! -f "$DB6" ] && echo "ERROR: $DB6 does not exist" && exit 1 - [ ! -w "$DB6" ] && echo "ERROR: $DB6 is not writable" && exit 1 -} - -checkWAN() { - [ -z "$1" ] && echo "Warning: failed to detect WAN interface." -} - -lookup() { - local MAC=$1 - local IP=$2 - local userDB=$3 - local USERSFILE= - local USER= - for USERSFILE in $userDB /tmp/dhcp.leases /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do - [ -e "$USERSFILE" ] || continue - - case $USERSFILE in - /tmp/dhcp.leases ) - USER=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ') - ;; - /etc/hosts ) - USER=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ') - ;; - * ) - USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,) - ;; - esac - - [ "$USER" = "*" ] && USER= - [ -n "$USER" ] && break - - done - - if [ -n "$DO_RDNS" -a -z "$USER" -a "$IP" != "NA" -a -n "$nslookup" ]; then - USER=`$nslookup $IP $DNS | awk '!/server can/{if($4){print $4; exit}}' | sed -re 's/[.]$//'` - fi - - [ -z "$USER" ] && USER=${MAC} - echo $USER -} - -detectIF() { - local IF= - if [ -f "$networkFuncs" ]; then - IF=`. $networkFuncs; network_get_device netdev $1; echo $netdev` - [ -n "$IF" ] && echo $IF && return - fi - - if [ -n "$uci" -a -x "$uci" ]; then - IF=`$uci get network.${1}.ifname 2>/dev/null` - [ $? -eq 0 -a -n "$IF" ] && echo $IF && return - fi - - if [ -n "$nvram" -a -x "$nvram" ]; then - IF=`$nvram get ${1}_ifname 2>/dev/null` - [ $? -eq 0 -a -n "$IF" ] && echo $IF && return - fi -} - -detectLAN() { - [ -e /sys/class/net/br-lan ] && echo br-lan && return - local lan=$(detectIF lan) - [ -n "$lan" ] && echo $lan && return -} - -detectWAN() { - local wan=$(detectIF wan) - [ -n "$wan" ] && echo $wan && return - wan=$(ip route show 2>/dev/null | grep default | sed -re '/^default/ s/default.*dev +([^ ]+).*/\1/') - [ -n "$wan" ] && echo $wan && return - [ -f "$networkFuncs" ] && wan=$(. $networkFuncs; network_find_wan wan; echo $wan) - [ -n "$wan" ] && echo $wan && return -} - -lockFunc() { - #Realize the lock function by busybox lock or flock command. - # if !(lock -n $lockFile) >/dev/null 2>&1; then - # exit 1 - # fi - #The following lock method is realized by other's function. - - local attempts=0 - local flag=0 - - while [ "$flag" = 0 ]; do - local tempfile=$(mktemp $tmpDir/lock.XXXXXX) - ln $tempfile $lockFile >/dev/null 2>&1 && flag=1 - rm $tempfile - - if [ "$flag" = 1 ]; then - [ -n "$DEBUG" ] && echo ${updatePID} "got lock after $attempts attempts" - flag=1 - else - sleep 1 - attempts=$(($attempts+1)) - [ -n "$DEBUG" ] && echo ${updatePID} "The $attempts attempts." - [ "$attempts" -ge 10 ] && exit - fi - done -} - -unlockFunc() { - #Realize the lock function by busybox lock or flock command. - # lock -u $lockFile - # rm -f $lockFile - # [ -n "$DEBUG" ] && echo ${updatePID} "released lock" - #The following lock method is realized by other's function. - - rm -f $lockFile - [ -n "$DEBUG" ] && echo ${updatePID} "released lock" -} - -# chain -newChain() { - local chain=$1 - local ipt=$2 - # Create the RRDIPT_$chain chain (it doesn't matter if it already exists). - - $ipt -t mangle -N RRDIPT_$chain 2> /dev/null - - # Add the RRDIPT_$chain CHAIN to the $chain chain if not present - $ipt -t mangle -C $chain -j RRDIPT_$chain 2>/dev/null - if [ $? -ne 0 ]; then - [ -n "$DEBUG" ] && echo "DEBUG: $ipt chain misplaced, recreating it..." - $ipt -t mangle -I $chain -j RRDIPT_$chain - fi -} - -# chain tun -newRuleIF() { - local chain=$1 - local IF=$2 - local ipt=$3 - local cmd= - - if [ "$chain" = "OUTPUT" ]; then - cmd="$ipt -t mangle -o $IF -j RETURN" - elif [ "$chain" = "INPUT" ]; then - cmd="$ipt -t mangle -i $IF -j RETURN" - fi - [ -n "$cmd" ] && eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain" -} - -publish() { - # sort DB - # busybox sort truncates numbers to 32 bits - grep -v '^#' $DB | awk -F, '{OFS=","; a=sprintf("%f",$6/1e6); $6=""; print a,$0}' | tr -s ',' | sort -rn | awk -F, '{OFS=",";$1=sprintf("%f",$1*1e6);print}' > $tmpDir/sorted_${updatePID}.tmp - - # create HTML page - local htmPage="$tmpDir/${pb_html##*/}" - rm -f $htmPage - cp $dataDir/usage.htm1 $htmPage - - while IFS=, read PEAKUSAGE_IN MAC IP IFACE SPEED_IN SPEED_OUT PEAKUSAGE_OUT TOTAL FIRSTSEEN LASTSEEN - do - echo " -new Array(\"$(lookup $MAC $IP $user_def)\",\"$MAC\",\"$IP\",$SPEED_IN,$SPEED_OUT, -$PEAKUSAGE_IN,$PEAKUSAGE_OUT,$TOTAL,\"$FIRSTSEEN\",\"$LASTSEEN\")," >> $htmPage - done < $tmpDir/sorted_${updatePID}.tmp - echo "0);" >> $htmPage - - sed "s/(date)/`date`/" < $dataDir/usage.htm2 >> $htmPage - mv $htmPage "$pb_html" -} - -updatePrepare() { - checkDbArg - createDbIfMissing - checkDB - [ -e $tmpDir ] || mkdir -p $tmpDir - - for46="$Monitor46" - local timeNow=$(cat /proc/uptime | awk '{print $1}') - - if [ -e "$logFile" ]; then - local timeLast4=$(awk -F'[: ]+' '/ipv4/{print $2}' "$logFile") - local timeLast6=$(awk -F'[: ]+' '/ipv6/{print $2}' "$logFile") - interval4=$(awk -v now=$timeNow -v last=$timeLast4 'BEGIN{print (now-last)}'); - interval6=$(awk -v now=$timeNow -v last=$timeLast6 'BEGIN{print (now-last)}'); - - for ii in 4 6; do - [[ -n "$(echo $for46 | grep ${ii})" ]] && { - if [[ "$(eval echo \$interval${ii})" \> "0.9" ]]; then - sed -i "s/^ipv${ii}: [0-9\.]\{1,\}/ipv${ii}: $timeNow/ig" "$logFile" - else - for46=`echo "$for46" | sed "s/${ii}//g"` - fi - } - done - else - echo -e "ipv4: $timeNow\nipv6: $timeNow" >"$logFile" - fi - return 0 -} - -update() { - updatePID=$( sh -c 'echo $PPID' ) - - lockFunc - - local wan=$(detectWAN) - checkWAN $wan - interfaces="$interfaces $wan" - - [ "$for46" = 4 ] && IPT='iptables' - [ "$for46" = 6 ] && IPT='ip6tables' - [ "$for46" = 46 ] && IPT='iptables ip6tables' - - for ii in $IPT ; do - if [ -z "$( ${ii}-save | grep RRDIPT )" ]; then - - for chain in $chains; do - newChain $chain $ii - done - - # track local data - for chain in INPUT OUTPUT; do - for interface in $interfaces; do - [ -n "$interface" ] && [ -e "/sys/class/net/$interface" ] && newRuleIF $chain $interface $ii - done - done - fi - # this will add rules for hosts in arp table - > $tmpDir/${ii}_${updatePID}.tmp - - for chain in $chains; do - $ii -nvxL RRDIPT_$chain -t mangle -Z >> $tmpDir/${ii}_${updatePID}.tmp - done - done - - [ -f $tmpDir/iptables_${updatePID}.tmp ] && ( - awk -v mode="$mode" -v interfaces="$interfaces" -v wanIF="$wan" -v interval=$interval4 \ - -v ipv6="0" -f $binDir/readDB.awk \ - $DB \ - /proc/net/arp \ - $tmpDir/iptables_${updatePID}.tmp - ) - - [ -f $tmpDir/ip6tables_${updatePID}.tmp ] && ( - echo "This file is geneated by 'ip -6 neigh'" > $tmpDir/ip6addr_${updatePID}.tmp - `ip -6 neigh >> $tmpDir/ip6addr_${updatePID}.tmp`; - - awk -v mode="$mode" -v interfaces="$interfaces" -v wanIF="$wan" -v interval=$interval6 \ - -v ipv6="1" -f $binDir/readDB.awk \ - "$DB6" \ - $tmpDir/ip6addr_${updatePID}.tmp \ - $tmpDir/ip6tables_${updatePID}.tmp - ) - - [ "$Monitor46" = 46 ] && ( - cp $DB $DB46 - cat $DB6 >> $DB46 - awk -f $binDir/readDB.awk "$DB46" - ) - - [ -n "$pb_html" ] && publish - - rm -f $tmpDir/*_${updatePID}.tmp - unlockFunc -} - -renamefile() { - local base=$(basename -- "$1") - local ext=$([ -z "${base/*.*/}" ] && echo ".${base##*.}" || echo '') - local base="${base%.*}" - echo "$(dirname $1)/${base}$2$ext" && return -} - -ending() { - iptables-save | grep -v RRDIPT | iptables-restore - ip6tables-save | grep -v RRDIPT | ip6tables-restore - - if checkPid $pidFile; then - local pid=$( cat $pidFile ) - rm -rf $lockFile $logFile $pidFile $tmpDir/* - kill -9 $pid >> /dev/null 2>&1 - fi - echo "exit!!" -} - -checkPid() { - [ -e "$1" ] && local pid=$(cat $1) || return 1 - [ -d "/proc/$pid" ] && { - [ -n "$( cat /proc/$pid/cmdline | grep wrtbwmon )" ] && return 0 - } - return 1 -} - -sleepProcess() { - sleep 1m - kill -CONT $1 >>/dev/null 2>&1 -} - -loop() { - trap 'ending' INT TERM HUP QUIT - if checkPid $pidFile; then - echo "Another wrtbwmon is on running!!!" - else - local loopPID=$( sh -c 'echo $PPID' ) - local SPID= - echo $loopPID > $pidFile - while true ;do - [ -n "$SPID" ] && kill -9 $SPID >>/dev/null 2>&1 - sleepProcess $loopPID & - SPID=$! - updatePrepare && update - kill -STOP $loopPID >>/dev/null 2>&1 - done - fi - trap INT TERM HUP QUIT -} - -tips() { - echo \ -"Usage: $0 [options...] -Options: - -k Exit the wrtbwmon! - -f dbfile Set the DB file path - -u usrfile Set the user_def file path - -p htmlfile Set the publish htm file path - -d Enter the foreground mode. - -D Enter the daemo mode. - -4 Listen to ipv4 only. - -6 Listen to ipv6 only. - -46 Listen to ipv4 and ipv6. - -Note: [user_file] is an optional file to match users with MAC addresses. - Its format is \"00:MA:CA:DD:RE:SS,username\", with one entry per line." -} - -############################################################ - -while [ $# != 0 ];do - case $1 in - "-k" ) - /etc/init.d/wrtbwmon stop - exit 0 - ;; - "-f" ) - shift - if [ $# -gt 0 ];then - DB=$1 - DB6="$(renamefile $DB .6)" - DB46="$(renamefile $DB .46)" - else - echo "No db file path seted, exit!!" - exit 1 - fi - ;; - "-u") - shift - if [ $# -gt 0 ];then - user_def=$1 - else - echo "No user define file path seted, exit!!" - exit 1 - fi - ;; - - "-p") - shift - if [ $# -gt 0 ];then - pb_html=$1 - else - echo "No publish html file path seted, exit!!" - exit 1 - fi - ;; - - "-d") - runMode=1 - ;; - - "-D") - runMode=2 - ;; - - "-4") - Monitor46=4 - ;; - - "-6") - Monitor46=6 - ;; - - "-46") - Monitor46=46 - ;; - - "&&" | "||" | ";") - break - ;; - - "*") - tips - ;; - esac - - shift -done - -if [ "$runMode" = '1' ]; then - loop -elif [ "$runMode" = '2' ]; then - loop >>/dev/null 2>&1 & -else - updatePrepare && update -fi diff --git a/package/ctcgfw/luci-app-wrtbwmon/usr/share/wrtbwmon/usage.htm1 b/package/ctcgfw/luci-app-wrtbwmon/usr/share/wrtbwmon/usage.htm1 deleted file mode 100644 index c469cb7d91..0000000000 --- a/package/ctcgfw/luci-app-wrtbwmon/usr/share/wrtbwmon/usage.htm1 +++ /dev/null @@ -1,34 +0,0 @@ -Traffic - -

Total Usage:

- - - - - - - - - - - -
UserDown SpeedUp SpeedDownloadUploadTotalFirst seenLast seen
-
This page was generated on (date) - diff --git a/package/lean/luci-app-wrtbwmon/Makefile b/package/lean/luci-app-wrtbwmon/Makefile new file mode 100644 index 0000000000..412b35fe52 --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/Makefile @@ -0,0 +1,17 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for Wrtbwmon +LUCI_DEPENDS:=+luci-app-nlbwmon +LUCI_PKGARCH:=all +PKG_VERSION:=1.0 +PKG_RELEASE:=7 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature + diff --git a/package/lean/luci-app-wrtbwmon/htdocs/luci-static/wrtbwmon.js b/package/lean/luci-app-wrtbwmon/htdocs/luci-static/wrtbwmon.js new file mode 100644 index 0000000000..36812e723b --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/htdocs/luci-static/wrtbwmon.js @@ -0,0 +1,562 @@ +var wrt = { + // variables for auto-update, interval is in seconds + scheduleTimeout: undefined, + updateTimeout: undefined, + isScheduled: true, + interval: 5, + // option on whether to show per host sub-totals + perHostTotals: false, + // variables for sorting + sortData: { + column: 7, + elId: 'thTotal', + dir: 'desc', + cache: {} + } +}; + +(function () { + var oldDate, oldValues = []; + + // find base path + var re = /(.*?admin\/nlbw\/[^/]+)/; + var basePath = window.location.pathname.match(re)[1]; + + //---------------------- + // HELPER FUNCTIONS + //---------------------- + + /** + * Human readable text for size + * @param size + * @returns {string} + */ + function getSize(size) { + var prefix = [' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']; + var precision, base = 1000, pos = 0; + while (size > base) { + size /= base; + pos++; + } + if (pos > 2) precision = 1000; else precision = 1; + return (Math.round(size * precision) / precision) + ' ' + prefix[pos] + 'B'; + } + + /** + * Human readable text for date + * @param date + * @returns {string} + */ + function dateToString(date) { + return date.toString().substring(0, 24); + } + + /** + * Gets the string representation of the date received from BE + * @param value + * @returns {*} + */ + function getDateString(value) { + var tmp = value.split('_'), + str = tmp[0].split('-').reverse().join('-') + 'T' + tmp[1]; + return dateToString(new Date(str)); + } + + /** + * Create a `tr` element with content + * @param content + * @returns {string} + */ + function createTR(content) { + var res = '' + data[2], {title: data[1]}), + createTD(getSize(dlSpeed) + '/s', {right: true}), + createTD(getSize(upSpeed) + '/s', {right: true}), + createTD(getSize(data[3]), {right: true}), + createTD(getSize(data[4]), {right: true}), + createTD(getSize(data[5]), {right: true}), + createTD(getDateString(data[6])), + createTD(getDateString(data[7])) + ]; + + // display row data + var result = ''; + for (var k = 0; k < displayData.length; k++) { + result += displayData[k]; + } + result = createTR(result); + return [result, rowData]; + } + + /** + * Creates the HTML output based on the `data` and `totals` inputs + * @param data + * @param totals + * @returns {string} HTML output + */ + function getDisplayData(data, totals) { + var result = + createTH('客户端', {id: 'thClient'}) + + createTH('下载带宽', {id: 'thDownload'}) + + createTH('上传带宽', {id: 'thUpload'}) + + createTH('总下载流量', {id: 'thTotalDown'}) + + createTH('总上传流量', {id: 'thTotalUp'}) + + createTH('流量合计', {id: 'thTotal'}) + + createTH('首次上线时间', {id: 'thFirstSeen'}) + + createTH('最后上线时间', {id: 'thLastSeen'}); + result = createTR(result); + for (var k = 0; k < data.length; k++) { + result += data[k][0]; + } + var totalsRow = createTH('总计'); + for (var m = 0; m < totals.length; m++) { + var t = totals[m]; + totalsRow += createTD(getSize(t) + (m < 2 ? '/s' : ''), {right: true}); + } + result += createTR(totalsRow); + return result; + } + + /** + * Calculates per host sub-totals and adds them in the data input + * @param data The data input + */ + function aggregateHostTotals(data) { + if (!wrt.perHostTotals) return; + + var curHost = 0, insertAt = 1; + while (curHost < data.length && insertAt < data.length) { + // grab the current hostname/mac, and walk the data looking for rows with the same host/mac + var hostName = data[curHost][1][0].toLowerCase(); + for (var k = curHost + 1; k < data.length; k++) { + if (data[k][1][0].toLowerCase() === hostName) { + // this is another row for the same host, group it with any other rows for this host + data.splice(insertAt, 0, data.splice(k, 1)[0]); + insertAt++; + } + } + + // if we found more than one row for the host, add a subtotal row + if (insertAt > curHost + 1) { + var hostTotals = [data[curHost][1][0], '', '', 0, 0, 0, 0, 0]; + for (var i = curHost; i < insertAt && i < data.length; i++) { + for (var j = 3; j < hostTotals.length; j++) { + hostTotals[j] += data[i][1][j]; + } + } + var hostTotalRow = createTH(data[curHost][1][0] + '
(host total)', {title: data[curHost][1][1]}); + for (var m = 3; m < hostTotals.length; m++) { + var t = hostTotals[m]; + hostTotalRow += createTD(getSize(t) + (m < 5 ? '/s' : ''), {right: true}); + } + hostTotalRow = createTR(hostTotalRow); + data.splice(insertAt, 0, [hostTotalRow, hostTotals]); + } + curHost = insertAt; + insertAt = curHost + 1; + } + } + + /** + * Sorting function used to sort the `data`. Uses the global sort settings + * @param x first item to compare + * @param y second item to compare + * @returns {number} 1 for desc, -1 for asc, 0 for equal + */ + function sortingFunction(x, y) { + // get data from global variable + var sortColumn = wrt.sortData.column, sortDirection = wrt.sortData.dir; + var a = x[1][sortColumn]; + var b = y[1][sortColumn]; + if (a === b) { + return 0; + } else if (sortDirection === 'desc') { + return a < b ? 1 : -1; + } else { + return a > b ? 1 : -1; + } + } + + /** + * Sets the relevant global sort variables and re-renders the table to apply the new sorting + * @param elId + * @param column + */ + function setSortColumn(elId, column) { + if (column === wrt.sortData.column) { + // same column clicked, switch direction + wrt.sortData.dir = wrt.sortData.dir === 'desc' ? 'asc' : 'desc'; + } else { + // change sort column + wrt.sortData.column = column; + // reset sort direction + wrt.sortData.dir = 'desc'; + } + wrt.sortData.elId = elId; + + // render table data from cache + renderTableData(wrt.sortData.cache.data, wrt.sortData.cache.totals); + } + + /** + * Registers the table events handlers for sorting when clicking the column headers + */ + function registerTableEventHandlers() { + // note these ordinals are into the data array, not the table output + document.getElementById('thClient').addEventListener('click', function () { + setSortColumn(this.id, 0); // hostname + }); + document.getElementById('thDownload').addEventListener('click', function () { + setSortColumn(this.id, 3); // dl speed + }); + document.getElementById('thUpload').addEventListener('click', function () { + setSortColumn(this.id, 4); // ul speed + }); + document.getElementById('thTotalDown').addEventListener('click', function () { + setSortColumn(this.id, 5); // total down + }); + document.getElementById('thTotalUp').addEventListener('click', function () { + setSortColumn(this.id, 6); // total up + }); + document.getElementById('thTotal').addEventListener('click', function () { + setSortColumn(this.id, 7); // total + }); + } + + /** + * Fetches and handles the updated `values` from the BE + * @param once If set to true, it re-schedules itself for execution based on selected interval + */ + function receiveData(once) { + var ajax = new XMLHttpRequest(); + ajax.onreadystatechange = function () { + // noinspection EqualityComparisonWithCoercionJS + if (this.readyState == 4 && this.status == 200) { + var re = /(var values = new Array[^;]*;)/, + match = ajax.responseText.match(re); + if (!match) { + handleError(); + } else { + // evaluate values + eval(match[1]); + //noinspection JSUnresolvedVariable + var v = values; + if (!v) { + handleError(); + } else { + handleValues(v); + // set old values + oldValues = v; + // set old date + oldDate = new Date(); + document.getElementById('updated').innerHTML = '数据更新时间 ' + dateToString(oldDate); + } + } + var int = wrt.interval; + if (!once && int > 0) reschedule(int); + } + }; + ajax.open('GET', basePath + '/usage_data', true); + ajax.send(); + } + + /** + * Registers DOM event listeners for user interaction + */ + function addEventListeners() { + document.getElementById('intervalSelect').addEventListener('change', function () { + var int = wrt.interval = this.value; + if (int > 0) { + // it is not scheduled, schedule it + if (!wrt.isScheduled) { + reschedule(int); + } + } else { + // stop the scheduling + stopSchedule(); + } + }); + + document.getElementById('resetDatabase').addEventListener('click', function () { + if (confirm('This will delete the database file. Are you sure?')) { + var ajax = new XMLHttpRequest(); + ajax.onreadystatechange = function () { + // noinspection EqualityComparisonWithCoercionJS + if (this.readyState == 4 && this.status == 204) { + location.reload(); + } + }; + ajax.open('GET', basePath + '/usage_reset', true); + ajax.send(); + } + }); + + document.getElementById('perHostTotals').addEventListener('change', function () { + wrt.perHostTotals = !wrt.perHostTotals; + }); + } + + //---------------------- + // AUTO-UPDATE + //---------------------- + + /** + * Stop auto-update schedule + */ + function stopSchedule() { + window.clearTimeout(wrt.scheduleTimeout); + window.clearTimeout(wrt.updateTimeout); + setUpdateMessage(''); + wrt.isScheduled = false; + } + + /** + * Start auto-update schedule + * @param seconds + */ + function reschedule(seconds) { + wrt.isScheduled = true; + seconds = seconds || 60; + updateSeconds(seconds); + wrt.scheduleTimeout = window.setTimeout(receiveData, seconds * 1000); + } + + /** + * Sets the text of the `#updating` element + * @param msg + */ + function setUpdateMessage(msg) { + document.getElementById('updating').innerHTML = msg; + } + + /** + * Updates the 'Updating in X seconds' message + * @param start + */ + function updateSeconds(start) { + setUpdateMessage('倒数 ' + start + ' 秒后刷新.'); + if (start > 0) { + wrt.updateTimeout = window.setTimeout(function () { + updateSeconds(start - 1); + }, 1000); + } + } + + //---------------------- + // END AUTO-UPDATE + //---------------------- + + /** + * Check for dependency, and if all is well, run callback + * @param cb Callback function + */ + function checkForDependency(cb) { + var ajax = new XMLHttpRequest(); + ajax.onreadystatechange = function () { + // noinspection EqualityComparisonWithCoercionJS + if (this.readyState == 4 && this.status == 200) { + // noinspection EqualityComparisonWithCoercionJS + if (ajax.responseText == "1") { + cb(); + } else { + alert("wrtbwmon is not installed!"); + } + } + }; + ajax.open('GET', basePath + '/check_dependency', true); + ajax.send(); + } + + checkForDependency(function () { + // register events + addEventListeners(); + // Main entry point + receiveData(); + }); + +})(); diff --git a/package/lean/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua b/package/lean/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua new file mode 100644 index 0000000000..25909c846d --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/luasrc/controller/wrtbwmon.lua @@ -0,0 +1,43 @@ +module("luci.controller.wrtbwmon", package.seeall) + +function index() + entry({"admin", "nlbw", "usage"}, alias("admin", "nlbw", "usage", "details"), _("Usage"), 60) + entry({"admin", "nlbw", "usage", "details"}, template("wrtbwmon"), _("Details"), 10).leaf=true + entry({"admin", "nlbw", "usage", "config"}, cbi("wrtbwmon/config"), _("Configuration"), 20).leaf=true + entry({"admin", "nlbw", "usage", "custom"}, form("wrtbwmon/custom"), _("User file"), 30).leaf=true + entry({"admin", "nlbw", "usage", "check_dependency"}, call("check_dependency")).dependent=true + entry({"admin", "nlbw", "usage", "usage_data"}, call("usage_data")).dependent=true + entry({"admin", "nlbw", "usage", "usage_reset"}, call("usage_reset")).dependent=true +end + +function usage_database_path() + local cursor = luci.model.uci.cursor() + if cursor:get("wrtbwmon", "general", "persist") == "1" then + return "/etc/config/usage.db" + else + return "/tmp/usage.db" + end +end + +function check_dependency() + local ret = "0" + if require("luci.model.ipkg").installed('iptables') then + ret = "1" + end + luci.http.prepare_content("text/plain") + luci.http.write(ret) +end + +function usage_data() + local db = usage_database_path() + local publish_cmd = "wrtbwmon publish " .. db .. " /tmp/usage.htm /etc/config/wrtbwmon.user" + local cmd = "wrtbwmon update " .. db .. " && " .. publish_cmd .. " && cat /tmp/usage.htm" + luci.http.prepare_content("text/html") + luci.http.write(luci.sys.exec(cmd)) +end + +function usage_reset() + local db = usage_database_path() + local ret = luci.sys.call("wrtbwmon update " .. db .. " && rm " .. db) + luci.http.status(204) +end diff --git a/package/lean/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua b/package/lean/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua new file mode 100644 index 0000000000..469d4f8f2c --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/config.lua @@ -0,0 +1,18 @@ +local m = Map("wrtbwmon", translate("Details")) + +local s = m:section(NamedSection, "general", "wrtbwmon", translate("General settings")) + +local o = s:option(Flag, "persist", translate("Persist database"), + translate("Check this to persist the database file")) +o.rmempty = false + +function o.write(self, section, value) + if value == '1' then + luci.sys.call("mv /tmp/usage.db /etc/config/usage.db") + elseif value == '0' then + luci.sys.call("mv /etc/config/usage.db /tmp/usage.db") + end + return Flag.write(self, section ,value) +end + +return m diff --git a/package/ctcgfw/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/custom.lua b/package/lean/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/custom.lua similarity index 69% rename from package/ctcgfw/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/custom.lua rename to package/lean/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/custom.lua index 46baa33127..671879b4cc 100644 --- a/package/ctcgfw/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/custom.lua +++ b/package/lean/luci-app-wrtbwmon/luasrc/model/cbi/wrtbwmon/custom.lua @@ -1,11 +1,10 @@ -local USER_FILE_PATH = "/etc/wrtbwmon.user" +local USER_FILE_PATH = "/etc/config/wrtbwmon.user" local fs = require "nixio.fs" local f = SimpleForm("wrtbwmon", translate("Usage - Custom User File"), - translate("This file is used to match users with MAC addresses. " - .. "Each line must have the following format: \"00:aa:bb:cc:ee:ff,username\".")) + translate("This file is used to match users with MAC addresses and it must have the following format: 00:aa:bb:cc:ee:ff,username")) local o = f:field(Value, "_custom") @@ -21,6 +20,4 @@ function o.write(self, section, value) fs.writefile(USER_FILE_PATH, value) end -f.submit = translate("Submit") - return f diff --git a/package/lean/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm b/package/lean/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm new file mode 100644 index 0000000000..68713b1238 --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/luasrc/view/wrtbwmon.htm @@ -0,0 +1,46 @@ +<%+header%> +

<%=translate("Usage")%>

+

+ +

+

+ + + +
+ + +
+

+ + +
<%=translate("Loading...")%>
+ + +<%+footer%> diff --git a/package/lean/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po b/package/lean/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po new file mode 100644 index 0000000000..3eb050e3f4 --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/po/zh-cn/wrtbwmon.po @@ -0,0 +1,56 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Usage" +msgstr "实时流量监测" + +msgid "Details" +msgstr "详细信息" + +msgid "Configuration" +msgstr "配置" + +msgid "User file" +msgstr "自定义主机信息" + +msgid "Usage - Configuration" +msgstr "详细设置" + +msgid "General settings" +msgstr "通用设置" + +msgid "Persist database" +msgstr "写入数据库到硬盘" + +msgid "Check this to persist the database file" +msgstr "把统计数据写入 /etc/config 中避免重启或者升级后丢失" + +msgid "Usage - Custom User File" +msgstr "自定义MAC地址对应的主机名" + +msgid "This file is used to match users with MAC addresses and it must have the following format: 00:aa:bb:cc:ee:ff,username" +msgstr "每一行的格式为 00:aa:bb:cc:ee:ff,username" + +msgid "Reset Database" +msgstr "重置数据库" + +msgid "Auto Refresh Interval" +msgstr "自动刷新间隔" + +msgid "Disabled" +msgstr "禁用" + +msgid "Second" +msgstr "秒" + +msgid "Seconds" +msgstr "秒" + +msgid "Minutes" +msgstr "分钟" + +msgid "Per-host Totals" +msgstr "合并每一客户端数据" + +msgid "Loading..." +msgstr "加载中..." diff --git a/package/lean/luci-app-wrtbwmon/root/etc/config/wrtbwmon b/package/lean/luci-app-wrtbwmon/root/etc/config/wrtbwmon new file mode 100644 index 0000000000..419270dbab --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/root/etc/config/wrtbwmon @@ -0,0 +1,4 @@ + +config wrtbwmon 'general' + option persist '0' + diff --git a/package/lean/luci-app-wrtbwmon/root/etc/init.d/wrtbwmon b/package/lean/luci-app-wrtbwmon/root/etc/init.d/wrtbwmon new file mode 100755 index 0000000000..d57c09ae1d --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/root/etc/init.d/wrtbwmon @@ -0,0 +1,22 @@ +#!/bin/sh /etc/rc.common +# +# start/stop wrtbwmon bandwidth monitor + +### BEGIN INIT INFO +# Provides: wrtbwmon +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: iptables-based bandwidth monitor +### END INIT INFO + +START=91 + +start(){ + /usr/sbin/wrtbwmon setup /tmp/usage.db +} + +stop(){ + /usr/sbin/wrtbwmon remove +} diff --git a/package/lean/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon b/package/lean/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon new file mode 100755 index 0000000000..bcb5b337f3 --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/root/etc/uci-defaults/luci-wrtbwmon @@ -0,0 +1,14 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete firewall.wrtbwmon + set firewall.wrtbwmon=include + set firewall.wrtbwmon.type=script + set firewall.wrtbwmon.path='/etc/wrtbwmon.include' + set firewall.wrtbwmon.reload=1 + commit firewall +EOF + +/etc/init.d/wrtbwmon enable +/etc/init.d/wrtbwmon start +exit 0 diff --git a/package/lean/luci-app-wrtbwmon/root/etc/wrtbwmon.include b/package/lean/luci-app-wrtbwmon/root/etc/wrtbwmon.include new file mode 100755 index 0000000000..39bcf43a10 --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/root/etc/wrtbwmon.include @@ -0,0 +1 @@ +/etc/init.d/wrtbwmon restart >/dev/null 2>&1 diff --git a/package/lean/luci-app-wrtbwmon/root/usr/sbin/readDB.awk b/package/lean/luci-app-wrtbwmon/root/usr/sbin/readDB.awk new file mode 100755 index 0000000000..fe67e4ae8b --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/root/usr/sbin/readDB.awk @@ -0,0 +1,157 @@ +#!/usr/bin/awk + +function inInterfaces(host){ + return(interfaces ~ "(^| )"host"($| )") +} + +function newRule(arp_ip, + ipt_cmd){ + # checking for existing rules shouldn't be necessary if newRule is + # always called after db is read, arp table is read, and existing + # iptables rules are read. + ipt_cmd="iptables -t mangle -j RETURN -s " arp_ip + system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD") + ipt_cmd="iptables -t mangle -j RETURN -d " arp_ip + system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD") +} + +function total(i){ + return(bw[i "/in"] + bw[i "/out"]) +} + +function date( cmd, d){ + cmd="date +%d-%m-%Y_%H:%M:%S" + cmd | getline d + close(cmd) + #!@todo could start a process with "while true; do date ...; done" + return(d) +} + +BEGIN { + od="" + fid=1 + debug=0 + rrd=0 +} + +/^#/ { # get DB filename + FS="," + dbFile=FILENAME + next +} + +# data from database; first file +FNR==NR { #!@todo this doesn't help if the DB file is empty. + if($2 == "NA") + #!@todo could get interface IP here + n=$1 + else + n=$2 + + hosts[n] = "" # add this host/interface to hosts + mac[n] = $1 + ip[n] = $2 + inter[n] = $3 + bw[n "/in"] = $4 + bw[n "/out"] = $5 + firstDate[n] = $7 + lastDate[n] = $8 + next +} + +# not triggered on the first file +FNR==1 { + FS=" " + fid++ #!@todo use fid for all files; may be problematic for empty files + next +} + +# arp: ip hw flags hw_addr mask device +fid==2 { + #!@todo regex match IPs and MACs for sanity + arp_ip = $1 + arp_flags = $3 + arp_mac = $4 + arp_dev = $6 + if(arp_flags != "0x0" && !(arp_ip in ip)){ + if(debug) + print "new host:", arp_ip, arp_flags > "/dev/stderr" + hosts[arp_ip] = "" + mac[arp_ip] = arp_mac + ip[arp_ip] = arp_ip + inter[arp_ip] = arp_dev + bw[arp_ip "/in"] = bw[arp_ip "/out"] = 0 + firstDate[arp_ip] = lastDate[arp_ip] = date() + } + next +} + +#!@todo could use mangle chain totals or tailing "unnact" rules to +# account for data for new hosts from their first presence on the +# network to rule creation. The "unnact" rules would have to be +# maintained at the end of the list, and new rules would be inserted +# at the top. + +# skip line +# read the chain name and deal with the data accordingly +fid==3 && $1 == "Chain"{ + rrd=$2 ~ /RRDIPT_.*/ + next +} + +fid==3 && rrd && (NF < 9 || $1=="pkts"){ next } + +fid==3 && rrd { # iptables input + if($6 != "*"){ + m=$6 + n=m "/out" + } else if($7 != "*"){ + m=$7 + n=m "/in" + } else if($8 != "0.0.0.0/0"){ + m=$8 + n=m "/out" + } else { # $9 != "0.0.0.0/0" + m=$9 + n=m "/in" + } + + # remove host from array; any hosts left in array at END get new + # iptables rules + + #!@todo this deletes a host if any rule exists; if only one + # directional rule is removed, this will not remedy the situation + delete hosts[m] + + if($2 > 0){ # counted some bytes + if(mode == "diff" || mode == "noUpdate") + print n, $2 + if(mode!="noUpdate"){ + if(inInterfaces(m)){ # if label is an interface + if(!(m in mac)){ # if label was not in db (also not in + # arp table, but interfaces won't be + # there anyway) + firstDate[m] = date() + mac[m] = inter[m] = m + ip[m] = "NA" + bw[m "/in"]=bw[m "/out"]= 0 + } + } + bw[n]+=$2 + lastDate[m] = date() + } + } +} + +END { + if(mode=="noUpdate") exit + close(dbFile) + system("rm -f " dbFile) + print "#mac,ip,iface,in,out,total,first_date,last_date" > dbFile + OFS="," + for(i in mac) + print mac[i], ip[i], inter[i], bw[i "/in"], bw[i "/out"], total(i), firstDate[i], lastDate[i] > dbFile + close(dbFile) + # for hosts without rules + for(host in hosts) if(!inInterfaces(host)) newRule(host) +} diff --git a/package/lean/luci-app-wrtbwmon/root/usr/sbin/wrtbwmon b/package/lean/luci-app-wrtbwmon/root/usr/sbin/wrtbwmon new file mode 100755 index 0000000000..b2c0b9a07a --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/root/usr/sbin/wrtbwmon @@ -0,0 +1,301 @@ +#!/bin/sh +# +# wrtbwmon: traffic logging tool for routers +# +# Peter Bailey (peter.eldridge.bailey+wrtbwmon AT gmail.com) +# +# Based on work by: +# Emmanuel Brucy (e.brucy AT qut.edu.au) +# Fredrik Erlandsson (erlis AT linux.nu) +# twist - http://wiki.openwrt.org/RrdTrafficWatch + +trap "rm -f /tmp/*_$$.tmp; kill $$" INT +binDir=/usr/sbin +dataDir=/usr/share/wrtbwmon +lockDir=/tmp/wrtbwmon.lock +pidFile=$lockDir/pid +networkFuncs=/lib/functions/network.sh +uci=`which uci 2>/dev/null` +nslookup=`which nslookup 2>/dev/null` +nvram=`which nvram 2>/dev/null` + +chains='INPUT OUTPUT FORWARD' +DEBUG= +interfaces='eth0 tun0' # in addition to detected WAN +DB=$2 +mode= + +# DNS server for reverse lookups provided in "DNS". +# don't perform reverse DNS lookups by default +DO_RDNS=${DNS-} + +header="#mac,ip,iface,in,out,total,first_date,last_date" + +createDbIfMissing() +{ + [ ! -f "$DB" ] && echo $header > "$DB" +} + +checkDbArg() +{ + [ -z "$DB" ] && echo "ERROR: Missing argument 2 (database file)" && exit 1 +} + +checkDB() +{ + [ ! -f "$DB" ] && echo "ERROR: $DB does not exist" && exit 1 + [ ! -w "$DB" ] && echo "ERROR: $DB is not writable" && exit 1 +} + +checkWAN() +{ + [ -z "$wan" ] && echo "Warning: failed to detect WAN interface." +} + +lookup() +{ + MAC=$1 + IP=$2 + userDB=$3 + for USERSFILE in $userDB /tmp/dhcp.leases /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do + [ -e "$USERSFILE" ] || continue + case $USERSFILE in + /tmp/dhcp.leases ) + USER=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ') + ;; + /etc/hosts ) + USER=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ') + ;; + * ) + USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,) + ;; + esac + [ "$USER" = "*" ] && USER= + [ -n "$USER" ] && break + done + if [ -n "$DO_RDNS" -a -z "$USER" -a "$IP" != "NA" -a -n "$nslookup" ]; then + USER=`$nslookup $IP $DNS | awk '!/server can/{if($4){print $4; exit}}' | sed -re 's/[.]$//'` + fi + [ -z "$USER" ] && USER=${MAC} + echo $USER +} + +detectIF() +{ + if [ -f "$networkFuncs" ]; then + IF=`. $networkFuncs; network_get_device netdev $1; echo $netdev` + [ -n "$IF" ] && echo $IF && return + fi + + if [ -n "$uci" -a -x "$uci" ]; then + IF=`$uci get network.${1}.ifname 2>/dev/null` + [ $? -eq 0 -a -n "$IF" ] && echo $IF && return + fi + + if [ -n "$nvram" -a -x "$nvram" ]; then + IF=`$nvram get ${1}_ifname 2>/dev/null` + [ $? -eq 0 -a -n "$IF" ] && echo $IF && return + fi +} + +detectLAN() +{ + [ -e /sys/class/net/br-lan ] && echo br-lan && return + lan=$(detectIF lan) + [ -n "$lan" ] && echo $lan && return +} + +detectWAN() +{ + [ -n "$WAN_IF" ] && echo $WAN_IF && return + wan=$(detectIF wan) + [ -n "$wan" ] && echo $wan && return + wan=$(ip route show 2>/dev/null | grep default | sed -re '/^default/ s/default.*dev +([^ ]+).*/\1/') + [ -n "$wan" ] && echo $wan && return + [ -f "$networkFuncs" ] && wan=$(. $networkFuncs; network_find_wan wan; echo $wan) + [ -n "$wan" ] && echo $wan && return +} + +lock() +{ + attempts=0 + while [ $attempts -lt 10 ]; do + mkdir $lockDir 2>/dev/null && break + attempts=$((attempts+1)) + pid=`cat $pidFile 2>/dev/null` + if [ -n "$pid" ]; then + if [ -d "/proc/$pid" ]; then + [ -n "$DEBUG" ] && echo "WARNING: Lockfile detected but process $(cat $pidFile) does not exist !" + rm -rf $lockDir + else + sleep 1 + fi + fi + done + mkdir $lockDir 2>/dev/null + echo $$ > $pidFile + [ -n "$DEBUG" ] && echo $$ "got lock after $attempts attempts" + trap '' INT +} + +unlock() +{ + rm -rf $lockDir + [ -n "$DEBUG" ] && echo $$ "released lock" + trap "rm -f /tmp/*_$$.tmp; kill $$" INT +} + +# chain +newChain() +{ + chain=$1 + # Create the RRDIPT_$chain chain (it doesn't matter if it already exists). + iptables -t mangle -N RRDIPT_$chain 2> /dev/null + + # Add the RRDIPT_$chain CHAIN to the $chain chain if not present + iptables -t mangle -C $chain -j RRDIPT_$chain 2>/dev/null + if [ $? -ne 0 ]; then + [ -n "$DEBUG" ] && echo "DEBUG: iptables chain misplaced, recreating it..." + iptables -t mangle -I $chain -j RRDIPT_$chain + fi +} + +# chain tun +newRuleIF() +{ + chain=$1 + IF=$2 + + #!@todo test + if [ "$chain" = "OUTPUT" ]; then + cmd="iptables -t mangle -o $IF -j RETURN" + eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain" + elif [ "$chain" = "INPUT" ]; then + cmd="iptables -t mangle -i $IF -j RETURN" + eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain" + fi +} + +update() +{ + #!@todo could let readDB.awk handle this; that would place header + #!info in fewer places + createDbIfMissing + + checkDB + checkWAN + + > /tmp/iptables_$$.tmp + lock + # only zero our own chains + for chain in $chains; do + iptables -nvxL RRDIPT_$chain -t mangle -Z >> /tmp/iptables_$$.tmp + done + # the iptables and readDB commands have to be separate. Otherwise, + # they will fight over iptables locks + awk -v mode="$mode" -v interfaces=\""$interfaces"\" -f $binDir/readDB.awk \ + $DB \ + /proc/net/arp \ + /tmp/iptables_$$.tmp + unlock +} + +############################################################ + +case $1 in + "dump" ) + checkDbArg + lock + tr ',' '\t' < "$DB" + unlock + ;; + + "update" ) + checkDbArg + wan=$(detectWAN) + interfaces="$interfaces $wan" + update + rm -f /tmp/*_$$.tmp + exit + ;; + + "publish" ) + checkDbArg + [ -z "$3" ] && echo "ERROR: Missing argument 3 (output html file)" && exit 1 + + # sort DB + lock + + # busybox sort truncates numbers to 32 bits + grep -v '^#' $DB | awk -F, '{OFS=","; a=sprintf("%f",$4/1e6); $4=""; print a,$0}' | tr -s ',' | sort -rn | awk -F, '{OFS=",";$1=sprintf("%f",$1*1e6);print}' > /tmp/sorted_$$.tmp + + # create HTML page + rm -f $3.tmp + cp $dataDir/usage.htm1 $3.tmp + + #!@todo fix publishing + while IFS=, read PEAKUSAGE_IN MAC IP IFACE PEAKUSAGE_OUT TOTAL FIRSTSEEN LASTSEEN + do + echo " +new Array(\"$(lookup $MAC $IP $4)\",\"$MAC\",\"$IP\", +$PEAKUSAGE_IN,$PEAKUSAGE_OUT,$TOTAL,\"$FIRSTSEEN\",\"$LASTSEEN\")," >> $3.tmp + done < /tmp/sorted_$$.tmp + echo "0);" >> $3.tmp + + sed "s/(date)/`date`/" < $dataDir/usage.htm2 >> $3.tmp + mv $3.tmp $3 + + unlock + + #Free some memory + rm -f /tmp/*_$$.tmp + ;; + + "setup" ) + checkDbArg + [ -w "$DB" ] && echo "Warning: using existing $DB" + createDbIfMissing + + for chain in $chains; do + newChain $chain + done + + #lan=$(detectLAN) + wan=$(detectWAN) + checkWAN + interfaces="$interfaces $wan" + + # track local data + for chain in INPUT OUTPUT; do + for interface in $interfaces; do + [ -n "$interface" ] && [ -e "/sys/class/net/$interface" ] && newRuleIF $chain $interface + done + done + + # this will add rules for hosts in arp table + update + + rm -f /tmp/*_$$.tmp + ;; + + "remove" ) + iptables-save | grep -v RRDIPT | iptables-restore + rm -rf "$lockDir" + ;; + + *) + echo \ +"Usage: $0 {setup|update|publish|remove} [options...] +Options: + $0 setup database_file + $0 update database_file + $0 publish database_file path_of_html_report [user_file] +Examples: + $0 setup /tmp/usage.db + $0 update /tmp/usage.db + $0 publish /tmp/usage.db /www/user/usage.htm /jffs/users.txt + $0 remove +Note: [user_file] is an optional file to match users with MAC addresses. + Its format is \"00:MA:CA:DD:RE:SS,username\", with one entry per line." + ;; +esac diff --git a/package/lean/luci-app-wrtbwmon/root/usr/share/wrtbwmon/usage.htm1 b/package/lean/luci-app-wrtbwmon/root/usr/share/wrtbwmon/usage.htm1 new file mode 100644 index 0000000000..1f0c342a7c --- /dev/null +++ b/package/lean/luci-app-wrtbwmon/root/usr/share/wrtbwmon/usage.htm1 @@ -0,0 +1,23 @@ +Traffic + +

Total Usage:

+ + + + + + + + + +
UserDownloadUploadTotalFirst seenLast seen
+
This page was generated on (date) +