update 2022-08-18 09:02:24

This commit is contained in:
github-actions[bot] 2022-08-18 09:02:24 +08:00
parent 0117f61877
commit f5db51c766
24 changed files with 759 additions and 269 deletions

View File

@ -6,11 +6,11 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=adguardhome
PKG_VERSION:=0.107.9
PKG_RELEASE:=59
PKG_VERSION:=0.107.10
PKG_RELEASE:=60
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=cbf221585eb5c325a72c751dfef0c8a83abbacc6
PKG_SOURCE_VERSION:=9200163f85e009680fe88457d4bc01a6b51c59de
PKG_SOURCE_URL:=https://github.com/AdguardTeam/AdGuardHome
PKG_MIRROR_HASH:=skip

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ function index()
_("用户列表"), 21).leaf=true
entry({"admin", "services", "appfilter", "base_setting"},
cbi("appfilter/base_setting"), _("应用过滤规则"), 22).leaf=true
cbi("appfilter/base_setting"), _("基本设置"), 22).leaf=true
entry({"admin", "services", "appfilter", "user_setting"},
cbi("appfilter/user_setting"), _("生效用户"), 23).leaf=true

View File

@ -13,12 +13,17 @@ local SYS = require "luci.sys"
local m, s
m = Map("appfilter", translate("App Filter"), translate(
"目前不支持旁路模式,请先关闭所有加速(acc)、广告过滤、多拨等可能冲突的模块"))
"请先关闭所有加速(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 = ""

View File

@ -14,14 +14,15 @@ local m, s
m = Map("appfilter", translate(""), translate(""))
s = m:section(TypedSection, "time", translate("Time Setting"))
s = m:section(TypedSection, "time", translate("Time Setting"),translate("时间2为选填开始和结束时间需要同时设置结束时间要大于开始时间"))
s.anonymous = true
hv = s:option(Value, "start_time", translate("Start Time"))
hv.default = "00:00"
hv.optional = false
hv = s:option(Value, "end_time", translate("End Time"))
hv.default = "23:59"
hv.optional = false
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
@ -33,4 +34,16 @@ 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

@ -124,11 +124,18 @@ msgstr "更新特征库失败,格式错误!"
msgid "Select feature file:"
msgstr "选择本地特征库文件:"
msgid "Start Time"
msgstr "开始时间"
msgid "Start Time1"
msgstr "开始时间1"
msgid "End Time"
msgstr "结束时间"
msgid "End Time1"
msgstr "结束时间1"
msgid "Start Time2"
msgstr "开始时间2"
msgid "End Time2"
msgstr "结束时间2"
msgid "App Name"
msgstr "App名称"

View File

@ -9,5 +9,3 @@ EOF
# remove LuCI cache
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
exit 0

View File

@ -0,0 +1,8 @@
#!/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

