This commit is contained in:
SirPdboy 2022-08-27 21:58:23 +08:00 committed by GitHub
parent 904de085e4
commit 2a74defe74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 0 additions and 8174 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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%>

View File

@ -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%>

View File

@ -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 "开启应用过滤"

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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;}

View File

@ -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

View File

@ -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);
}

View File

@ -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))

View File

@ -1,8 +0,0 @@
1 聊天
2 游戏
3 视频
4 购物
5 音乐
6 招聘
7 下载
8 常用网站

View File

@ -1,8 +0,0 @@
1 chat
2 game
3 video
4 shopping
5 music
6 recruitment
7 download
8 website

View File

@ -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

View File

@ -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
}

View File

@ -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()

View File

@ -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

View File

@ -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;;]

View File

@ -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;;]

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}