mirror of
https://github.com/sirpdboy/sirpdboy-package.git
synced 2025-01-07 03:17:03 +08:00
d
This commit is contained in:
parent
904de085e4
commit
2a74defe74
@ -1,15 +0,0 @@
|
||||
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Open App Filter Module
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+kmod-oaf +appfilter
|
||||
PKG_NAME:=luci-app-oaf
|
||||
PKG_VERSION:=5.0
|
||||
PKG_RELEASE:=1
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
File diff suppressed because one or more lines are too long
@ -1,208 +0,0 @@
|
||||
|
||||
module("luci.controller.appfilter", package.seeall)
|
||||
local utl = require "luci.util"
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/appfilter") then
|
||||
return
|
||||
end
|
||||
|
||||
local page
|
||||
entry({"admin", "control", "appfilter"},
|
||||
alias("admin", "control", "appfilter", "user_list"),
|
||||
_("应用过滤"), 20).dependent = true
|
||||
|
||||
entry({"admin", "control", "appfilter", "user_list"},
|
||||
arcombine(cbi("appfilter/user_list",{hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}),
|
||||
cbi("appfilter/dev_status", {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true})),
|
||||
_("用户列表"), 21).leaf=true
|
||||
|
||||
entry({"admin", "control", "appfilter", "base_setting"},
|
||||
cbi("appfilter/base_setting"), _("基本设置"), 22).leaf=true
|
||||
|
||||
entry({"admin", "control", "appfilter", "user_setting"},
|
||||
cbi("appfilter/user_setting"), _("生效用户"), 23).leaf=true
|
||||
|
||||
entry({"admin", "control", "appfilter", "time_setting"},
|
||||
cbi("appfilter/time_setting"), _("生效时间"), 24).leaf=true
|
||||
|
||||
entry({"admin", "control", "appfilter", "feature"},
|
||||
cbi("appfilter/feature", {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), _("特征库升级"), 25).leaf=true
|
||||
|
||||
page = entry({"admin", "network", "user_status"}, call("user_status"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "dev_app_status"}, call("dev_app_status"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "dev_visit_list"}, call("get_dev_visit_list"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "feature_upgrade"}, call("handle_feature_upgrade"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "dev_visit_time"}, call("get_dev_visit_time"), nil)
|
||||
page.leaf = true
|
||||
page = entry({"admin", "network", "app_class_visit_time"}, call("get_app_class_visit_time"), nil)
|
||||
page.leaf = true
|
||||
end
|
||||
|
||||
function get_hostname_by_mac(dst_mac)
|
||||
leasefile="/tmp/dhcp.leases"
|
||||
local fd = io.open(leasefile, "r")
|
||||
if not fd then return end
|
||||
while true do
|
||||
local ln = fd:read("*l")
|
||||
if not ln then
|
||||
break
|
||||
end
|
||||
local ts, mac, ip, name, duid = ln:match("^(%d+) (%S+) (%S+) (%S+) (%S+)")
|
||||
if dst_mac == mac then
|
||||
fd:close()
|
||||
return name
|
||||
end
|
||||
end
|
||||
fd:close()
|
||||
return ""
|
||||
end
|
||||
|
||||
|
||||
function handle_feature_upgrade()
|
||||
local fs = require "nixio.fs"
|
||||
local http = require "luci.http"
|
||||
local image_tmp = "/tmp/feature.cfg"
|
||||
|
||||
local fp
|
||||
http.setfilehandler(
|
||||
function(meta, chunk, eof)
|
||||
|
||||
fp = io.open(image_tmp, "w")
|
||||
|
||||
if fp and chunk then
|
||||
fp:write(chunk)
|
||||
end
|
||||
if fp and eof then
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
|
||||
end
|
||||
|
||||
function get_app_name_by_id(appid)
|
||||
local class_fd = io.popen("find /tmp/appfilter/ -type f -name *.class |xargs cat |grep "..appid.."|awk '{print $2}'")
|
||||
if class_fd then
|
||||
local name = class_fd:read("*l")
|
||||
class_fd:close()
|
||||
return name
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function cmp_func(a,b)
|
||||
return a.latest_time > b.latest_time
|
||||
end
|
||||
|
||||
|
||||
function user_status()
|
||||
local json = require "luci.jsonc"
|
||||
luci.http.prepare_content("application/json")
|
||||
local fd = io.open("/proc/net/af_client","r")
|
||||
status_buf=fd:read('*a')
|
||||
fd:close()
|
||||
user_array=json.parse(status_buf)
|
||||
|
||||
local visit_obj=utl.ubus("appfilter", "visit_list", {});
|
||||
local user_array=visit_obj.dev_list
|
||||
local history={}
|
||||
for i, v in pairs(user_array) do
|
||||
visit_array=user_array[i].visit_info
|
||||
for j,s in pairs(visit_array) do
|
||||
print(user_array[i].mac, user_array[i].ip,visit_array[j].appid, visit_array[j].latest_time)
|
||||
total_time=visit_array[j].latest_time - visit_array[j].first_time;
|
||||
history[#history+1]={
|
||||
mac=user_array[i].mac,
|
||||
ip=user_array[i].ip,
|
||||
hostname=get_hostname_by_mac(user_array[i].mac),
|
||||
appid=visit_array[j].appid,
|
||||
appname=get_app_name_by_id(visit_array[j].appid),
|
||||
total_num=0,
|
||||
drop_num=0,
|
||||
latest_action=visit_array[j].latest_action,
|
||||
latest_time=os.date("%Y/%m/%d %H:%M:%S", visit_array[j].latest_time),
|
||||
first_time=os.date("%Y/%m/%d %H:%M:%S", visit_array[j].first_time),
|
||||
total_time=total_time
|
||||
}
|
||||
end
|
||||
end
|
||||
table.sort(history, cmp_func)
|
||||
luci.http.write_json(history);
|
||||
end
|
||||
|
||||
|
||||
function dev_app_status()
|
||||
local json = require "luci.jsonc"
|
||||
luci.http.prepare_content("application/json")
|
||||
local visit_obj=utl.ubus("appfilter", "dev_list", {});
|
||||
luci.http.write_json(visit_obj);
|
||||
end
|
||||
|
||||
|
||||
function get_dev_visit_time(mac)
|
||||
local json = require "luci.jsonc"
|
||||
luci.http.prepare_content("application/json")
|
||||
local fd = io.open("/proc/net/af_client","r")
|
||||
status_buf=fd:read('*a')
|
||||
fd:close()
|
||||
user_array=json.parse(status_buf)
|
||||
local req_obj = {}
|
||||
req_obj.mac = mac;
|
||||
local visit_obj=utl.ubus("appfilter", "dev_visit_time", req_obj);
|
||||
local user_array=visit_obj.app_list
|
||||
luci.http.write_json(user_array);
|
||||
end
|
||||
|
||||
function get_app_class_visit_time(mac)
|
||||
local json = require "luci.jsonc"
|
||||
luci.http.prepare_content("application/json")
|
||||
local req_obj = {}
|
||||
req_obj.mac = mac;
|
||||
local visit_obj=utl.ubus("appfilter", "app_class_visit_time", req_obj);
|
||||
local class_array=visit_obj.class_list
|
||||
luci.http.write_json(class_array);
|
||||
end
|
||||
|
||||
|
||||
function get_dev_visit_list(mac)
|
||||
local json = require "luci.jsonc"
|
||||
luci.http.prepare_content("application/json")
|
||||
local req_obj = {}
|
||||
req_obj.mac = mac;
|
||||
|
||||
local visit_obj=utl.ubus("appfilter", "visit_list", req_obj);
|
||||
local user_array=visit_obj.dev_list
|
||||
local history={}
|
||||
for i, v in pairs(user_array) do
|
||||
visit_array=user_array[i].visit_info
|
||||
for j,s in pairs(visit_array) do
|
||||
print(user_array[i].mac, user_array[i].ip,visit_array[j].appid, visit_array[j].latest_time)
|
||||
total_time=visit_array[j].latest_time - visit_array[j].first_time;
|
||||
history[#history+1]={
|
||||
mac=user_array[i].mac,
|
||||
ip=user_array[i].ip,
|
||||
hostname=get_hostname_by_mac(user_array[i].mac),
|
||||
appid=visit_array[j].appid,
|
||||
appname=get_app_name_by_id(visit_array[j].appid),
|
||||
total_num=0,
|
||||
drop_num=0,
|
||||
latest_action=visit_array[j].latest_action,
|
||||
latest_time=os.date("%Y/%m/%d %H:%M:%S", visit_array[j].latest_time),
|
||||
first_time=os.date("%Y/%m/%d %H:%M:%S", visit_array[j].first_time),
|
||||
total_time=total_time
|
||||
}
|
||||
end
|
||||
end
|
||||
table.sort(history, cmp_func)
|
||||
luci.http.write_json(history);
|
||||
end
|
@ -1,90 +0,0 @@
|
||||
local ds = require "luci.dispatcher"
|
||||
local nxo = require "nixio"
|
||||
local nfs = require "nixio.fs"
|
||||
local ipc = require "luci.ip"
|
||||
local sys = require "luci.sys"
|
||||
local utl = require "luci.util"
|
||||
local dsp = require "luci.dispatcher"
|
||||
local uci = require "luci.model.uci"
|
||||
local lng = require "luci.i18n"
|
||||
local jsc = require "luci.jsonc"
|
||||
local http = luci.http
|
||||
local SYS = require "luci.sys"
|
||||
local m, s
|
||||
|
||||
m = Map("appfilter", translate("App Filter"), translate(
|
||||
"请先关闭所有加速(acc)、广告过滤、多拨等可能冲突的模块"))
|
||||
|
||||
s = m:section(TypedSection, "global", translate("Basic Settings"))
|
||||
s:option(Flag, "enable", translate("Enable App Filter"), translate(""))
|
||||
s.anonymous = true
|
||||
|
||||
o=s:option(ListValue, "work_mode", translate("工作模式"),translate("请正确选择模式,一般经过了WAN口转发则为主路由,建议切换模式后重启设备"))
|
||||
o.default=0
|
||||
o:value(0,"主路由模式")
|
||||
o:value(1,"旁路由模式")
|
||||
|
||||
local rule_count = 0
|
||||
local version = ""
|
||||
|
||||
s = m:section(TypedSection, "appfilter", translate("App Filter Rules"))
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
local class_fd = io.popen("find /tmp/appfilter/ -type f -name '*.class'")
|
||||
if class_fd then
|
||||
while true do
|
||||
local apps
|
||||
local class
|
||||
local path = class_fd:read("*l")
|
||||
if not path then
|
||||
break
|
||||
end
|
||||
|
||||
class = path:match("([^/]+)%.class$")
|
||||
s:tab(class, translate(class))
|
||||
apps = s:taboption(class, MultiValue, class .. "apps", translate(""))
|
||||
apps.rmempty = true
|
||||
apps.widget = "checkbox"
|
||||
apps.size = 10
|
||||
|
||||
local fd = io.open(path)
|
||||
if fd then
|
||||
local line
|
||||
while true do
|
||||
local cmd
|
||||
local cmd_fd
|
||||
line = fd:read("*l")
|
||||
if not line then
|
||||
break
|
||||
end
|
||||
if string.len(line) < 5 then
|
||||
break
|
||||
end
|
||||
if not string.find(line, "#") then
|
||||
cmd = "echo " .. line .. "|awk '{print $1}'"
|
||||
cmd_fd = io.popen(cmd)
|
||||
id = cmd_fd:read("*l");
|
||||
cmd_fd:close()
|
||||
|
||||
cmd = "echo " .. line .. "|awk '{print $2}'"
|
||||
cmd_fd = io.popen(cmd)
|
||||
name = cmd_fd:read("*l")
|
||||
|
||||
cmd_fd:close()
|
||||
if not id then
|
||||
break
|
||||
end
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
apps:value(id, name)
|
||||
end
|
||||
end
|
||||
fd:close()
|
||||
end
|
||||
end
|
||||
class_fd:close()
|
||||
end
|
||||
|
||||
return m
|
@ -1,21 +0,0 @@
|
||||
local ds = require "luci.dispatcher"
|
||||
local nxo = require "nixio"
|
||||
local nfs = require "nixio.fs"
|
||||
local ipc = require "luci.ip"
|
||||
local sys = require "luci.sys"
|
||||
local utl = require "luci.util"
|
||||
local dsp = require "luci.dispatcher"
|
||||
local uci = require "luci.model.uci"
|
||||
local lng = require "luci.i18n"
|
||||
local jsc = require "luci.jsonc"
|
||||
|
||||
local m, s
|
||||
arg[1] = arg[1] or ""
|
||||
m = Map("appfilter", translate("Data Statistics") .. "(" .. arg[1] .. ")", translate(""))
|
||||
|
||||
local v
|
||||
v = m:section(SimpleSection)
|
||||
v.template = "admin_network/dev_status"
|
||||
v.mac = arg[1]
|
||||
m.redirect = luci.dispatcher.build_url("admin", "control", "appfilter")
|
||||
return m
|
@ -1,91 +0,0 @@
|
||||
local ds = require "luci.dispatcher"
|
||||
local nxo = require "nixio"
|
||||
local nfs = require "nixio.fs"
|
||||
local ipc = require "luci.ip"
|
||||
local sys = require "luci.sys"
|
||||
local utl = require "luci.util"
|
||||
local dsp = require "luci.dispatcher"
|
||||
local uci = require "luci.model.uci"
|
||||
local lng = require "luci.i18n"
|
||||
local jsc = require "luci.jsonc"
|
||||
local http = luci.http
|
||||
local SYS = require "luci.sys"
|
||||
local m, s
|
||||
|
||||
m = Map("appfilter", translate(""),
|
||||
translate("特征库用于描述app特征,app过滤效果和个数依赖特征库"))
|
||||
|
||||
local rule_count = 0
|
||||
local version = ""
|
||||
if nixio.fs.access("/tmp/feature.cfg") then
|
||||
rule_count = tonumber(SYS.exec("cat /tmp/feature.cfg | wc -l"))
|
||||
version = SYS.exec("cat /tmp/feature.cfg |grep \"#version\" | awk '{print $2}'")
|
||||
end
|
||||
|
||||
local display_str = "<strong>当前版本: </strong>" .. version .. "<br><strong>特征码个数:</strong> " ..
|
||||
rule_count ..
|
||||
"<br><strong> 下载地址:</strong><a href=\"https://destan19.github.io\">https://destan19.github.io</a>"
|
||||
s = m:section(TypedSection, "feature", translate("Update feature"), display_str)
|
||||
|
||||
fu = s:option(FileUpload, "")
|
||||
fu.template = "cbi/oaf_upload"
|
||||
s.anonymous = true
|
||||
|
||||
um = s:option(DummyValue, "rule_data")
|
||||
um.template = "cbi/oaf_dvalue"
|
||||
|
||||
local dir, fd
|
||||
dir = "/tmp/upload/"
|
||||
nixio.fs.mkdir(dir)
|
||||
http.setfilehandler(function(meta, chunk, eof)
|
||||
if not fd then
|
||||
if not meta then
|
||||
return
|
||||
end
|
||||
if meta and chunk then
|
||||
fd = nixio.open(dir .. meta.file, "w")
|
||||
end
|
||||
if not fd then
|
||||
return
|
||||
end
|
||||
end
|
||||
if chunk and fd then
|
||||
fd:write(chunk)
|
||||
end
|
||||
if eof and fd then
|
||||
fd:close()
|
||||
local fd2 = io.open("/tmp/upload/" .. meta.file)
|
||||
local line = fd2:read("*l");
|
||||
fd2:close()
|
||||
local ret = string.match(line, "#version")
|
||||
local lang = m.uci:get_all("luci.main.lang")
|
||||
local feature_file = ""
|
||||
if "" == lang or "auto" == lang then
|
||||
feature_file = "/etc/appfilter/feature.cfg"
|
||||
else
|
||||
feature_file = "/etc/appfilter/feature_" .. lang .. ".cfg"
|
||||
end
|
||||
if ret ~= nil then
|
||||
local cmd = "cp /tmp/upload/" .. meta.file .. " " .. feature_file;
|
||||
os.execute(cmd);
|
||||
os.execute("chmod 666 " .. feature_file);
|
||||
os.execute("rm /tmp/appfilter -fr");
|
||||
luci.sys.exec("/etc/init.d/appfilter restart &");
|
||||
um.value = translate("Update the feature file successfully, please refresh the page")
|
||||
else
|
||||
um.value = translate("Failed to update feature file, format error")
|
||||
end
|
||||
os.execute("rm /tmp/upload/* -fr");
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
if luci.http.formvalue("upload") then
|
||||
local f = luci.http.formvalue("ulfile")
|
||||
if #f <= 0 then
|
||||
-- um.value = translate("No specify upload file.")
|
||||
end
|
||||
elseif luci.http.formvalue("download") then
|
||||
Download()
|
||||
end
|
||||
return m
|
@ -1,49 +0,0 @@
|
||||
local ds = require "luci.dispatcher"
|
||||
local nxo = require "nixio"
|
||||
local nfs = require "nixio.fs"
|
||||
local ipc = require "luci.ip"
|
||||
local sys = require "luci.sys"
|
||||
local utl = require "luci.util"
|
||||
local dsp = require "luci.dispatcher"
|
||||
local uci = require "luci.model.uci"
|
||||
local lng = require "luci.i18n"
|
||||
local jsc = require "luci.jsonc"
|
||||
local http = luci.http
|
||||
local SYS = require "luci.sys"
|
||||
local m, s
|
||||
|
||||
m = Map("appfilter", translate(""), translate(""))
|
||||
|
||||
s = m:section(TypedSection, "time", translate("Time Setting"),translate("时间2为选填,开始和结束时间需要同时设置,结束时间要大于开始时间"))
|
||||
s.anonymous = true
|
||||
|
||||
|
||||
o=s:option(ListValue, "time_mode", translate("时间匹配模式:"),translate(""))
|
||||
o.default=0
|
||||
o:value(0,"时间范围内规则生效")
|
||||
o:value(1,"时间范围外规则生效")
|
||||
|
||||
days = s:option(MultiValue, "days", "", translate(""))
|
||||
days.widget = "checkbox"
|
||||
days.size = 10
|
||||
days:value("0", translate("Sun"));
|
||||
days:value("1", translate("Mon"));
|
||||
days:value("2", translate("Tue"));
|
||||
days:value("3", translate("Wed"));
|
||||
days:value("4", translate("Thur"));
|
||||
days:value("5", translate("Fri"));
|
||||
days:value("6", translate("Sat"));
|
||||
|
||||
hv = s:option(Value, "start_time", translate("Start Time1"),translate("格式xx:xx,下同"))
|
||||
hv.optional = false
|
||||
hv = s:option(Value, "end_time", translate("End Time1"))
|
||||
hv.optional = false
|
||||
|
||||
hv = s:option(Value, "start_time2", translate("Start Time2"))
|
||||
hv.optional = false
|
||||
hv = s:option(Value, "end_time2", translate("End Time2"))
|
||||
hv.optional = false
|
||||
|
||||
|
||||
|
||||
return m
|
@ -1,19 +0,0 @@
|
||||
local ds = require "luci.dispatcher"
|
||||
local nxo = require "nixio"
|
||||
local nfs = require "nixio.fs"
|
||||
local ipc = require "luci.ip"
|
||||
local sys = require "luci.sys"
|
||||
local utl = require "luci.util"
|
||||
local dsp = require "luci.dispatcher"
|
||||
local uci = require "luci.model.uci"
|
||||
local lng = require "luci.i18n"
|
||||
local jsc = require "luci.jsonc"
|
||||
local http = luci.http
|
||||
local SYS = require "luci.sys"
|
||||
local m, s
|
||||
|
||||
m = Map("appfilter", translate(""), translate(""))
|
||||
|
||||
m:section(SimpleSection).template = "admin_network/user_status"
|
||||
|
||||
return m
|
@ -1,91 +0,0 @@
|
||||
local ds = require "luci.dispatcher"
|
||||
local nxo = require "nixio"
|
||||
local nfs = require "nixio.fs"
|
||||
local ipc = require "luci.ip"
|
||||
local sys = require "luci.sys"
|
||||
local utl = require "luci.util"
|
||||
local dsp = require "luci.dispatcher"
|
||||
local uci = require "luci.model.uci"
|
||||
local lng = require "luci.i18n"
|
||||
local jsc = require "luci.jsonc"
|
||||
local http = luci.http
|
||||
local SYS = require "luci.sys"
|
||||
local m, s
|
||||
|
||||
m = Map("appfilter", translate("App Filter"), translate(""))
|
||||
|
||||
function get_hostname_by_mac(dst_mac)
|
||||
leasefile = "/tmp/dhcp.leases"
|
||||
local fd = io.open(leasefile, "r")
|
||||
if not fd then
|
||||
return
|
||||
end
|
||||
while true do
|
||||
local ln = fd:read("*l")
|
||||
if not ln then
|
||||
break
|
||||
end
|
||||
local ts, mac, ip, name, duid = ln:match("^(%d+) (%S+) (%S+) (%S+) (%S+)")
|
||||
print(ln)
|
||||
if dst_mac == mac then
|
||||
fd:close()
|
||||
return name
|
||||
end
|
||||
end
|
||||
fd:close()
|
||||
return nil
|
||||
end
|
||||
|
||||
function get_cmd_result(command)
|
||||
local fd
|
||||
local result
|
||||
fd = io.popen(command);
|
||||
if not fd then
|
||||
return ""
|
||||
end
|
||||
result = fd:read("*l");
|
||||
fd:close()
|
||||
return result
|
||||
end
|
||||
|
||||
s = m:section(TypedSection, "user", translate("Select users"))
|
||||
s.anonymous = true
|
||||
users = s:option(MultiValue, "users", "", translate(
|
||||
"It takes effect for all users by default, and only takes effect for the selected users when checked"))
|
||||
users.widget = "checkbox"
|
||||
-- users.widget="select"
|
||||
users.size = 1
|
||||
|
||||
local fd = io.open("/tmp/dev_list", "r")
|
||||
if not fd then
|
||||
return m
|
||||
end
|
||||
while true do
|
||||
local line = fd:read("*l")
|
||||
if not line then
|
||||
break
|
||||
end
|
||||
if not string.match(line, "^Id") then
|
||||
local ip = get_cmd_result(string.format("echo '%s' | awk '{print $3}'", line))
|
||||
local mac = get_cmd_result(string.format("echo '%s' | awk '{print $2}'", line))
|
||||
local hostname = get_cmd_result(string.format("echo '%s' | awk '{print $4}'", line))
|
||||
if mac ~= nil then
|
||||
if not hostname or hostname == "*" then
|
||||
users:value(mac, mac);
|
||||
else
|
||||
users:value(mac, hostname .. "(" .. mac .. ")");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
fd:close()
|
||||
|
||||
local config_users = m.uci:get_all("appfilter.user.users")
|
||||
if config_users ~= nil and config_users ~= false then
|
||||
local r = utl.split(config_users, "%s+", nil, true)
|
||||
local max = table.getn(r)
|
||||
for i = 1, max, 1 do
|
||||
users:value(r[i], r[i]);
|
||||
end
|
||||
end
|
||||
return m
|
@ -1,382 +0,0 @@
|
||||
<style type="text/css">
|
||||
<% local dsp=require "luci.dispatcher"
|
||||
|
||||
-%>#display {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#main {
|
||||
min-width: 600px;
|
||||
height: 300px;
|
||||
display: inline-block;
|
||||
flex: 2 2 10%;
|
||||
}
|
||||
|
||||
#main2 {
|
||||
min-width: 600px;
|
||||
height: 300px;
|
||||
display: inline-block;
|
||||
flex: 2 2 10%;
|
||||
}
|
||||
|
||||
table.imagetable {
|
||||
font-family: verdana, arial, sans-serif;
|
||||
font-size: 11px;
|
||||
color: #333333;
|
||||
border-width: 1px;
|
||||
border-color: #999999;
|
||||
border-collapse: collapse;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
< !-- table.imagetable th {
|
||||
background: #f5f5f5 border-width: 0px;
|
||||
padding: 5px;
|
||||
border-style: solid;
|
||||
border-color: #999999;
|
||||
}
|
||||
|
||||
table.imagetable td {
|
||||
background: #ffffffff border-width: 0px;
|
||||
padding: 5px;
|
||||
border-style: solid;
|
||||
border-color: #999999;
|
||||
}
|
||||
|
||||
-->
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/echarts.min.js?v=5.0"></script>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
window.onload = function () {
|
||||
|
||||
}
|
||||
var app_class_data;
|
||||
var app_time_data;
|
||||
var mac = '<%=self.mac%>';
|
||||
function get_display_time(total_time) {
|
||||
var hour = parseInt(total_time / 3600);
|
||||
var seconds = total_time % 3600;
|
||||
var min = parseInt(seconds / 60)
|
||||
var seconds2 = seconds % 60;
|
||||
var total_time_str;
|
||||
|
||||
if (hour > 0)
|
||||
total_time_str = hour + "<%:h%>" + min + "<%:m%>"
|
||||
else {
|
||||
if (min == 0 && seconds2 != 0)
|
||||
min = 1;
|
||||
total_time_str = min + "<%:m%>"
|
||||
}
|
||||
return total_time_str;
|
||||
}
|
||||
|
||||
function display_app_visit_view(data) {
|
||||
var myChart = echarts.init(document.getElementById('main2'));
|
||||
var dev_array = new Array();
|
||||
var m2R2Data = new Array()
|
||||
var total_time = 0
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var dev_obj = data[i];
|
||||
var m2_obj = {};
|
||||
m2_obj.value = dev_obj.visit_time;
|
||||
m2_obj.legendname = dev_obj.app_id;
|
||||
|
||||
var tmp_time = get_display_time(dev_obj.visit_time);
|
||||
|
||||
m2_obj.name = dev_obj.app_id + " " + tmp_time;
|
||||
total_time += dev_obj.visit_time
|
||||
m2R2Data.push(m2_obj);
|
||||
}
|
||||
|
||||
var total_time_str = get_display_time(total_time);
|
||||
option = {
|
||||
title: [
|
||||
{
|
||||
text: "<%:App Time Statistics%>",
|
||||
textStyle: {
|
||||
fontSize: 16,
|
||||
color: "black"
|
||||
},
|
||||
left: "2%"
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
subtext: total_time_str,
|
||||
textStyle: {
|
||||
fontSize: 15,
|
||||
color: "black"
|
||||
},
|
||||
subtextStyle: {
|
||||
fontSize: 15,
|
||||
color: 'black'
|
||||
},
|
||||
textAlign: "center",
|
||||
x: '34.5%',
|
||||
y: '44%',
|
||||
}],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: function (parms) {
|
||||
var total_time = get_display_time(parms.data.value);
|
||||
var str = parms.seriesName + "</br>" +
|
||||
parms.marker + "" + parms.data.legendname + "</br>" +
|
||||
"<%:Visit Time%>: " + total_time + "</br>" +
|
||||
"<%:Percentage%>: " + parms.percent + "%";
|
||||
return str;
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
type: "scroll",
|
||||
orient: 'vertical',
|
||||
left: '70%',
|
||||
align: 'left',
|
||||
top: 'middle',
|
||||
textStyle: {
|
||||
color: '#8C8C8C'
|
||||
},
|
||||
height: 250
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "<%:Visit Time%>",
|
||||
type: 'pie',
|
||||
center: ['35%', '50%'],
|
||||
radius: ['40%', '65%'],
|
||||
clockwise: false,
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'outter',
|
||||
formatter: function (parms) {
|
||||
return parms.data.legendname
|
||||
}
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
normal: {
|
||||
length: 8,
|
||||
length2: 7,
|
||||
smooth: true,
|
||||
}
|
||||
},
|
||||
data: m2R2Data
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
function display_app_class_view(data) {
|
||||
console.log("begin display.");
|
||||
var myChart = echarts.init(document.getElementById('main'));
|
||||
var dev_array = new Array();
|
||||
var m2R2Data = new Array()
|
||||
var total_time = 0
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var dev_obj = data[i];
|
||||
if (dev_obj.visit_time == 0)
|
||||
continue;
|
||||
|
||||
var m2_obj = {};
|
||||
m2_obj.value = dev_obj.visit_time;
|
||||
m2_obj.legendname = dev_obj.name;
|
||||
|
||||
var tmp_time = get_display_time(dev_obj.visit_time);
|
||||
|
||||
m2_obj.name = dev_obj.name + " " + tmp_time;
|
||||
total_time += dev_obj.visit_time
|
||||
m2R2Data.push(m2_obj);
|
||||
}
|
||||
|
||||
var total_time_str = get_display_time(total_time);
|
||||
|
||||
option = {
|
||||
title: [
|
||||
{
|
||||
text: "<%:App classification time statistics%>",
|
||||
textStyle: {
|
||||
fontSize: 16,
|
||||
color: "black"
|
||||
},
|
||||
left: "2%"
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
subtext: total_time_str,
|
||||
textStyle: {
|
||||
fontSize: 15,
|
||||
color: "black"
|
||||
},
|
||||
subtextStyle: {
|
||||
fontSize: 15,
|
||||
color: 'black'
|
||||
},
|
||||
textAlign: "center",
|
||||
x: '34.5%',
|
||||
y: '44%',
|
||||
}],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: function (parms) {
|
||||
var total_time = get_display_time(parms.data.value);
|
||||
var str = parms.seriesName + "</br>" +
|
||||
parms.marker + "" + parms.data.legendname + "</br>" + "<%:Visit Time%>: " + total_time + "</br>" +
|
||||
"<%:Percentage%>: " + parms.percent + "%";
|
||||
return str;
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
type: "scroll",
|
||||
orient: 'vertical',
|
||||
left: '70%',
|
||||
align: 'left',
|
||||
top: 'middle',
|
||||
textStyle: {
|
||||
color: '#8C8C8C'
|
||||
},
|
||||
height: 250
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "<%:Visit Time%>",
|
||||
type: 'pie',
|
||||
center: ['35%', '50%'],
|
||||
radius: ['40%', '65%'],
|
||||
clockwise: false,
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'outter',
|
||||
formatter: function (parms) {
|
||||
return parms.data.legendname
|
||||
}
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
normal: {
|
||||
length: 8,
|
||||
length2: 7,
|
||||
smooth: true,
|
||||
}
|
||||
},
|
||||
data: m2R2Data
|
||||
}
|
||||
]
|
||||
};
|
||||
myChart.setOption(option);
|
||||
}
|
||||
new XHR().get('<%=url('admin/network/app_class_visit_time')%>/' + mac, null,
|
||||
function (x, st) {
|
||||
display_app_class_view(st);
|
||||
}
|
||||
);
|
||||
|
||||
new XHR().get('<%=url('admin/network/dev_visit_time')%>/' + mac, null,
|
||||
function (x, st) {
|
||||
display_app_visit_view(st);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
new XHR().get('<%=url('admin/network/dev_visit_list')%>/' + mac, null,
|
||||
function (x, st) {
|
||||
var tb = document.getElementById('user_status_table');
|
||||
var str = JSON.stringify(st);
|
||||
if (st && tb) {
|
||||
/* clear all rows */
|
||||
while (tb.rows.length > 1)
|
||||
tb.deleteRow(1);
|
||||
for (var i = 0; i < st.length; i++) {
|
||||
var action_status = ""
|
||||
if (st[i].latest_action == 1)
|
||||
action_status = "<%:Filtered%>"
|
||||
else
|
||||
action_status = "<%:Unfiltered%>"
|
||||
var hostname = ""
|
||||
if (st[i].hostname == "" || st[i].hostname == "*") {
|
||||
hostname = "--";
|
||||
}
|
||||
else {
|
||||
hostname = st[i].hostname;
|
||||
}
|
||||
var tr = tb.insertRow(-1);
|
||||
tr.className = 'tr cbi-rowstyle-' + ((i % 2) + 1);
|
||||
tr.insertCell(-1).innerHTML = st[i].appname;
|
||||
tr.insertCell(-1).innerHTML = hostname;
|
||||
tr.insertCell(-1).innerHTML = st[i].mac;
|
||||
tr.insertCell(-1).innerHTML = st[i].first_time;
|
||||
var hour = parseInt(st[i].total_time / 3600);
|
||||
var seconds = st[i].total_time % 3600;
|
||||
var min = parseInt(seconds / 60)
|
||||
var total_time_str;
|
||||
if (st[i].latest_action == 1)
|
||||
total_time_str = "-"
|
||||
else {
|
||||
if (hour > 0)
|
||||
total_time_str = hour + "<%:h%>" + min + "<%:m%>"
|
||||
else {
|
||||
if (min == 0)
|
||||
min = 1;
|
||||
total_time_str = min + "<%:m%>"
|
||||
}
|
||||
}
|
||||
|
||||
tr.insertCell(-1).innerHTML = total_time_str;
|
||||
tr.insertCell(-1).innerHTML = action_status;
|
||||
var childs = tr.childNodes;
|
||||
Array.prototype.forEach.call(childs, function (child) {
|
||||
child.className = 'td';
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//]]></script>
|
||||
|
||||
|
||||
<div class="cbi-section cbi-tblsection">
|
||||
<div id="display">
|
||||
<div id="main" class="main left"></div>
|
||||
<div id="main2" class="main2 left"></div>
|
||||
</div>
|
||||
<table class="table cbi-section-table" id="user_status_table">
|
||||
<tr class="tr table-titles">
|
||||
<th class="th">
|
||||
<%:App Name%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Hostname%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Mac%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Start Time%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Visit Time%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Filter Status%>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="tr table-titles">
|
||||
<td class="td" colspan="8"><em><br />
|
||||
<%:Collecting data...%>
|
||||
</em></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
@ -1,82 +0,0 @@
|
||||
<% local dsp=require "luci.dispatcher" -%>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(5, '<%=url('admin/network/dev_app_status')%>', null,
|
||||
function (x, st) {
|
||||
var tb = document.getElementById('user_status_table');
|
||||
var dev_list_str = JSON.stringify(st);
|
||||
if (st && tb) {
|
||||
while (tb.rows.length > 1)
|
||||
tb.deleteRow(1);
|
||||
var devlist = st.devlist
|
||||
for (var i = 0; i < devlist.length; i++) {
|
||||
var hostname = ""
|
||||
if (devlist[i].hostname == "" || devlist[i].hostname == "*") {
|
||||
hostname = "--";
|
||||
}
|
||||
else {
|
||||
hostname = devlist[i].hostname;
|
||||
}
|
||||
var tr = tb.insertRow(-1);
|
||||
tr.className = 'tr cbi-rowstyle-' + ((i % 2) + 1);
|
||||
tr.insertCell(-1).innerHTML = i + 1;
|
||||
tr.insertCell(-1).innerHTML = hostname;
|
||||
tr.insertCell(-1).innerHTML = "<a href='<%=url('admin/control/appfilter/user_list/')%>" + devlist[i].mac + "'>" + devlist[i].mac + "</a>";
|
||||
tr.insertCell(-1).innerHTML = devlist[i].ip;
|
||||
var app_list_str = "";
|
||||
for (var j = 0; j < devlist[i].applist.length; j++) {
|
||||
console.log(devlist[i].applist[j].name);
|
||||
app_list_str += devlist[i].applist[j].name;
|
||||
if (j != devlist[i].applist.length - 1)
|
||||
app_list_str += ","
|
||||
}
|
||||
if (app_list_str == "") {
|
||||
app_list_str = "--"
|
||||
}
|
||||
tr.insertCell(-1).innerHTML = app_list_str;
|
||||
if (devlist[i].online == 1) {
|
||||
tr.insertCell(-1).innerHTML = "<%:Online%>";
|
||||
} else {
|
||||
tr.insertCell(-1).innerHTML = "<%:Offline%>";
|
||||
}
|
||||
var childs = tr.childNodes;
|
||||
Array.prototype.forEach.call(childs, function (child) {
|
||||
child.className = 'td';
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//]]></script>
|
||||
|
||||
|
||||
<div class="cbi-section cbi-tblsection">
|
||||
<table class="table cbi-section-table" id="user_status_table">
|
||||
<tr class="tr table-titles">
|
||||
<th class="th">
|
||||
<%:Id%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Hostname%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Mac%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Ip%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Common App(TOP5)%>
|
||||
</th>
|
||||
<th class="th">
|
||||
<%:Online Status%>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="tr">
|
||||
<td class="td" colspan="8"><em><br />
|
||||
<%:Collecting data...%>
|
||||
</em></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
@ -1,8 +0,0 @@
|
||||
<%+cbi/valueheader%>
|
||||
<span style="color: red">
|
||||
<%
|
||||
local val = self:cfgvalue(section) or self.default or ""
|
||||
write(pcdata(val))
|
||||
%>
|
||||
</span>
|
||||
<%+cbi/valuefooter%>
|
@ -1,5 +0,0 @@
|
||||
<%+cbi/valueheader%>
|
||||
<label class="cbi-value" style="display:inline-block; width: 130px" for="ulfile"><%:Select feature file:%></label>
|
||||
<input class="cbi-input-file" style="width: 500px" type="file" id="ulfile" name="ulfile" />
|
||||
<input type="submit" class="cbi-button cbi-input-apply" name="upload" value="<%:Upload%>" />
|
||||
<%+cbi/valuefooter%>
|
@ -1,167 +0,0 @@
|
||||
|
||||
msgid "website"
|
||||
msgstr "常用网站"
|
||||
|
||||
msgid "appfilter"
|
||||
msgstr "应用过滤"
|
||||
|
||||
msgid "App Filter"
|
||||
msgstr "应用过滤"
|
||||
|
||||
msgid "game"
|
||||
msgstr "游戏"
|
||||
|
||||
msgid "web"
|
||||
msgstr "网页"
|
||||
|
||||
msgid "video"
|
||||
msgstr "视频"
|
||||
|
||||
msgid "chat"
|
||||
msgstr "聊天"
|
||||
|
||||
msgid "download"
|
||||
msgstr "下载"
|
||||
|
||||
msgid "p2p"
|
||||
msgstr "p2p"
|
||||
|
||||
msgid "music"
|
||||
msgstr "音乐"
|
||||
|
||||
msgid "shopping"
|
||||
msgstr "购物"
|
||||
|
||||
msgid "working"
|
||||
msgstr "办公"
|
||||
|
||||
msgid "employee"
|
||||
msgstr "招聘"
|
||||
|
||||
msgid "Basic Settings"
|
||||
msgstr "基本设置"
|
||||
|
||||
msgid "App Filter Rules"
|
||||
msgstr "应用过滤规则"
|
||||
|
||||
msgid "It takes effect for all users by default, and only takes effect for the selected users when checked"
|
||||
msgstr "默认对所有用户生效,勾选后只对选择的用户生效"
|
||||
|
||||
msgid "Select users"
|
||||
msgstr "选择用户"
|
||||
|
||||
msgid "Id"
|
||||
msgstr "编号"
|
||||
|
||||
msgid "Hostname"
|
||||
msgstr "主机名"
|
||||
|
||||
msgid "Common App(TOP5)"
|
||||
msgstr "常用APP(TOP5)"
|
||||
|
||||
msgid "Online Status"
|
||||
msgstr "在线状态"
|
||||
|
||||
msgid "Client List"
|
||||
msgstr "终端列表"
|
||||
|
||||
msgid "Online"
|
||||
msgstr "在线"
|
||||
|
||||
msgid "Offline"
|
||||
msgstr "离线"
|
||||
|
||||
msgid "App Time Statistics"
|
||||
msgstr "App 时间统计"
|
||||
|
||||
msgid "Filter Status"
|
||||
msgstr "过滤状态"
|
||||
|
||||
msgid "Data Statistics"
|
||||
msgstr "数据统计"
|
||||
|
||||
|
||||
|
||||
msgid "Current Version"
|
||||
msgstr "当前版本"
|
||||
|
||||
msgid "App Feature Num"
|
||||
msgstr "特征码个数"
|
||||
|
||||
msgid "Update feature"
|
||||
msgstr "特征库更新"
|
||||
|
||||
msgid "Time Setting"
|
||||
msgstr "时间控制"
|
||||
|
||||
msgid "Sun"
|
||||
msgstr "周日"
|
||||
|
||||
msgid "Mon"
|
||||
msgstr "周一"
|
||||
|
||||
msgid "Tue"
|
||||
msgstr "周二"
|
||||
|
||||
msgid "Wed"
|
||||
msgstr "周三"
|
||||
|
||||
msgid "Thur"
|
||||
msgstr "周四"
|
||||
|
||||
msgid "Fri"
|
||||
msgstr "周五"
|
||||
|
||||
msgid "Sat"
|
||||
msgstr "周六"
|
||||
|
||||
msgid "Update the feature file successfully, please refresh the page"
|
||||
msgstr "更新特征库成功,请刷新页面!"
|
||||
|
||||
msgid "Failed to update feature file, format error"
|
||||
msgstr "更新特征库失败,格式错误!"
|
||||
|
||||
msgid "Select feature file:"
|
||||
msgstr "选择本地特征库文件:"
|
||||
|
||||
msgid "Start Time1"
|
||||
msgstr "开始时间1"
|
||||
|
||||
msgid "End Time1"
|
||||
msgstr "结束时间1"
|
||||
|
||||
|
||||
msgid "Start Time2"
|
||||
msgstr "开始时间2"
|
||||
|
||||
msgid "End Time2"
|
||||
msgstr "结束时间2"
|
||||
|
||||
msgid "App Name"
|
||||
msgstr "App名称"
|
||||
|
||||
msgid "Visit Time"
|
||||
msgstr "访问时间"
|
||||
|
||||
msgid "App classification time statistics"
|
||||
msgstr "App分类时间统计"
|
||||
|
||||
msgid "Percentage"
|
||||
msgstr "占比"
|
||||
|
||||
msgid "Filtered"
|
||||
msgstr "已过滤"
|
||||
|
||||
msgid "Unfiltered"
|
||||
msgstr "未过滤"
|
||||
|
||||
msgid "h"
|
||||
msgstr "小时"
|
||||
|
||||
msgid "m"
|
||||
msgstr "分"
|
||||
|
||||
msgid "Enable App Filter"
|
||||
msgstr "开启应用过滤"
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
del ucitrack.@appfilter[-1]
|
||||
add ucitrack appfilter
|
||||
set ucitrack.@appfilter[-1].exec="/usr/bin/oaf_rule reload"
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
# remove LuCI cache
|
||||
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
|
@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
set appfilter.time.time_mode="0"
|
||||
set appfilter.time.start_time2=""
|
||||
set appfilter.time.end_time2=""
|
||||
commit appfilter
|
||||
EOF
|
@ -1,39 +0,0 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=oaf
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
PKG_AUTOLOAD:=oaf
|
||||
RSTRIP:=:
|
||||
|
||||
define KernelPackage/oaf
|
||||
SECTION:=Derry Apps
|
||||
CATEGORY:=Derry Apps
|
||||
TITLE:=open app filter kernel module
|
||||
FILES:=$(PKG_BUILD_DIR)/oaf.ko
|
||||
DEPENDS:=+kmod-ipt-conntrack
|
||||
KCONFIG:=
|
||||
AUTOLOAD:=$(call AutoLoad,0,$(PKG_AUTOLOAD))
|
||||
endef
|
||||
|
||||
define KernelPackage/oaf/description
|
||||
open appfilter kernel module
|
||||
endef
|
||||
|
||||
|
||||
MAKE_OPTS:= \
|
||||
$(KERNEL_MAKE_FLAGS) \
|
||||
M="$(PKG_BUILD_DIR)" \
|
||||
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
|
||||
$(EXTRA_KCONFIG)
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C "$(LINUX_DIR)" \
|
||||
$(MAKE_OPTS) \
|
||||
modules
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,oaf))
|
||||
|
@ -1,2 +0,0 @@
|
||||
oaf-objs := app_filter.o af_utils.o regexp.o cJSON.o app_filter_config.o af_log.o af_client.o af_client_fs.o
|
||||
obj-m += oaf.o
|
@ -1,438 +0,0 @@
|
||||
/*
|
||||
Author:Derry
|
||||
Date: 2019/11/12
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_acct.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/ip.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "af_client.h"
|
||||
#include "af_client_fs.h"
|
||||
#include "af_log.h"
|
||||
#include "af_utils.h"
|
||||
#include "app_filter.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
DEFINE_RWLOCK(af_client_lock);
|
||||
|
||||
u32 total_client = 0;
|
||||
struct list_head af_client_list_table[MAX_AF_CLIENT_HASH_SIZE];
|
||||
|
||||
int af_send_msg_to_user(char *pbuf, uint16_t len);
|
||||
|
||||
static void
|
||||
nf_client_list_init(void)
|
||||
{
|
||||
int i;
|
||||
AF_CLIENT_LOCK_W();
|
||||
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++)
|
||||
{
|
||||
INIT_LIST_HEAD(&af_client_list_table[i]);
|
||||
}
|
||||
AF_CLIENT_UNLOCK_W();
|
||||
AF_INFO("client list init......ok\n");
|
||||
}
|
||||
|
||||
static void
|
||||
nf_client_list_clear(void)
|
||||
{
|
||||
int i;
|
||||
af_client_info_t *p = NULL;
|
||||
char mac_str[32] = {0};
|
||||
|
||||
AF_DEBUG("clean list\n");
|
||||
AF_CLIENT_LOCK_W();
|
||||
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++)
|
||||
{
|
||||
while (!list_empty(&af_client_list_table[i]))
|
||||
{
|
||||
p = list_first_entry(&af_client_list_table[i], af_client_info_t, hlist);
|
||||
memset(mac_str, 0x0, sizeof(mac_str));
|
||||
sprintf(mac_str, MAC_FMT, MAC_ARRAY(p->mac));
|
||||
AF_DEBUG("clean mac:%s\n", mac_str);
|
||||
list_del(&(p->hlist));
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
AF_CLIENT_UNLOCK_W();
|
||||
}
|
||||
|
||||
void af_client_list_reset_report_num(void)
|
||||
{
|
||||
int i;
|
||||
af_client_info_t *node = NULL;
|
||||
AF_CLIENT_LOCK_W();
|
||||
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++)
|
||||
{
|
||||
list_for_each_entry(node, &af_client_list_table[i], hlist)
|
||||
{
|
||||
node->report_count = 0;
|
||||
}
|
||||
}
|
||||
AF_CLIENT_UNLOCK_W();
|
||||
}
|
||||
|
||||
int get_mac_hash_code(unsigned char *mac)
|
||||
{
|
||||
if (!mac)
|
||||
return 0;
|
||||
else
|
||||
return mac[5] & (MAX_AF_CLIENT_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
af_client_info_t *find_af_client(unsigned char *mac)
|
||||
{
|
||||
af_client_info_t *node;
|
||||
unsigned int index;
|
||||
|
||||
index = get_mac_hash_code(mac);
|
||||
list_for_each_entry(node, &af_client_list_table[index], hlist)
|
||||
{
|
||||
if (0 == memcmp(node->mac, mac, 6))
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
af_client_info_t *find_and_add_af_client(unsigned char *mac)
|
||||
{
|
||||
af_client_info_t *nfc;
|
||||
nfc = find_af_client(mac);
|
||||
if (!nfc){
|
||||
nfc = nf_client_add(mac);
|
||||
}
|
||||
return nfc;
|
||||
}
|
||||
|
||||
|
||||
af_client_info_t *find_af_client_by_ip(unsigned int ip)
|
||||
{
|
||||
af_client_info_t *node;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++)
|
||||
{
|
||||
list_for_each_entry(node, &af_client_list_table[i], hlist)
|
||||
{
|
||||
if (node->ip == ip)
|
||||
{
|
||||
AF_LMT_DEBUG("match node->ip=%pI4, ip=%pI4\n", &node->ip, &ip);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
af_client_info_t *
|
||||
nf_client_add(unsigned char *mac)
|
||||
{
|
||||
af_client_info_t *node;
|
||||
int index = 0;
|
||||
|
||||
node = (af_client_info_t *)kmalloc(sizeof(af_client_info_t), GFP_ATOMIC);
|
||||
if (node == NULL)
|
||||
{
|
||||
AF_ERROR("kmalloc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(node, 0, sizeof(af_client_info_t));
|
||||
memcpy(node->mac, mac, MAC_ADDR_LEN);
|
||||
|
||||
node->create_jiffies = jiffies;
|
||||
node->update_jiffies = jiffies;
|
||||
index = get_mac_hash_code(mac);
|
||||
|
||||
AF_LMT_INFO("new client mac=" MAC_FMT "\n", MAC_ARRAY(node->mac));
|
||||
total_client++;
|
||||
list_add(&(node->hlist), &af_client_list_table[index]);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void check_client_expire(void)
|
||||
{
|
||||
af_client_info_t *node;
|
||||
int i;
|
||||
AF_CLIENT_LOCK_W();
|
||||
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++)
|
||||
{
|
||||
list_for_each_entry(node, &af_client_list_table[i], hlist)
|
||||
{
|
||||
AF_DEBUG("mac:" MAC_FMT " update:%lu interval:%lu\n", MAC_ARRAY(node->mac),
|
||||
node->update_jiffies, (jiffies - node->update_jiffies) / HZ);
|
||||
if (jiffies > (node->update_jiffies + MAX_CLIENT_ACTIVE_TIME * HZ))
|
||||
{
|
||||
AF_INFO("del client:" MAC_FMT "\n", MAC_ARRAY(node->mac));
|
||||
list_del(&(node->hlist));
|
||||
kfree(node);
|
||||
AF_CLIENT_UNLOCK_W();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
AF_CLIENT_UNLOCK_W();
|
||||
}
|
||||
|
||||
#define MAX_EXPIRED_VISIT_INFO_COUNT 10
|
||||
void flush_expired_visit_info(af_client_info_t *node)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
u_int32_t cur_timep = 0;
|
||||
int timeout = 0;
|
||||
cur_timep = af_get_timestamp_sec();
|
||||
for (i = 0; i < MAX_RECORD_APP_NUM; i++)
|
||||
{
|
||||
if (node->visit_info[i].app_id == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_RECORD_APP_NUM; i++)
|
||||
{
|
||||
if (count >= MAX_EXPIRED_VISIT_INFO_COUNT)
|
||||
break;
|
||||
|
||||
if (node->visit_info[i].total_num > 3)
|
||||
{
|
||||
timeout = 180;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout = 60;
|
||||
}
|
||||
|
||||
if (cur_timep - node->visit_info[i].latest_time > timeout)
|
||||
{
|
||||
// 3?<3F><>o?<3F><>??3y????
|
||||
memset(&node->visit_info[i], 0x0, sizeof(app_visit_info_t));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __af_visit_info_report(af_client_info_t *node)
|
||||
{
|
||||
unsigned char mac_str[32] = {0};
|
||||
unsigned char ip_str[32] = {0};
|
||||
int i;
|
||||
int count = 0;
|
||||
char *out = NULL;
|
||||
cJSON *visit_obj = NULL;
|
||||
cJSON *visit_info_array = NULL;
|
||||
cJSON *root_obj = NULL;
|
||||
|
||||
root_obj = cJSON_CreateObject();
|
||||
if (!root_obj)
|
||||
{
|
||||
AF_ERROR("create json obj failed");
|
||||
return 0;
|
||||
}
|
||||
sprintf(mac_str, MAC_FMT, MAC_ARRAY(node->mac));
|
||||
sprintf(ip_str, "%pI4", &node->ip);
|
||||
cJSON_AddStringToObject(root_obj, "mac", mac_str);
|
||||
cJSON_AddStringToObject(root_obj, "ip", ip_str);
|
||||
cJSON_AddNumberToObject(root_obj, "app_num", node->visit_app_num);
|
||||
visit_info_array = cJSON_CreateArray();
|
||||
for (i = 0; i < MAX_RECORD_APP_NUM; i++)
|
||||
{
|
||||
if (node->visit_info[i].app_id == 0)
|
||||
continue;
|
||||
count++;
|
||||
visit_obj = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(visit_obj, "appid", node->visit_info[i].app_id);
|
||||
cJSON_AddNumberToObject(visit_obj, "latest_action", node->visit_info[i].latest_action);
|
||||
cJSON_AddNumberToObject(visit_obj, "up_bytes", node->visit_info[i].total_up_bytes);
|
||||
cJSON_AddNumberToObject(visit_obj, "down_bytes", node->visit_info[i].total_down_bytes);
|
||||
memset((char *)&node->visit_info[i], 0x0, sizeof(app_visit_info_t));
|
||||
cJSON_AddItemToArray(visit_info_array, visit_obj);
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(root_obj, "visit_info", visit_info_array);
|
||||
out = cJSON_Print(root_obj);
|
||||
if (!out)
|
||||
return 0;
|
||||
cJSON_Minify(out);
|
||||
if (count > 0 || node->report_count == 0)
|
||||
{
|
||||
AF_INFO("report:%s count=%d\n", out, node->report_count);
|
||||
node->report_count++;
|
||||
af_send_msg_to_user(out, strlen(out));
|
||||
}
|
||||
cJSON_Delete(root_obj);
|
||||
kfree(out);
|
||||
return 0;
|
||||
}
|
||||
void af_visit_info_report(void)
|
||||
{
|
||||
af_client_info_t *node;
|
||||
int i;
|
||||
AF_CLIENT_LOCK_W();
|
||||
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++)
|
||||
{
|
||||
list_for_each_entry(node, &af_client_list_table[i], hlist)
|
||||
{
|
||||
// flush_expired_visit_info(node);
|
||||
AF_INFO("report %s\n", node->mac);
|
||||
__af_visit_info_report(node);
|
||||
}
|
||||
}
|
||||
AF_CLIENT_UNLOCK_W();
|
||||
}
|
||||
static inline int get_packet_dir(struct net_device *in)
|
||||
{
|
||||
if (0 == strncmp(in->name, "br", 2))
|
||||
{
|
||||
return PKT_DIR_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PKT_DIR_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
|
||||
static u_int32_t af_client_hook(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
#else
|
||||
static u_int32_t af_client_hook(unsigned int hook,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
#endif
|
||||
struct ethhdr *ethhdr = NULL;
|
||||
unsigned char smac[ETH_ALEN];
|
||||
af_client_info_t *nfc = NULL;
|
||||
int pkt_dir = 0;
|
||||
struct iphdr *iph = NULL;
|
||||
|
||||
// 4.10-->4.11 nfct-->_nfct
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
struct nf_conn *ct = (struct nf_conn *)skb->_nfct;
|
||||
#else
|
||||
struct nf_conn *ct = (struct nf_conn *)skb->nfct;
|
||||
#endif
|
||||
if (ct == NULL)
|
||||
{
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
|
||||
if (!skb->dev)
|
||||
return NF_ACCEPT;
|
||||
|
||||
pkt_dir = get_packet_dir(skb->dev);
|
||||
#else
|
||||
if (!in)
|
||||
{
|
||||
AF_ERROR("in is NULL\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
pkt_dir = get_packet_dir(in);
|
||||
#endif
|
||||
|
||||
if (PKT_DIR_UP != pkt_dir)
|
||||
return NF_ACCEPT;
|
||||
|
||||
ethhdr = eth_hdr(skb);
|
||||
if (ethhdr)
|
||||
{
|
||||
memcpy(smac, ethhdr->h_source, ETH_ALEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(smac, &skb->cb[40], ETH_ALEN);
|
||||
}
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
if (!iph)
|
||||
{
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
AF_CLIENT_LOCK_W();
|
||||
nfc = find_af_client(smac);
|
||||
if (!nfc)
|
||||
{
|
||||
if (skb->dev)
|
||||
AF_DEBUG("from dev:%s [%s] %pI4--->%pI4", skb->dev->name, (iph->protocol == IPPROTO_TCP ? "TCP" : "UDP"),
|
||||
&iph->saddr, &iph->daddr);
|
||||
nfc = nf_client_add(smac);
|
||||
}
|
||||
if (nfc && nfc->ip != iph->saddr)
|
||||
{
|
||||
AF_DEBUG("update node " MAC_FMT " ip %pI4--->%pI4\n", MAC_ARRAY(nfc->mac), &nfc->ip, &iph->saddr);
|
||||
nfc->update_jiffies = jiffies;
|
||||
nfc->ip = iph->saddr;
|
||||
}
|
||||
AF_CLIENT_UNLOCK_W();
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
|
||||
static struct nf_hook_ops af_client_ops[] = {
|
||||
{
|
||||
.hook = af_client_hook,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_INET_FORWARD,
|
||||
.priority = NF_IP_PRI_FIRST + 1,
|
||||
},
|
||||
};
|
||||
#else
|
||||
static struct nf_hook_ops af_client_ops[] = {
|
||||
{
|
||||
.hook = af_client_hook,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_INET_FORWARD,
|
||||
.priority = NF_IP_PRI_FIRST + 1,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
int af_client_init(void)
|
||||
{
|
||||
nf_client_list_init();
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
nf_register_net_hooks(&init_net, af_client_ops, ARRAY_SIZE(af_client_ops));
|
||||
#else
|
||||
nf_register_hooks(af_client_ops, ARRAY_SIZE(af_client_ops));
|
||||
#endif
|
||||
AF_INFO("init app afclient ........ok\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void af_client_exit(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
nf_unregister_net_hooks(&init_net, af_client_ops, ARRAY_SIZE(af_client_ops));
|
||||
#else
|
||||
nf_unregister_hooks(af_client_ops, ARRAY_SIZE(af_client_ops));
|
||||
#endif
|
||||
nf_client_list_clear();
|
||||
return;
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
#ifndef __AF_CLIENT_H__
|
||||
#define __AF_CLIENT_H__
|
||||
#include "app_filter.h"
|
||||
|
||||
extern rwlock_t af_client_lock;
|
||||
|
||||
extern u32 nfc_debug_level;
|
||||
|
||||
#define MAX_AF_CLIENT_HASH_SIZE 64
|
||||
#define NF_CLIENT_TIMER_EXPIRE 1
|
||||
#define MAX_CLIENT_ACTIVE_TIME 90
|
||||
|
||||
#define AF_CLIENT_LOCK_R() read_lock_bh(&af_client_lock);
|
||||
#define AF_CLIENT_UNLOCK_R() read_unlock_bh(&af_client_lock);
|
||||
#define AF_CLIENT_LOCK_W() write_lock_bh(&af_client_lock);
|
||||
#define AF_CLIENT_UNLOCK_W() write_unlock_bh(&af_client_lock);
|
||||
|
||||
#define NIPQUAD(addr) \
|
||||
((unsigned char *)&addr)[0], \
|
||||
((unsigned char *)&addr)[1], \
|
||||
((unsigned char *)&addr)[2], \
|
||||
((unsigned char *)&addr)[3]
|
||||
#define NIPQUAD_FMT "%u.%u.%u.%u"
|
||||
|
||||
enum NFC_PKT_DIR
|
||||
{
|
||||
PKT_DIR_DOWN,
|
||||
PKT_DIR_UP
|
||||
};
|
||||
|
||||
#define MAX_VISIT_HISTORY_TIME 24
|
||||
#define MAX_RECORD_APP_NUM 64
|
||||
|
||||
typedef struct app_visit_info
|
||||
{
|
||||
unsigned int app_id;
|
||||
unsigned int total_num;
|
||||
unsigned int drop_num;
|
||||
unsigned long latest_time;
|
||||
unsigned int latest_action;
|
||||
unsigned int total_down_bytes;
|
||||
unsigned int total_up_bytes;
|
||||
unsigned long history_time[MAX_VISIT_HISTORY_TIME];
|
||||
unsigned int action[MAX_VISIT_HISTORY_TIME];
|
||||
} app_visit_info_t;
|
||||
|
||||
typedef struct af_client_info
|
||||
{
|
||||
struct list_head hlist;
|
||||
unsigned char mac[MAC_ADDR_LEN];
|
||||
unsigned int ip;
|
||||
unsigned long create_jiffies;
|
||||
unsigned long update_jiffies;
|
||||
unsigned int visit_app_num;
|
||||
int report_count;
|
||||
app_visit_info_t visit_info[MAX_RECORD_APP_NUM];
|
||||
} af_client_info_t;
|
||||
|
||||
int af_client_init(void);
|
||||
|
||||
void af_client_exit(void);
|
||||
af_client_info_t *find_af_client_by_ip(unsigned int ip);
|
||||
af_client_info_t *find_af_client(unsigned char *mac);
|
||||
|
||||
void check_client_expire(void);
|
||||
|
||||
void af_visit_info_report(void);
|
||||
|
||||
void af_client_list_reset_report_num(void);
|
||||
af_client_info_t *nf_client_add(unsigned char *mac);
|
||||
af_client_info_t *find_and_add_af_client(unsigned char *mac);
|
||||
|
||||
#endif
|
@ -1,194 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "af_log.h"
|
||||
#include "af_client.h"
|
||||
|
||||
extern struct list_head af_client_list_table[MAX_AF_CLIENT_HASH_SIZE];
|
||||
struct af_client_iter_state
|
||||
{
|
||||
unsigned int bucket;
|
||||
void *head;
|
||||
};
|
||||
|
||||
static void *af_client_get_first(struct seq_file *seq)
|
||||
{
|
||||
struct af_client_iter_state *st = seq->private;
|
||||
for (st->bucket = 0; st->bucket < MAX_AF_CLIENT_HASH_SIZE; st->bucket++)
|
||||
{
|
||||
if (!list_empty(&(af_client_list_table[st->bucket])))
|
||||
{
|
||||
st->head = &(af_client_list_table[st->bucket]);
|
||||
return af_client_list_table[st->bucket].next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *af_client_get_next(struct seq_file *seq,
|
||||
void *head)
|
||||
{
|
||||
struct af_client_iter_state *st = seq->private;
|
||||
struct hlist_node *node = (struct hlist_node *)head;
|
||||
|
||||
node = node->next;
|
||||
if (node != st->head)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
st->bucket++;
|
||||
for (; st->bucket < MAX_AF_CLIENT_HASH_SIZE; st->bucket++)
|
||||
{
|
||||
if (!list_empty(&(af_client_list_table[st->bucket])))
|
||||
{
|
||||
st->head = &(af_client_list_table[st->bucket]);
|
||||
return af_client_list_table[st->bucket].next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void *af_client_get_idx(struct seq_file *seq, loff_t pos)
|
||||
{
|
||||
void *head = af_client_get_first(seq);
|
||||
|
||||
if (head)
|
||||
while (pos && (head = af_client_get_next(seq, head)))
|
||||
pos--;
|
||||
|
||||
return pos ? NULL : head;
|
||||
}
|
||||
|
||||
static void *af_client_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
AF_CLIENT_LOCK_R();
|
||||
if (*pos == 0)
|
||||
{
|
||||
return SEQ_START_TOKEN;
|
||||
}
|
||||
|
||||
return af_client_get_idx(s, *pos - 1);
|
||||
}
|
||||
|
||||
static void *af_client_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
(*pos)++;
|
||||
if (v == SEQ_START_TOKEN)
|
||||
return af_client_get_idx(s, 0);
|
||||
|
||||
return af_client_get_next(s, v);
|
||||
}
|
||||
|
||||
static void af_client_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
AF_CLIENT_UNLOCK_R();
|
||||
}
|
||||
|
||||
static int af_client_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
unsigned char mac_str[32] = {0};
|
||||
unsigned char ip_str[32] = {0};
|
||||
static int index = 0;
|
||||
af_client_info_t *node = (af_client_info_t *)v;
|
||||
if (v == SEQ_START_TOKEN)
|
||||
{
|
||||
index = 0;
|
||||
seq_printf(s, "%-4s %-20s %-20s\n", "Id", "Mac", "Ip");
|
||||
return 0;
|
||||
}
|
||||
index++;
|
||||
sprintf(mac_str, MAC_FMT, MAC_ARRAY(node->mac));
|
||||
sprintf(ip_str, "%pI4", &node->ip);
|
||||
seq_printf(s, "%-4d %-20s %-20s\n", index, mac_str, ip_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations nf_client_seq_ops = {
|
||||
.start = af_client_seq_start,
|
||||
.next = af_client_seq_next,
|
||||
.stop = af_client_seq_stop,
|
||||
.show = af_client_seq_show};
|
||||
|
||||
static int af_client_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *seq;
|
||||
struct af_client_iter_state *iter;
|
||||
int err;
|
||||
|
||||
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
|
||||
if (!iter)
|
||||
return -ENOMEM;
|
||||
|
||||
err = seq_open(file, &nf_client_seq_ops);
|
||||
if (err)
|
||||
{
|
||||
kfree(iter);
|
||||
return err;
|
||||
}
|
||||
|
||||
seq = file->private_data;
|
||||
seq->private = iter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 5, 0)
|
||||
static const struct file_operations af_client_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = af_client_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
#else
|
||||
static const struct proc_ops af_client_fops = {
|
||||
.proc_flags = PROC_ENTRY_PERMANENT,
|
||||
.proc_read = seq_read,
|
||||
.proc_open = af_client_open,
|
||||
.proc_lseek = seq_lseek,
|
||||
.proc_release = seq_release_private,
|
||||
};
|
||||
#endif
|
||||
|
||||
#define AF_CLIENT_PROC_STR "af_client"
|
||||
|
||||
int init_af_client_procfs(void)
|
||||
{
|
||||
struct proc_dir_entry *pde;
|
||||
struct net *net = &init_net;
|
||||
pde = proc_create(AF_CLIENT_PROC_STR, 0440, net->proc_net, &af_client_fops);
|
||||
|
||||
if (!pde)
|
||||
{
|
||||
AF_ERROR("nf_client proc file created error\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void finit_af_client_procfs(void)
|
||||
{
|
||||
struct net *net = &init_net;
|
||||
remove_proc_entry(AF_CLIENT_PROC_STR, net->proc_net);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#ifndef __AF_CLIENT_FS_H__
|
||||
#define __AF_CLIENT_FS_H__
|
||||
|
||||
int init_af_client_procfs(void);
|
||||
void finit_af_client_procfs(void);
|
||||
|
||||
#endif
|
@ -1,87 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include "app_filter.h"
|
||||
#include "af_log.h"
|
||||
int af_log_lvl = 1;
|
||||
int af_test_mode = 0;
|
||||
// todo: rename af_log.c
|
||||
int g_oaf_enable __read_mostly = 0;
|
||||
int af_work_mode = AF_MODE_GATEWAY;
|
||||
/*
|
||||
cat /proc/sys/oaf/debug
|
||||
*/
|
||||
static struct ctl_table oaf_table[] = {
|
||||
{
|
||||
.procname = "debug",
|
||||
.data = &af_log_lvl,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0666,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "test_mode",
|
||||
.data = &af_test_mode,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0666,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "enable",
|
||||
.data = &g_oaf_enable,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0666,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "work_mode",
|
||||
.data = &af_work_mode,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0666,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static struct ctl_table oaf_root_table[] = {
|
||||
{
|
||||
.procname = "oaf",
|
||||
.mode = 0555,
|
||||
.child = oaf_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
static struct ctl_table_header *oaf_table_header;
|
||||
|
||||
|
||||
static int af_init_log_sysctl(void)
|
||||
{
|
||||
oaf_table_header = register_sysctl_table(oaf_root_table);
|
||||
if (oaf_table_header == NULL){
|
||||
printk("init log sysctl...failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
printk("init oaf sysctl...ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_fini_log_sysctl(void)
|
||||
{
|
||||
if (oaf_table_header)
|
||||
unregister_sysctl_table(oaf_table_header);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int af_log_init(void){
|
||||
af_init_log_sysctl();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int af_log_exit(void){
|
||||
af_fini_log_sysctl();
|
||||
return 0;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#ifndef __AF_DEBUG_H__
|
||||
#define __AF_DEBUG_H__
|
||||
extern int af_log_lvl;
|
||||
extern int af_test_mode;
|
||||
extern int af_work_mode;
|
||||
#define LOG(level, fmt, ...) do { \
|
||||
if ((level) <= af_log_lvl) { \
|
||||
printk(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LLOG(level, fmt, ...) do { \
|
||||
if ((level) <= af_log_lvl) { \
|
||||
pr_info_ratelimited(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define AF_ERROR(...) LOG(0, ##__VA_ARGS__)
|
||||
#define AF_WARN(...) LOG(1, ##__VA_ARGS__)
|
||||
#define AF_INFO(...) LOG(2, ##__VA_ARGS__)
|
||||
#define AF_DEBUG(...) LOG(3, ##__VA_ARGS__)
|
||||
|
||||
#define AF_LMT_ERROR(...) LLOG(0, ##__VA_ARGS__)
|
||||
#define AF_LMT_WARN(...) LLOG(1, ##__VA_ARGS__)
|
||||
#define AF_LMT_INFO(...) LLOG(2, ##__VA_ARGS__)
|
||||
#define AF_LMT_DEBUG(...) LLOG(3, ##__VA_ARGS__)
|
||||
|
||||
|
||||
#define TEST_MODE() (af_test_mode)
|
||||
int af_log_init(void);
|
||||
int af_log_exit(void);
|
||||
#endif
|
@ -1,330 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/version.h>
|
||||
#include "af_utils.h"
|
||||
u_int32_t af_get_timestamp_sec(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
|
||||
struct timespec64 ts;
|
||||
ktime_get_real_ts64(&ts);
|
||||
return (u_int32_t)ts.tv_sec;
|
||||
#else
|
||||
struct timespec ts;
|
||||
ts = current_kernel_time();
|
||||
return ts.tv_sec;
|
||||
#endif
|
||||
|
||||
}
|
||||
char *k_trim(char *s)
|
||||
{
|
||||
char *start, *last, *bk;
|
||||
int len;
|
||||
|
||||
start = s;
|
||||
while (isspace(*start))
|
||||
start++;
|
||||
|
||||
bk = last = s + strlen(s) - 1;
|
||||
while (last > start && isspace(*last))
|
||||
last--;
|
||||
|
||||
if ((s != start) || (bk != last))
|
||||
{
|
||||
len = last - start + 1;
|
||||
strncpy(s, start, len);
|
||||
s[len] = '\0';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int check_local_network_ip(unsigned int ip)
|
||||
{
|
||||
if ((ip & 0xffff0000) == 0xc0a80000)
|
||||
return 1;
|
||||
else if ((ip & 0xfff00000) == 0xac100000)
|
||||
return 1;
|
||||
else if ((ip & 0xff000000) == 0x0a000000)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_str(char *name, unsigned char *p, int len)
|
||||
{
|
||||
#define MAX_DUMP_STR_LEN 64
|
||||
char buf[MAX_DUMP_STR_LEN] = {0};
|
||||
if (len > MAX_DUMP_STR_LEN) {
|
||||
len = MAX_DUMP_STR_LEN - 1;
|
||||
}
|
||||
printk("%s: ",name);
|
||||
strncpy(buf, p, len);
|
||||
printk("[%s]\n", buf);
|
||||
}
|
||||
|
||||
void dump_hex(char *name, unsigned char *p, int len)
|
||||
{
|
||||
#define MAX_DUMP_STR_LEN 64
|
||||
int i;
|
||||
if (len > MAX_DUMP_STR_LEN) {
|
||||
len = MAX_DUMP_STR_LEN - 1;
|
||||
}
|
||||
printk("%s: ",name);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i % 16 == 0)
|
||||
printk("\n");
|
||||
printk("%02X ",*(p + i));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
#ifndef va_arg
|
||||
typedef signed int acpi_native_int;
|
||||
#ifndef _VALIST
|
||||
#define _VALIST
|
||||
typedef char *va_list;
|
||||
#endif
|
||||
|
||||
#define _AUPBND (sizeof (acpi_native_int) - 1)
|
||||
#define _ADNBND (sizeof (acpi_native_int) - 1)
|
||||
|
||||
|
||||
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
|
||||
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
|
||||
#define va_end(ap) (void) 0
|
||||
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TOLOWER
|
||||
#define TOLOWER(x) ((x) | 0x20)
|
||||
#endif
|
||||
|
||||
|
||||
static long long k_simple_strtoll(const char *cp, char **endp, unsigned int base)
|
||||
{
|
||||
if (*cp == '-')
|
||||
return -simple_strtoull(cp + 1, endp, base);
|
||||
|
||||
return simple_strtoull(cp, endp, base);
|
||||
}
|
||||
|
||||
static int skip_atoi(const char **s)
|
||||
{
|
||||
int i=0;
|
||||
while (isdigit(**s))
|
||||
i = i*10 + *((*s)++) - '0';
|
||||
return i;
|
||||
}
|
||||
|
||||
char *skip_spaces(const char *str)
|
||||
{
|
||||
while (isspace(*str) && ((unsigned char )*str != 0xa0))
|
||||
++str;
|
||||
return (char *)str;
|
||||
}
|
||||
static int k_vsscanf(const char *buf, const char *fmt, va_list args)
|
||||
{
|
||||
const char *str = buf;
|
||||
char *next;
|
||||
char digit;
|
||||
int num = 0;
|
||||
u8 qualifier;
|
||||
u8 base;
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
|
||||
int field_width;
|
||||
#else
|
||||
s16 field_width;
|
||||
#endif
|
||||
bool is_sign;
|
||||
while (*fmt && *str) {
|
||||
if (isspace(*fmt)) {
|
||||
fmt = skip_spaces(++fmt);
|
||||
str = skip_spaces(str);
|
||||
}
|
||||
|
||||
if (*fmt != '%' && *fmt) {
|
||||
if (*fmt++ != *str++)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!*fmt)
|
||||
break;
|
||||
++fmt;
|
||||
|
||||
if (*fmt == '*') {
|
||||
while (!isspace(*fmt) && *fmt != '%' && *fmt)
|
||||
fmt++;
|
||||
while (!isspace(*str) && *str)
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
field_width = -1;
|
||||
if (isdigit(*fmt))
|
||||
field_width = skip_atoi(&fmt);
|
||||
qualifier = -1;
|
||||
if (*fmt == 'h' || TOLOWER(*fmt) == 'l' ||
|
||||
TOLOWER(*fmt) == 'z') {
|
||||
qualifier = *fmt++;
|
||||
if (unlikely(qualifier == *fmt)) {
|
||||
if (qualifier == 'h') {
|
||||
qualifier = 'H';
|
||||
fmt++;
|
||||
} else if (qualifier == 'l') {
|
||||
qualifier = 'L';
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!*fmt || !*str)
|
||||
break;
|
||||
base = 10;
|
||||
is_sign = 0;
|
||||
switch (*fmt++) {
|
||||
case 'c':
|
||||
{
|
||||
char *s = (char *)va_arg(args, char*);
|
||||
if (field_width == -1)
|
||||
field_width = 1;
|
||||
do {
|
||||
*s++ = *str++;
|
||||
} while (--field_width > 0 && *str);
|
||||
num++;
|
||||
}
|
||||
continue;
|
||||
case 's':
|
||||
{
|
||||
char *s = (char *)va_arg(args, char *);
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
|
||||
if(field_width == -1)
|
||||
field_width = INT_MAX;
|
||||
#else
|
||||
if (field_width == -1)
|
||||
field_width = SHRT_MAX;
|
||||
#endif
|
||||
str = skip_spaces(str);
|
||||
|
||||
while (*str && (!isspace(*str) || ((unsigned char )*str == 0xA0) )&& field_width--)
|
||||
*s++ = *str++;
|
||||
*s = '\0';
|
||||
num++;
|
||||
}
|
||||
continue;
|
||||
case 'n':
|
||||
{
|
||||
int *i = (int *)va_arg(args, int*);
|
||||
*i = str - buf;
|
||||
}
|
||||
continue;
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
break;
|
||||
case 'i':
|
||||
base = 0;
|
||||
case 'd':
|
||||
is_sign = 1;
|
||||
case 'u':
|
||||
break;
|
||||
case '%':
|
||||
if (*str++ != '%')
|
||||
return num;
|
||||
continue;
|
||||
default:
|
||||
return num;
|
||||
}
|
||||
str = skip_spaces(str);
|
||||
digit = *str;
|
||||
if (is_sign && digit == '-')
|
||||
digit = *(str + 1);
|
||||
if (!digit
|
||||
|| (base == 16 && !isxdigit(digit))
|
||||
|| (base == 10 && !isdigit(digit))
|
||||
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|
||||
|| (base == 0 && !isdigit(digit)))
|
||||
break;
|
||||
|
||||
switch (qualifier) {
|
||||
case 'H':
|
||||
if (is_sign) {
|
||||
signed char *s = (signed char *)va_arg(args, signed char *);
|
||||
*s = (signed char)simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned char *s = (unsigned char *)va_arg(args, unsigned char *);
|
||||
*s = (unsigned char)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (is_sign) {
|
||||
short *s = (short *)va_arg(args, short *);
|
||||
*s = (short)simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned short *s = (unsigned short *)va_arg(args, unsigned short *);
|
||||
*s = (unsigned short)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (is_sign) {
|
||||
long *l = (long *)va_arg(args, long *);
|
||||
*l = simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned long *l = (unsigned long *)va_arg(args, unsigned long *);
|
||||
*l = simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if (is_sign) {
|
||||
long long *l = (long long *)va_arg(args, long long *);
|
||||
*l = k_simple_strtoll(str, &next, base);
|
||||
} else {
|
||||
unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *);
|
||||
*l = simple_strtoull(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'Z':
|
||||
case 'z':
|
||||
{
|
||||
size_t *s = (size_t *)va_arg(args, size_t *);
|
||||
*s = (size_t)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (is_sign) {
|
||||
int *i = (int *)va_arg(args, int *);
|
||||
*i = (int)simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned int *i = (unsigned int *)va_arg(args, unsigned int*);
|
||||
*i = (unsigned int)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
}
|
||||
num++;
|
||||
if (!next)
|
||||
break;
|
||||
str = next;
|
||||
}
|
||||
if (*fmt == '%' && *(fmt + 1) == 'n') {
|
||||
int *p = (int *)va_arg(args, int *);
|
||||
*p = str - buf;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
int k_sscanf(const char *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
va_start(args, fmt);
|
||||
i = k_vsscanf(buf, fmt, args);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
#ifndef AF_UTILS_H
|
||||
#define AF_UTILS_H
|
||||
u_int32_t af_get_timestamp_sec(void);
|
||||
|
||||
char *k_trim(char *s);
|
||||
|
||||
int check_local_network_ip(unsigned int ip);
|
||||
|
||||
void dump_str(char *name, unsigned char *p, int len);
|
||||
|
||||
void dump_hex(char *name, unsigned char *p, int len);
|
||||
|
||||
int k_sscanf(const char *buf, const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +0,0 @@
|
||||
#ifndef APP_FILTER_H
|
||||
#define APP_FILTER_H
|
||||
|
||||
#define AF_VERSION "5.0"
|
||||
#define AF_FEATURE_CONFIG_FILE "/tmp/feature.cfg"
|
||||
|
||||
#define MAX_DPI_PKT_NUM 64
|
||||
#define MIN_HTTP_DATA_LEN 16
|
||||
#define MAX_APP_NAME_LEN 64
|
||||
#define MAX_FEATURE_NUM_PER_APP 16
|
||||
#define MIN_FEATURE_STR_LEN 16
|
||||
#define MAX_FEATURE_STR_LEN 128
|
||||
#define MAX_HOST_URL_LEN 128
|
||||
#define MAX_REQUEST_URL_LEN 128
|
||||
#define MAX_FEATURE_BITS 16
|
||||
#define MAX_POS_INFO_PER_FEATURE 16
|
||||
#define MAX_FEATURE_LINE_LEN 256
|
||||
#define MIN_FEATURE_LINE_LEN 16
|
||||
#define MAX_URL_MATCH_LEN 64
|
||||
#define MAX_BYPASS_DPI_PKT_LEN 600
|
||||
|
||||
//#define CONFIG_KERNEL_FUNC_TEST 1
|
||||
|
||||
#define HTTP_GET_METHOD_STR "GET"
|
||||
#define HTTP_POST_METHOD_STR "POST"
|
||||
#define HTTP_HEADER "HTTP"
|
||||
#define NIPQUAD(addr) \
|
||||
((unsigned char *)&addr)[0], \
|
||||
((unsigned char *)&addr)[1], \
|
||||
((unsigned char *)&addr)[2], \
|
||||
((unsigned char *)&addr)[3]
|
||||
#define NIPQUAD_FMT "%u.%u.%u.%u"
|
||||
#define MAC_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
#define AF_TRUE 1
|
||||
#define AF_FALSE 0
|
||||
|
||||
#define AF_APP_TYPE(a) (a) / 1000
|
||||
#define AF_APP_ID(a) (a) % 1000
|
||||
#define MAC_ADDR_LEN 6
|
||||
|
||||
#define HTTPS_URL_OFFSET 9
|
||||
#define HTTPS_LEN_OFFSET 7
|
||||
|
||||
enum AF_FEATURE_PARAM_INDEX{
|
||||
AF_PROTO_PARAM_INDEX,
|
||||
AF_SRC_PORT_PARAM_INDEX,
|
||||
AF_DST_PORT_PARAM_INDEX,
|
||||
AF_HOST_URL_PARAM_INDEX,
|
||||
AF_REQUEST_URL_PARAM_INDEX,
|
||||
AF_DICT_PARAM_INDEX,
|
||||
};
|
||||
|
||||
|
||||
#define OAF_NETLINK_ID 29
|
||||
#define MAX_OAF_NL_MSG_LEN 1024
|
||||
|
||||
enum E_MSG_TYPE{
|
||||
AF_MSG_INIT,
|
||||
AF_MSG_MAX
|
||||
};
|
||||
enum AF_WORK_MODE {
|
||||
AF_MODE_GATEWAY,
|
||||
AF_MODE_BYPASS,
|
||||
AF_MODE_BRIDGE,
|
||||
};
|
||||
|
||||
typedef struct af_msg{
|
||||
int action;
|
||||
void *data;
|
||||
}af_msg_t;
|
||||
|
||||
struct af_msg_hdr{
|
||||
int magic;
|
||||
int len;
|
||||
};
|
||||
|
||||
enum e_http_method{
|
||||
HTTP_METHOD_GET = 1,
|
||||
HTTP_METHOD_POST,
|
||||
};
|
||||
typedef struct http_proto{
|
||||
int match;
|
||||
int method;
|
||||
char *url_pos;
|
||||
int url_len;
|
||||
char *host_pos;
|
||||
int host_len;
|
||||
char *data_pos;
|
||||
int data_len;
|
||||
}http_proto_t;
|
||||
|
||||
typedef struct https_proto{
|
||||
int match;
|
||||
char *url_pos;
|
||||
int url_len;
|
||||
}https_proto_t;
|
||||
|
||||
typedef struct flow_info{
|
||||
struct nf_conn *ct;
|
||||
u_int32_t src;
|
||||
u_int32_t dst;
|
||||
int l4_protocol;
|
||||
u_int16_t sport;
|
||||
u_int16_t dport;
|
||||
unsigned char *l4_data;
|
||||
int l4_len;
|
||||
http_proto_t http;
|
||||
https_proto_t https;
|
||||
u_int32_t app_id;
|
||||
u_int8_t app_name[MAX_APP_NAME_LEN];
|
||||
u_int8_t drop;
|
||||
u_int8_t dir;
|
||||
u_int16_t total_len;
|
||||
}flow_info_t;
|
||||
|
||||
|
||||
|
||||
typedef struct af_pos_info{
|
||||
int pos;
|
||||
unsigned char value;
|
||||
}af_pos_info_t;
|
||||
|
||||
#define MAX_PORT_RANGE_NUM 5
|
||||
|
||||
typedef struct range_value
|
||||
{
|
||||
int not ;
|
||||
int start;
|
||||
int end;
|
||||
} range_value_t;
|
||||
|
||||
typedef struct port_info
|
||||
{
|
||||
u_int8_t mode; // 0: match, 1: not match
|
||||
int num;
|
||||
range_value_t range_list[MAX_PORT_RANGE_NUM];
|
||||
} port_info_t;
|
||||
|
||||
typedef struct af_feature_node{
|
||||
struct list_head head;
|
||||
u_int32_t app_id;
|
||||
char app_name[MAX_APP_NAME_LEN];
|
||||
char feature_str[MAX_FEATURE_NUM_PER_APP][MAX_FEATURE_STR_LEN];
|
||||
u_int32_t proto;
|
||||
u_int32_t sport;
|
||||
u_int32_t dport;
|
||||
port_info_t dport_info;
|
||||
char host_url[MAX_HOST_URL_LEN];
|
||||
char request_url[MAX_REQUEST_URL_LEN];
|
||||
int pos_num;
|
||||
af_pos_info_t pos_info[MAX_POS_INFO_PER_FEATURE];
|
||||
}af_feature_node_t;
|
||||
|
||||
typedef struct af_mac_info {
|
||||
struct list_head hlist;
|
||||
unsigned char mac[MAC_ADDR_LEN];
|
||||
}af_mac_info_t;
|
||||
|
||||
int af_register_dev(void);
|
||||
void af_unregister_dev(void);
|
||||
void af_init_app_status(void);
|
||||
int af_get_app_status(int appid);
|
||||
int regexp_match(char *reg, char *text);
|
||||
void af_mac_list_init(void);
|
||||
void af_mac_list_clear(void);
|
||||
af_mac_info_t * find_af_mac(unsigned char *mac);
|
||||
int is_user_match_enable(void);
|
||||
extern int g_oaf_enable;
|
||||
|
||||
#endif
|
@ -1,455 +0,0 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/ip.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/device.h>
|
||||
#include "cJSON.h"
|
||||
#include "app_filter.h"
|
||||
#include "af_utils.h"
|
||||
#include "af_log.h"
|
||||
#define AF_MAX_APP_TYPE_NUM 16
|
||||
#define AF_MAX_APP_NUM 256
|
||||
#define AF_DEV_NAME "appfilter"
|
||||
|
||||
DEFINE_RWLOCK(af_rule_lock);
|
||||
|
||||
#define af_rule_read_lock() read_lock_bh(&af_rule_lock);
|
||||
#define af_rule_read_unlock() read_unlock_bh(&af_rule_lock);
|
||||
#define af_rule_write_lock() write_lock_bh(&af_rule_lock);
|
||||
#define af_rule_write_unlock() write_unlock_bh(&af_rule_lock);
|
||||
|
||||
static struct mutex af_cdev_mutex;
|
||||
struct af_config_dev
|
||||
{
|
||||
dev_t id;
|
||||
struct cdev char_dev;
|
||||
struct class *c;
|
||||
};
|
||||
struct af_config_dev g_af_dev;
|
||||
|
||||
struct af_cdev_file
|
||||
{
|
||||
size_t size;
|
||||
char buf[256 << 10];
|
||||
};
|
||||
|
||||
enum AF_CONFIG_CMD
|
||||
{
|
||||
AF_CMD_ADD_APPID = 1,
|
||||
AF_CMD_DEL_APPID,
|
||||
AF_CMD_CLEAN_APPID,
|
||||
AF_CMD_SET_MAC_LIST,
|
||||
};
|
||||
|
||||
char g_app_id_array[AF_MAX_APP_TYPE_NUM][AF_MAX_APP_NUM] = {0};
|
||||
|
||||
void af_show_app_status(void)
|
||||
{
|
||||
int i, j;
|
||||
AF_DEBUG("#########show app status##########\n");
|
||||
for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++)
|
||||
{
|
||||
for (j = 0; j < AF_MAX_APP_NUM; j++)
|
||||
{
|
||||
|
||||
af_rule_read_lock();
|
||||
if (g_app_id_array[i][j] == AF_TRUE)
|
||||
{
|
||||
AF_DEBUG("%d, %d\n", i, j);
|
||||
}
|
||||
af_rule_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
AF_DEBUG("\n\n\n");
|
||||
}
|
||||
|
||||
int af_change_app_status(cJSON *data_obj, int status)
|
||||
{
|
||||
int i;
|
||||
int id;
|
||||
int type;
|
||||
cJSON *appid_arr = NULL;
|
||||
if (!data_obj)
|
||||
{
|
||||
AF_ERROR("data obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
appid_arr = cJSON_GetObjectItem(data_obj, "apps");
|
||||
if (!appid_arr)
|
||||
{
|
||||
AF_ERROR("apps obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < cJSON_GetArraySize(appid_arr); i++)
|
||||
{
|
||||
cJSON *appid_obj = cJSON_GetArrayItem(appid_arr, i);
|
||||
if (!appid_obj)
|
||||
return -1;
|
||||
id = AF_APP_ID(appid_obj->valueint);
|
||||
type = AF_APP_TYPE(appid_obj->valueint);
|
||||
af_rule_write_lock();
|
||||
g_app_id_array[type][id] = status;
|
||||
af_rule_write_unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_RWLOCK(af_mac_lock);
|
||||
#define MAX_AF_MAC_HASH_SIZE 64
|
||||
#define AF_MAC_LOCK_R() read_lock_bh(&af_mac_lock);
|
||||
#define AF_MAC_UNLOCK_R() read_unlock_bh(&af_mac_lock);
|
||||
#define AF_MAC_LOCK_W() write_lock_bh(&af_mac_lock);
|
||||
#define AF_MAC_UNLOCK_W() write_unlock_bh(&af_mac_lock);
|
||||
|
||||
u32 total_mac = 0;
|
||||
struct list_head af_mac_list_table[MAX_AF_MAC_HASH_SIZE];
|
||||
|
||||
void af_mac_list_init(void)
|
||||
{
|
||||
int i;
|
||||
AF_MAC_LOCK_W();
|
||||
for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
|
||||
{
|
||||
INIT_LIST_HEAD(&af_mac_list_table[i]);
|
||||
}
|
||||
AF_MAC_UNLOCK_W();
|
||||
AF_INFO("client list init......ok\n");
|
||||
}
|
||||
|
||||
void af_mac_list_clear(void)
|
||||
{
|
||||
int i;
|
||||
af_mac_info_t *p = NULL;
|
||||
char mac_str[32] = {0};
|
||||
|
||||
AF_DEBUG("clean list\n");
|
||||
AF_MAC_LOCK_W();
|
||||
for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
|
||||
{
|
||||
while (!list_empty(&af_mac_list_table[i]))
|
||||
{
|
||||
p = list_first_entry(&af_mac_list_table[i], af_mac_info_t, hlist);
|
||||
memset(mac_str, 0x0, sizeof(mac_str));
|
||||
sprintf(mac_str, MAC_FMT, MAC_ARRAY(p->mac));
|
||||
AF_DEBUG("clean mac:%s\n", mac_str);
|
||||
list_del(&(p->hlist));
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
total_mac = 0;
|
||||
AF_MAC_UNLOCK_W();
|
||||
}
|
||||
|
||||
int hash_mac(unsigned char *mac)
|
||||
{
|
||||
if (!mac)
|
||||
return 0;
|
||||
else
|
||||
return mac[5] & (MAX_AF_MAC_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
af_mac_info_t *find_af_mac(unsigned char *mac)
|
||||
{
|
||||
af_mac_info_t *node;
|
||||
unsigned int index;
|
||||
|
||||
index = hash_mac(mac);
|
||||
list_for_each_entry(node, &af_mac_list_table[index], hlist)
|
||||
{
|
||||
if (0 == memcmp(node->mac, mac, 6))
|
||||
{
|
||||
AF_DEBUG("match mac:" MAC_FMT "\n", MAC_ARRAY(node->mac));
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static af_mac_info_t *
|
||||
af_mac_add(unsigned char *mac)
|
||||
{
|
||||
af_mac_info_t *node;
|
||||
int index = 0;
|
||||
|
||||
node = (af_mac_info_t *)kmalloc(sizeof(af_mac_info_t), GFP_ATOMIC);
|
||||
if (node == NULL)
|
||||
{
|
||||
AF_ERROR("kmalloc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(node, 0, sizeof(af_mac_info_t));
|
||||
memcpy(node->mac, mac, MAC_ADDR_LEN);
|
||||
|
||||
index = hash_mac(mac);
|
||||
|
||||
AF_LMT_INFO("new client mac=" MAC_FMT "\n", MAC_ARRAY(node->mac));
|
||||
total_mac++;
|
||||
list_add(&(node->hlist), &af_mac_list_table[index]);
|
||||
return node;
|
||||
}
|
||||
|
||||
int is_user_match_enable(void)
|
||||
{
|
||||
return total_mac > 0;
|
||||
}
|
||||
int mac_to_hex(u8 *mac, u8 *mac_hex)
|
||||
{
|
||||
u32 mac_tmp[MAC_ADDR_LEN];
|
||||
int ret = 0, i = 0;
|
||||
ret = sscanf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
(unsigned int *)&mac_tmp[0],
|
||||
(unsigned int *)&mac_tmp[1],
|
||||
(unsigned int *)&mac_tmp[2],
|
||||
(unsigned int *)&mac_tmp[3],
|
||||
(unsigned int *)&mac_tmp[4],
|
||||
(unsigned int *)&mac_tmp[5]);
|
||||
if (MAC_ADDR_LEN != ret)
|
||||
return -1;
|
||||
for (i = 0; i < MAC_ADDR_LEN; i++)
|
||||
{
|
||||
mac_hex[i] = mac_tmp[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int af_set_mac_list(cJSON *data_obj)
|
||||
{
|
||||
int i;
|
||||
cJSON *mac_arr = NULL;
|
||||
u8 mac_hex[MAC_ADDR_LEN] = {0};
|
||||
if (!data_obj)
|
||||
{
|
||||
AF_ERROR("data obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
mac_arr = cJSON_GetObjectItem(data_obj, "mac_list");
|
||||
if (!mac_arr)
|
||||
{
|
||||
AF_ERROR("apps obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
af_mac_list_clear();
|
||||
for (i = 0; i < cJSON_GetArraySize(mac_arr); i++)
|
||||
{
|
||||
cJSON *mac_obj = cJSON_GetArrayItem(mac_arr, i);
|
||||
if (!mac_obj)
|
||||
{
|
||||
AF_ERROR("appid obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
if (-1 == mac_to_hex(mac_obj->valuestring, mac_hex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
af_mac_add(mac_hex);
|
||||
}
|
||||
AF_DEBUG("## mac num = %d\n", total_mac);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void af_init_app_status(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++)
|
||||
{
|
||||
for (j = 0; j < AF_MAX_APP_NUM; j++)
|
||||
{
|
||||
af_rule_write_lock();
|
||||
g_app_id_array[i][j] = AF_FALSE;
|
||||
af_rule_write_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
int af_get_app_status(int appid)
|
||||
{
|
||||
int status = 0;
|
||||
int id = AF_APP_ID(appid);
|
||||
int type = AF_APP_TYPE(appid);
|
||||
af_rule_read_lock();
|
||||
status = g_app_id_array[type][id];
|
||||
af_rule_read_unlock();
|
||||
return status;
|
||||
}
|
||||
/*
|
||||
add:
|
||||
{
|
||||
"op":1,
|
||||
"data"{
|
||||
"apps":[]
|
||||
}
|
||||
}
|
||||
clean
|
||||
{
|
||||
"op":3,
|
||||
}
|
||||
|
||||
*/
|
||||
int af_config_handle(char *config, unsigned int len)
|
||||
{
|
||||
cJSON *config_obj = NULL;
|
||||
cJSON *cmd_obj = NULL;
|
||||
cJSON *data_obj = NULL;
|
||||
if (!config || len == 0)
|
||||
{
|
||||
AF_ERROR("config or len is invalid\n");
|
||||
return -1;
|
||||
}
|
||||
config_obj = cJSON_Parse(config);
|
||||
if (!config_obj)
|
||||
{
|
||||
AF_ERROR("config_obj is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
cmd_obj = cJSON_GetObjectItem(config_obj, "op");
|
||||
if (!cmd_obj)
|
||||
{
|
||||
AF_ERROR("not find op object\n");
|
||||
return -1;
|
||||
}
|
||||
data_obj = cJSON_GetObjectItem(config_obj, "data");
|
||||
|
||||
switch (cmd_obj->valueint)
|
||||
{
|
||||
case AF_CMD_ADD_APPID:
|
||||
if (!data_obj)
|
||||
break;
|
||||
af_change_app_status(data_obj, AF_TRUE);
|
||||
break;
|
||||
case AF_CMD_DEL_APPID:
|
||||
if (!data_obj)
|
||||
break;
|
||||
af_change_app_status(data_obj, AF_FALSE);
|
||||
break;
|
||||
case AF_CMD_CLEAN_APPID:
|
||||
af_init_app_status();
|
||||
break;
|
||||
case AF_CMD_SET_MAC_LIST:
|
||||
af_set_mac_list(data_obj);
|
||||
break;
|
||||
default:
|
||||
AF_ERROR("invalid cmd %d\n", cmd_obj->valueint);
|
||||
return -1;
|
||||
}
|
||||
af_show_app_status();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_cdev_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct af_cdev_file *file;
|
||||
file = vzalloc(sizeof(*file));
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&af_cdev_mutex);
|
||||
filp->private_data = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t af_cdev_read(struct file *filp, char *buf, size_t count, loff_t *off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_cdev_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct af_cdev_file *file = filp->private_data;
|
||||
AF_DEBUG("config size: %d,data = %s\n", (int)file->size, file->buf);
|
||||
af_config_handle(file->buf, file->size);
|
||||
filp->private_data = NULL;
|
||||
mutex_unlock(&af_cdev_mutex);
|
||||
vfree(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t af_cdev_write(struct file *filp, const char *buffer, size_t count, loff_t *off)
|
||||
{
|
||||
struct af_cdev_file *file = filp->private_data;
|
||||
int ret;
|
||||
if (file->size + count > sizeof(file->buf))
|
||||
{
|
||||
AF_ERROR("config overflow, cur_size: %d, block_size: %d, max_size: %d",
|
||||
(int)file->size, (int)count, (int)sizeof(file->buf));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = copy_from_user(file->buf + file->size, buffer, count);
|
||||
if (ret != 0)
|
||||
return -EINVAL;
|
||||
|
||||
file->size += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations af_cdev_ops = {
|
||||
owner : THIS_MODULE,
|
||||
release : af_cdev_release,
|
||||
open : af_cdev_open,
|
||||
write : af_cdev_write,
|
||||
read : af_cdev_read,
|
||||
};
|
||||
|
||||
int af_register_dev(void)
|
||||
{
|
||||
struct device *dev;
|
||||
int res;
|
||||
mutex_init(&af_cdev_mutex);
|
||||
|
||||
res = alloc_chrdev_region(&g_af_dev.id, 0, 1, AF_DEV_NAME);
|
||||
if (res != 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cdev_init(&g_af_dev.char_dev, &af_cdev_ops);
|
||||
res = cdev_add(&g_af_dev.char_dev, g_af_dev.id, 1);
|
||||
if (res < 0)
|
||||
{
|
||||
goto REGION_OUT;
|
||||
}
|
||||
|
||||
g_af_dev.c = class_create(THIS_MODULE, AF_DEV_NAME);
|
||||
if (IS_ERR_OR_NULL(g_af_dev.c))
|
||||
{
|
||||
goto CDEV_OUT;
|
||||
}
|
||||
|
||||
dev = device_create(g_af_dev.c, NULL, g_af_dev.id, NULL, AF_DEV_NAME);
|
||||
if (IS_ERR_OR_NULL(dev))
|
||||
{
|
||||
goto CLASS_OUT;
|
||||
}
|
||||
AF_INFO("register char dev....ok\n");
|
||||
|
||||
return 0;
|
||||
|
||||
CLASS_OUT:
|
||||
class_destroy(g_af_dev.c);
|
||||
CDEV_OUT:
|
||||
cdev_del(&g_af_dev.char_dev);
|
||||
REGION_OUT:
|
||||
unregister_chrdev_region(g_af_dev.id, 1);
|
||||
|
||||
AF_ERROR("register char dev....fail\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void af_unregister_dev(void)
|
||||
{
|
||||
device_destroy(g_af_dev.c, g_af_dev.id);
|
||||
class_destroy(g_af_dev.c);
|
||||
cdev_del(&g_af_dev.char_dev);
|
||||
unregister_chrdev_region(g_af_dev.id, 1);
|
||||
AF_INFO("unregister char dev....ok\n");
|
||||
}
|
@ -1,519 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// cJSON
|
||||
// JSON parser in C.
|
||||
|
||||
#if 0
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#if 0
|
||||
#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
|
||||
#define strcasecmp stricmp
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static void *(*cJSON_malloc)(size_t sz) = malloc;
|
||||
static void *(*cJSON_realloc)(void *ptr, size_t sz) = realloc;
|
||||
static void (*cJSON_free)(void *ptr) = free;
|
||||
#endif
|
||||
|
||||
static void *cJSON_malloc(size_t sz) {
|
||||
return kmalloc(sz, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void *cJSON_realloc(void *ptr, size_t sz)
|
||||
{
|
||||
return krealloc(ptr, sz, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void cJSON_free(void *ptr)
|
||||
{
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
static char* cJSON_strdup(const char* str)
|
||||
{
|
||||
size_t len;
|
||||
char* copy;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,str,len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_realloc = realloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
||||
cJSON_realloc= (hooks->realloc_fn)?hooks->realloc_fn:realloc;
|
||||
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Internal constructor.
|
||||
static cJSON *cJSON_New_Item(void)
|
||||
{
|
||||
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
||||
if (node) memset(node,0,sizeof(cJSON));
|
||||
return node;
|
||||
}
|
||||
|
||||
// Delete a cJSON structure.
|
||||
void cJSON_Delete(cJSON *c)
|
||||
{
|
||||
cJSON *next;
|
||||
while (c)
|
||||
{
|
||||
next=c->next;
|
||||
if (c->child) cJSON_Delete(c->child);
|
||||
if (c->valuestring) cJSON_free(c->valuestring);
|
||||
if (c->string) cJSON_free(c->string);
|
||||
cJSON_free(c);
|
||||
c=next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static const char *parse_number(cJSON *item,const char *num)
|
||||
{
|
||||
int n=0,sign=1;
|
||||
|
||||
if (*num=='-') sign=-1,num++; /* Has sign? */
|
||||
if (*num=='0') num++; /* is zero */
|
||||
if (*num>='1' && *num<='9') do n=(n*10)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
|
||||
item->valueint=(int)n;
|
||||
item->type=cJSON_Number;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static char *print_number(cJSON *item)
|
||||
{
|
||||
char *str;
|
||||
str=(char*)cJSON_malloc(21);
|
||||
if (str)
|
||||
sprintf(str,"%d",item->valueint);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// Parse the input text into an unescaped cstring, and populate item.
|
||||
static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
{
|
||||
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc;
|
||||
if (*str!='\"') return 0; // not a string!
|
||||
|
||||
while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes.
|
||||
|
||||
out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly.
|
||||
if (!out) return 0;
|
||||
|
||||
ptr=str+1;ptr2=out;
|
||||
while (*ptr!='\"' && *ptr>31)
|
||||
{
|
||||
if (*ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
switch (*ptr)
|
||||
{
|
||||
case 'b': *ptr2++='\b'; break;
|
||||
case 'f': *ptr2++='\f'; break;
|
||||
case 'n': *ptr2++='\n'; break;
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
|
||||
sscanf(ptr+1,"%4x",&uc); // get the unicode char.
|
||||
len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;
|
||||
|
||||
switch (len) {
|
||||
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 1: *--ptr2 =(uc | firstByteMark[len]);
|
||||
}
|
||||
ptr2+=len;ptr+=4;
|
||||
break;
|
||||
default: *ptr2++=*ptr; break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
*ptr2=0;
|
||||
if (*ptr=='\"') ptr++;
|
||||
item->valuestring=out;
|
||||
item->type=cJSON_String;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Render the cstring provided to an escaped version that can be printed.
|
||||
static char *print_string_ptr(const char *str)
|
||||
{
|
||||
const char *ptr;char *ptr2,*out;int len=0;
|
||||
|
||||
ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;}
|
||||
|
||||
out=(char*)cJSON_malloc(len+3);
|
||||
ptr2=out;ptr=str;
|
||||
*ptr2++='\"';
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
*ptr2++='\\';
|
||||
switch (*ptr++)
|
||||
{
|
||||
case '\\': *ptr2++='\\'; break;
|
||||
case '\"': *ptr2++='\"'; break;
|
||||
case '\b': *ptr2++='b'; break;
|
||||
case '\f': *ptr2++='f'; break;
|
||||
case '\n': *ptr2++='n'; break;
|
||||
case '\r': *ptr2++='r'; break;
|
||||
case '\t': *ptr2++='t'; break;
|
||||
default: ptr2--; break; // eviscerate with prejudice.
|
||||
}
|
||||
}
|
||||
}
|
||||
*ptr2++='\"';*ptr2++=0;
|
||||
return out;
|
||||
}
|
||||
// Invote print_string_ptr (which is useful) on an item.
|
||||
static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
|
||||
|
||||
// Predeclare these prototypes.
|
||||
static const char *parse_value(cJSON *item,const char *value);
|
||||
static char *print_value(cJSON *item,int depth);
|
||||
static const char *parse_array(cJSON *item,const char *value);
|
||||
static char *print_array(cJSON *item,int depth);
|
||||
static const char *parse_object(cJSON *item,const char *value);
|
||||
static char *print_object(cJSON *item,int depth);
|
||||
|
||||
// Utility to jump whitespace and cr/lf
|
||||
static const char *skip(const char *in) {while (in && *in<=32) in++; return in;}
|
||||
|
||||
// Parse an object - create a new root, and populate.
|
||||
cJSON *cJSON_Parse(const char *value)
|
||||
{
|
||||
cJSON *c=cJSON_New_Item();
|
||||
if (!c) return 0; /* memory fail */
|
||||
|
||||
if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;}
|
||||
return c;
|
||||
}
|
||||
|
||||
// Render a cJSON item/entity/structure to text.
|
||||
char *cJSON_Print(cJSON *item) {return print_value(item,0);}
|
||||
|
||||
// Parser core - when encountering text, process appropriately.
|
||||
static const char *parse_value(cJSON *item,const char *value)
|
||||
{
|
||||
if (!value) return 0; // Fail on null.
|
||||
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
|
||||
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
|
||||
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
|
||||
if (*value=='\"') { return parse_string(item,value); }
|
||||
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
|
||||
if (*value=='[') { return parse_array(item,value); }
|
||||
if (*value=='{') { return parse_object(item,value); }
|
||||
|
||||
return 0; // failure.
|
||||
}
|
||||
|
||||
// Render a value to text.
|
||||
static char *print_value(cJSON *item,int depth)
|
||||
{
|
||||
char *out=0;
|
||||
switch (item->type)
|
||||
{
|
||||
case cJSON_NULL: out=cJSON_strdup("null"); break;
|
||||
case cJSON_False: out=cJSON_strdup("false");break;
|
||||
case cJSON_True: out=cJSON_strdup("true"); break;
|
||||
case cJSON_Number: out=print_number(item);break;
|
||||
case cJSON_String: out=print_string(item);break;
|
||||
case cJSON_Array: out=print_array(item,depth);break;
|
||||
case cJSON_Object: out=print_object(item,depth);break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Build an array from input text.
|
||||
static const char *parse_array(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='[') return 0; // not an array!
|
||||
|
||||
item->type=cJSON_Array;
|
||||
value=skip(value+1);
|
||||
if (*value==']') return value+1; // empty array.
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0; // memory fail
|
||||
value=skip(parse_value(child,skip(value))); // skip any spacing, get the value.
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; // memory fail
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_value(child,skip(value+1)));
|
||||
if (!value) return 0; // memory fail
|
||||
}
|
||||
|
||||
if (*value==']') return value+1; // end of array
|
||||
return 0; // malformed.
|
||||
}
|
||||
|
||||
// Render an array to text
|
||||
static char *print_array(cJSON *item,int depth)
|
||||
{
|
||||
char *out,*ptr,*ret;int len=5;
|
||||
cJSON *child=item->child;
|
||||
|
||||
out=(char*)cJSON_malloc(len);*out='[';
|
||||
ptr=out+1;*ptr=0;
|
||||
while (child)
|
||||
{
|
||||
ret=print_value(child,depth+1);
|
||||
if (!ret) {cJSON_free(out);return 0;} // Check for failure!
|
||||
len+=strlen(ret)+3;
|
||||
out=(char*)cJSON_realloc(out,len);
|
||||
ptr=out+strlen(out);
|
||||
ptr+=sprintf(ptr,ret);
|
||||
if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;}
|
||||
child=child->next;
|
||||
cJSON_free(ret);
|
||||
}
|
||||
*ptr++=']';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Build an object from the text.
|
||||
static const char *parse_object(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='{') return 0; // not an object!
|
||||
|
||||
item->type=cJSON_Object;
|
||||
value=skip(value+1);
|
||||
if (*value=='}') return value+1; // empty array.
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
value=skip(parse_string(child,skip(value)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') return 0; // fail!
|
||||
value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value.
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; // memory fail
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_string(child,skip(value+1)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') return 0; // fail!
|
||||
value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value.
|
||||
if (!value) return 0;
|
||||
}
|
||||
|
||||
if (*value=='}') return value+1; // end of array
|
||||
return 0; // malformed.
|
||||
}
|
||||
|
||||
// Render an object to text.
|
||||
static char *print_object(cJSON *item,int depth)
|
||||
{
|
||||
char *out,*ptr,*ret,*str;int len=7,i;
|
||||
cJSON *child=item->child;
|
||||
|
||||
depth++;len+=depth;out=(char*)cJSON_malloc(len);*out='{';
|
||||
ptr=out+1;*ptr++='\n';*ptr=0;
|
||||
while (child)
|
||||
{
|
||||
str=print_string_ptr(child->string);
|
||||
if (!str) {cJSON_free(out);return 0;}
|
||||
ret=print_value(child,depth);
|
||||
if (!ret) {cJSON_free(str);cJSON_free(out);return 0;} // Check for failure!
|
||||
len+=strlen(ret)+strlen(str)+4+depth;
|
||||
out=(char*)cJSON_realloc(out,len);
|
||||
ptr=out+strlen(out);
|
||||
for (i=0;i<depth;i++) *ptr++='\t';
|
||||
ptr+=sprintf(ptr,str);
|
||||
*ptr++=':';*ptr++='\t';
|
||||
ptr+=sprintf(ptr,ret);
|
||||
if (child->next) *ptr++=',';
|
||||
*ptr++='\n';*ptr=0;
|
||||
child=child->next;
|
||||
cJSON_free(str);cJSON_free(ret);
|
||||
}
|
||||
for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
|
||||
|
||||
static void skip_oneline_comment(char **input)
|
||||
{
|
||||
*input += static_strlen("//");
|
||||
|
||||
for (; (*input)[0] != '\0'; ++(*input))
|
||||
{
|
||||
if ((*input)[0] == '\n') {
|
||||
*input += static_strlen("\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void skip_multiline_comment(char **input)
|
||||
{
|
||||
*input += static_strlen("/*");
|
||||
|
||||
for (; (*input)[0] != '\0'; ++(*input))
|
||||
{
|
||||
if (((*input)[0] == '*') && ((*input)[1] == '/'))
|
||||
{
|
||||
*input += static_strlen("*/");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void minify_string(char **input, char **output) {
|
||||
(*output)[0] = (*input)[0];
|
||||
*input += static_strlen("\"");
|
||||
*output += static_strlen("\"");
|
||||
|
||||
|
||||
for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
|
||||
(*output)[0] = (*input)[0];
|
||||
|
||||
if ((*input)[0] == '\"') {
|
||||
(*output)[0] = '\"';
|
||||
*input += static_strlen("\"");
|
||||
*output += static_strlen("\"");
|
||||
return;
|
||||
} else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
|
||||
(*output)[1] = (*input)[1];
|
||||
*input += static_strlen("\"");
|
||||
*output += static_strlen("\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cJSON_Minify(char *json)
|
||||
{
|
||||
char *into = json;
|
||||
|
||||
if (json == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (json[0] != '\0')
|
||||
{
|
||||
switch (json[0])
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
json++;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
if (json[1] == '/')
|
||||
{
|
||||
skip_oneline_comment(&json);
|
||||
}
|
||||
else if (json[1] == '*')
|
||||
{
|
||||
skip_multiline_comment(&json);
|
||||
} else {
|
||||
json++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
minify_string(&json, (char**)&into);
|
||||
break;
|
||||
|
||||
default:
|
||||
into[0] = json[0];
|
||||
json++;
|
||||
into++;
|
||||
}
|
||||
}
|
||||
|
||||
/* and null-terminate. */
|
||||
*into = '\0';
|
||||
}
|
||||
|
||||
// Get Array size/item / object item.
|
||||
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
|
||||
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item) item--,c=c->next; return c;}
|
||||
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
|
||||
// Utility for array list handling.
|
||||
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||
|
||||
// Add item to array/object.
|
||||
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
|
||||
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
|
||||
|
||||
// Create basic types:
|
||||
cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;}
|
||||
cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;}
|
||||
cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateNumber(int num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valueint=(int)num;return item;}
|
||||
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;}
|
||||
cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;}
|
||||
cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;}
|
||||
|
||||
// Create Arrays:
|
||||
cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
#include <linux/slab.h>
|
||||
|
||||
// cJSON Types:
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
|
||||
// The cJSON structure:
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem
|
||||
struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object.
|
||||
|
||||
int type; // The type of the item, as above.
|
||||
|
||||
char *valuestring; // The item's string, if type==cJSON_String
|
||||
int valueint; // The item's number, if type==cJSON_Number
|
||||
char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object.
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void *(*realloc_fn)(void *ptr, size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
// Supply malloc, realloc and free functions to cJSON
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished.
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
// Render a cJSON entity to text for transfer/storage. Free the char* when finished.
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
// Delete a cJSON entity and all subentities.
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
// Returns the number of items in an array (or object).
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
// Get item "string" from object. Case insensitive.
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
// These calls create a cJSON item of the appropriate type.
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateNumber(int num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
extern void cJSON_Minify(char *json);
|
||||
// These utilities create an Array of count items.
|
||||
extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
|
||||
|
||||
// Append item to the specified array/object.
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
#endif
|
@ -1,302 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
//#include "regexp.h"
|
||||
|
||||
typedef enum{CHAR, DOT, BEGIN, END, STAR, PLUS, QUES, LIST, TYPENUM}TYPE;
|
||||
|
||||
typedef struct RE{
|
||||
TYPE type;
|
||||
int ch;
|
||||
char *ccl;
|
||||
int nccl;
|
||||
struct RE *next;
|
||||
}RE;
|
||||
|
||||
int match_longest = 0;
|
||||
char *match_first = NULL;
|
||||
|
||||
|
||||
static void * getmem(size_t size)
|
||||
{
|
||||
void *tmp;
|
||||
if((tmp = kmalloc(size, GFP_ATOMIC))==NULL)
|
||||
{
|
||||
printk("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static size_t creat_list(char *str, int start, int end)
|
||||
{
|
||||
size_t cnt = end - start + 1;
|
||||
for(; start <= end ;start++)
|
||||
*str++ = start;
|
||||
return (cnt > 0)?cnt:0;
|
||||
}
|
||||
|
||||
static int in_list(char ch, RE *regexp)
|
||||
{
|
||||
char *str = regexp->ccl;
|
||||
if(regexp->type != LIST)
|
||||
return 0;
|
||||
for(; *str && ch != *str; str++)
|
||||
;
|
||||
return (*str != '\0') ^ regexp->nccl;
|
||||
}
|
||||
|
||||
static void regexp_free(RE *regexp)
|
||||
{
|
||||
RE *tmp;
|
||||
for(; regexp; regexp = tmp)
|
||||
{
|
||||
tmp = regexp->next;
|
||||
kfree(regexp);
|
||||
}
|
||||
}
|
||||
|
||||
static RE* compile(char *regexp)
|
||||
{
|
||||
RE head, *tail, *tmp;
|
||||
char *pstr;
|
||||
int err_flag = 0;
|
||||
|
||||
for(tail = &head; *regexp != '\0' && err_flag == 0; regexp++)
|
||||
{
|
||||
tmp = getmem(sizeof(RE));
|
||||
switch(*regexp){
|
||||
case '\\':
|
||||
regexp++;
|
||||
if(*regexp == 'd')
|
||||
{
|
||||
tmp->type = LIST;
|
||||
tmp->nccl = 0;
|
||||
tmp->ccl = getmem(11);
|
||||
creat_list(tmp->ccl, '0','9');
|
||||
tmp->ccl[11] = '\0';
|
||||
}else if(*regexp == 'D')
|
||||
{
|
||||
tmp->type = LIST;
|
||||
tmp->nccl = 1;
|
||||
tmp->ccl = getmem(11);
|
||||
creat_list(tmp->ccl, '0','9');
|
||||
tmp->ccl[11] = '\0';
|
||||
}else
|
||||
{
|
||||
tmp->type = CHAR;
|
||||
tmp->ch = *(regexp + 1);
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
tmp->type = DOT;
|
||||
break;
|
||||
case '^':
|
||||
tmp->type = BEGIN;
|
||||
tmp->ch = '^';
|
||||
break;
|
||||
case '$':
|
||||
tmp->type = END;
|
||||
tmp->ch = '$';
|
||||
break;
|
||||
case '*':
|
||||
tmp->type = STAR;
|
||||
break;
|
||||
case '+':
|
||||
tmp->type = PLUS;
|
||||
break;
|
||||
case '?':
|
||||
tmp->type = QUES;
|
||||
break;
|
||||
case '[':
|
||||
pstr = tmp->ccl = getmem(256);
|
||||
tmp->nccl = 0;
|
||||
if(*++regexp == '^')
|
||||
{
|
||||
tmp->nccl = 1;
|
||||
regexp++;
|
||||
}
|
||||
while(*regexp != '\0' && *regexp != ']')
|
||||
{
|
||||
if(*regexp != '-')
|
||||
{
|
||||
*pstr++ = *regexp++;
|
||||
continue;
|
||||
}
|
||||
if(pstr == tmp->ccl || *(regexp + 1) == ']')
|
||||
{
|
||||
err_flag = 1;
|
||||
break;
|
||||
}
|
||||
pstr += creat_list(pstr, *(regexp - 1) + 1, *(regexp + 1));
|
||||
regexp += 2;
|
||||
}
|
||||
*pstr = '\0';
|
||||
if(*regexp == '\0')
|
||||
err_flag = 1;
|
||||
tmp->type = LIST;
|
||||
break;
|
||||
default:
|
||||
tmp->type = CHAR;
|
||||
tmp->ch = *regexp;
|
||||
}
|
||||
|
||||
tail->next = tmp;
|
||||
tail = tmp;
|
||||
}
|
||||
|
||||
tail->next = NULL;
|
||||
if(err_flag)
|
||||
{
|
||||
regexp_free(head.next);
|
||||
return NULL;
|
||||
}
|
||||
return head.next;
|
||||
}
|
||||
|
||||
#define MATCH_ONE(reg, text) \
|
||||
(reg->type == DOT || in_list(*text, reg) || *text == reg->ch)
|
||||
#define MATCH_ONE_P(reg, text) \
|
||||
(in_list(*text++, reg) || *(text - 1) == reg->ch || reg->type == DOT)
|
||||
|
||||
static int matchhere(RE *regexp, char *text);
|
||||
|
||||
static int matchstar(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
do{
|
||||
if(matchhere(regexp, text))
|
||||
return 1;
|
||||
}while(*text != '\0' && MATCH_ONE_P(cur, text));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchstar_l(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
char *t;
|
||||
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
|
||||
;
|
||||
do{
|
||||
if(matchhere(regexp, t))
|
||||
return 1;
|
||||
}while(t-- > text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchplus(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
while(*text != '\0' && MATCH_ONE_P(cur, text))
|
||||
{
|
||||
if(matchhere(regexp, text))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchplus_l(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
char *t;
|
||||
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
|
||||
;
|
||||
for(; t > text; t--)
|
||||
{
|
||||
if(matchhere(regexp, t))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchques(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
int cnt = 1;
|
||||
char *t = text;
|
||||
if(*t != '\0' && cnt-- && MATCH_ONE(cur, t))
|
||||
t++;
|
||||
do{
|
||||
if(matchhere(regexp, t))
|
||||
return 1;
|
||||
}while(t-- > text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*matchfun[TYPENUM][2])(RE *, RE *, char *) = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
matchstar, matchstar_l,
|
||||
matchplus, matchplus_l,
|
||||
matchques, matchques,
|
||||
};
|
||||
|
||||
static int matchhere(RE *regexp, char *text)
|
||||
{
|
||||
if(regexp == NULL)
|
||||
return 1;
|
||||
if(regexp->type == END && regexp->next == NULL)
|
||||
return *text == '\0';
|
||||
if(regexp->next && matchfun[regexp->next->type][match_longest])
|
||||
return matchfun[regexp->next->type][match_longest](regexp, regexp->next->next, text);
|
||||
|
||||
if(*text != '\0' && MATCH_ONE(regexp, text))
|
||||
return matchhere(regexp->next, text + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* return value:
|
||||
* -1 error
|
||||
* 0 not match
|
||||
* 1 matched
|
||||
*/
|
||||
int regexp_match(char *reg, char *text)
|
||||
{
|
||||
int ret;
|
||||
RE *regexp = compile(reg);
|
||||
if(regexp == NULL)
|
||||
return -1;
|
||||
|
||||
if(regexp->type == BEGIN)
|
||||
{
|
||||
ret = matchhere(regexp->next, text);
|
||||
goto out;
|
||||
}
|
||||
|
||||
do{
|
||||
if(ret = matchhere(regexp, text))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
}while(*text++ != '\0');
|
||||
|
||||
out:
|
||||
regexp_free(regexp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void TEST_reg_func(char *reg, char * str, int ret)
|
||||
{
|
||||
|
||||
if (ret != regexp_match(reg, str)) {
|
||||
if (reg)
|
||||
printk("reg = %s,", reg);
|
||||
else
|
||||
printk("reg = null");
|
||||
if (str)
|
||||
printk("str = %s ", str);
|
||||
else
|
||||
printk("str= null");
|
||||
printk("error, unit test.... failed, ret = %d\n",ret);
|
||||
}
|
||||
else {
|
||||
if (reg && str)
|
||||
printk("[unit test] %s %s......ok,ret = %d\n", reg, str, ret);
|
||||
}
|
||||
}
|
||||
|
||||
void TEST_regexp(void)
|
||||
{
|
||||
TEST_reg_func(".*baidu.com$", "www.baidu.com", 1);
|
||||
TEST_reg_func("^sina.com", "www.sina.com.cn", 0);
|
||||
TEST_reg_func("^sina.com", "sina.com.cn", 1);
|
||||
TEST_reg_func(".*baidu.com$", "www.baidu.com223", 0);
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=appfilter
|
||||
PKG_VERSION:=5.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
#include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
define Package/appfilter
|
||||
SECTION:=Derry Apps
|
||||
CATEGORY:=Derry Apps
|
||||
DEPENDS:=+libubox +libubus +libuci +libpthread +libjson-c +libblobmsg-json
|
||||
TITLE:=App filter userspace module
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
cp -rf ./src/* $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR)/ \
|
||||
CC="$(TARGET_CROSS)gcc" \
|
||||
CFLAGS="$(TARGET_CFLAGS)" \
|
||||
LIBS="$(TARGET_LDFLAGS) -lm -lpthread -lubox -luci -lubus -ljson-c -lblobmsg_json" \
|
||||
all
|
||||
endef
|
||||
|
||||
|
||||
define Build/Compile/Default
|
||||
|
||||
endef
|
||||
|
||||
define Package/appfilter/description
|
||||
open appfilter app
|
||||
endef
|
||||
|
||||
|
||||
define Package/appfilter/install
|
||||
echo "install"
|
||||
$(INSTALL_DIR) $(1)/usr/bin $(1)/etc/init.d
|
||||
$(INSTALL_DIR) $(1)/etc/appfilter
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(CP) ./files/*.cfg $(1)/etc/appfilter/
|
||||
$(CP) ./files/*.txt $(1)/etc/appfilter/
|
||||
$(INSTALL_BIN) ./files/appfilter.init $(1)/etc/init.d/appfilter
|
||||
$(INSTALL_BIN) ./files/oaf_rule $(1)/usr/bin
|
||||
$(INSTALL_BIN) ./files/gen_class.sh $(1)/usr/bin
|
||||
$(INSTALL_BIN) ./files/appfilter.config $(1)/etc/config/appfilter
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/oafd $(1)/usr/bin
|
||||
endef
|
||||
|
||||
|
||||
$(eval $(call BuildPackage,appfilter))
|
||||
|
@ -1,8 +0,0 @@
|
||||
1 聊天
|
||||
2 游戏
|
||||
3 视频
|
||||
4 购物
|
||||
5 音乐
|
||||
6 招聘
|
||||
7 下载
|
||||
8 常用网站
|
@ -1,8 +0,0 @@
|
||||
1 chat
|
||||
2 game
|
||||
3 video
|
||||
4 shopping
|
||||
5 music
|
||||
6 recruitment
|
||||
7 download
|
||||
8 website
|
@ -1,16 +0,0 @@
|
||||
config global global
|
||||
option enable '0'
|
||||
option work_mode '0'
|
||||
|
||||
config appfilter appfilter
|
||||
|
||||
config feature feature
|
||||
|
||||
config time 'time'
|
||||
option time_mode '0'
|
||||
option days '0 1 2 3 4 5 6'
|
||||
option start_time '00:00'
|
||||
option end_time '23:59'
|
||||
option start_time2 ''
|
||||
option end_time2 ''
|
||||
config user user
|
@ -1,48 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/functions.sh
|
||||
|
||||
START=96
|
||||
USE_PROCD=1
|
||||
OAFD_BIN="/usr/bin/oafd"
|
||||
FEATURE_FILE="/tmp/feature.cfg"
|
||||
CLASS_FILE="/tmp/app_class.txt"
|
||||
service_triggers()
|
||||
{
|
||||
procd_add_reload_trigger "appfilter"
|
||||
}
|
||||
|
||||
stop_service(){
|
||||
killall -9 oafd
|
||||
rmmod oaf
|
||||
}
|
||||
|
||||
start_service(){
|
||||
lang=`uci get luci.main.lang`
|
||||
test -f $FEATURE_FILE && rm $FEATURE_FILE
|
||||
test -f $CLASS_FILE && rm $CLASS_FILE
|
||||
if [ x"" == x"$lang" -o x"auto" == x"$lang" ];then
|
||||
ln -s /etc/appfilter/feature.cfg $FEATURE_FILE
|
||||
ln -s /etc/appfilter/app_class.txt $CLASS_FILE
|
||||
else
|
||||
if [ -f "/etc/appfilter/feature_$lang.cfg" ];then
|
||||
ln -s /etc/appfilter/feature_$lang.cfg $FEATURE_FILE
|
||||
else
|
||||
ln -s /etc/appfilter/feature.cfg $FEATURE_FILE
|
||||
fi
|
||||
|
||||
if [ -f "/etc/appfilter/app_class_$lang.txt" ];then
|
||||
ln -s /etc/appfilter/app_class_$lang.txt $CLASS_FILE
|
||||
else
|
||||
ln -s /etc/appfilter/app_class.txt $CLASS_FILE
|
||||
fi
|
||||
fi
|
||||
gen_class.sh /tmp/feature.cfg
|
||||
insmod oaf
|
||||
/usr/bin/oaf_rule reload
|
||||
procd_open_instance
|
||||
procd_set_param respawn 60 5 5
|
||||
procd_set_param stderr 1
|
||||
procd_set_param command "$OAFD_BIN"
|
||||
procd_close_instance
|
||||
}
|
@ -1,262 +0,0 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local libubus = require "ubus"
|
||||
local uloop = require "uloop"
|
||||
|
||||
local UBUS_STATUS_OK = 0
|
||||
local UBUS_STATUS_INVALID_COMMAND = 1
|
||||
local UBUS_STATUS_INVALID_ARGUMENT = 2
|
||||
local UBUS_STATUS_METHOD_NOT_FOUND = 3
|
||||
local UBUS_STATUS_NOT_FOUND = 4
|
||||
local UBUS_STATUS_NO_DATA = 5
|
||||
local UBUS_STATUS_PERMISSION_DENIED = 6
|
||||
local UBUS_STATUS_TIMEOUT = 7
|
||||
local UBUS_STATUS_NOT_SUPPORTED = 8
|
||||
local UBUS_STATUS_UNKNOWN_ERROR = 9
|
||||
local UBUS_STATUS_CONNECTION_FAILED = 10
|
||||
local UBUS_STATUS_ALREADY_EXISTS = 11
|
||||
|
||||
local cfg_file = "/etc/appfilter/feature.cfg"
|
||||
|
||||
local cfg = {}
|
||||
local class = {}
|
||||
local ubus
|
||||
|
||||
cfg.__index = cfg
|
||||
class.__index = class
|
||||
function cfg:init(file)
|
||||
local f = io.open(file, "r")
|
||||
local t = {}
|
||||
local t2 = {}
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(t, line)
|
||||
local tt = line:match("#class (%S+)")
|
||||
if tt then
|
||||
table.insert(t2, tt)
|
||||
end
|
||||
end
|
||||
setmetatable(t, self)
|
||||
setmetatable(t2, self)
|
||||
return t,t2
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function cfg:lookup(o)
|
||||
if not o then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
local tab = self
|
||||
for _, v in ipairs(tab) do
|
||||
if v:match(o) then
|
||||
if v:match("#class") then
|
||||
local tt = {}
|
||||
local t2 = {}
|
||||
local found
|
||||
for _, t in ipairs(tab) do
|
||||
repeat
|
||||
if t:match(o) then
|
||||
found = true
|
||||
table.insert(tt, t)
|
||||
break
|
||||
end
|
||||
|
||||
if t:match("#class") then
|
||||
found = false
|
||||
table.insert(t2, t)
|
||||
break
|
||||
end
|
||||
|
||||
if found then
|
||||
table.insert(tt, t)
|
||||
else
|
||||
table.insert(t2, t)
|
||||
end
|
||||
until true
|
||||
end
|
||||
setmetatable(tt, self)
|
||||
setmetatable(t2, self)
|
||||
return tt, t2
|
||||
else
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function cfg:lookup_class(m)
|
||||
if not m then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
local t1, t2 = self:lookup(m)
|
||||
if type(t1) ~= "table" then return nil end
|
||||
return t1, t2
|
||||
end
|
||||
|
||||
function cfg:add_class(m)
|
||||
if not m then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
local f = io.open(cfg_file, "r+")
|
||||
local tab = self
|
||||
if f then
|
||||
io.output(f)
|
||||
for _, v in ipairs(tab) do
|
||||
io.write(v)
|
||||
io.write("\n")
|
||||
end
|
||||
io.write("#class "..m)
|
||||
f:flush()
|
||||
f:close()
|
||||
return UBUS_STATUS_OK
|
||||
else
|
||||
return UBUS_STATUS_NOT_FOUND
|
||||
end
|
||||
end
|
||||
|
||||
function cfg:add_app(m, name, proto, sport, dport, url, request, dict)
|
||||
if not name then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
local id
|
||||
local offset
|
||||
local f = io.open(cfg_file, "r+")
|
||||
io.output(f)
|
||||
local t1,t2 = self:lookup_class(m)
|
||||
if t1[#t1] == nil or "" then
|
||||
offset = 0
|
||||
id = math.modf(string.match(t1[#t1-1], "(%d+) %S+:") +1)
|
||||
else
|
||||
offset = 1
|
||||
id = math.modf(string.match(t1[#t1], "(%d+) %S+:") +1)
|
||||
end
|
||||
|
||||
local str = string.format("%d %s:[%s;%s;%s;%s;%s;%s]", id, name, proto, sport or "", dport or "", url or "", request or "", dict or "")
|
||||
table.insert(t1, #t1+offset, str)
|
||||
if f then
|
||||
for _, v in ipairs(t2) do
|
||||
if v then
|
||||
io.write(v)
|
||||
io.write("\n")
|
||||
end
|
||||
end
|
||||
for _, v in ipairs(t1) do
|
||||
if v then
|
||||
io.write(v)
|
||||
io.write("\n")
|
||||
end
|
||||
end
|
||||
f:flush()
|
||||
f:close()
|
||||
end
|
||||
return id
|
||||
end
|
||||
|
||||
function cfg:del_app(id, name)
|
||||
local t = self
|
||||
local f = io.open(cfg_file, "r+")
|
||||
local ret
|
||||
if id then
|
||||
for i, v in ipairs(t) do
|
||||
if v:match(id) then
|
||||
table.remove(t, i)
|
||||
ret = i
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if name then
|
||||
for i, v in ipairs(t) do
|
||||
if v:match(name) then
|
||||
table.remove(t, i)
|
||||
ret = i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if f then
|
||||
io.output(f)
|
||||
for _, v in ipairs(t) do
|
||||
io.write(v)
|
||||
io.write("\n")
|
||||
end
|
||||
f:flush()
|
||||
f:close()
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local methods = {
|
||||
["appfilter"] = {
|
||||
add_class = {
|
||||
function(req, msg)
|
||||
if not msg.class then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
local t = cfg:init(cfg_file)
|
||||
local ret
|
||||
if t:lookup_class(msg.class) then return ubus.reply(req, {ret = UBUS_STATUS_ALREADY_EXISTS}) end
|
||||
ret = t:add_class(msg.class)
|
||||
ubus.reply(req, {msg = ret})
|
||||
end, {class = libubus.STRING}
|
||||
},
|
||||
add_app = {
|
||||
function (req, msg)
|
||||
if not msg.class then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
if not msg.name then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
if not msg.proto then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
local t = cfg:init(cfg_file)
|
||||
local ret
|
||||
if t:lookup(msg.name) then return ubus.reply(req, {ret = UBUS_STATUS_ALREADY_EXISTS}) end
|
||||
ret = t:add_app(msg.class, msg.name, msg.proto, msg.sport, msg.dport, msg.url, msg.request, msg.dict)
|
||||
ubus.reply(req, {ret = ret})
|
||||
end,{class = libubus.STRING, name = libubus.STRING, proto = libubus.STRING, sport = libubus.INT32, dport = libubus.INT32, url = libubus.STRING, request = libubus.STRING, dict = libubus.STRING}
|
||||
},
|
||||
del_app = {
|
||||
function(req, msg)
|
||||
local t = cfg:init(cfg_file)
|
||||
local ret = t:del_app(msg.id, msg.name)
|
||||
ubus.reply(req, {ret = ret})
|
||||
end,{id = libubus.INT32, name = libubus.STRING}
|
||||
},
|
||||
list_class = {
|
||||
function (req, msg)
|
||||
local _, c = cfg:init(cfg_file)
|
||||
ubus.reply(req, {result = c})
|
||||
end,{}
|
||||
},
|
||||
list_app = {
|
||||
function (req, msg)
|
||||
if not msg.class then return UBUS_STATUS_INVALID_ARGUMENT end
|
||||
local t = cfg:init(cfg_file)
|
||||
local ret = {}
|
||||
for i, v in ipairs(t:lookup_class(msg.class)) do
|
||||
if not v:match("#class") then
|
||||
local id, name = v:match("(%d+) (%S+):%[")
|
||||
ret[i-1] = {id = id, name = name}
|
||||
end
|
||||
end
|
||||
ubus.reply(req, {result = ret})
|
||||
end,{class = libubus.STRING}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ubus_init()
|
||||
local conn = libubus.connect()
|
||||
if not conn then
|
||||
error("Failed to connect to ubus")
|
||||
end
|
||||
|
||||
conn:add(methods)
|
||||
|
||||
return {
|
||||
call = function(object, method, params)
|
||||
return conn:call(object, method, params or {})
|
||||
end,
|
||||
reply = function(req, msg)
|
||||
conn:reply(req, msg)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local function main()
|
||||
uloop.init()
|
||||
ubus = ubus_init()
|
||||
uloop.run()
|
||||
end
|
||||
|
||||
main()
|
@ -1,88 +0,0 @@
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/functions.sh
|
||||
|
||||
config_apply()
|
||||
{
|
||||
test -z "$1" && return 1
|
||||
|
||||
if [ -e "/dev/appfilter" ];then
|
||||
echo "config json str=$1"
|
||||
echo "$1" >/dev/appfilter
|
||||
fi
|
||||
}
|
||||
|
||||
clean_rule()
|
||||
{
|
||||
json_init
|
||||
echo "clean appfilter rule..."
|
||||
|
||||
json_add_int "op" 3
|
||||
json_add_object "data"
|
||||
json_str=`json_dump`
|
||||
|
||||
config_apply "$json_str"
|
||||
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
load_rule()
|
||||
{
|
||||
json_init
|
||||
|
||||
config_load appfilter
|
||||
config_get enable "global" enable
|
||||
echo "enable = $enable"
|
||||
if [ x"$enable" != x"1" ];then
|
||||
echo "appfilter is disabled"
|
||||
echo 0 >/proc/sys/oaf/enable>/dev/null
|
||||
return 0
|
||||
else
|
||||
insmod oaf >/dev/null
|
||||
echo 1 >/proc/sys/oaf/enable
|
||||
fi
|
||||
echo "appfilter is enabled"
|
||||
json_add_int "op" 1
|
||||
|
||||
json_add_object "data"
|
||||
json_add_array "apps"
|
||||
|
||||
for file in `ls /tmp/appfilter/*.class`
|
||||
do
|
||||
class_name=`echo "$file" | awk -F/ '{print $4}'| awk -F. '{print $1}'`
|
||||
config_get appid_list "appfilter" "${class_name}apps"
|
||||
echo "appid_list=$appid_list"
|
||||
|
||||
if ! test -z "$appid_list";then
|
||||
for appid in $appid_list:
|
||||
do
|
||||
json_add_int "" $appid
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
json_str=`json_dump`
|
||||
config_apply "$json_str"
|
||||
json_cleanup
|
||||
}
|
||||
load_mac_list()
|
||||
{
|
||||
json_init
|
||||
config_load appfilter
|
||||
json_add_int "op" 4
|
||||
json_add_object "data"
|
||||
json_add_array "mac_list"
|
||||
config_get appid_list "user" "users"
|
||||
echo "appid list=$appid_list"
|
||||
for appid in $appid_list:
|
||||
do
|
||||
echo "appid=$appid"
|
||||
json_add_string "" $appid
|
||||
done
|
||||
json_str=`json_dump`
|
||||
config_apply "$json_str"
|
||||
echo "json str=$json_str"
|
||||
json_cleanup
|
||||
}
|
||||
clean_rule
|
||||
load_rule
|
||||
load_mac_list
|
@ -1,216 +0,0 @@
|
||||
#version v22.3.24
|
||||
#id name:[proto;sport;dport;host url;request;dict]
|
||||
#class chat
|
||||
1001 QQ:[tcp;;;;;00:02|-1:03,tcp;;;;;02:02|-1:03,tcp;;14000;;;,tcp;;8080;;;00:ca|01:3c,tcp;;;;;00:00|01:00|02:00|03:15]
|
||||
1002 微信:[tcp;;;;;01:f1|02:03,tcp;;;;;00:ab|01:00|02:00,tcp;;80;;/mmtls;]
|
||||
1003 微博:[tcp;;443;weibo;;]
|
||||
1004 陌陌:[tcp;;;momo;;,tcp;;;;;04:2f|05:66|06:65|07:65,tcp;;;;;00:03|01:03|02:00]
|
||||
1005 支付宝:[tcp;;443;alipay.com;;]
|
||||
1006 钉钉:[tcp;;;dingtalk;;,tcp;;;;d?host=;,tcp;;;;/man/api;,tcp;;;;/beacon;]
|
||||
1007 Soul:[tcp;;;soulapp;;]
|
||||
1008 伊对:[tcp;;;520yidui;;]
|
||||
1009 探探:[tcp;;;tancdn;;,tcp;;;tantanapp;;]
|
||||
1010 多闪:[tcp;;;ppkankan;;]
|
||||
|
||||
#class game
|
||||
2001 王者荣耀:[tcp;;;;;00:33|01:66|02:00|03:09,udp;;;;;00:01|01:02|02:00|03:00]
|
||||
2003 英雄联盟:[udp;;;;;44:00|45:00|46:00|47:02]
|
||||
2015 我的世界:[tcp;;443;g79mclobt.nie.netease;;]
|
||||
2005 欢乐斗地主:[tcp;;8000;;;00:74|01:67|02:77|03:5f]
|
||||
2006 梦幻西游:[tcp;;;;;00:0e|01:00|02:fe|03:ff]
|
||||
2007 明日之后:[udp;;;;;00:05|01:09|02:00,tcp;;;;;00:02|01:00|02:00|03:00|04:00|05:00]
|
||||
2008 QQ飞车:[udp;;;;;00:28|01:28,tcp;;10000;;;00:33|01:66|02:00|03:08]
|
||||
2009 跑跑卡丁车:[tcp;;8888;;;00:33|01:66|02:00|03:08]
|
||||
2010 开心消消乐:[tcp;;80;happyelements;;]
|
||||
2011 狂野飙车:[tcp;;;asphalt9;;]
|
||||
2012 率土之滨:[tcp;;10001;;;00:00|01:00,tcp;;8001;;;00:00|01:00]
|
||||
2013 一刀传世:[tcp;;8040;;;00:47|01:45]
|
||||
2014 第五人格:[tcp;;4010;;;,tcp;;4010;;;,tcp;;4020;;;,tcp;;4030;;;,tcp;;4040;;;,tcp;;4050;;;,tcp;;4060;;;,tcp;;4070;;;,tcp;;4080;;;,tcp;;4090;;;]
|
||||
2016 皇室战争:[udp;;9339;;;]
|
||||
2017 炉石传说:[tcp;;3724;;;00:73:01:00:02:00]
|
||||
|
||||
|
||||
#class video
|
||||
3001 抖音短视频:[tcp;;;-dy-;;,tcp;;;-dy.;;,tcp;;;douyin;;]
|
||||
3002 火山小视频:[tcp;;;.huoshan.com;;,tcp;;;hs.pstatp.com;;,tcp;;;hs.ixigua.com;;]
|
||||
3003 腾讯视频:[tcp;;443;v.qq.com;;,tcp;;443;video.qq.com;;,tcp;;443;btrace.qq.com;;]
|
||||
3004 爱奇艺:[tcp;;;iqiyi;;,tcp;;;qy.net;;]
|
||||
3005 微视:[tcp;;80;;;00:34|01:16|02:75,tcp;;80;weishi.qq.com;;]
|
||||
3006 斗鱼直播:[tcp;;;douyu;;,tcp;;;douyu;;-2:2f|-1:00]
|
||||
3008 虎牙直播:[tcp;;;huya;;,udp;;;;;01:00|02:00|03:00|04:23,udp;;;;;01:00|02:00|03:00|04:24]
|
||||
3009 快手:[tcp;;;kuaishou;;,tcp;;;ksyuncdn.com;;,tcp;;;.gifshow.com;;,tcp;;;yximgs.com;;,tcp;;80;;/ksc;,tcp;;;kwaicdn;;,tcp;;;kwimgs;;]
|
||||
3010 小红书:[tcp;;;xiaohongshu;;,tcp;;;xhscdn;;]
|
||||
3011 花椒直播:[tcp;;;huajiao;;]
|
||||
3012 映客直播:[tcp;;;;.inke.cn;]
|
||||
3013 YY:[udp;;;;;02:00|03:00|04:08,udp;;;;;00:4f|01:00|02:00]
|
||||
3014 哔哩哔哩:[tcp;;;bilivideo;;,tcp;;;bilibili.com;;,tcp;;;;;00:47|05:75|06:70|07:67,tcp;;;;/bfs/emote/;,,tcp;;;hdslb.com;;]
|
||||
3016 芒果tv:[tcp;;443;mgtv;;,tcp;;80;mgtv;;,tcp;;443;hitv;;]
|
||||
3017 西瓜视频:[tcp;;;ixigua;;,tcp;;443;snsdk;;,tcp;;;xg-p.ixigua;;,tcp;;;bdxigua;;]
|
||||
3018 搜狐视频:[tcp;;;aty.sohu.com;;,tcp;;;tv.itc.cn;;]
|
||||
3019 播聊:[tcp;;80;randlove.cn;;,tcp;;;yueliao;;,tcp;;;5glive;;]
|
||||
3020 咪咕视频:[tcp;;;miguvideo;;,tcp;;;migu.cn;;]
|
||||
3021 韩剧TV:[tcp;;;hanju.koudaibaobao;;]
|
||||
3022 人人视频:[tcp;;;rr.tv;;]
|
||||
3023 央视影音:[tcp;;;cntv;;]
|
||||
3024 土豆视频:[tcp;;;youku;;,tcp;;;ykimg;;]
|
||||
3025 最右:[tcp;;;izuiyou;;]
|
||||
3026 风行视频:[tcp;;;funshion;;]
|
||||
3027 企鹅电竞:[tcp;;;egame.qq;;,tcp;;;liveplay;;,tcp;;;;pggame;]
|
||||
3028 波波视频:[tcp;;;miaopai;;]
|
||||
3029 酷狗短酷:[tcp;;;bssdl.kugou;;]
|
||||
3030 酷狗直播:[tcp;;;rt-m.kugou;;,tcp;;;kgimg.com;;]
|
||||
|
||||
|
||||
#class shopping
|
||||
4001 淘宝:[tcp;;;taobao;;,tcp;;;alicdn.com;;,tcp;;;tmall.com;;,tcp;;;;;00:d3|01:00,,tcp;;;;;00:d4|01:00,,tcp;;;;;00:d3|01:00]
|
||||
4002 京东:[tcp;;;360buyimg;;,tcp;;;jd.com;;,tcp;;;jdcdn.com;;,tcp;;;;;00:d5|01:00]
|
||||
4003 唯品会:[tcp;;;vips-mobile;;,tcp;;;vipshop;;,tcp;;;vip.com;;,tcp;;;vipstatic.com;;,tcp;;;appsimg.com;;]
|
||||
4004 拼多多:[tcp;;;pinduoduo;;,tcp;;;yangkeduo.com;;,tcp;;;s1p.cdntip.com;;]
|
||||
4010 饿了么:[tcp;;;eleme;;]
|
||||
4011 美团:[tcp;;;meituan;;]
|
||||
4012 闲鱼:[tcp;;;xianyu;;]
|
||||
4021 转转:[tcp;;;zhuanzhuan;;,tcp;;;zhuanstatic;;]
|
||||
4005 蘑菇街:[tcp;;;mogujie;;,tcp;;;mogucdn;;,tcp;;;;;00:73|01:ea|02:68|03:fb|04:3f]
|
||||
4006 苏宁易购:[tcp;;;.suning.;;]
|
||||
4007 当当网:[tcp;;;.dangdang.com;;]
|
||||
4008 1号店:[tcp;;;.yhd.com;;]
|
||||
4009 朴朴超市:[tcp;;;pupumall;;,tcp;;;pupuapi;;]
|
||||
4013 叮咚买菜:[tcp;;;ddxq.mobi;;]
|
||||
4014 小米有品:[tcp;;;youpin;;,tcp;;;shopapi.io.mi.com;;]
|
||||
4015 微店:[tcp;;;weidian;;]
|
||||
4016 折800:[tcp;;;zhe800.com;;]
|
||||
4017 HM:[tcp;;;www.hm.com;;,tcp;;;measurement.com;;]
|
||||
4018 好省:[tcp;;;hzhstb.com;;]
|
||||
4019 什么值得买:[tcp;;;smzdm.com;;]
|
||||
4020 大众点评:[tcp;;;dianping.com;;]
|
||||
4022 网易严选:[tcp;;;yanxuan;;]
|
||||
4023 识货:[tcp;;;shihuo;;]
|
||||
4024 考拉海购:[tcp;;;kaola;;]
|
||||
4025 宜家家居:[tcp;;;ikea.cn;;]
|
||||
4026 小象优品:[tcp;;;xiaoxiangyoupin;;]
|
||||
|
||||
#class music
|
||||
5001 网易云音乐:[tcp;;;music.163;;,tcp;;;music.126;;]
|
||||
5002 QQ音乐:[tcp;;;;^/amobile.music.tc.qq.com;,tcp;;;qqmusic;;]
|
||||
5003 酷狗音乐:[tcp;;;kugou;;,tcp;;;kgimg;;,tcp;;;fanxing;;]
|
||||
5004 酷我音乐:[tcp;;;.kuwo.cn;;]
|
||||
5005 喜马拉雅:[tcp;;;.ximalaya.com;;]
|
||||
5006 千千音乐:[tcp;;;music.taihe.com;;]
|
||||
5007 虾米音乐:[tcp;;;xiami;;]
|
||||
5008 音悦台:[tcp;;;yinyuetai.com;;]
|
||||
5009 豆瓣FM:[tcp;;;douban.fm;;]
|
||||
5010 唱吧:[tcp;;;changba.com;;]
|
||||
5011 音乐随心听:[tcp;;;fm.taihe.com;;]
|
||||
5012 懒人听书:[tcp;;;lrts.me;;]
|
||||
|
||||
#class employee
|
||||
6001 前程无忧:[tcp;;;51job;;]
|
||||
6002 智联招聘:[tcp;;;zhaopin;;]
|
||||
6003 猎聘:[tcp;;;liepin;;]
|
||||
6004 赶集网:[tcp;;;58.com;;,tcp;;;58cdn;;]
|
||||
6005 同城急聘:[tcp;;;xiaomei;;]
|
||||
6006 领英:[tcp;;;linkedin;;]
|
||||
6007 斗米:[tcp;;;doumi;;]
|
||||
6008 看准:[tcp;;;kanzhun.com;;]
|
||||
6009 应届生求职:[tcp;;;yingjiesheng.com;;]
|
||||
6010 中华英才网:[tcp;;;chinahr.com;;]
|
||||
6011 拉勾网:[tcp;;;lagou.com;;]
|
||||
6012 大街网:[tcp;;;dajie.com;;]
|
||||
6013 boss直聘:[tcp;;;zhipin.com;;]
|
||||
6014 实习僧:[tcp;;;shixiseng.com;;]
|
||||
|
||||
#class download
|
||||
7001 迅雷:[udp;12345;;;;,udp;15000;;;;,tcp;;54321;;;,tcp;;12345;;;,udp;6881;;;;,udp;;12346;;;,udp;12346;;;;]
|
||||
7002 AppStore:[tcp;;;itunes.apple.com;;] HIDE:0
|
||||
7003 samba共享:[tcp;;445;;;] HIDE:0
|
||||
7004 ftp文件传输:[tcp;;21;;;] HIDE:0
|
||||
7005 vivo应用商店:[tcp;;443;appstore.vivo;;,tcp;;443;apkappdefwsdl.vivo;;] HIDE:0
|
||||
7006 王者荣耀更新:[tcp;;80;;/sgame/;]
|
||||
7007 天翼云盘:[tcp;;;ctyunapi;;]
|
||||
7008 腾讯微云:[tcp;;;weiyun.com;;,tcp;;;aegis.qq.com;;,tcp;;;pingtas.qq.com;;,tcp;;443;;;00:77|01:6e|02:73]
|
||||
7009 坚果云:[tcp;;;jianguoyun;;]
|
||||
7010 蓝奏云:[tcp;;;pan.lanzou.com;;]
|
||||
7011 华为云:[tcp;;;cloud.huawei.com;;,tcp;;;hicloud.com;;,tcp;;;myhuaweicloud.cn;;]
|
||||
7020 windows更新:[tcp;;80;update.microsoft.com;;,tcp;;;windowsupdate.com;;]
|
||||
7030 向日葵:[tcp;;;oray.com;;,tcp;;;oray.net;;]
|
||||
7031 TeamViewer:[tcp;;;teamviewer;;]
|
||||
7032 阿里云盘:[tcp;;;aliyundrive;;]
|
||||
7035 SSH:[tcp;;;;;00:53|01:53|02:48]
|
||||
|
||||
#class website
|
||||
8001 百度:[tcp;;;baidu.com;;]
|
||||
8002 新浪:[tcp;;;sina.com;;]
|
||||
8003 搜狐:[tcp;;;sohu.com;;]
|
||||
8004 网易:[tcp;;;163.com;;,tcp;;443;126.com;;]
|
||||
8005 凤凰网:[tcp;;;ifeng.com;;]
|
||||
8006 人民网:[tcp;;;people.com.cn;;]
|
||||
8007 凤凰网:[tcp;;;ifeng.com;;]
|
||||
8008 中华网:[tcp;;;china.com;;]
|
||||
8009 hao123:[tcp;;;hao123.com;;,]
|
||||
8010 2345:[tcp;;;2345.com;;,]
|
||||
8011 4399游戏:[tcp;;;4399.com;;]
|
||||
8012 7k7k游戏:[tcp;;;7k7k.com;;]
|
||||
8013 17173游戏:[tcp;;;17173.com;;]
|
||||
8014 37网游:[tcp;;;37.com;;]
|
||||
8015 游民星空:[tcp;;;gamersky.com;;]
|
||||
8016 游侠网:[tcp;;;ali213.net;;]
|
||||
8017 世纪佳缘:[tcp;;;jiayuan.com;;]
|
||||
8018 珍爱网:[tcp;;;zhenai.com;;]
|
||||
8019 百合网:[tcp;;;baihe.com;;]
|
||||
8020 天涯社区:[tcp;;;tianya.cn;;]
|
||||
8021 携程网:[tcp;;;ctrip.com;;]
|
||||
8022 飞猪:[tcp;;;fliggy.com;;]
|
||||
8023 12306:[tcp;;;12306.cn;;]
|
||||
8024 马蜂窝:[tcp;;;mafengwo.cn;;]
|
||||
8025 途牛:[tcp;;;tuniu.com;;]
|
||||
8026 穷游网:[tcp;;;qyer.com;;]
|
||||
8027 驴妈妈:[tcp;;;lvmama.com;;]
|
||||
8028 同程旅游:[tcp;;;ly.com;;]
|
||||
8029 太平洋汽车:[tcp;;;pcauto.com.cn;;]
|
||||
8030 易车网:[tcp;;;bitauto.com;;]
|
||||
8031 爱卡汽车:[tcp;;;xcar.com.cn;;]
|
||||
8032 雪球:[tcp;;;xueqiu.com;;]
|
||||
8033 东方财富:[tcp;;;eastmoney.com;;]
|
||||
8034 证券之星:[tcp;;;stockstar.com;;]
|
||||
8035 和讯:[tcp;;;hexun.com;;]
|
||||
8036 第一财经:[tcp;;;yicai.com;;]
|
||||
8037 全景网:[tcp;;;p5w.net;;]
|
||||
8038 中彩网:[tcp;;;zhcw.com;;]
|
||||
8039 中国体育彩票:[tcp;;;lottery.gov.cn;;]
|
||||
8040 竞彩网:[tcp;;;sporttery.cn;;]
|
||||
8041 豆丁:[tcp;;;docin.com;;]
|
||||
8042 豆瓣:[tcp;;;douban.com;;]
|
||||
8043 知乎:[tcp;;;zhihu.com;;]
|
||||
8044 缤客:[tcp;;;booking.com;;]
|
||||
8046 猫扑:[tcp;;;mop.com;;]
|
||||
8047 赶集网:[tcp;;;ganji.com;;]
|
||||
8048 安居客:[tcp;;;anjuke.com;;]
|
||||
8049 房天下:[tcp;;;fang.com;;]
|
||||
8050 链家:[tcp;;;lianjia.com;;]
|
||||
8051 百姓网:[tcp;;;baixing.com;;]
|
||||
8052 下厨房:[tcp;;;xiachufang.com;;]
|
||||
8053 大众点评:[tcp;;;dianping.com;;]
|
||||
8054 58同城:[tcp;;;58.com;;]
|
||||
8055 天眼查:[tcp;;;tianyancha.com;;]
|
||||
8056 千图网:[tcp;;;58pic.com;;]
|
||||
8057 csdn社区:[tcp;;;csdn.net;;]
|
||||
8058 有道词典:[tcp;;;dict.youdao.com;;]
|
||||
8059 动漫之家:[tcp;;;dmzj.com;;]
|
||||
8060 汽车之家:[tcp;;;autohome.com.cn;;]
|
||||
8061 纵横中文网:[tcp;;;zongheng.com;;]
|
||||
8062 起点中文网:[tcp;;;qidian.com;;]
|
||||
8063 飞卢:[tcp;;;faloo.com;;]
|
||||
8064 潇湘书院:[tcp;;;xxsy.net;;]
|
||||
8065 cctv5:[tcp;;;sports.cctv.com;;]
|
||||
8066 虎扑体育:[tcp;;;www.hupu.com;;]
|
||||
8067 建设银行:[tcp;;;ccb.com;;]
|
||||
8068 农业银行:[tcp;;;abchina.com;;]
|
||||
8069 中国银行:[tcp;;;boc.cn;;]
|
||||
8070 交通银行:[tcp;;;bankcomm.com;;]
|
||||
8071 招商银行:[tcp;;;cmbchina.com;;]
|
||||
8072 邮政储蓄:[tcp;;;psbc.com;;]
|
||||
8073 兴业银行:[tcp;;;cib.com.cn;;]
|
||||
8074 浦发银行:[tcp;;;spdb.com.cn;;]
|
||||
8075 中信银行:[tcp;;;citicbank.com;;]
|
||||
8076 上海银行:[tcp;;;bosc.cn;;]
|
||||
|
@ -1,51 +0,0 @@
|
||||
#version v21.9.1
|
||||
#id name:[proto;sport;dport;host url;request;dict]
|
||||
#class chat
|
||||
1001 Facebook:[tcp;;;facebook.com;;]
|
||||
1002 Whatsapp:[tcp;;;whatsapp;;]
|
||||
1003 Twitter:[tcp;;;twitter.com;;]
|
||||
1004 Instagram:[tcp;;;instagram.com;;]
|
||||
1005 VK:[tcp;;;vk.com;;]
|
||||
1006 Line:[tcp;;;line;;]
|
||||
|
||||
#class video
|
||||
3001 YouTube:[tcp;;;youtube;;]
|
||||
3002 NetFlix:[tcp;;;netflix;;]
|
||||
3003 Vimeo:[tcp;;;vimeo;;]
|
||||
3004 DailyMotion:[tcp;;;dailymotion;;]
|
||||
3005 Hulu:[tcp;;;hulu;;]
|
||||
3006 Vube:[tcp;;;vube;;]
|
||||
3007 Twitch:[tcp;;;twitch;;]
|
||||
3008 LiveLeak:[tcp;;;itemfix;;]
|
||||
3009 LiveLeak:[tcp;;;itemfix;;]
|
||||
3010 Xvideos:[tcp;;;xvideos.com;;]
|
||||
3011 Pornhub:[tcp;;;pornhub.com;;]
|
||||
|
||||
#class shopping
|
||||
4001 Amazon:[tcp;;;amazon.com;;]
|
||||
4002 eBay:[tcp;;;ebay.com;;]
|
||||
4003 Etsy:[tcp;;;etsy.com;;]
|
||||
4004 Wish:[tcp;;;wish.com;;]
|
||||
4005 Alibaba:[tcp;;;alibaba;;]
|
||||
4006 Aliexpress:[tcp;;;aliexpress.com;;]
|
||||
4007 Walmart:[tcp;;;walmart.com;;]
|
||||
4008 Sears:[tcp;;;sears.com;;]
|
||||
4009 Kohls:[tcp;;;kohls.com;;]
|
||||
4010 Costco:[tcp;;;costco.com;;]
|
||||
4011 Asos:[tcp;;;asos.com;;]
|
||||
4012 Cuyana:[tcp;;;cuyana.com;;]
|
||||
|
||||
#class download
|
||||
7001 Google Play:[tcp;;;play.google.com;;]
|
||||
7002 AppStore:[tcp;;80;iosapps.itunes.apple.com;;]
|
||||
|
||||
#class website
|
||||
8001 Google:[tcp;;;www.google.com;;]
|
||||
8002 Wiki:[tcp;;;www.wikipedia.com;;]
|
||||
8003 Yahoo:[tcp;;;www.yahoo.com;;]
|
||||
8004 Apple:[tcp;;;www.apple.com;;]
|
||||
8010 Reddit:[tcp;;;www.reddit.com;;]
|
||||
8011 Outlook:[tcp;;;www.outlook.live.com;;]
|
||||
8012 Naver:[tcp;;;www.naver.com;;]
|
||||
8013 Fandom:[tcp;;;www.fandom.com;;]
|
||||
8015 Globo:[tcp;;;www.globo.com;;]
|
@ -1,30 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
f_file=$1
|
||||
test -z "$f_file" && return
|
||||
test -d /tmp/appfilter && return
|
||||
cur_class=""
|
||||
cur_class_file=""
|
||||
mkdir /tmp/appfilter
|
||||
while read line
|
||||
do
|
||||
echo "$line"| grep "^#class"
|
||||
if [ $? -eq 0 ];then
|
||||
class=`echo $line| grep '#class' | awk '{print $2}'`
|
||||
if ! test -z "$class";then
|
||||
cur_class=$class
|
||||
cur_class_file="/tmp/appfilter/${cur_class}.class"
|
||||
if [ -e "$cur_class_file" ];then
|
||||
rm $cur_class_file
|
||||
fi
|
||||
touch $cur_class_file
|
||||
fi
|
||||
fi
|
||||
test -z "$cur_class" && continue
|
||||
appid=`echo "$line" |awk '{print $1}'`
|
||||
appname=`echo "$line" | awk '{print $2}' | awk -F: '{print $1}'`
|
||||
|
||||
echo "$appid $appname" >> $cur_class_file
|
||||
done < $f_file
|
||||
echo "ok"
|
||||
|
@ -1,95 +0,0 @@
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/functions.sh
|
||||
|
||||
|
||||
config_apply()
|
||||
{
|
||||
test -z "$1" && return 1
|
||||
|
||||
if [ -e "/dev/appfilter" ];then
|
||||
echo "config json str=$1"
|
||||
echo "$1" >/dev/appfilter
|
||||
fi
|
||||
}
|
||||
|
||||
clean_rule()
|
||||
{
|
||||
json_init
|
||||
echo "clean appfilter rule..."
|
||||
|
||||
json_add_int "op" 3
|
||||
json_add_object "data"
|
||||
json_str=`json_dump`
|
||||
|
||||
config_apply "$json_str"
|
||||
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
load_rule()
|
||||
{
|
||||
json_init
|
||||
json_add_int "op" 1
|
||||
json_add_object "data"
|
||||
json_add_array "apps"
|
||||
|
||||
for file in `ls /tmp/appfilter/*.class`
|
||||
do
|
||||
class_name=`echo "$file" | awk -F/ '{print $4}'| awk -F. '{print $1}'`
|
||||
config_get appid_list "appfilter" "${class_name}apps"
|
||||
|
||||
if ! test -z "$appid_list";then
|
||||
for appid in $appid_list:
|
||||
do
|
||||
json_add_int "" $appid
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
json_str=`json_dump`
|
||||
config_apply "$json_str"
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
load_mac_list()
|
||||
{
|
||||
json_init
|
||||
config_load appfilter
|
||||
json_add_int "op" 4
|
||||
json_add_object "data"
|
||||
json_add_array "mac_list"
|
||||
config_get mac_list "user" "users"
|
||||
echo "mac list=$mac_list"
|
||||
if [ x"$mac_list" != x"" ];then
|
||||
for mac in $mac_list:
|
||||
do
|
||||
json_add_string "" $mac
|
||||
done
|
||||
fi
|
||||
json_str=`json_dump`
|
||||
config_apply "$json_str"
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
reload_rule(){
|
||||
config_load appfilter
|
||||
clean_rule
|
||||
load_rule
|
||||
load_mac_list
|
||||
}
|
||||
|
||||
reload_base_config(){
|
||||
local old_work_mode
|
||||
config_load appfilter
|
||||
config_get work_mode "global" "work_mode"
|
||||
echo "work mode=$work_mode"
|
||||
echo "$work_mode" >/proc/sys/oaf/work_mode
|
||||
}
|
||||
|
||||
case $1 in
|
||||
"reload")
|
||||
echo "reload appfilter rule..."
|
||||
reload_base_config
|
||||
reload_rule
|
||||
;;
|
||||
esac
|
@ -1,6 +0,0 @@
|
||||
OBJS:=appfilter_user.o appfilter_netlink.o appfilter_ubus.o appfilter_config.o main.o
|
||||
EXEC:=oafd
|
||||
all: $(OBJS)
|
||||
$(CC) -o $(EXEC) $(OBJS) $(LIBS)
|
||||
clean:
|
||||
rm $(EXEC) *.o
|
@ -1,329 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "appfilter_config.h"
|
||||
#include <uci.h>
|
||||
|
||||
app_name_info_t app_name_table[MAX_SUPPORT_APP_NUM];
|
||||
int g_app_count = 0;
|
||||
int g_cur_class_num = 0;
|
||||
char CLASS_NAME_TABLE[MAX_APP_TYPE][MAX_CLASS_NAME_LEN];
|
||||
|
||||
const char *config_path = "./config";
|
||||
static struct uci_context *uci_ctx = NULL;
|
||||
static struct uci_package *uci_appfilter;
|
||||
|
||||
|
||||
int uci_get_int_value(struct uci_context *ctx, char *key)
|
||||
{
|
||||
struct uci_element *e;
|
||||
struct uci_ptr ptr;
|
||||
int ret = -1;
|
||||
int dummy;
|
||||
char *parameters ;
|
||||
char param_tmp[128] = {0};
|
||||
strcpy(param_tmp, key);
|
||||
if (uci_lookup_ptr(ctx, &ptr, param_tmp, true) != UCI_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
|
||||
ctx->err = UCI_ERR_NOTFOUND;
|
||||
goto done;
|
||||
}
|
||||
|
||||
e = ptr.last;
|
||||
switch(e->type) {
|
||||
case UCI_TYPE_SECTION:
|
||||
ret = -1;
|
||||
goto done;
|
||||
case UCI_TYPE_OPTION:
|
||||
ret = atoi(ptr.o->v.string);
|
||||
goto done;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
done:
|
||||
|
||||
if (ptr.p)
|
||||
uci_unload(ctx, ptr.p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int uci_get_value(struct uci_context *ctx, char *key, char *output, int out_len)
|
||||
{
|
||||
struct uci_element *e;
|
||||
struct uci_ptr ptr;
|
||||
int ret = UCI_OK;
|
||||
int dummy;
|
||||
char *parameters ;
|
||||
char param_tmp[128] = {0};
|
||||
strcpy(param_tmp, key);
|
||||
if (uci_lookup_ptr(ctx, &ptr, param_tmp, true) != UCI_OK) {
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
|
||||
ctx->err = UCI_ERR_NOTFOUND;
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
e = ptr.last;
|
||||
switch(e->type) {
|
||||
case UCI_TYPE_SECTION:
|
||||
snprintf(output, out_len, "%s", ptr.s->type);
|
||||
break;
|
||||
case UCI_TYPE_OPTION:
|
||||
snprintf(output, out_len, "%s", ptr.o->v.string);
|
||||
break;
|
||||
default:
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
done:
|
||||
if (ptr.p)
|
||||
uci_unload(ctx, ptr.p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//
|
||||
static struct uci_package *
|
||||
config_init_package(const char *config)
|
||||
{
|
||||
struct uci_context *ctx = uci_ctx;
|
||||
struct uci_package *p = NULL;
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
ctx = uci_alloc_context();
|
||||
uci_ctx = ctx;
|
||||
ctx->flags &= ~UCI_FLAG_STRICT;
|
||||
//if (config_path)
|
||||
// uci_set_confdir(ctx, config_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = uci_lookup_package(ctx, config);
|
||||
if (p)
|
||||
uci_unload(ctx, p);
|
||||
}
|
||||
|
||||
if (uci_load(ctx, config, &p))
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
char *get_app_name_by_id(int id)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < g_app_count; i++)
|
||||
{
|
||||
if (id == app_name_table[i].id)
|
||||
return app_name_table[i].name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void init_app_name_table(void)
|
||||
{
|
||||
int count = 0;
|
||||
char line_buf[2048] = {0};
|
||||
|
||||
FILE *fp = fopen("/tmp/feature.cfg", "r");
|
||||
if (!fp)
|
||||
{
|
||||
printf("open file failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(line_buf, sizeof(line_buf), fp))
|
||||
{
|
||||
if (strstr(line_buf, "#"))
|
||||
continue;
|
||||
if (strlen(line_buf) < 10)
|
||||
continue;
|
||||
if (!strstr(line_buf, ":"))
|
||||
continue;
|
||||
char *pos1 = strstr(line_buf, ":");
|
||||
char app_info_buf[128] = {0};
|
||||
int app_id;
|
||||
char app_name[64] = {0};
|
||||
memset(app_name, 0x0, sizeof(app_name));
|
||||
strncpy(app_info_buf, line_buf, pos1 - line_buf);
|
||||
sscanf(app_info_buf, "%d %s", &app_id, app_name);
|
||||
app_name_table[g_app_count].id = app_id;
|
||||
strcpy(app_name_table[g_app_count].name, app_name);
|
||||
g_app_count++;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void init_app_class_name_table(void)
|
||||
{
|
||||
char line_buf[2048] = {0};
|
||||
int class_id;
|
||||
char class_name[64] = {0};
|
||||
FILE *fp = fopen("/tmp/app_class.txt", "r");
|
||||
if (!fp)
|
||||
{
|
||||
printf("open file failed\n");
|
||||
return;
|
||||
}
|
||||
while (fgets(line_buf, sizeof(line_buf), fp))
|
||||
{
|
||||
sscanf(line_buf, "%d %s", &class_id, class_name);
|
||||
strcpy(CLASS_NAME_TABLE[class_id - 1], class_name);
|
||||
g_cur_class_num++;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
//00:00 9:1
|
||||
int check_time_valid(char *t)
|
||||
{
|
||||
if (!t)
|
||||
return 0;
|
||||
if (strlen(t) < 3 || strlen(t) > 5 || (!strstr(t, ":")))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dump_af_time(af_ctl_time_t *t)
|
||||
{
|
||||
int i;
|
||||
printf("---------dump af time-------------\n");
|
||||
printf("%d:%d ---->%d:%d\n", t->start.hour, t->start.min,
|
||||
t->end.hour, t->end.min);
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
printf("%d ", t->days[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
af_ctl_time_t *load_appfilter_ctl_time_config(void)
|
||||
{
|
||||
char start_time_str[64] = {0};
|
||||
char end_time_str[64] = {0};
|
||||
char start_time_str2[64] = {0};
|
||||
char end_time_str2[64] = {0};
|
||||
char days_str[64] = {0};
|
||||
int value = 0;
|
||||
int ret = 0;
|
||||
af_ctl_time_t *t = NULL;
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
memset(start_time_str, 0x0, sizeof(start_time_str));
|
||||
memset(end_time_str, 0x0, sizeof(end_time_str));
|
||||
memset(start_time_str2, 0x0, sizeof(start_time_str2));
|
||||
memset(end_time_str2, 0x0, sizeof(end_time_str2));
|
||||
|
||||
uci_get_value(ctx, "appfilter.time.start_time", start_time_str, sizeof(start_time_str));
|
||||
uci_get_value(ctx, "appfilter.time.end_time", end_time_str, sizeof(end_time_str));
|
||||
uci_get_value(ctx, "appfilter.time.start_time2", start_time_str2, sizeof(start_time_str2));
|
||||
uci_get_value(ctx, "appfilter.time.end_time2", end_time_str2, sizeof(end_time_str2));
|
||||
uci_get_value(ctx, "appfilter.time.days", days_str, sizeof(days_str));
|
||||
|
||||
|
||||
t = malloc(sizeof(af_ctl_time_t));
|
||||
|
||||
value = uci_get_int_value(ctx, "appfilter.time.time_mode");
|
||||
if (value < 0)
|
||||
t->time_mode = 0;
|
||||
else
|
||||
t->time_mode = value;
|
||||
if (check_time_valid(start_time_str) && check_time_valid(end_time_str)){
|
||||
sscanf(start_time_str, "%d:%d", &t->start.hour, &t->start.min);
|
||||
sscanf(end_time_str, "%d:%d", &t->end.hour, &t->end.min);
|
||||
}
|
||||
if (check_time_valid(start_time_str2) && check_time_valid(end_time_str2)){
|
||||
sscanf(start_time_str2, "%d:%d", &t->start2.hour, &t->start2.min);
|
||||
sscanf(end_time_str2, "%d:%d", &t->end2.hour, &t->end2.min);
|
||||
}
|
||||
|
||||
char *p = strtok(days_str, " ");
|
||||
if (!p)
|
||||
goto EXIT;
|
||||
do
|
||||
{
|
||||
int day = atoi(p);
|
||||
if (day >= 0 && day <= 6)
|
||||
t->days[day] = 1;
|
||||
else
|
||||
ret = 0;
|
||||
} while (p = strtok(NULL, " "));
|
||||
EXIT:
|
||||
uci_free_context(ctx);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int config_get_appfilter_enable(void)
|
||||
{
|
||||
int enable = 0;
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
enable = uci_get_int_value(ctx, "appfilter.global.enable");
|
||||
if (enable < 0)
|
||||
enable = 0;
|
||||
|
||||
uci_free_context(ctx);
|
||||
return enable;
|
||||
}
|
||||
|
||||
int appfilter_config_alloc(void)
|
||||
{
|
||||
char *err;
|
||||
uci_appfilter = config_init_package("appfilter");
|
||||
if (!uci_appfilter)
|
||||
{
|
||||
uci_get_errorstr(uci_ctx, &err, NULL);
|
||||
printf("Failed to load appfilter config (%s)\n", err);
|
||||
free(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int appfilter_config_free(void)
|
||||
{
|
||||
if (uci_appfilter)
|
||||
{
|
||||
uci_unload(uci_ctx, uci_appfilter);
|
||||
uci_appfilter = NULL;
|
||||
}
|
||||
if (uci_ctx)
|
||||
{
|
||||
uci_free_context(uci_ctx);
|
||||
uci_ctx = NULL;
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __APPFILTER_CONFIG_H__
|
||||
#define __APPFILTER_CONFIG_H__
|
||||
#define MAX_SUPPORT_APP_NUM 1024
|
||||
#define MAX_CLASS_NAME_LEN 32
|
||||
#include "appfilter_user.h"
|
||||
extern int g_cur_class_num;
|
||||
extern int g_app_count;
|
||||
extern char CLASS_NAME_TABLE[MAX_APP_TYPE][MAX_CLASS_NAME_LEN];
|
||||
typedef struct af_time
|
||||
{
|
||||
int hour;
|
||||
int min;
|
||||
} af_time_t;
|
||||
typedef struct af_ctl_time
|
||||
{
|
||||
int time_mode; // 0,1
|
||||
af_time_t start;
|
||||
af_time_t end;
|
||||
af_time_t start2; // todo: time group list
|
||||
af_time_t end2;
|
||||
int days[7];
|
||||
} af_ctl_time_t;
|
||||
|
||||
typedef struct app_name_info
|
||||
{
|
||||
int id;
|
||||
char name[64];
|
||||
} app_name_info_t;
|
||||
void init_app_name_table(void);
|
||||
void init_app_class_name_table(void);
|
||||
char *get_app_name_by_id(int id);
|
||||
|
||||
int appfilter_config_alloc(void);
|
||||
|
||||
int appfilter_config_free(void);
|
||||
af_ctl_time_t *load_appfilter_ctl_time_config(void);
|
||||
int config_get_appfilter_enable(void);
|
||||
|
||||
#endif
|
@ -1,241 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/socket.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubox/utils.h>
|
||||
#include <libubus.h>
|
||||
#include <json-c/json.h>
|
||||
#include "appfilter_user.h"
|
||||
#include "appfilter_netlink.h"
|
||||
#define MAX_NL_RCV_BUF_SIZE 4096
|
||||
|
||||
#define REPORT_INTERVAL_SECS 60
|
||||
void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
char buf[MAX_NL_RCV_BUF_SIZE];
|
||||
struct sockaddr_nl nladdr;
|
||||
struct iovec iov = {buf, sizeof(buf)};
|
||||
struct nlmsghdr *h;
|
||||
int type;
|
||||
int id;
|
||||
char *mac = NULL;
|
||||
printf("%s %d\n", __func__, __LINE__);
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_name = &nladdr,
|
||||
.msg_namelen = sizeof(nladdr),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
ret = recvmsg(u->fd, &msg, 0);
|
||||
} while ((-1 == ret) && (EINTR == errno));
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("recv msg error\n");
|
||||
return;
|
||||
}
|
||||
else if (0 == ret)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
h = (struct nlmsghdr *)buf;
|
||||
char *kmsg = (char *)NLMSG_DATA(h);
|
||||
struct af_msg_hdr *af_hdr = (struct af_msg_hdr *)kmsg;
|
||||
if (af_hdr->magic != 0xa0b0c0d0)
|
||||
{
|
||||
printf("magic error %x\n", af_hdr->magic);
|
||||
return;
|
||||
}
|
||||
if (af_hdr->len <= 0 || af_hdr->len >= MAX_OAF_NETLINK_MSG_LEN)
|
||||
{
|
||||
printf("data len error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *kdata = kmsg + sizeof(struct af_msg_hdr);
|
||||
struct json_object *root = json_tokener_parse(kdata);
|
||||
if (!root)
|
||||
{
|
||||
printf("parse json failed:%s", kdata);
|
||||
return;
|
||||
}
|
||||
printf("recv msg = %s\n", kdata);
|
||||
|
||||
struct json_object *mac_obj = json_object_object_get(root, "mac");
|
||||
|
||||
if (!mac_obj)
|
||||
{
|
||||
printf("parse mac obj failed\n");
|
||||
json_object_put(root);
|
||||
return;
|
||||
}
|
||||
|
||||
mac = json_object_get_string(mac_obj);
|
||||
|
||||
dev_node_t *node = find_dev_node(mac);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
node = add_dev_node(mac);
|
||||
if (!node)
|
||||
{
|
||||
printf("add dev node failed\n");
|
||||
json_object_put(root);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct json_object *ip_obj = json_object_object_get(root, "ip");
|
||||
if (ip_obj)
|
||||
strncpy(node->ip, json_object_get_string(ip_obj), sizeof(node->ip));
|
||||
struct json_object *visit_array = json_object_object_get(root, "visit_info");
|
||||
if (!visit_array)
|
||||
{
|
||||
json_object_put(root);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < json_object_array_length(visit_array); i++)
|
||||
{
|
||||
struct json_object *visit_obj = json_object_array_get_idx(visit_array, i);
|
||||
struct json_object *appid_obj = json_object_object_get(visit_obj, "appid");
|
||||
struct json_object *action_obj = json_object_object_get(visit_obj, "latest_action");
|
||||
struct json_object *up_obj = json_object_object_get(visit_obj, "up_bytes");
|
||||
struct json_object *down_obj = json_object_object_get(visit_obj, "down_bytes");
|
||||
struct timeval cur_time;
|
||||
|
||||
gettimeofday(&cur_time, NULL);
|
||||
int appid = json_object_get_int(appid_obj);
|
||||
int action = json_object_get_int(action_obj);
|
||||
|
||||
type = appid / 1000;
|
||||
id = appid % 1000;
|
||||
if (id <= 0 || type <= 0)
|
||||
continue;
|
||||
node->stat[type - 1][id - 1].total_time += REPORT_INTERVAL_SECS;
|
||||
|
||||
// node->stat[type - 1][id - 1].total_down_bytes += json_object_get_int(down_obj);
|
||||
// node->stat[type - 1][id - 1].total_up_bytes += json_object_get_int(up_obj);
|
||||
|
||||
int hash = hash_appid(appid);
|
||||
visit_info_t *head = node->visit_htable[hash];
|
||||
|
||||
if (head && (cur_time.tv_sec - head->latest_time) < 300)
|
||||
{
|
||||
head->latest_time = cur_time.tv_sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s %d\n", __func__, __LINE__);
|
||||
|
||||
visit_info_t *visit_node = (visit_info_t *)calloc(1, sizeof(visit_info_t));
|
||||
visit_node->action = action;
|
||||
visit_node->appid = appid;
|
||||
visit_node->latest_time = cur_time.tv_sec;
|
||||
visit_node->first_time = cur_time.tv_sec - MIN_VISIT_TIME;
|
||||
visit_node->next = NULL;
|
||||
add_visit_info_node(&node->visit_htable[hash], visit_node);
|
||||
|
||||
//printf("add visit info curtime=%d\n", cur_time.tv_sec);
|
||||
}
|
||||
}
|
||||
|
||||
json_object_put(root);
|
||||
}
|
||||
|
||||
#define MAX_NL_MSG_LEN 1024
|
||||
int send_msg_to_kernel(int fd, void *msg, int len)
|
||||
{
|
||||
struct sockaddr_nl saddr, daddr;
|
||||
memset(&daddr, 0, sizeof(daddr));
|
||||
daddr.nl_family = AF_NETLINK;
|
||||
daddr.nl_pid = 0; // to kernel
|
||||
daddr.nl_groups = 0;
|
||||
printf("%s %d\n", __func__, __LINE__);
|
||||
|
||||
int ret = 0;
|
||||
struct nlmsghdr *nlh = NULL;
|
||||
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_NL_MSG_LEN));
|
||||
nlh->nlmsg_len = NLMSG_SPACE(MAX_NL_MSG_LEN);
|
||||
nlh->nlmsg_flags = 0;
|
||||
nlh->nlmsg_type = 0;
|
||||
nlh->nlmsg_seq = 0;
|
||||
nlh->nlmsg_pid = DEFAULT_USR_NL_PID;
|
||||
|
||||
char msg_buf[MAX_NL_MSG_LEN] = {0};
|
||||
struct af_msg_hdr *hdr = (struct af_msg_hdr *)msg_buf;
|
||||
hdr->magic = 0xa0b0c0d0;
|
||||
hdr->len = len;
|
||||
char *p_data = msg_buf + sizeof(struct af_msg_hdr);
|
||||
memcpy(p_data, msg, len);
|
||||
|
||||
// memset(nlh, 0, sizeof(struct nlmsghdr));
|
||||
|
||||
memcpy(NLMSG_DATA(nlh), msg_buf, len + sizeof(struct af_msg_hdr));
|
||||
|
||||
ret = sendto(fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl));
|
||||
if (!ret)
|
||||
{
|
||||
perror("sendto error\n");
|
||||
return -1;
|
||||
}
|
||||
printf("%s %d\n", __func__, __LINE__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int appfilter_nl_init(void)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_nl nls;
|
||||
fd = socket(AF_NETLINK, SOCK_RAW, OAF_NETLINK_ID);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf("Connect netlink %d failed %s", OAF_NETLINK_ID, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
memset(&nls, 0, sizeof(struct sockaddr_nl));
|
||||
nls.nl_pid = DEFAULT_USR_NL_PID;
|
||||
nls.nl_groups = 0;
|
||||
nls.nl_family = AF_NETLINK;
|
||||
|
||||
if (bind(fd, (void *)&nls, sizeof(struct sockaddr_nl)))
|
||||
{
|
||||
printf("Bind failed %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __APPFILTER_NETLINK_H__
|
||||
#define __APPFILTER_NETLINK_H__
|
||||
#define DEFAULT_USR_NL_PID 999
|
||||
#define OAF_NETLINK_ID 29
|
||||
#define MAX_OAF_NETLINK_MSG_LEN 1024
|
||||
|
||||
struct af_msg_hdr
|
||||
{
|
||||
int magic;
|
||||
int len;
|
||||
};
|
||||
|
||||
enum E_MSG_TYPE
|
||||
{
|
||||
AF_MSG_INIT,
|
||||
AF_MSG_MAX
|
||||
};
|
||||
|
||||
typedef struct af_msg
|
||||
{
|
||||
int action;
|
||||
void *data;
|
||||
} af_msg_t;
|
||||
int appfilter_nl_init(void);
|
||||
void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev);
|
||||
int send_msg_to_kernel(int fd, void *msg, int len);
|
||||
#endif
|
@ -1,526 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubox/utils.h>
|
||||
#include <libubus.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/socket.h>
|
||||
#include <sys/socket.h>
|
||||
#include <json-c/json.h>
|
||||
#include <sys/time.h>
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <libubox/blobmsg.h>
|
||||
#include "appfilter_user.h"
|
||||
#include "appfilter_config.h"
|
||||
|
||||
struct ubus_context *ubus_ctx = NULL;
|
||||
static struct blob_buf b;
|
||||
|
||||
extern char *format_time(int timetamp);
|
||||
|
||||
void get_hostname_by_mac(char *mac, char *hostname)
|
||||
{
|
||||
if (!mac || !hostname)
|
||||
return;
|
||||
FILE *fp = fopen("/tmp/dhcp.leases", "r");
|
||||
if (!fp)
|
||||
{
|
||||
printf("open dhcp lease file....failed\n");
|
||||
return;
|
||||
}
|
||||
char line_buf[256] = {0};
|
||||
while (fgets(line_buf, sizeof(line_buf), fp))
|
||||
{
|
||||
char hostname_buf[128] = {0};
|
||||
char mac_buf[32] = {0};
|
||||
sscanf(line_buf, "%*s %s %*s %s", mac_buf, hostname_buf);
|
||||
if (0 == strcmp(mac, mac_buf))
|
||||
{
|
||||
strcpy(hostname, hostname_buf);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void ubus_dump_visit_list(struct blob_buf *b, char *mac)
|
||||
{
|
||||
int i, j;
|
||||
void *c, *array;
|
||||
void *t;
|
||||
void *s;
|
||||
|
||||
array = blobmsg_open_array(b, "dev_list");
|
||||
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
if (mac && strcmp(mac, node->mac))
|
||||
{
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
t = blobmsg_open_table(b, NULL);
|
||||
blobmsg_add_string(b, "hostname", "unknown");
|
||||
blobmsg_add_string(b, "mac", node->mac);
|
||||
blobmsg_add_string(b, "ip", node->ip);
|
||||
void *visit_array;
|
||||
|
||||
visit_array = blobmsg_open_array(b, "visit_info");
|
||||
for (j = 0; j < MAX_VISIT_HASH_SIZE; j++)
|
||||
{
|
||||
visit_info_t *p_info = node->visit_htable[j];
|
||||
while (p_info)
|
||||
{
|
||||
char *first_time_str = format_time(p_info->first_time);
|
||||
char *latest_time_str = format_time(p_info->latest_time);
|
||||
int total_time = p_info->latest_time - p_info->first_time;
|
||||
s = blobmsg_open_table(b, NULL);
|
||||
blobmsg_add_string(b, "appname", "unknown");
|
||||
blobmsg_add_u32(b, "appid", p_info->appid);
|
||||
blobmsg_add_u32(b, "latest_action", p_info->action);
|
||||
blobmsg_add_u32(b, "first_time", p_info->first_time);
|
||||
blobmsg_add_u32(b, "latest_time", p_info->latest_time);
|
||||
blobmsg_close_table(b, s);
|
||||
if (first_time_str)
|
||||
free(first_time_str);
|
||||
if (latest_time_str)
|
||||
free(latest_time_str);
|
||||
p_info = p_info->next;
|
||||
}
|
||||
}
|
||||
|
||||
blobmsg_close_array(b, visit_array);
|
||||
blobmsg_close_table(b, t);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
blobmsg_close_array(b, array);
|
||||
}
|
||||
|
||||
void update_app_visit_time_list(char *mac, struct app_visit_stat_info *visit_info)
|
||||
{
|
||||
int i, j, s;
|
||||
int num = 0;
|
||||
|
||||
dev_node_t *node = find_dev_node(mac);
|
||||
if (!node)
|
||||
{
|
||||
printf("not found mac:%s\n", mac);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < MAX_APP_TYPE; i++)
|
||||
{
|
||||
for (j = 0; j < MAX_APP_ID_NUM; j++)
|
||||
{
|
||||
unsigned long long min = visit_info->visit_list[0].total_time;
|
||||
int min_index = 0;
|
||||
if (node->stat[i][j].total_time == 0)
|
||||
continue;
|
||||
if (num < MAX_APP_STAT_NUM)
|
||||
{
|
||||
min_index = num;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s = 0; s < MAX_APP_STAT_NUM; s++)
|
||||
{
|
||||
if (visit_info->visit_list[s].total_time < min)
|
||||
{
|
||||
min_index = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
num++;
|
||||
if (node->stat[i][j].total_time > visit_info->visit_list[min_index].total_time)
|
||||
{
|
||||
visit_info->visit_list[min_index].total_time = node->stat[i][j].total_time;
|
||||
visit_info->visit_list[min_index].app_id = (i + 1) * 1000 + j + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num < MAX_APP_STAT_NUM)
|
||||
visit_info->num = num;
|
||||
else
|
||||
visit_info->num = MAX_APP_STAT_NUM;
|
||||
}
|
||||
|
||||
void update_app_class_visit_time_list(char *mac, int *visit_time)
|
||||
{
|
||||
int i, j, s;
|
||||
int num = 0;
|
||||
|
||||
dev_node_t *node = find_dev_node(mac);
|
||||
if (!node)
|
||||
{
|
||||
printf("not found mac:%s\n", mac);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < MAX_APP_TYPE; i++)
|
||||
{
|
||||
for (j = 0; j < MAX_APP_ID_NUM; j++)
|
||||
{
|
||||
if (node->stat[i][j].total_time == 0)
|
||||
continue;
|
||||
visit_time[i] += node->stat[i][j].total_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ubus_get_dev_visit_time_info(char *mac, struct blob_buf *b)
|
||||
{
|
||||
int i, j;
|
||||
void *c, *array;
|
||||
void *t;
|
||||
void *s;
|
||||
struct app_visit_stat_info info;
|
||||
memset((char *)&info, 0x0, sizeof(info));
|
||||
update_app_visit_time_list(mac, &info);
|
||||
}
|
||||
|
||||
static int
|
||||
appfilter_handle_visit_list(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int ret;
|
||||
blob_buf_init(&b, 0);
|
||||
char *msg_obj_str = blobmsg_format_json(msg, true);
|
||||
if (!msg_obj_str)
|
||||
{
|
||||
printf("format json failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct json_object *req_obj = json_tokener_parse(msg_obj_str);
|
||||
struct json_object *mac_obj = json_object_object_get(req_obj, "mac");
|
||||
|
||||
if (!mac_obj)
|
||||
{
|
||||
ubus_dump_visit_list(&b, NULL);
|
||||
}
|
||||
else
|
||||
ubus_dump_visit_list(&b, json_object_get_string(mac_obj));
|
||||
ubus_send_reply(ctx, req, b.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct app_visit_time_info
|
||||
{
|
||||
int app_id;
|
||||
unsigned long long total_time;
|
||||
} app_visit_time_info_t;
|
||||
|
||||
int visit_time_compare(const void *a, const void *b)
|
||||
{
|
||||
app_visit_time_info_t *p1 = (app_visit_time_info_t *)a;
|
||||
app_visit_time_info_t *p2 = (app_visit_time_info_t *)b;
|
||||
return p1->total_time < p2->total_time ? 1 : -1;
|
||||
}
|
||||
|
||||
#define MAX_STAT_APP_NUM 128
|
||||
void update_top5_app(dev_node_t *node, app_visit_time_info_t top5_app_list[])
|
||||
{
|
||||
int i, j;
|
||||
//memset(app_array, 0x0, sizeof(int) *size);
|
||||
app_visit_time_info_t app_visit_array[MAX_STAT_APP_NUM];
|
||||
memset(app_visit_array, 0x0, sizeof(app_visit_array));
|
||||
int app_visit_num = 0;
|
||||
|
||||
for (i = 0; i < MAX_APP_TYPE; i++)
|
||||
{
|
||||
for (j = 0; j < MAX_APP_ID_NUM; j++)
|
||||
{
|
||||
if (node->stat[i][j].total_time == 0)
|
||||
continue;
|
||||
app_visit_array[app_visit_num].app_id = (i + 1) * 1000 + j + 1;
|
||||
app_visit_array[app_visit_num].total_time = node->stat[i][j].total_time;
|
||||
app_visit_num++;
|
||||
}
|
||||
}
|
||||
|
||||
qsort((void *)app_visit_array, app_visit_num, sizeof(app_visit_time_info_t), visit_time_compare);
|
||||
#if 0
|
||||
for (i = 0; i < app_visit_num; i++){
|
||||
printf("appid %d-----------total time %llu\n", app_visit_array[i].app_id,
|
||||
app_visit_array[i].total_time);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
top5_app_list[i] = app_visit_array[i];
|
||||
//printf("appid %d-----------total time %llu\n", app_visit_array[i].app_id,
|
||||
// app_visit_array[i].total_time);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
appfilter_handle_dev_list(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int i, j;
|
||||
struct json_object *root_obj = json_object_new_object();
|
||||
|
||||
struct json_object *dev_array = json_object_new_array();
|
||||
int count = 0;
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
if (node->online == 0)
|
||||
{
|
||||
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
struct json_object *dev_obj = json_object_new_object();
|
||||
struct json_object *app_array = json_object_new_array();
|
||||
app_visit_time_info_t top5_app_list[5];
|
||||
memset(top5_app_list, 0x0, sizeof(top5_app_list));
|
||||
update_top5_app(node, top5_app_list);
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
if (top5_app_list[j].app_id == 0)
|
||||
break;
|
||||
struct json_object *app_obj = json_object_new_object();
|
||||
json_object_object_add(app_obj, "id", json_object_new_int(top5_app_list[j].app_id));
|
||||
json_object_object_add(app_obj, "name", json_object_new_string(get_app_name_by_id(top5_app_list[j].app_id)));
|
||||
json_object_array_add(app_array, app_obj);
|
||||
}
|
||||
|
||||
json_object_object_add(dev_obj, "applist", app_array);
|
||||
json_object_object_add(dev_obj, "mac", json_object_new_string(node->mac));
|
||||
char hostname[128] = {0};
|
||||
get_hostname_by_mac(node->mac, hostname);
|
||||
json_object_object_add(dev_obj, "ip", json_object_new_string(node->ip));
|
||||
|
||||
json_object_object_add(dev_obj, "online", json_object_new_int(1));
|
||||
json_object_object_add(dev_obj, "hostname", json_object_new_string(hostname));
|
||||
json_object_object_add(dev_obj, "latest_app", json_object_new_string("test"));
|
||||
json_object_array_add(dev_array, dev_obj);
|
||||
|
||||
node = node->next;
|
||||
count++;
|
||||
if (count >= MAX_SUPPORT_DEV_NUM)
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
if (node->online != 0)
|
||||
{
|
||||
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
struct json_object *dev_obj = json_object_new_object();
|
||||
struct json_object *app_array = json_object_new_array();
|
||||
app_visit_time_info_t top5_app_list[5];
|
||||
memset(top5_app_list, 0x0, sizeof(top5_app_list));
|
||||
update_top5_app(node, top5_app_list);
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
if (top5_app_list[j].app_id == 0)
|
||||
break;
|
||||
struct json_object *app_obj = json_object_new_object();
|
||||
json_object_object_add(app_obj, "id", json_object_new_int(top5_app_list[j].app_id));
|
||||
json_object_object_add(app_obj, "name", json_object_new_string(get_app_name_by_id(top5_app_list[j].app_id)));
|
||||
json_object_array_add(app_array, app_obj);
|
||||
}
|
||||
|
||||
json_object_object_add(dev_obj, "applist", app_array);
|
||||
json_object_object_add(dev_obj, "mac", json_object_new_string(node->mac));
|
||||
char hostname[32] = {0};
|
||||
get_hostname_by_mac(node->mac, hostname);
|
||||
json_object_object_add(dev_obj, "ip", json_object_new_string(node->ip));
|
||||
|
||||
json_object_object_add(dev_obj, "online", json_object_new_int(0));
|
||||
json_object_object_add(dev_obj, "hostname", json_object_new_string(hostname));
|
||||
json_object_object_add(dev_obj, "latest_app", json_object_new_string("test"));
|
||||
json_object_array_add(dev_array, dev_obj);
|
||||
node = node->next;
|
||||
count++;
|
||||
if (count >= MAX_SUPPORT_DEV_NUM)
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
|
||||
END:
|
||||
|
||||
json_object_object_add(root_obj, "devlist", dev_array);
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_object(&b, root_obj);
|
||||
ubus_send_reply(ctx, req, b.head);
|
||||
json_object_put(root_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
appfilter_handle_visit_time(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int ret;
|
||||
struct app_visit_stat_info info;
|
||||
blob_buf_init(&b, 0);
|
||||
memset((char *)&info, 0x0, sizeof(info));
|
||||
char *msg_obj_str = blobmsg_format_json(msg, true);
|
||||
if (!msg_obj_str)
|
||||
{
|
||||
printf("format json failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct json_object *req_obj = json_tokener_parse(msg_obj_str);
|
||||
struct json_object *mac_obj = json_object_object_get(req_obj, "mac");
|
||||
if (!mac_obj)
|
||||
{
|
||||
printf("mac is NULL\n");
|
||||
return 0;
|
||||
}
|
||||
update_app_visit_time_list(json_object_get_string(mac_obj), &info);
|
||||
|
||||
struct json_object *resp_obj = json_object_new_object();
|
||||
struct json_object *app_info_array = json_object_new_array();
|
||||
json_object_object_add(resp_obj, "app_list", app_info_array);
|
||||
int i;
|
||||
for (i = 0; i < info.num; i++)
|
||||
{
|
||||
struct json_object *app_info_obj = json_object_new_object();
|
||||
json_object_object_add(app_info_obj, "app_id",
|
||||
json_object_new_string(get_app_name_by_id(info.visit_list[i].app_id)));
|
||||
json_object_object_add(app_info_obj, "visit_time",
|
||||
json_object_new_int(info.visit_list[i].total_time));
|
||||
json_object_array_add(app_info_array, app_info_obj);
|
||||
}
|
||||
|
||||
blobmsg_add_object(&b, resp_obj);
|
||||
ubus_send_reply(ctx, req, b.head);
|
||||
json_object_put(resp_obj);
|
||||
json_object_put(req_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_app_class_visit_time(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
blob_buf_init(&b, 0);
|
||||
char *msg_obj_str = blobmsg_format_json(msg, true);
|
||||
if (!msg_obj_str)
|
||||
{
|
||||
printf("format json failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct json_object *req_obj = json_tokener_parse(msg_obj_str);
|
||||
struct json_object *mac_obj = json_object_object_get(req_obj, "mac");
|
||||
if (!mac_obj)
|
||||
{
|
||||
printf("mac is NULL\n");
|
||||
return 0;
|
||||
}
|
||||
int app_class_visit_time[MAX_APP_TYPE];
|
||||
memset(app_class_visit_time, 0x0, sizeof(app_class_visit_time));
|
||||
update_app_class_visit_time_list(json_object_get_string(mac_obj), app_class_visit_time);
|
||||
|
||||
struct json_object *resp_obj = json_object_new_object();
|
||||
struct json_object *app_class_array = json_object_new_array();
|
||||
json_object_object_add(resp_obj, "class_list", app_class_array);
|
||||
for (i = 0; i < MAX_APP_TYPE; i++)
|
||||
{
|
||||
if (i >= g_cur_class_num)
|
||||
break;
|
||||
struct json_object *app_class_obj = json_object_new_object();
|
||||
json_object_object_add(app_class_obj, "type", json_object_new_int(i));
|
||||
json_object_object_add(app_class_obj, "name", json_object_new_string(CLASS_NAME_TABLE[i]));
|
||||
json_object_object_add(app_class_obj, "visit_time", json_object_new_int(app_class_visit_time[i]));
|
||||
json_object_array_add(app_class_array, app_class_obj);
|
||||
}
|
||||
|
||||
blobmsg_add_object(&b, resp_obj);
|
||||
ubus_send_reply(ctx, req, b.head);
|
||||
json_object_put(resp_obj);
|
||||
json_object_put(req_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct blobmsg_policy empty_policy[1] = {
|
||||
//[DEV_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
|
||||
};
|
||||
|
||||
static struct ubus_method appfilter_object_methods[] = {
|
||||
UBUS_METHOD("visit_list", appfilter_handle_visit_list, empty_policy),
|
||||
UBUS_METHOD("dev_visit_time", appfilter_handle_visit_time, empty_policy),
|
||||
UBUS_METHOD("app_class_visit_time", handle_app_class_visit_time, empty_policy),
|
||||
UBUS_METHOD("dev_list", appfilter_handle_dev_list, empty_policy),
|
||||
};
|
||||
|
||||
static struct ubus_object_type main_object_type =
|
||||
UBUS_OBJECT_TYPE("appfilter", appfilter_object_methods);
|
||||
|
||||
static struct ubus_object main_object = {
|
||||
.name = "appfilter",
|
||||
.type = &main_object_type,
|
||||
.methods = appfilter_object_methods,
|
||||
.n_methods = ARRAY_SIZE(appfilter_object_methods),
|
||||
};
|
||||
|
||||
static void appfilter_add_object(struct ubus_object *obj)
|
||||
{
|
||||
int ret = ubus_add_object(ubus_ctx, obj);
|
||||
|
||||
if (ret != 0)
|
||||
fprintf(stderr, "Failed to publish object '%s': %s\n", obj->name, ubus_strerror(ret));
|
||||
}
|
||||
|
||||
int appfilter_ubus_init(void)
|
||||
{
|
||||
ubus_ctx = ubus_connect("/var/run/ubus/ubus.sock");
|
||||
if (!ubus_ctx){
|
||||
ubus_ctx = ubus_connect("/var/run/ubus.sock");
|
||||
}
|
||||
if (!ubus_ctx){
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
appfilter_add_object(&main_object);
|
||||
ubus_add_uloop(ubus_ctx);
|
||||
return 0;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __APPFILTER_UBUS_H__
|
||||
#define __APPFILTER_UBUS_H__
|
||||
int appfilter_ubus_init(void);
|
||||
#endif
|
@ -1,516 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubox/utils.h>
|
||||
#include <libubus.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/socket.h>
|
||||
#include <sys/socket.h>
|
||||
#include "appfilter_user.h"
|
||||
|
||||
dev_node_t *dev_hash_table[MAX_DEV_NODE_HASH_SIZE];
|
||||
int g_cur_user_num = 0;
|
||||
unsigned int hash_mac(unsigned char *mac)
|
||||
{
|
||||
if (!mac)
|
||||
return 0;
|
||||
else
|
||||
return mac[0] & (MAX_DEV_NODE_HASH_SIZE - 1);
|
||||
}
|
||||
int get_timestamp(void)
|
||||
{
|
||||
struct timeval cur_time;
|
||||
gettimeofday(&cur_time, NULL);
|
||||
return cur_time.tv_sec;
|
||||
}
|
||||
|
||||
int hash_appid(int appid)
|
||||
{
|
||||
return appid % (MAX_VISIT_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
void add_visit_info_node(visit_info_t **head, visit_info_t *node)
|
||||
{
|
||||
if (*head == NULL)
|
||||
{
|
||||
*head = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->next = *head;
|
||||
*head = node;
|
||||
}
|
||||
}
|
||||
|
||||
void init_dev_node_htable()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_hash_table[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dev_node_t *add_dev_node(char *mac)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
if (g_cur_user_num >= MAX_SUPPORT_USER_NUM)
|
||||
{
|
||||
printf("error, user num reach max %d\n", g_cur_user_num);
|
||||
return NULL;
|
||||
}
|
||||
hash = hash_mac(mac);
|
||||
if (hash >= MAX_DEV_NODE_HASH_SIZE)
|
||||
{
|
||||
printf("hash code error %d\n", hash);
|
||||
return NULL;
|
||||
}
|
||||
dev_node_t *node = (dev_node_t *)calloc(1, sizeof(dev_node_t));
|
||||
if (!node)
|
||||
return NULL;
|
||||
strncpy(node->mac, mac, sizeof(node->mac));
|
||||
node->online = 1;
|
||||
node->online_time = get_timestamp();
|
||||
if (dev_hash_table[hash] == NULL)
|
||||
dev_hash_table[hash] = node;
|
||||
else
|
||||
{
|
||||
node->next = dev_hash_table[hash];
|
||||
dev_hash_table[hash] = node;
|
||||
}
|
||||
g_cur_user_num++;
|
||||
printf("add mac:%s to htable[%d]....success\n", mac, hash);
|
||||
return node;
|
||||
}
|
||||
|
||||
dev_node_t *find_dev_node(char *mac)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
dev_node_t *p = NULL;
|
||||
hash = hash_mac(mac);
|
||||
if (hash >= MAX_DEV_NODE_HASH_SIZE)
|
||||
{
|
||||
printf("hash code error %d\n", hash);
|
||||
return NULL;
|
||||
}
|
||||
p = dev_hash_table[hash];
|
||||
while (p)
|
||||
{
|
||||
if (0 == strncmp(p->mac, mac, sizeof(p->mac)))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dev_foreach(void *arg, iter_func iter)
|
||||
{
|
||||
int i, j;
|
||||
dev_node_t *node = NULL;
|
||||
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
iter(arg, node);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *format_time(int timetamp)
|
||||
{
|
||||
char time_buf[64] = {0};
|
||||
time_t seconds = timetamp;
|
||||
struct tm *auth_tm = localtime(&seconds);
|
||||
strftime(time_buf, sizeof(time_buf), "%Y %m %d %H:%M:%S", auth_tm);
|
||||
return strdup(time_buf);
|
||||
}
|
||||
|
||||
void update_dev_hostname(void)
|
||||
{
|
||||
char line_buf[256] = {0};
|
||||
char hostname_buf[128] = {0};
|
||||
char mac_buf[32] = {0};
|
||||
char ip_buf[32] = {0};
|
||||
|
||||
FILE *fp = fopen("/tmp/dhcp.leases", "r");
|
||||
if (!fp)
|
||||
{
|
||||
printf("open dhcp lease file....failed\n");
|
||||
return;
|
||||
}
|
||||
while (fgets(line_buf, sizeof(line_buf), fp))
|
||||
{
|
||||
if (strlen(line_buf) <= 16)
|
||||
continue;
|
||||
sscanf(line_buf, "%*s %s %s %s", mac_buf, ip_buf, hostname_buf);
|
||||
dev_node_t *node = find_dev_node(mac_buf);
|
||||
if (!node)
|
||||
continue;
|
||||
if (strlen(hostname_buf) > 0)
|
||||
{
|
||||
strncpy(node->hostname, hostname_buf, sizeof(node->hostname));
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void clean_dev_online_status(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
if (node->online){
|
||||
node->offline_time = get_timestamp();
|
||||
node->online = 0;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Id Mac Ip
|
||||
1 10:bf:48:37:0c:94 192.168.66.244
|
||||
*/
|
||||
void update_dev_online_status(void)
|
||||
{
|
||||
char line_buf[256] = {0};
|
||||
char mac_buf[32] = {0};
|
||||
char ip_buf[32] = {0};
|
||||
|
||||
FILE *fp = fopen("/proc/net/af_client", "r");
|
||||
if (!fp)
|
||||
{
|
||||
printf("open dev file....failed\n");
|
||||
return;
|
||||
}
|
||||
fgets(line_buf, sizeof(line_buf), fp); // title
|
||||
while (fgets(line_buf, sizeof(line_buf), fp))
|
||||
{
|
||||
sscanf(line_buf, "%*s %s %s", mac_buf, ip_buf);
|
||||
if (strlen(mac_buf) < 17)
|
||||
{
|
||||
printf("invalid mac:%s\n", mac_buf);
|
||||
continue;
|
||||
}
|
||||
dev_node_t *node = find_dev_node(mac_buf);
|
||||
if (!node)
|
||||
{
|
||||
node = add_dev_node(mac_buf);
|
||||
if (!node)
|
||||
continue;
|
||||
strncpy(node->ip, ip_buf, sizeof(node->ip));
|
||||
}
|
||||
node->online = 1;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
#define DEV_OFFLINE_TIME (SECONDS_PER_DAY * 3)
|
||||
|
||||
int check_dev_expire(void)
|
||||
{
|
||||
int i, j;
|
||||
int count = 0;
|
||||
int cur_time = get_timestamp();
|
||||
int offline_time = 0;
|
||||
int expire_count = 0;
|
||||
int visit_count = 0;
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
if (node->online)
|
||||
goto NEXT;
|
||||
visit_count = 0;
|
||||
offline_time = cur_time - node->offline_time;
|
||||
if (offline_time > DEV_OFFLINE_TIME)
|
||||
{
|
||||
node->expire = 1;
|
||||
for (j = 0; j < MAX_VISIT_HASH_SIZE; j++)
|
||||
{
|
||||
visit_info_t *p_info = node->visit_htable[j];
|
||||
while (p_info)
|
||||
{
|
||||
p_info->expire = 1;
|
||||
visit_count++;
|
||||
p_info = p_info->next;
|
||||
}
|
||||
}
|
||||
expire_count++;
|
||||
printf("dev:%s expired, offline time = %ds, count=%d, visit_count=%d\n",
|
||||
node->mac, offline_time, expire_count, visit_count);
|
||||
}
|
||||
NEXT:
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
return expire_count;
|
||||
}
|
||||
|
||||
void flush_dev_expire_node(void)
|
||||
{
|
||||
int i, j;
|
||||
int count = 0;
|
||||
dev_node_t *node = NULL;
|
||||
dev_node_t *prev = NULL;
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
prev = NULL;
|
||||
while (node)
|
||||
{
|
||||
if (node->expire)
|
||||
{
|
||||
if (NULL == prev)
|
||||
{
|
||||
dev_hash_table[i] = node->next;
|
||||
free(node);
|
||||
node = dev_hash_table[i];
|
||||
prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = node->next;
|
||||
free(node);
|
||||
node = prev->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = node;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_dev_list(void)
|
||||
{
|
||||
int i, j;
|
||||
int count = 0;
|
||||
char hostname_buf[MAX_HOSTNAME_SIZE] = {0};
|
||||
char ip_buf[MAX_IP_LEN] = {0};
|
||||
clean_dev_online_status();
|
||||
update_dev_hostname();
|
||||
update_dev_online_status();
|
||||
FILE *fp = fopen(OAF_DEV_LIST_FILE, "w");
|
||||
if (!fp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "%-4s %-20s %-20s %-32s %-8s\n", "Id", "Mac Addr", "Ip Addr", "Hostname", "Online");
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
if (node->online != 0)
|
||||
{
|
||||
if (strlen(node->hostname) == 0)
|
||||
strcpy(hostname_buf, "*");
|
||||
else
|
||||
strcpy(hostname_buf, node->hostname);
|
||||
if (strlen(node->ip) == 0)
|
||||
strcpy(ip_buf, "*");
|
||||
else
|
||||
strcpy(ip_buf, node->ip);
|
||||
fprintf(fp, "%-4d %-20s %-20s %-32s %-8d\n",
|
||||
i + 1, node->mac, ip_buf, hostname_buf, node->online);
|
||||
count++;
|
||||
}
|
||||
if (count >= MAX_SUPPORT_DEV_NUM)
|
||||
{
|
||||
goto EXIT;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
if (node->online == 0)
|
||||
{
|
||||
if (strlen(node->hostname) == 0)
|
||||
strcpy(hostname_buf, "*");
|
||||
else
|
||||
strcpy(hostname_buf, node->hostname);
|
||||
|
||||
if (strlen(node->ip) == 0)
|
||||
strcpy(ip_buf, "*");
|
||||
else
|
||||
strcpy(ip_buf, node->ip);
|
||||
|
||||
fprintf(fp, "%-4d %-20s %-20s %-32s %-8d\n",
|
||||
i + 1, node->mac, ip_buf, hostname_buf, node->online);
|
||||
}
|
||||
if (count >= MAX_SUPPORT_DEV_NUM)
|
||||
goto EXIT;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
EXIT:
|
||||
fclose(fp);
|
||||
}
|
||||
// 记录最大保存时间 todo: support config
|
||||
#define MAX_RECORD_TIME (7 * 24 * 60 * 60) // 7day
|
||||
// 超过1天后清除短时间的记录
|
||||
#define RECORD_REMAIN_TIME (24 * 60 * 60) // 1day
|
||||
#define INVALID_RECORD_TIME (5 * 60) // 5min
|
||||
|
||||
void check_dev_visit_info_expire(void)
|
||||
{
|
||||
int i, j;
|
||||
int count = 0;
|
||||
int cur_time = get_timestamp();
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
for (j = 0; j < MAX_VISIT_HASH_SIZE; j++)
|
||||
{
|
||||
visit_info_t *p_info = node->visit_htable[j];
|
||||
while (p_info)
|
||||
{
|
||||
int total_time = p_info->latest_time - p_info->first_time;
|
||||
int interval_time = cur_time - p_info->first_time;
|
||||
if (interval_time > MAX_RECORD_TIME || interval_time < 0){
|
||||
p_info->expire = 1;
|
||||
}
|
||||
else if (interval_time > RECORD_REMAIN_TIME){
|
||||
if (total_time < INVALID_RECORD_TIME)
|
||||
p_info->expire = 1;
|
||||
}
|
||||
p_info = p_info->next;
|
||||
}
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flush_expire_visit_info(void)
|
||||
{
|
||||
int i, j;
|
||||
int count = 0;
|
||||
visit_info_t *prev = NULL;
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
for (j = 0; j < MAX_VISIT_HASH_SIZE; j++)
|
||||
{
|
||||
visit_info_t *p_info = node->visit_htable[j];
|
||||
prev = NULL;
|
||||
while (p_info)
|
||||
{
|
||||
if (p_info->expire){
|
||||
if (NULL == prev){
|
||||
node->visit_htable[j] = p_info->next;
|
||||
free(p_info);
|
||||
p_info = node->visit_htable[j];
|
||||
prev = NULL;
|
||||
}
|
||||
else{
|
||||
prev->next = p_info->next;
|
||||
free(p_info);
|
||||
p_info = prev->next;
|
||||
}
|
||||
}
|
||||
else{
|
||||
prev = p_info;
|
||||
p_info = p_info->next;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void dump_dev_visit_list(void)
|
||||
{
|
||||
int i, j;
|
||||
int count = 0;
|
||||
FILE *fp = fopen(OAF_VISIT_LIST_FILE, "w");
|
||||
if (!fp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "%-4s %-20s %-20s %-8s %-32s %-32s %-32s %-8s\n", "Id", "Mac Addr",
|
||||
"Ip Addr", "Appid", "First Time", "Latest Time", "Total Time(s)", "Expire");
|
||||
for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++)
|
||||
{
|
||||
dev_node_t *node = dev_hash_table[i];
|
||||
while (node)
|
||||
{
|
||||
for (j = 0; j < MAX_VISIT_HASH_SIZE; j++)
|
||||
{
|
||||
visit_info_t *p_info = node->visit_htable[j];
|
||||
while (p_info)
|
||||
{
|
||||
char *first_time_str = format_time(p_info->first_time);
|
||||
char *latest_time_str = format_time(p_info->latest_time);
|
||||
int total_time = p_info->latest_time - p_info->first_time;
|
||||
fprintf(fp, "%-4d %-20s %-20s %-8d %-32s %-32s %-32d %-4d\n",
|
||||
count, node->mac, node->ip, p_info->appid, first_time_str,
|
||||
latest_time_str, total_time, p_info->expire);
|
||||
if (first_time_str)
|
||||
free(first_time_str);
|
||||
if (latest_time_str)
|
||||
free(latest_time_str);
|
||||
p_info = p_info->next;
|
||||
count++;
|
||||
if (count > 50)
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
EXIT:
|
||||
fclose(fp);
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __FILTER_USER_H__
|
||||
#define __FILTER_USER_H__
|
||||
#define MAX_IP_LEN 32
|
||||
#define MAX_MAC_LEN 32
|
||||
#define MAX_VISIT_HASH_SIZE 64
|
||||
#define MAX_DEV_NODE_HASH_SIZE 64
|
||||
#define MAX_HOSTNAME_SIZE 64
|
||||
#define MAX_SUPPORT_USER_NUM 64
|
||||
#define OAF_VISIT_LIST_FILE "/tmp/visit_list"
|
||||
#define OAF_DEV_LIST_FILE "/tmp/dev_list"
|
||||
#define MIN_VISIT_TIME 5 // default 5s
|
||||
#define MAX_APP_STAT_NUM 8
|
||||
#define MAX_VISITLIST_DUMP_NUM 16
|
||||
#define MAX_APP_TYPE 16
|
||||
#define MAX_APP_ID_NUM 128
|
||||
#define MAX_SUPPORT_DEV_NUM 64
|
||||
#define SECONDS_PER_DAY (24 * 3600)
|
||||
|
||||
//extern dev_node_t *dev_hash_table[MAX_DEV_NODE_HASH_SIZE];
|
||||
|
||||
/*
|
||||
{
|
||||
"mac": "10:bf:48:37:0c:94",
|
||||
"ip": "192.168.100.244",
|
||||
"app_num": 0,
|
||||
"visit_info": [{
|
||||
"appid": 8002,
|
||||
"latest_action": 1,
|
||||
"latest_time": 1602604293,
|
||||
"total_num": 4,
|
||||
"drop_num": 4,
|
||||
"history_info": []
|
||||
}]
|
||||
}
|
||||
*/
|
||||
/* 单个访问记录结构 */
|
||||
typedef struct visit_info
|
||||
{
|
||||
int appid;
|
||||
int first_time;
|
||||
int latest_time;
|
||||
int action;
|
||||
int expire; /*定期清除无效数据*/
|
||||
struct visit_info *next;
|
||||
} visit_info_t;
|
||||
|
||||
/* 用于记录某个app总时间和总流量 */
|
||||
typedef struct visit_stat
|
||||
{
|
||||
unsigned long long total_time;
|
||||
unsigned long long total_down_bytes;
|
||||
unsigned long long total_up_bytes;
|
||||
} visit_stat_t;
|
||||
|
||||
typedef struct dev_node
|
||||
{
|
||||
char mac[MAX_MAC_LEN];
|
||||
char ip[MAX_IP_LEN];
|
||||
char hostname[MAX_HOSTNAME_SIZE];
|
||||
int online;
|
||||
int expire;
|
||||
int offline_time;
|
||||
int online_time;
|
||||
visit_info_t *visit_htable[MAX_VISIT_HASH_SIZE];
|
||||
visit_stat_t stat[MAX_APP_TYPE][MAX_APP_ID_NUM];
|
||||
struct dev_node *next;
|
||||
} dev_node_t;
|
||||
|
||||
struct app_visit_info
|
||||
{
|
||||
int app_id;
|
||||
char app_name[32];
|
||||
int total_time;
|
||||
};
|
||||
|
||||
struct app_visit_stat_info
|
||||
{
|
||||
int num;
|
||||
struct app_visit_info visit_list[MAX_APP_STAT_NUM];
|
||||
};
|
||||
typedef void (*iter_func)(void *arg, dev_node_t *dev);
|
||||
//todo:dev for each
|
||||
extern dev_node_t *dev_hash_table[MAX_DEV_NODE_HASH_SIZE];
|
||||
|
||||
dev_node_t *add_dev_node(char *mac);
|
||||
void init_dev_node_htable();
|
||||
void dump_dev_list(void);
|
||||
void dump_dev_visit_list(void);
|
||||
dev_node_t *find_dev_node(char *mac);
|
||||
void dev_foreach(void *arg, iter_func iter);
|
||||
void add_visit_info_node(visit_info_t **head, visit_info_t *node);
|
||||
void check_dev_visit_info_expire(void);
|
||||
void flush_expire_visit_info();
|
||||
int check_dev_expire(void);
|
||||
void flush_dev_expire_node(void);
|
||||
void flush_expire_visit_info(void);
|
||||
#endif
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Derry <destan19@126.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <libubox/utils.h>
|
||||
#include <libubus.h>
|
||||
#include "appfilter_user.h"
|
||||
#include "appfilter_netlink.h"
|
||||
#include "appfilter_ubus.h"
|
||||
#include "appfilter_config.h"
|
||||
#include <time.h>
|
||||
void check_appfilter_enable(void)
|
||||
{
|
||||
int enable = 1;
|
||||
struct tm *t;
|
||||
af_ctl_time_t *af_t = NULL;
|
||||
time_t tt;
|
||||
time(&tt);
|
||||
enable = config_get_appfilter_enable();
|
||||
|
||||
if (0 == enable)
|
||||
goto EXIT;
|
||||
af_t = load_appfilter_ctl_time_config();
|
||||
if (!af_t)
|
||||
{
|
||||
enable = 0;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
t = localtime(&tt);
|
||||
if (af_t->days[t->tm_wday] != 1)
|
||||
{
|
||||
if (af_t->time_mode == 0){
|
||||
enable = 0;
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
int cur_mins = t->tm_hour * 60 + t->tm_min;
|
||||
if (((af_t->start.hour * 60 + af_t->start.min < cur_mins) && (cur_mins < af_t->end.hour * 60 + af_t->end.min))
|
||||
|| ((af_t->start2.hour * 60 + af_t->start2.min < cur_mins) && (cur_mins < af_t->end2.hour * 60 + af_t->end2.min))
|
||||
)
|
||||
{
|
||||
if (af_t->time_mode == 0){
|
||||
enable = 1;
|
||||
}
|
||||
else{
|
||||
enable = 0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (af_t->time_mode == 0){
|
||||
enable = 0;
|
||||
}
|
||||
else{
|
||||
enable = 1;
|
||||
}
|
||||
}
|
||||
EXIT:
|
||||
if (enable)
|
||||
{
|
||||
system("echo 1 >/proc/sys/oaf/enable ");
|
||||
}
|
||||
else
|
||||
system("echo 0 >/proc/sys/oaf/enable ");
|
||||
if (af_t)
|
||||
free(af_t);
|
||||
}
|
||||
|
||||
void dev_list_timeout_handler(struct uloop_timeout *t)
|
||||
{
|
||||
dump_dev_list();
|
||||
check_dev_visit_info_expire();
|
||||
flush_expire_visit_info();
|
||||
//dump_dev_visit_list();
|
||||
check_appfilter_enable();
|
||||
//todo: dev list expire
|
||||
if (check_dev_expire()){
|
||||
flush_expire_visit_info();
|
||||
flush_dev_expire_node();
|
||||
}
|
||||
uloop_timeout_set(t, 10000);
|
||||
}
|
||||
|
||||
struct uloop_timeout dev_tm = {
|
||||
.cb = dev_list_timeout_handler};
|
||||
|
||||
static struct uloop_fd appfilter_nl_fd = {
|
||||
.cb = appfilter_nl_handler,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
uloop_init();
|
||||
printf("init appfilter\n");
|
||||
init_dev_node_htable();
|
||||
init_app_name_table();
|
||||
init_app_class_name_table();
|
||||
if (appfilter_ubus_init() < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to connect to ubus\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
appfilter_nl_fd.fd = appfilter_nl_init();
|
||||
uloop_fd_add(&appfilter_nl_fd, ULOOP_READ);
|
||||
af_msg_t msg;
|
||||
msg.action = AF_MSG_INIT;
|
||||
send_msg_to_kernel(appfilter_nl_fd.fd, (void *)&msg, sizeof(msg));
|
||||
uloop_timeout_set(&dev_tm, 5000);
|
||||
uloop_timeout_add(&dev_tm);
|
||||
uloop_run();
|
||||
uloop_done();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user