diff --git a/luci-app-oaf/luasrc/controller/appfilter.lua b/luci-app-oaf/luasrc/controller/appfilter.lua index 284d39a..9f5b47a 100755 --- a/luci-app-oaf/luasrc/controller/appfilter.lua +++ b/luci-app-oaf/luasrc/controller/appfilter.lua @@ -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 diff --git a/luci-app-oaf/luasrc/model/cbi/appfilter/base_setting.lua b/luci-app-oaf/luasrc/model/cbi/appfilter/base_setting.lua index f88ecba..9458ec1 100755 --- a/luci-app-oaf/luasrc/model/cbi/appfilter/base_setting.lua +++ b/luci-app-oaf/luasrc/model/cbi/appfilter/base_setting.lua @@ -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 = "" diff --git a/luci-app-oaf/luasrc/model/cbi/appfilter/time_setting.lua b/luci-app-oaf/luasrc/model/cbi/appfilter/time_setting.lua index 7a10ee7..b950551 100755 --- a/luci-app-oaf/luasrc/model/cbi/appfilter/time_setting.lua +++ b/luci-app-oaf/luasrc/model/cbi/appfilter/time_setting.lua @@ -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 diff --git a/luci-app-oaf/po/zh-cn/oaf.po b/luci-app-oaf/po/zh-cn/oaf.po index 9bf2e2e..53990b5 100755 --- a/luci-app-oaf/po/zh-cn/oaf.po +++ b/luci-app-oaf/po/zh-cn/oaf.po @@ -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名称" diff --git a/luci-app-oaf/root/etc/uci-defaults/91_luci-oaf b/luci-app-oaf/root/etc/uci-defaults/91_luci-oaf index b9f5023..24bf73a 100755 --- a/luci-app-oaf/root/etc/uci-defaults/91_luci-oaf +++ b/luci-app-oaf/root/etc/uci-defaults/91_luci-oaf @@ -9,5 +9,3 @@ EOF # remove LuCI cache rm -rf /tmp/luci-indexcache /tmp/luci-modulecache - -exit 0 diff --git a/luci-app-oaf/root/etc/uci-defaults/92_oaf_time b/luci-app-oaf/root/etc/uci-defaults/92_oaf_time new file mode 100755 index 0000000..75146d3 --- /dev/null +++ b/luci-app-oaf/root/etc/uci-defaults/92_oaf_time @@ -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 diff --git a/oaf/src/af_client.c b/oaf/src/af_client.c index af0a079..971446d 100755 --- a/oaf/src/af_client.c +++ b/oaf/src/af_client.c @@ -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(); diff --git a/oaf/src/af_client.h b/oaf/src/af_client.h index 9cc2126..ed83565 100755 --- a/oaf/src/af_client.h +++ b/oaf/src/af_client.h @@ -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 diff --git a/oaf/src/af_log.c b/oaf/src/af_log.c index 42e390e..dba9c10 100755 --- a/oaf/src/af_log.c +++ b/oaf/src/af_log.c @@ -4,13 +4,13 @@ #include #include #include - +#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, + }, { } }; diff --git a/oaf/src/af_log.h b/oaf/src/af_log.h index 009be65..f37b8d6 100755 --- a/oaf/src/af_log.h +++ b/oaf/src/af_log.h @@ -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__); \ diff --git a/oaf/src/af_utils.c b/oaf/src/af_utils.c index e1625d9..cb8103b 100755 --- a/oaf/src/af_utils.c +++ b/oaf/src/af_utils.c @@ -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) { diff --git a/oaf/src/af_utils.h b/oaf/src/af_utils.h index a57f3f2..f2f7be0 100755 --- a/oaf/src/af_utils.h +++ b/oaf/src/af_utils.h @@ -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); diff --git a/oaf/src/app_filter.c b/oaf/src/app_filter.c index fa19636..e9ca013 100755 --- a/oaf/src/app_filter.c +++ b/oaf/src/app_filter.c @@ -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) diff --git a/oaf/src/app_filter.h b/oaf/src/app_filter.h index fd59d8a..2577fea 100755 --- a/oaf/src/app_filter.h +++ b/oaf/src/app_filter.h @@ -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; diff --git a/open-app-filter/files/appfilter.config b/open-app-filter/files/appfilter.config index 00b28d5..e28cb39 100755 --- a/open-app-filter/files/appfilter.config +++ b/open-app-filter/files/appfilter.config @@ -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 diff --git a/open-app-filter/files/oaf_rule b/open-app-filter/files/oaf_rule index 74872f5..0aa57d3 100755 --- a/open-app-filter/files/oaf_rule +++ b/open-app-filter/files/oaf_rule @@ -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 diff --git a/open-app-filter/src/appfilter_config.c b/open-app-filter/src/appfilter_config.c index 273191a..1fcb959 100755 --- a/open-app-filter/src/appfilter_config.c +++ b/open-app-filter/src/appfilter_config.c @@ -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) diff --git a/open-app-filter/src/appfilter_config.h b/open-app-filter/src/appfilter_config.h index 1d6187d..1d29e10 100755 --- a/open-app-filter/src/appfilter_config.h +++ b/open-app-filter/src/appfilter_config.h @@ -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; diff --git a/open-app-filter/src/appfilter_netlink.c b/open-app-filter/src/appfilter_netlink.c index ec1bb04..33a2442 100755 --- a/open-app-filter/src/appfilter_netlink.c +++ b/open-app-filter/src/appfilter_netlink.c @@ -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); } diff --git a/open-app-filter/src/appfilter_user.c b/open-app-filter/src/appfilter_user.c index 70568de..6b1e217 100755 --- a/open-app-filter/src/appfilter_user.c +++ b/open-app-filter/src/appfilter_user.c @@ -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); diff --git a/open-app-filter/src/appfilter_user.h b/open-app-filter/src/appfilter_user.h index fc17067..fa88d80 100755 --- a/open-app-filter/src/appfilter_user.h +++ b/open-app-filter/src/appfilter_user.h @@ -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 diff --git a/open-app-filter/src/main.c b/open-app-filter/src/main.c index ab647dd..586db2f 100755 --- a/open-app-filter/src/main.c +++ b/open-app-filter/src/main.c @@ -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);