--[[ @object-name:clients @object-desc:客户端管理相关接口 --]] local M = {} local rpc = require "oui.rpc" local uci = require "uci" local ubus = require "oui.ubus" local fs = require "oui.fs" --[[ @method-type:call @method-name:get_list @method-desc:获取设备列表 @out array clients 客户端列表 @out string clients.mac 客户端的mac地址. @out string clients.ip 客户端的ip. @out number clients.tx 客户端的上行速率(单位为Bps). @out number clients.rx 客户端的下行速率(单位为Bps). @out number clients.total_tx 客户端的总上行流量(单位为Byte) @out number clients.total_rx 客户端的总下行流量(单位为Byte). @out number clients.limit_tx 设置客户端限速的上行速率(单位为 KB/S). @out number clients.limit_rx 设置客户端限速的下行速率(单位为 KB/S). @out bool clients.blocked gl防火墙黑名单,true为加入黑名单,false为不加入黑名单. @out string clients.online_time 客户端上线时的时间戳. @out bool clients.online true为在线,false为下线. @out string clients.iface 客户端连接的接口名称. @out number clients.type 客户端连接的接口类型,0-2.4G,1-5G,2-lan,3-2.4G guest,4-5G guest,5-unknown,6-Dongle,7-旁路由. @out string ?clients.name 客户端设备的主机名[无值不返回]. @out bool clients.remote 如果为true,表示为当前客户端正在连接路由器. @out string ?clients.alias 用户设置的名称[无值不返回]. @out string ?clients.class 用户设置的设备类型[无值不返回]. @out number ?err_code Error code. @out string ?err_msg Error message. @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"id\":1,\"params\":[\"\",\"clients\",\"get_list\",{}]} @out-example:{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"clients\":[{\"mac\":\"18:c0:4d:dc:4f:cc\",\"type\":2,\"limit_tx\":2048,\"limit_rx\":2048,\"remote\":false,\"name\":\"DESKTOP-HO0T5C1\",\"vendor\":\"unknown\",\"ip\":\"192.168.8.148\",\"tx\":0,\"total_rx\":397117728,\"rx\":0,\"blocked\":false,\"iface\":\"eth0\",\"online\":true,\"online_time\":\"1638517436\",\"total_tx\":470371319}]}} --]] function M.get_list() local limits = {} local c = uci.cursor() local drop_in_mode = c:get("edgerouter", "global", "enabled") or "0" local drop_in_gateway = c:get("edgerouter", "wandhcp", "gateway") or "0.0.0.0" c:foreach("qos", "queue", function(s) limits[s.mac] = s end) local block_macs = {} for _, mac in ipairs(c:get("gl_block", "block_mac", "mac") or {}) do block_macs[mac] = true end local r = ubus.call("gl-clients", "list", {}) or {} local alias_class = {} c:foreach("gl-client", "client", function(s) alias_class[s.mac] = s end) local clients = {} for mac, info in pairs(r.clients or {}) do local limit = limits[mac] or {} local limit_tx = limit.upload or 0 local limit_rx = limit.download or 0 info.mac = mac info.alias = alias_class[mac] and alias_class[mac].alias info.class = alias_class[mac] and alias_class[mac].class info.limit_tx = tonumber(limit_tx) info.limit_rx = tonumber(limit_rx) info.blocked = block_macs[mac] or false info.remote = info.ip == ngx.var.remote_addr if drop_in_mode == "0" then if info.type ~= 7 then clients[#clients + 1] = info end else if info.ip ~= drop_in_gateway then clients[#clients + 1] = info end end end return { clients = clients } end --[[ @method-type:call @method-name:block_client @method-desc:设置客户端的黑名单属性 @in string mac 要设置黑名单的客户端的mac地址. @in bool block 如果为true,指定mac的客户端上不了互联网. @out number ?err_code Error code, -1:Invalid user,-5:No parameter found. @out string ?err_msg Error message. @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"id\":1,\"params\":[\"\",\"clients\",\"block_client\",{\"mac\":\"84:7a:88:79:e5:13\",\"block\":true}]} @out-example:{\"jsonrpc\":\"2.0\",\"id\": 1,\"result\": null} --]] function M.block_client(param) local c = uci.cursor() local mac = string.upper(param.mac) local block = param.block if type(param.mac) ~= "string" then return rpc.ERROR_CODE_INVALID_PARAMS, "mac required" end c:set("gl_block", "block_mac", "access") c:set("gl_block", "block_mac", "name", "mac_block") local blocked = c:get("gl_block", "block_mac", "mac") or {} for i, m in ipairs(blocked) do if m == mac then table.remove(blocked, i) end end if block then blocked[#blocked + 1] = mac end if #blocked == 0 then c:delete("gl_block", "block_mac", "mac") else c:set("gl_block", "block_mac", "mac", blocked) end c:commit("gl_block") fs.sync() ngx.pipe.spawn({"/etc/init.d/firewall", "reload"}):wait() end --[[ @method-type:call @method-name:remove_offline @method-desc:删除离线客户端 @in string mac 要删除的客户端的mac地址(如果值为FF:FF:FF:FF:FF:FF表示删除所有离线客户端). @out number ?err_code Error code, -1:Invalid user,-5:No parameter found. @out string ?err_msg Error message. @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"id\":1,\"params\":[\"\",\"clients\",\"remove_offline\",{\"mac\":\"FF:FF:FF:FF:FF:FF\"}]} @out-example:{\"jsonrpc\":\"2.0\",\"id\": 1,\"result\": null} --]] function M.remove_offline(param) local mac = param.mac if type(mac) ~= "string" then return rpc.ERROR_CODE_INVALID_PARAMS, "mac required" end ubus.call("gl-clients", "remove_offline", {mac = mac}) fs.sync() end --[[ @method-type:call @method-name:clean_traffic @method-desc: 清空所有客户端的流量统计 @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"id\":1,\"params\":[\"\",\"clients\",\"clean_traffic\",{}]} @out-example:{\"jsonrpc\":\"2.0\",\"id\": 1,\"result\": []} --]] function M.clean_traffic() ubus.call("gl-clients", "clean_traffic") fs.sync() end --[[ @method-type:call @method-name:get_status @method-desc:获取客户端在线总数状态 @out number cable_total 有线客户端的在线总数. @out number wireless_total 无线客户端的在线总数. @out number ?err_code Error code, -1:Invalid user,-5:No parameter found. @out string ?err_msg Error message. @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"id\":1,\"params\":[\"\",\"clients\",\"get_status\",{}]} @out-example:{\"jsonrpc\":\"2.0\",\"id\": 1,\"result\": {\"cable_total\":\"1\",\"wireless_total\":\"0\"}} --]] function M.get_status() local r = ubus.call("gl-clients", "status", {}) or {cable_total = 0, wireless_total = 0} local cable_total = 0 local wireless_total = 0 for _, info in pairs(r.clients or {}) do if info.online then local typ = info.type if typ == 2 then cable_total = cable_total + 1 elseif typ ~= 5 then wireless_total = wireless_total + 1 end end end return r end --[[ @method-type:call @method-name:set_info @method-desc:设置名称 @in string mac MAC 地址 @in string ?clients.alias 用户设置的名称 @in string ?clients.class 用户设置的设备类型 @in-example: {\"jsonrpc\":\"2.0\",\"method\":\"call\",\"id\":1,\"params\":[\"\",\"clients\",\"set_info\",{\"mac\":\"16:c3:7b:72:19:74\",\"alias"\:\"test\",\"class\":\"tv\"}]} @out-example:{\"jsonrpc\":\"2.0\",\"id\": 1,\"result\": null} --]] function M.set_info(param) local c = uci.cursor() if not fs.access("/etc/config/gl-client") then os.execute("touch /etc/config/gl-client") end if not param.mac then return end if not param.alias and not param.class then return end local found = false c:foreach("gl-client", "client", function(s) if s.mac:upper() == param.mac:upper() then if param.alias then c:set("gl-client", s[".name"], "alias", param.alias) end if param.class then c:set("gl-client", s[".name"], "class", param.class) end found = true end end) if not found then local sid = c:add("gl-client", "client") c:set("gl-client", sid, "mac", param.mac:upper()) if param.alias then c:set("gl-client", sid, "alias", param.alias) end if param.class then c:set("gl-client", sid, "class", param.class) end end c:commit("gl-client") fs.sync() end return M