diff --git a/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua b/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua index 7275081..fc5d250 100755 --- a/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua +++ b/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua @@ -1,16 +1,3 @@ ---[[ -LuCI - Lua Configuration Interface - -Copyright 2008 Steven Barth - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ -]]-- local ds = require "luci.dispatcher" @@ -81,6 +68,57 @@ if class_fd then end class_fd:close() end + + +s=m:section(TypedSection,"user",translate("Select users")) +s.anonymous = true +users = s:option(MultiValue, "users", "", translate("Select at least one user, otherwise it will take effect for all users")) +users.widget="checkbox" + +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 + +users.widget="checkbox" +--users.widget="select" +users.size=1 + +local fd = io.open("/proc/net/arp", "r") +if not fd then return end +while true do + local line = fd:read("*l") + if not line then + break + end + if not line:match("Ip*") then + local ip, hw_type, flags, mac, mask, device = line:match("(%S+) %s+ (%S+) %s+ (%S+) %s+ (%S+) %s+ (%S+) %s+ (%S+)") + if device:match("lan") then + local hostname=get_hostname_by_mac(mac) + if not hostname then + users:value(mac, mac); + else + users:value(mac, hostname); + end + end + end +end + m:section(SimpleSection).template = "admin_network/user_status" diff --git a/luci-app-oaf/po/zh-cn/oaf.po b/luci-app-oaf/po/zh-cn/oaf.po index b133f74..3717faa 100755 --- a/luci-app-oaf/po/zh-cn/oaf.po +++ b/luci-app-oaf/po/zh-cn/oaf.po @@ -41,8 +41,13 @@ msgstr "基本设置" msgid "App Filter Rules" msgstr "应用过滤规则" +msgid "Select at least one user, otherwise it will take effect for all users" +msgstr "至少选择一个用户,否则对所有用户生效" + +msgid "Select users" +msgstr "选择用户" + msgid "Enable App Filter" msgstr "开启应用过滤" - diff --git a/luci-app-oaf/root/etc/uci-defaults/92_add_user_section b/luci-app-oaf/root/etc/uci-defaults/92_add_user_section new file mode 100755 index 0000000..a584078 --- /dev/null +++ b/luci-app-oaf/root/etc/uci-defaults/92_add_user_section @@ -0,0 +1,7 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + set appfilter.user=user + commit appfilter +EOF +exit 0 diff --git a/oaf/src/af_client.c b/oaf/src/af_client.c index 9bb143f..549960c 100755 --- a/oaf/src/af_client.c +++ b/oaf/src/af_client.c @@ -22,6 +22,7 @@ #include "af_client_fs.h" #include "af_log.h" #include "af_utils.h" +#include "app_filter.h" DEFINE_RWLOCK(af_client_lock); diff --git a/oaf/src/af_client.h b/oaf/src/af_client.h index 859bc5b..4dd16c9 100755 --- a/oaf/src/af_client.h +++ b/oaf/src/af_client.h @@ -1,12 +1,12 @@ #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 MAC_ADDR_LEN 6 #define NF_CLIENT_TIMER_EXPIRE 1 #define MAX_CLIENT_ACTIVE_TIME 90 @@ -53,8 +53,7 @@ typedef struct af_client_info { app_visit_info_t visit_info[MAX_RECORD_APP_NUM]; }af_client_info_t; -#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" + int af_client_init(void); diff --git a/oaf/src/af_utils.c b/oaf/src/af_utils.c index 5ea2daf..8473a07 100755 --- a/oaf/src/af_utils.c +++ b/oaf/src/af_utils.c @@ -296,6 +296,7 @@ static int k_vsscanf(const char *buf, const char *fmt, va_list args) return num; } + int k_sscanf(const char *buf, const char *fmt, ...) { va_list args; diff --git a/oaf/src/app_filter.c b/oaf/src/app_filter.c index 97f3d7a..55d21ce 100755 --- a/oaf/src/app_filter.c +++ b/oaf/src/app_filter.c @@ -681,27 +681,36 @@ int af_match_one(flow_info_t *flow, af_feature_node_t *node) int app_filter_match(flow_info_t *flow) { af_feature_node_t *n,*node; + af_client_info_t *client = NULL; feature_list_read_lock(); if(!list_empty(&af_feature_head)) { list_for_each_entry_safe(node, n, &af_feature_head, head) { if(af_match_one(flow, node)) { flow->app_id = node->app_id; + client = find_af_client_by_ip(flow->src); + if (!client){ + goto EXIT; + } + // ˻ûĹˣûƥ䵽û + if (is_user_match_enable() && !find_af_mac(client->mac)){ + AF_ERROR("not match mac:"MAC_FMT"\n", MAC_ARRAY(client->mac)); + goto EXIT; + } if (af_get_app_status(node->app_id)){ flow->drop = AF_TRUE; feature_list_read_unlock(); return AF_TRUE; } else { - flow->drop = AF_FALSE; - feature_list_read_unlock(); - return AF_FALSE; + goto EXIT; } } - } } +EXIT: + flow->drop = AF_FALSE; feature_list_read_unlock(); return AF_FALSE; } @@ -940,6 +949,7 @@ static int __init app_filter_init(void) AF_INFO("appfilter version:"AF_VERSION"\n"); af_log_init(); af_register_dev(); + af_mac_list_init(); af_init_app_status(); load_feature_config(); init_af_client_procfs(); @@ -970,6 +980,7 @@ static void app_filter_fini(void) #endif af_clean_feature_list(); + af_mac_list_clear(); af_unregister_dev(); af_log_exit(); af_client_exit(); diff --git a/oaf/src/app_filter.h b/oaf/src/app_filter.h index 458be92..2f3bef3 100755 --- a/oaf/src/app_filter.h +++ b/oaf/src/app_filter.h @@ -29,12 +29,15 @@ ((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 @@ -105,13 +108,20 @@ typedef struct af_feature_node{ 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 diff --git a/oaf/src/app_filter_config.c b/oaf/src/app_filter_config.c index 2ac6194..4615fd5 100755 --- a/oaf/src/app_filter_config.c +++ b/oaf/src/app_filter_config.c @@ -50,6 +50,7 @@ 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}; @@ -104,7 +105,147 @@ int af_change_app_status(cJSON * data_obj, int status) 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_ERROR("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){ + u8 mac_tmp[MAC_ADDR_LEN]; + int ret = 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; + memcpy(mac_hex, mac_tmp, MAC_ADDR_LEN); + return 0; +} +int af_set_mac_list(cJSON * data_obj) +{ + int i; + int id; + int type; + u8 mac_hex[MAC_ADDR_LEN] = {0}; + if (!data_obj) { + AF_ERROR("data obj is null\n"); + return -1; + } + cJSON *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)){ + AF_ERROR("mac format error: %s\n", mac_obj->valuestring); + continue; + } + af_mac_add(mac_hex); + } + printk("## mac num = %d\n", total_mac); + return 0; +} void af_init_app_status(void) { @@ -177,6 +318,9 @@ int af_config_handle(char *config, unsigned int len) 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; diff --git a/open-app-filter/files/appfilter.sh b/open-app-filter/files/appfilter.sh index e600aac..b096c9f 100755 --- a/open-app-filter/files/appfilter.sh +++ b/open-app-filter/files/appfilter.sh @@ -64,6 +64,25 @@ load_rule() 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