diff --git a/luci-app-oaf/Makefile b/luci-app-oaf/Makefile
index 5d89424..f5ed5fb 100755
--- a/luci-app-oaf/Makefile
+++ b/luci-app-oaf/Makefile
@@ -9,7 +9,7 @@ LUCI_TITLE:=Open App Filter Module
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+kmod-oaf +appfilter
PKG_NAME:=luci-app-oaf
-PKG_VERSION:=1.0
+PKG_VERSION:=3.0
PKG_RELEASE:=1
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
diff --git a/luci-app-oaf/luasrc/controller/appfilter.lua b/luci-app-oaf/luasrc/controller/appfilter.lua
index f9ff51e..6bb4a09 100755
--- a/luci-app-oaf/luasrc/controller/appfilter.lua
+++ b/luci-app-oaf/luasrc/controller/appfilter.lua
@@ -9,4 +9,88 @@ function index()
page = entry({"admin", "network", "appfilter"}, cbi("appfilter/appfilter"), _("appfilter"))
page.dependent = true
+
+ page = entry({"admin", "network", "user_status"}, call("user_status"), 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+)")
+ print(ln)
+ if dst_mac == mac then
+ print("match mac", mac, "hostname=", name);
+ fd:close()
+ return name
+ end
+ end
+ fd:close()
+ return ""
+end
+
+function get_app_name_by_id(appid)
+ local class_fd = io.popen("find /etc/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 s = require "luci.tools.status"
+ local json = require "luci.jsonc"
+ luci.http.prepare_content("application/json")
+ tb={}
+ obj={};
+ obj.hostname="derry"
+ obj.ip="192.168.10.199"
+ obj.mac="192.168.10.199"
+ tb[#tb+1]=obj
+ --local fs=require "nixio.fs"
+ --local ok, status_data = pcall(json.parse, fs.readfile("/proc/net/af_client"))
+ --luci.http.write_json(tb);
+ local fd = io.open("/proc/net/af_client","r")
+
+ status_buf=fd:read('*a')
+ fd:close()
+ user_array=json.parse(status_buf)
+
+ 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)
+ 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=visit_array[j].total_num,
+ drop_num=visit_array[j].drop_num,
+ latest_action=visit_array[j].latest_action,
+ latest_time=os.date("%Y/%m/%d %H:%M:%S", visit_array[j].latest_time)
+ }
+ end
+ end
+ table.sort(history, cmp_func)
+ --luci.http.write(history);
+ luci.http.write_json(history);
+end
+
diff --git a/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua b/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua
index 3a67412..ea50ac7 100755
--- a/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua
+++ b/luci-app-oaf/luasrc/model/cbi/appfilter/appfilter.lua
@@ -81,6 +81,7 @@ if class_fd then
end
class_fd:close()
end
+m:section(SimpleSection).template = "admin_network/user_status"
return m
diff --git a/luci-app-oaf/luasrc/view/admin_network/user_status.htm b/luci-app-oaf/luasrc/view/admin_network/user_status.htm
new file mode 100755
index 0000000..7dc7373
--- /dev/null
+++ b/luci-app-oaf/luasrc/view/admin_network/user_status.htm
@@ -0,0 +1,59 @@
+
+
+
+
<%:访问记录%>
+
+
+
<%:Hostname%>
+
<%:mac地址%>
+
<%:ip地址%>
+
<%:应用名称%>
+
<%:丢包次数%>
+
<%:总访问次数%>
+
<%:最后访问时间%>
+
<%:过滤状态%>
+
+
+
+
<%:Collecting data...%>
+
+
+
+
diff --git a/luci-app-oaf/po/zh-cn/oaf.po b/luci-app-oaf/po/zh-cn/oaf.po
index deb3a4f..b133f74 100755
--- a/luci-app-oaf/po/zh-cn/oaf.po
+++ b/luci-app-oaf/po/zh-cn/oaf.po
@@ -1,4 +1,7 @@
+msgid "website"
+msgstr "常用网站"
+
msgid "appfilter"
msgstr "应用过滤"
@@ -39,4 +42,7 @@ msgid "App Filter Rules"
msgstr "应用过滤规则"
msgid "Enable App Filter"
-msgstr "开启应用过滤"
\ No newline at end of file
+msgstr "开启应用过滤"
+
+
+
diff --git a/oaf/Makefile b/oaf/Makefile
index f0725ce..51aa424 100755
--- a/oaf/Makefile
+++ b/oaf/Makefile
@@ -3,11 +3,13 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=oaf
-PKG_RELEASE:=3
+PKG_VERSION:=3.0
+PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
PKG_AUTOLOAD:=oaf
+RSTRIP:=:
define KernelPackage/oaf
SECTION:=Derry Apps
diff --git a/oaf/src/Makefile b/oaf/src/Makefile
index 7b5aad0..96c1f61 100755
--- a/oaf/src/Makefile
+++ b/oaf/src/Makefile
@@ -1,2 +1,2 @@
-oaf-objs := app_filter.o af_utils.o regexp.o cJSON.o app_filter_config.o af_log.o
+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
diff --git a/oaf/src/af_client.c b/oaf/src/af_client.c
new file mode 100755
index 0000000..3bede34
--- /dev/null
+++ b/oaf/src/af_client.c
@@ -0,0 +1,277 @@
+/*
+ Author:Derry
+ Date: 2019/11/12
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "af_client.h"
+#include "af_client_fs.h"
+#include "af_log.h"
+
+DEFINE_RWLOCK(af_client_lock);
+
+u32 total_client = 0;
+struct list_head af_client_list_table[MAX_AF_CLIENT_HASH_SIZE];
+
+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();
+}
+
+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)){
+ node->update_jiffies = jiffies;
+ return node;
+ }
+ }
+ return NULL;
+}
+
+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;
+}
+
+static 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:%d cur:%d, interval:%d\n", MAC_ARRAY(node->mac),
+ node->update_jiffies, HZ, (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();
+}
+
+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 nfclient_hook(void *priv,
+ struct sk_buff *skb,
+ const struct nf_hook_state *state) {
+#else
+static u_int32_t nfclient_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;
+// 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);
+ }
+
+ struct iphdr *iph = NULL;
+ iph = ip_hdr(skb);
+ if (!iph) {
+ return NF_ACCEPT;
+ }
+
+ AF_CLIENT_LOCK_W();
+ nfc = find_af_client(smac);
+ if (!nfc){
+ AF_DEBUG("from dev:%s [%s] %pI4--->%pI4", skb->dev, (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->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 = nfclient_hook,
+ .pf = PF_INET,
+ .hooknum = NF_INET_FORWARD,
+ .priority = NF_IP_PRI_FIRST + 1,
+ },
+};
+#else
+static struct nf_hook_ops af_client_ops[] = {
+ {
+ .hook = nfclient_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 ;
+}
+
+
diff --git a/oaf/src/af_client.h b/oaf/src/af_client.h
new file mode 100755
index 0000000..c391241
--- /dev/null
+++ b/oaf/src/af_client.h
@@ -0,0 +1,65 @@
+#ifndef __AF_CLIENT_H__
+#define __AF_CLIENT_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
+
+
+#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 32
+
+
+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 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;
+ 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);
+
+void af_client_exit(void);
+af_client_info_t * find_af_client_by_ip(unsigned int ip);
+
+#endif
diff --git a/oaf/src/af_client_fs.c b/oaf/src/af_client_fs.c
new file mode 100755
index 0000000..8a64fff
--- /dev/null
+++ b/oaf/src/af_client_fs.c
@@ -0,0 +1,222 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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)
+{
+ seq_printf(s, "%s", "]");
+ 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;
+ int i;
+ int j;
+ if (v == SEQ_START_TOKEN) {
+ index = 0;
+ seq_printf(s, "%s", "[");
+ return 0;
+ }
+ if(index > 0)
+ seq_printf(s, "%s", ",");
+ index++;
+ af_client_info_t *node = (af_client_info_t *)v;
+
+ cJSON *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);
+ cJSON *visit_info_array = cJSON_CreateArray();
+
+ for(i = 0; i < MAX_RECORD_APP_NUM; i++){
+ if(node->visit_info[i].app_id == 0)
+ break;
+ cJSON *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, "latest_time", node->visit_info[i].latest_time);
+ cJSON_AddNumberToObject(visit_obj, "total_num", node->visit_info[i].total_num);
+ cJSON_AddNumberToObject(visit_obj, "drop_num", node->visit_info[i].drop_num);
+ cJSON *history_array = cJSON_CreateArray();
+ for(j = 0; j < MAX_VISIT_HISTORY_TIME; j++){
+ if(node->visit_info[i].history_time[j] <= 0)
+ continue;
+ cJSON *history_obj = cJSON_CreateObject();
+ cJSON_AddNumberToObject(visit_obj, "action", node->visit_info[i].history_time[j]);
+ cJSON_AddNumberToObject(visit_obj, "time", node->visit_info[i].action[j]);
+ cJSON_AddItemToArray(history_array, history_obj);
+ }
+
+ cJSON_AddItemToObject(visit_obj, "history_info", history_array);
+ cJSON_AddItemToArray(visit_info_array, visit_obj);
+ }
+
+ cJSON_AddItemToObject(root_obj, "visit_info", visit_info_array);
+ char *out = cJSON_Print(root_obj);
+ if(!out)
+ return 0;
+ cJSON_Minify(out);
+ seq_printf(s, "%s", out);
+ kfree(out);
+ 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;
+}
+
+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,
+};
+
+
+#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);
+}
+
diff --git a/oaf/src/af_client_fs.h b/oaf/src/af_client_fs.h
new file mode 100755
index 0000000..0140c27
--- /dev/null
+++ b/oaf/src/af_client_fs.h
@@ -0,0 +1,7 @@
+#ifndef __AF_CLIENT_FS_H__
+#define __AF_CLIENT_FS_H__
+
+int init_af_client_procfs(void);
+void finit_af_client_procfs(void);
+
+#endif
diff --git a/oaf/src/app_filter.c b/oaf/src/app_filter.c
index 3ad15a2..67e8607 100755
--- a/oaf/src/app_filter.c
+++ b/oaf/src/app_filter.c
@@ -7,7 +7,6 @@
#include
#include
#include
-
#include
#include
#include
@@ -23,10 +22,13 @@
#include "app_filter.h"
#include "af_utils.h"
#include "af_log.h"
+#include "af_client.h"
+#include "af_client_fs.h"
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("destan19@126.com");
MODULE_DESCRIPTION("app filter module");
-MODULE_VERSION("1.0.1");
+MODULE_VERSION("3.0.1");
struct list_head af_feature_head = LIST_HEAD_INIT(af_feature_head);
DEFINE_RWLOCK(af_feature_lock);
@@ -148,7 +150,7 @@ int add_app_feature(int appid, char *name, char *feature)
char dict[128] = {0};
int proto = IPPROTO_TCP;
if (!name || !feature) {
- printk("error, name or feature is null\n");
+ AF_ERROR("error, name or feature is null\n");
return -1;
}
// tcp;8000;www.sina.com;0:get_name;00:0a-01:11
@@ -183,8 +185,8 @@ int add_app_feature(int appid, char *name, char *feature)
param_num ++;
begin = p + 1;
}
- if (AF_DICT_PARAM_INDEX != param_num) {
- printk("invalid feature:%s\n", feature);
+ if (AF_DICT_PARAM_INDEX != param_num && strlen(feature) > MIN_FEATURE_STR_LEN) {
+ AF_ERROR("22 invalid feature:%s\n", feature);
return -1;
}
strncpy(dict, begin, p - begin);
@@ -276,18 +278,17 @@ void load_feature_buf_from_file(char **config_buf)
printk("open feature file failed\n");
return -1;
}
- //inode = fp->f_dentry->d_inode;
- //inode = fp->f_path.dentry->d_inode;
+
inode = fp->f_inode;
size = inode->i_size;
- printk("file size: %d\n", size);
+ AF_INFO("feature file size: %d\n", size);
if (size == 0) {
- printk("warning,file size = %d\n", size);
+ AF_WARN("warning, file size = %d\n", size);
return;
}
*config_buf = (char *) kzalloc( sizeof(char) * size, GFP_KERNEL);
if(NULL == *config_buf ) {
- printk("alloc buf fail\n");
+ AF_ERROR("alloc buf fail\n");
filp_close(fp, NULL);
return -1;
}
@@ -299,7 +300,6 @@ void load_feature_buf_from_file(char **config_buf)
#else
vfs_read(fp, *config_buf, size, &(fp->f_pos));
#endif
- //fp->f_op->read(fp, *config_buf, size, &(fp->f_pos));
set_fs(fs);
filp_close(fp, NULL);
return size;
@@ -307,11 +307,11 @@ void load_feature_buf_from_file(char **config_buf)
void load_feature_config(void)
{
- printk("begin load feature config.....\n");
+ AF_INFO("begin load feature config.....\n");
char *feature_buf = NULL;
load_feature_buf_from_file(&feature_buf);
if (!feature_buf) {
- printk("error, feature buf is null\n");
+ AF_ERROR("error, feature buf is null\n");
return;
}
@@ -375,7 +375,7 @@ int parse_flow_base(struct sk_buff *skb, flow_info_t *flow)
return -1;
}
iph = ip_hdr(skb);
- if ( !iph ) {
+ if (!iph) {
return -1;
}
flow->ct = ct;
@@ -389,14 +389,14 @@ int parse_flow_base(struct sk_buff *skb, flow_info_t *flow)
flow->l4_len = ntohs(iph->tot_len) - iph->ihl * 4 - tcph->doff * 4;
flow->dport = htons(tcph->dest);
flow->sport = htons(tcph->source);
- break;
+ return 0;
case IPPROTO_UDP:
udph = (struct udphdr *)(iph + 1);
flow->l4_data = skb->data + iph->ihl * 4 + 8;
flow->l4_len = ntohs(udph->len) - 8;
flow->dport = htons(udph->dest);
flow->sport = htons(udph->source);
- break;
+ return 0;
case IPPROTO_ICMP:
break;
default:
@@ -688,10 +688,12 @@ int app_filter_match(flow_info_t *flow)
{
flow->app_id = node->app_id;
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;
}
@@ -705,6 +707,89 @@ int app_filter_match(flow_info_t *flow)
}
#define APP_FILTER_DROP_BITS 0xf0000000
+u_int32_t af_get_timestamp_sec(void)
+{
+ struct timespec ts;
+ ts = current_kernel_time();
+ return ts.tv_sec;
+}
+
+
+
+int __af_update_client_app_info(flow_info_t *flow, af_client_info_t *node)
+{
+ int i;
+ int index = -1;
+ if(!node)
+ return -1;
+ if(!flow)
+ return -1;
+ AF_INFO("%s %d visit_app_num = %d\n", __func__, __LINE__, node->visit_app_num);
+ int found = 0;
+
+ for(i = 0; i < MAX_RECORD_APP_NUM; i++){
+ if(node->visit_info[i].app_id == flow->app_id){
+ index = i;
+ found = 1;
+ break;
+ }
+ if(node->visit_info[i].app_id == 0)
+ break;
+ }
+
+ if(!found){
+ index = 0;
+ //ѯϵ
+ for(i = 0; i < MAX_RECORD_APP_NUM; i++){
+ if(node->visit_info[i].latest_time == 0){
+ index = i;
+ break;
+ }
+ if(node->visit_info[i].latest_time < node->visit_info[index].latest_time){
+ // ֮ǰ
+ node->visit_info[i].total_num = 0;
+ node->visit_info[i].drop_num = 0;
+ index = i;
+ }
+ }
+ }
+
+
+ if(index < 0 || index >= MAX_RECORD_APP_NUM){
+ AF_ERROR("invalid index:%d\n\n", index);
+ return 0;
+ }
+ node->visit_info[index].total_num++;
+ if(flow->drop)
+ node->visit_info[index].drop_num++;
+
+ node->visit_info[index].app_id = flow->app_id;
+ node->visit_info[index].latest_time = af_get_timestamp_sec();
+ AF_DEBUG("update time = %u\n", node->visit_info[index].latest_time);
+ node->visit_info[index].latest_action = flow->drop;
+ AF_INFO("[%d] %pI4 visit %d, time=%d action=%s, %d/%d\n", index, &node->ip, flow->app_id,
+ node->visit_info[index].latest_time, node->visit_info[index].latest_action ? "Drop" : "Accept",
+ node->visit_info[index].drop_num, node->visit_info[index].total_num);
+ // todo: history
+ return 0;
+}
+
+void af_update_client_app_info(flow_info_t *flow)
+{
+ int i;
+ int index = 0;
+ 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();
+}
/* netfilterעĹ */
@@ -728,18 +813,17 @@ static u_int32_t app_filter_hook(unsigned int hook,
#else
struct nf_conn *ct = (struct nf_conn *)skb->nfct;
#endif
- if (ct == NULL) {
- //AF_ERROR("ct is null\n");
+ if(ct == NULL) {
return NF_ACCEPT;
}
- if (!nf_ct_is_confirmed(ct)){
+ if(!nf_ct_is_confirmed(ct)){
return NF_ACCEPT;
}
#if defined(CONFIG_NF_CONNTRACK_MARK)
- if (ct->mark != 0)
- if (APP_FILTER_DROP_BITS == (ct->mark & APP_FILTER_DROP_BITS)){
+ if(ct->mark != 0)
+ if(APP_FILTER_DROP_BITS == (ct->mark & APP_FILTER_DROP_BITS)){
return NF_DROP;
}
#endif
@@ -748,7 +832,7 @@ static u_int32_t app_filter_hook(unsigned int hook,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
struct nf_conn_acct *acct;
acct = nf_conn_acct_find(ct);
- if (!acct)
+ 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);
@@ -764,22 +848,25 @@ static u_int32_t app_filter_hook(unsigned int hook,
+ (unsigned long long)atomic64_read(&counter[IP_CT_DIR_REPLY].packets);
#endif
- if (total_packets > MAX_PARSE_PKT_NUM){
+ if(total_packets > MAX_PARSE_PKT_NUM){
return NF_ACCEPT;
}
memset((char *)&flow, 0x0, sizeof(flow_info_t));
- parse_flow_base(skb, &flow);
+ 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);
+ af_update_client_app_info(&flow);
- if (app_filter_match(&flow)){
+ if(flow.drop){
#if defined(CONFIG_NF_CONNTRACK_MARK)
ct->mark |= APP_FILTER_DROP_BITS;
#endif
- AF_INFO("##########drop appid = %d#############\n\n\n", flow.app_id);
+ AF_LMT_INFO("##drop appid = %d\n\n\n", flow.app_id);
return NF_DROP;
}
return NF_ACCEPT;
@@ -826,26 +913,26 @@ void TEST_cJSON(void)
kfree(out);
}
+
/*
ģʼ
*/
static int __init app_filter_init(void)
{
AF_INFO("appfilter version:"AF_VERSION"\n");
- AF_DEBUG("app filter module init\n");
af_log_init();
- //TEST_regexp();
af_register_dev();
af_init_app_status();
load_feature_config();
+ init_af_client_procfs();
// show_feature_list();
-// TEST_cJSON();
+ af_client_init();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_register_net_hooks(&init_net, app_filter_ops, ARRAY_SIZE(app_filter_ops));
#else
nf_register_hooks(app_filter_ops, ARRAY_SIZE(app_filter_ops));
#endif
- printk("init app filter ........ok\n");
+ AF_INFO("init app filter ........ok\n");
return 0;
}
@@ -854,7 +941,7 @@ static int __init app_filter_init(void)
*/
static void app_filter_fini(void)
{
- AF_DEBUG("app filter module exit\n");
+ AF_INFO("app filter module exit\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_unregister_net_hooks(&init_net, app_filter_ops, ARRAY_SIZE(app_filter_ops));
#else
@@ -864,9 +951,12 @@ static void app_filter_fini(void)
af_clean_feature_list();
af_unregister_dev();
af_log_exit();
+ af_client_exit();
+ finit_af_client_procfs();
return ;
}
+
module_init(app_filter_init);
module_exit(app_filter_fini);
diff --git a/oaf/src/app_filter.h b/oaf/src/app_filter.h
index b1e51db..b45c1d3 100755
--- a/oaf/src/app_filter.h
+++ b/oaf/src/app_filter.h
@@ -1,13 +1,14 @@
#ifndef APP_FILTER_H
#define APP_FILTER_H
-#define AF_VERSION "1.0.1"
+#define AF_VERSION "3.0.1"
#define AF_FEATURE_CONFIG_FILE "/etc/appfilter/feature.cfg"
#define MAX_PARSE_PKT_NUM 16
#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
@@ -80,6 +81,7 @@ typedef struct flow_info{
http_proto_t http;
https_proto_t https;
u_int32_t app_id;
+ u_int8_t drop;
}flow_info_t;
diff --git a/oaf/src/cJSON.c b/oaf/src/cJSON.c
index 8b22453..e71f1d8 100755
--- a/oaf/src/cJSON.c
+++ b/oaf/src/cJSON.c
@@ -396,6 +396,102 @@ static char *print_object(cJSON *item,int depth)
*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;}
diff --git a/oaf/src/cJSON.h b/oaf/src/cJSON.h
index e7c794c..97b701c 100755
--- a/oaf/src/cJSON.h
+++ b/oaf/src/cJSON.h
@@ -77,7 +77,7 @@ 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);
diff --git a/open-app-filter/Makefile b/open-app-filter/Makefile
index a9a495d..e8f9d31 100755
--- a/open-app-filter/Makefile
+++ b/open-app-filter/Makefile
@@ -2,6 +2,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=appfilter
+PKG_VERSION:=3.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
diff --git a/open-app-filter/files/feature.cfg b/open-app-filter/files/feature.cfg
index 733308e..09faf0b 100755
--- a/open-app-filter/files/feature.cfg
+++ b/open-app-filter/files/feature.cfg
@@ -4,6 +4,7 @@
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;;]
#class game
2001 王者荣耀:[tcp;;;;;00:33|01:66|02:00|03:09,udp;;;;;00:01|01:02|02:00|03:00]
@@ -45,12 +46,23 @@
4004 拼多多:[tcp;;;pinduoduo;;,tcp;;;yangkeduo.com;;,tcp;;;s1p.cdntip.com;;]
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;;]
+
#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;;]
@@ -60,6 +72,13 @@
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;;;;,tcp;;;xunlei.com;;,tcp;;;sandai;;,udp;;8000;;;,udp;;12346;;;,udp;12346;;;;]
@@ -68,3 +87,81 @@
7004 ftp文件传输:[tcp;;21;;;]
7005 Vivo应用商店:[tcp;;443;appstore.vivo;;,tcp;;443;apkappdefwsdl.vivo;;]
+#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;;]
+8045 缤客:[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;;]
+