@ -102,12 +102,22 @@ af_client_info_t *find_af_client(unsigned char *mac)
{
if (0 == memcmp(node->mac, mac, 6))
{
node->update_jiffies = jiffies;
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)
{
@ -128,7 +138,7 @@ af_client_info_t *find_af_client_by_ip(unsigned int ip)
return NULL;
}
static af_client_info_t *
af_client_info_t *
nf_client_add(unsigned char *mac)
{
af_client_info_t *node;
@ -154,6 +164,9 @@ nf_client_add(unsigned char *mac)
return node;
}
void check_client_expire(void)
{
af_client_info_t *node;
@ -243,8 +256,6 @@ int __af_visit_info_report(af_client_info_t *node)
{
if (node->visit_info[i].app_id == 0)
continue;
if (node->visit_info[i].total_num < 3)
continue;
count++;
visit_obj = cJSON_CreateObject();
cJSON_AddNumberToObject(visit_obj, "appid", node->visit_info[i].app_id);
@ -373,6 +384,7 @@ static u_int32_t af_client_hook(unsigned int hook,
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();

View File

@ -60,11 +60,14 @@ 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

@ -4,13 +4,13 @@
#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
*/
@ -36,6 +36,13 @@ static struct ctl_table oaf_table[] = {
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "work_mode",
.data = &af_work_mode,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
}
};

View File

@ -2,6 +2,7 @@
#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__); \

View File

@ -19,6 +19,27 @@ u_int32_t af_get_timestamp_sec(void)
#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)
{

View File

@ -2,6 +2,8 @@
#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);

View File

@ -42,7 +42,7 @@ DEFINE_RWLOCK(af_feature_lock);
#define MAX_OAF_NETLINK_MSG_LEN 1024
int __add_app_feature(int appid, char *name, int proto, int src_port,
int dst_port, char *host_url, char *request_url, char *dict)
port_info_t dport_info, char *host_url, char *request_url, char *dict)
{
af_feature_node_t *node = NULL;
char *p = dict;
@ -61,7 +61,7 @@ int __add_app_feature(int appid, char *name, int proto, int src_port,
node->app_id = appid;
strcpy(node->app_name, name);
node->proto = proto;
node->dport = dst_port;
node->dport_info = dport_info;
node->sport = src_port;
strcpy(node->host_url, host_url);
strcpy(node->request_url, request_url);
@ -85,13 +85,10 @@ int __add_app_feature(int appid, char *name, int proto, int src_port,
}
if (begin != dict)
{
strncpy(pos, begin, p - begin);
}
else
{
strcpy(pos, dict);
}
k_sscanf(pos, "%d:%x", &index, &value);
node->pos_info[node->pos_num].pos = index;
node->pos_info[node->pos_num].value = value;
@ -102,13 +99,119 @@ int __add_app_feature(int appid, char *name, int proto, int src_port,
}
return 0;
}
int validate_range_value(char *range_str){
if (!range_str)
return 0;
char *p = range_str;
while(*p){
if (*p == ' ' || *p == '!' || *p == '-' ||
((*p >= '0') && (*p <= '9'))){
p++;
continue;
}
else{
printk("error, invalid char %x\n", *p);
return 0;
}
}
return 1;
}
int parse_range_value(char *range_str, range_value_t *range){
char pure_range[128] = {0};
if (!validate_range_value(range_str)){
printk("validate range str failed, value = %s\n", range_str);
return -1;
}
k_trim(range_str);
if (range_str[0] == '!'){
range->not = 1;
strcpy(pure_range, range_str + 1);
}
else{
range->not = 0;
strcpy(pure_range, range_str);
}
k_trim(pure_range);
int start, end;
if (strstr(pure_range, "-")){
if (2 != sscanf(pure_range, "%d-%d",&start, &end))
return -1;
}
else{
if (1 != sscanf(pure_range, "%d", &start))
return -1;
end = start;
}
range->start = start;
range->end = end;
return 0;
}
int parse_port_info(char *port_str, port_info_t *info){
char *p = port_str;
char *begin = port_str;
int param_num = 0;
char one_port_buf[128] = {0};
k_trim(port_str);
if (strlen(port_str) == 0)
return -1;
while(*p++) {
if (*p != '|')
continue;
memset(one_port_buf, 0x0, sizeof(one_port_buf));
strncpy(one_port_buf, begin, p - begin);
if (0 == parse_range_value(one_port_buf, &info->range_list[info->num])){
info->num++;
}
param_num++;
begin = p + 1;
}
memset(one_port_buf, 0x0, sizeof(one_port_buf));
strncpy(one_port_buf, begin, p - begin);
if (0 == parse_range_value(one_port_buf, &info->range_list[info->num])){
info->num++;
}
return 0;
}
int af_match_port(port_info_t *info, int port){
int i;
int with_not = 0;
if (info->num == 0)
return 1;
for (i = 0; i < info->num; i++){
if (info->range_list[i].not){
with_not = 1;
break;
}
}
for (i = 0; i < info->num; i++){
if (with_not){
if (info->range_list[i].not && port >= info->range_list[i].start
&& port <= info->range_list[i].end){
return 0;
}
}
else{
if (port >= info->range_list[i].start
&& port <= info->range_list[i].end){
return 1;
}
}
}
if (with_not)
return 1;
else
return 0;
}
//[tcp;;443;baidu.com;;]
int add_app_feature(int appid, char *name, char *feature)
{
char proto_str[16] = {0};
char src_port_str[16] = {0};
port_info_t dport_info;
char dst_port_str[16] = {0};
char host_url[32] = {0};
char request_url[128] = {0};
@ -126,6 +229,7 @@ int add_app_feature(int appid, char *name, char *feature)
return -1;
}
// tcp;8000;www.sina.com;0:get_name;00:0a-01:11
memset(&dport_info, 0x0, sizeof(dport_info));
while (*p++)
{
if (*p != ';')
@ -172,8 +276,10 @@ int add_app_feature(int appid, char *name, char *feature)
return -1;
}
sscanf(src_port_str, "%d", &src_port);
sscanf(dst_port_str, "%d", &dst_port);
__add_app_feature(appid, name, proto, src_port, dst_port, host_url, request_url, dict);
// sscanf(dst_port_str, "%d", &dst_port);
parse_port_info(dst_port_str, &dport_info);
__add_app_feature(appid, name, proto, src_port, dport_info, host_url, request_url, dict);
return 0;
}
@ -333,7 +439,7 @@ static void af_clean_feature_list(void)
feature_list_write_unlock();
}
int parse_flow_base(struct sk_buff *skb, flow_info_t *flow)
int parse_flow_proto(struct sk_buff *skb, flow_info_t *flow)
{
struct tcphdr *tcph = NULL;
struct udphdr *udph = NULL;
@ -341,17 +447,9 @@ int parse_flow_base(struct sk_buff *skb, flow_info_t *flow)
struct iphdr *iph = NULL;
if (!skb)
return -1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
ct = (struct nf_conn *)skb->_nfct;
#else
ct = (struct nf_conn *)skb->nfct;
#endif
if (!ct)
return -1;
iph = ip_hdr(skb);
if (!iph)
return -1;
flow->ct = ct;
flow->src = iph->saddr;
flow->dst = iph->daddr;
flow->l4_protocol = iph->protocol;
@ -379,7 +477,7 @@ int parse_flow_base(struct sk_buff *skb, flow_info_t *flow)
return -1;
}
int parse_https_proto(flow_info_t *flow)
int dpi_https_proto(flow_info_t *flow)
{
int i;
short url_len = 0;
@ -398,6 +496,7 @@ int parse_https_proto(flow_info_t *flow)
if (!(p[0] == 0x16 && p[1] == 0x03 && p[2] == 0x01))
return -1;
for (i = 0; i < data_len; i++)
{
if (i + HTTPS_URL_OFFSET >= data_len)
@ -425,7 +524,7 @@ int parse_https_proto(flow_info_t *flow)
return -1;
}
void parse_http_proto(flow_info_t *flow)
void dpi_http_proto(flow_info_t *flow)
{
int i = 0;
int start = 0;
@ -658,9 +757,8 @@ int af_match_one(flow_info_t *flow, af_feature_node_t *node)
{
return AF_FALSE;
}
if (node->dport != 0 && flow->dport != node->dport)
{
if (!af_match_port(&node->dport_info, flow->dport)){
return AF_FALSE;
}
@ -702,7 +800,6 @@ int app_filter_match(flow_info_t *flow)
}
if (is_user_match_enable() && !find_af_mac(client->mac))
{
AF_DEBUG("not match mac:" MAC_FMT "\n", MAC_ARRAY(client->mac));
goto EXIT;
}
if (af_get_app_status(node->app_id))
@ -724,7 +821,7 @@ EXIT:
return AF_FALSE;
}
#define APP_FILTER_DROP_BITS 0x80000000
#define NF_DROP_BIT 0x80000000
static int af_get_visit_index(af_client_info_t *node, int app_id)
{
@ -740,49 +837,177 @@ static int af_get_visit_index(af_client_info_t *node, int app_id)
return 0;
}
int __af_update_client_app_info(flow_info_t *flow, af_client_info_t *node)
int af_update_client_app_info(af_client_info_t *node, int app_id, int drop)
{
int index = -1;
if (!node)
return -1;
if (!flow)
return -1;
index = af_get_visit_index(node, flow->app_id);
index = af_get_visit_index(node, app_id);
if (index < 0 || index >= MAX_RECORD_APP_NUM)
{
AF_ERROR("invalid index:%d\n\n", index);
return 0;
}
// todo: up bytes
node->visit_info[index].total_down_bytes += flow->l4_len + 66;
node->visit_info[index].total_num++;
if (flow->drop)
if (drop)
node->visit_info[index].drop_num++;
node->visit_info[index].app_id = flow->app_id;
node->visit_info[index].app_id = app_id;
node->visit_info[index].latest_time = af_get_timestamp_sec();
node->visit_info[index].latest_action = flow->drop;
node->visit_info[index].latest_action = drop;
return 0;
}
void af_update_client_app_info(flow_info_t *flow)
{
af_client_info_t *node = NULL;
if (!flow)
return;
if (flow->app_id <= 0)
return;
AF_CLIENT_LOCK_W();
node = find_af_client_by_ip(flow->src);
if (node)
{
__af_update_client_app_info(flow, node);
}
AF_CLIENT_UNLOCK_W();
int af_send_msg_to_user(char *pbuf, uint16_t len);
int af_match_bcast_packet(flow_info_t *f){
if (!f)
return 0;
if (0 == f->src || 0 == f->dst
|| 0xffffffff == f->dst || 0 == f->dst)
return 1;
return 0;
}
int af_match_local_packet(flow_info_t *f){
if (!f)
return 0;
if (0x0100007f == f->src || 0x0100007f == f->dst){
return 1;
}
return 0;
}
int dpi_main(struct sk_buff *skb, flow_info_t *flow){
dpi_http_proto(flow);
dpi_https_proto(flow);
if (TEST_MODE())
dump_flow_info(flow);
return 0;
}
void af_get_smac(struct sk_buff *skb, u_int8_t *smac){
struct ethhdr *ethhdr = NULL;
ethhdr = eth_hdr(skb);
if (ethhdr)
memcpy(smac, ethhdr->h_source, ETH_ALEN);
else
memcpy(smac, &skb->cb[40], ETH_ALEN);
}
u_int32_t app_filter_hook_bypass_handle(struct sk_buff *skb, struct net_device *dev){
flow_info_t flow;
u_int8_t smac[ETH_ALEN];
af_client_info_t *client = NULL;
if (!skb || !dev)
return NF_ACCEPT;
if (skb->len > MAX_BYPASS_DPI_PKT_LEN)
return NF_ACCEPT;
memset((char *)&flow, 0x0, sizeof(flow_info_t));
if (parse_flow_proto(skb, &flow) < 0)
return NF_ACCEPT;
if (af_match_bcast_packet(&flow) || af_match_local_packet(&flow))
return NF_ACCEPT;
af_get_smac(skb, smac);
AF_CLIENT_LOCK_W();
client = find_and_add_af_client(smac);
if (!client){
AF_CLIENT_UNLOCK_W();
return NF_ACCEPT;
}
client->update_jiffies = jiffies;
AF_CLIENT_UNLOCK_W();
if (0 != dpi_main(skb, &flow))
return NF_ACCEPT;
client->ip = flow.src;
app_filter_match(&flow);
if (flow.app_id != 0){
af_update_client_app_info(client, flow.app_id, flow.drop);
}
if (flow.drop)
{
return NF_DROP;
}
return NF_ACCEPT;
}
u_int32_t app_filter_hook_gateway_handle(struct sk_buff *skb, struct net_device *dev){
unsigned long long total_packets = 0;
flow_info_t flow;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = NULL;
struct nf_conn_acct *acct;
af_client_info_t *client = NULL;
int app_id = 0;
int drop = 0;
memset((char *)&flow, 0x0, sizeof(flow_info_t));
if (parse_flow_proto(skb, &flow) < 0)
return NF_ACCEPT;
ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL || !nf_ct_is_confirmed(ct))
return NF_ACCEPT;
AF_CLIENT_LOCK_R();
client = find_af_client_by_ip(flow.src);
if (!client){
AF_CLIENT_UNLOCK_R();
return NF_ACCEPT;
}
client->update_jiffies = jiffies;
AF_CLIENT_UNLOCK_R();
if (ct->mark != 0)
{
app_id = ct->mark & (~NF_DROP_BIT);
if (app_id > 1000 && app_id < 9999){
if (NF_DROP_BIT == (ct->mark & NF_DROP_BIT))
drop = 1;
AF_CLIENT_LOCK_W();
af_update_client_app_info(client, app_id, drop);
AF_CLIENT_UNLOCK_W();
if (drop){
return NF_DROP;
}
}
}
acct = nf_conn_acct_find(ct);
if(!acct)
return NF_ACCEPT;
total_packets = (unsigned long long)atomic64_read(&acct->counter[IP_CT_DIR_ORIGINAL].packets)
+ (unsigned long long)atomic64_read(&acct->counter[IP_CT_DIR_REPLY].packets);
if(total_packets > MAX_DPI_PKT_NUM)
return NF_ACCEPT;
if (0 != dpi_main(skb, &flow))
return NF_ACCEPT;
app_filter_match(&flow);
if (flow.app_id != 0)
{
ct->mark = flow.app_id;
AF_CLIENT_LOCK_W();
af_update_client_app_info(client, flow.app_id, flow.drop);
AF_CLIENT_UNLOCK_W();
AF_LMT_INFO("match %s %pI4(%d)--> %pI4(%d) len = %d, %d\n ", IPPROTO_TCP == flow.l4_protocol ? "tcp" : "udp",
&flow.src, flow.sport, &flow.dst, flow.dport, skb->len, flow.app_id);
}
if (flow.drop)
{
ct->mark |= NF_DROP_BIT;
AF_LMT_INFO("##Drop app %s flow, appid is %d\n", flow.app_name, flow.app_id);
return NF_DROP;
}
return NF_ACCEPT;
}
int af_send_msg_to_user(char *pbuf, uint16_t len);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
static u_int32_t app_filter_hook(void *priv,
@ -797,74 +1022,34 @@ static u_int32_t app_filter_hook(unsigned int hook,
int (*okfn)(struct sk_buff *))
{
#endif
unsigned long long total_packets = 0;
flow_info_t flow;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = NULL;
struct nf_conn_acct *acct;
if (!g_oaf_enable)
return NF_ACCEPT;
ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL)
if (AF_MODE_BYPASS == af_work_mode)
return NF_ACCEPT;
#if defined(CONFIG_NF_CONNTRACK_MARK)
if (ct->mark != 0)
{
if (APP_FILTER_DROP_BITS == (ct->mark & APP_FILTER_DROP_BITS))
return NF_DROP;
}
#endif
// 3.12.74-->3.13-rc1
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
acct = nf_conn_acct_find(ct);
if(!acct)
return NF_ACCEPT;
total_packets = (unsigned long long)atomic64_read(&acct->counter[IP_CT_DIR_ORIGINAL].packets)
+ (unsigned long long)atomic64_read(&acct->counter[IP_CT_DIR_REPLY].packets);
#else
struct nf_conn_counter *counter;
counter = nf_conn_acct_find(ct);
if (!counter)
return NF_ACCEPT;
total_packets = (unsigned long long)atomic64_read(&counter[IP_CT_DIR_ORIGINAL].packets)
+ (unsigned long long)atomic64_read(&counter[IP_CT_DIR_REPLY].packets);
#endif
if(total_packets > MAX_PARSE_PKT_NUM){
return NF_ACCEPT;
}
memset((char *)&flow, 0x0, sizeof(flow_info_t));
if (parse_flow_base(skb, &flow) < 0)
return NF_ACCEPT;
parse_http_proto(&flow);
parse_https_proto(&flow);
if (TEST_MODE())
dump_flow_info(&flow);
app_filter_match(&flow);
if (flow.app_id != 0)
{
if (flow.app_id > 1000 && flow.app_id <= 8999)
{
af_update_client_app_info(&flow);
AF_LMT_INFO("match %s %pI4(%d)--> %pI4(%d) len = %d, %d\n ", IPPROTO_TCP == flow.l4_protocol ? "tcp" : "udp",
&flow.src, flow.sport, &flow.dst, flow.dport, skb->len, flow.app_id);
}
}
if (flow.drop)
{
#if defined(CONFIG_NF_CONNTRACK_MARK)
ct->mark |= APP_FILTER_DROP_BITS;
#endif
AF_LMT_INFO("##Drop app %s flow, appid is %d\n", flow.app_name, flow.app_id);
return NF_DROP;
}
return NF_ACCEPT;
return app_filter_hook_gateway_handle(skb, skb->dev);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
static u_int32_t app_filter_by_pass_hook(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
#else
static u_int32_t app_filter_by_pass_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
#endif
if (!g_oaf_enable)
return NF_ACCEPT;
if (AF_MODE_GATEWAY == af_work_mode)
return NF_ACCEPT;
return app_filter_hook_bypass_handle(skb, skb->dev);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
static struct nf_hook_ops app_filter_ops[] __read_mostly = {
{
@ -872,6 +1057,13 @@ static struct nf_hook_ops app_filter_ops[] __read_mostly = {
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_MANGLE + 1,
},
{
.hook = app_filter_by_pass_hook,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_MANGLE + 1,
},
};
#else
@ -943,14 +1135,12 @@ int af_send_msg_to_user(char *pbuf, uint16_t len)
nl_skb = nlmsg_new(len + sizeof(struct af_msg_hdr), GFP_ATOMIC);
if (!nl_skb)
{
printk("netlink alloc failure\n");
return -1;
}
nlh = nlmsg_put(nl_skb, 0, 0, OAF_NETLINK_ID, len + sizeof(struct af_msg_hdr), 0);
if (nlh == NULL)
{
printk("error, nlh is NULL\n");
nlmsg_free(nl_skb);
return -1;
}
@ -989,15 +1179,9 @@ static void oaf_msg_rcv(struct sk_buff *skb)
umsg = NLMSG_DATA(nlh);
af_hdr = (struct af_msg_hdr *)umsg;
if (af_hdr->magic != 0xa0b0c0d0)
{
printk("magic error %x\n", af_hdr->magic);
return;
}
if (af_hdr->len <= 0 || af_hdr->len >= MAX_OAF_NETLINK_MSG_LEN)
{
printk("data len error\n");
return;
}
udata = umsg + sizeof(struct af_msg_hdr);
if (udata)

View File

@ -4,7 +4,7 @@
#define AF_VERSION "5.0"
#define AF_FEATURE_CONFIG_FILE "/tmp/feature.cfg"
#define MAX_PARSE_PKT_NUM 64
#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
@ -17,6 +17,7 @@
#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
@ -59,6 +60,11 @@ 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;
@ -116,6 +122,22 @@ typedef struct af_pos_info{
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;
@ -124,6 +146,7 @@ typedef struct af_feature_node{
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;

View File

@ -1,12 +1,16 @@
config global global
option enable '0'
option work_mode '0'
config appfilter appfilter
config feature feature
config time 'time'
option end_time '23:59'
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

@ -78,10 +78,18 @@ reload_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

@ -229,29 +229,43 @@ 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;
ret |= uci_get_value(ctx, "appfilter.time.start_time", start_time_str, sizeof(start_time_str));
ret |= uci_get_value(ctx, "appfilter.time.end_time", end_time_str, sizeof(end_time_str));
ret |= uci_get_value(ctx, "appfilter.time.days", days_str, sizeof(days_str));
if (ret != 0){
printf("time config error\n");
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));
if (!check_time_valid(start_time_str) || !check_time_valid(end_time_str)){
printf("format error\n");
return NULL;
}
t = malloc(sizeof(af_ctl_time_t));
sscanf(start_time_str, "%d:%d", &t->start.hour, &t->start.min);
sscanf(end_time_str, "%d:%d", &t->end.hour, &t->end.min);
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)

View File

@ -34,8 +34,11 @@ typedef struct af_time
} 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;

View File

@ -44,6 +44,8 @@ void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev)
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__);
@ -90,6 +92,7 @@ void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev)
printf("parse json failed:%s", kdata);
return;
}
printf("recv msg = %s\n", kdata);
struct json_object *mac_obj = json_object_object_get(root, "mac");
@ -137,10 +140,10 @@ void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev)
int appid = json_object_get_int(appid_obj);
int action = json_object_get_int(action_obj);
int type = appid / 1000;
int id = appid % 1000;
printf("%s %d\n", __func__, __LINE__);
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);
@ -148,6 +151,7 @@ void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev)
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;
@ -163,7 +167,6 @@ void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev)
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("%s %d\n", __func__, __LINE__);
//printf("add visit info curtime=%d\n", cur_time.tv_sec);
}

View File

@ -190,8 +190,10 @@ void clean_dev_online_status(void)
dev_node_t *node = dev_hash_table[i];
while (node)
{
node->online = 0;
node->offline_time = get_timestamp();
if (node->online){
node->offline_time = get_timestamp();
node->online = 0;
}
node = node->next;
}
}
@ -201,7 +203,7 @@ void clean_dev_online_status(void)
Id Mac Ip
1 10:bf:48:37:0c:94 192.168.66.244
*/
void check_dev_expire(void)
void update_dev_online_status(void)
{
char line_buf[256] = {0};
char mac_buf[32] = {0};
@ -234,6 +236,88 @@ void check_dev_expire(void)
}
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;
@ -242,7 +326,7 @@ void dump_dev_list(void)
char ip_buf[MAX_IP_LEN] = {0};
clean_dev_online_status();
update_dev_hostname();
check_dev_expire();
update_dev_online_status();
FILE *fp = fopen(OAF_DEV_LIST_FILE, "w");
if (!fp)
{
@ -359,9 +443,6 @@ void flush_expire_visit_info(void)
while (p_info)
{
if (p_info->expire){
printf("del node %-20s %-20s %d\n",
node->mac, node->ip, p_info->appid
);
if (NULL == prev){
node->visit_htable[j] = p_info->next;
free(p_info);

View File

@ -35,6 +35,7 @@ THE SOFTWARE.
#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];
@ -78,6 +79,7 @@ typedef struct dev_node
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];
@ -110,5 +112,7 @@ 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

@ -47,26 +47,37 @@ void check_appfilter_enable(void)
enable = 0;
goto EXIT;
}
t = localtime(&tt);
if (af_t->days[t->tm_wday] != 1)
{
enable = 0;
goto EXIT;
if (af_t->time_mode == 0){
enable = 0;
goto EXIT;
}
}
if (af_t->start.hour <= af_t->end.hour)
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))
)
{
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))
{
if (af_t->time_mode == 0){
enable = 1;
}
else{
enable = 0;
}
}
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 ");
@ -79,13 +90,16 @@ EXIT:
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);
}
@ -108,7 +122,8 @@ int main(int argc, char **argv)
{
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);