增加上网记录统计功能,增加客户端统计模块
This commit is contained in:
parent
7d76a613ba
commit
0055281ca0
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -81,6 +81,7 @@ if class_fd then
|
||||
end
|
||||
class_fd:close()
|
||||
end
|
||||
m:section(SimpleSection).template = "admin_network/user_status"
|
||||
|
||||
|
||||
return m
|
||||
|
59
luci-app-oaf/luasrc/view/admin_network/user_status.htm
Executable file
59
luci-app-oaf/luasrc/view/admin_network/user_status.htm
Executable file
@ -0,0 +1,59 @@
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(5, '<%=url('admin/network/user_status')%>', null,
|
||||
function(x, st)
|
||||
{
|
||||
var tb = document.getElementById('user_status_table');
|
||||
if (st && st && tb)
|
||||
{
|
||||
var rows = [];
|
||||
for (var i = 0; i < st.length; i++)
|
||||
{
|
||||
if(st[i].hostname == ""){
|
||||
st[i].hostname="unknown"
|
||||
}
|
||||
var action_status=""
|
||||
if(st[i].latest_action == 1)
|
||||
action_status="已过滤"
|
||||
else
|
||||
action_status="未过滤"
|
||||
|
||||
<!--st[i].latest_time=st[i].latest_time+"<br>"+st[i].latest_time-->
|
||||
rows.push([
|
||||
st[i].hostname,
|
||||
st[i].mac,
|
||||
st[i].ip,
|
||||
st[i].appname,
|
||||
st[i].drop_num.toString(),
|
||||
st[i].total_num.toString(),
|
||||
st[i].latest_time,
|
||||
action_status
|
||||
]);
|
||||
}
|
||||
|
||||
cbi_update_table(tb, rows, '<em><%:no data%></em>');
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
//]]></script>
|
||||
|
||||
<div class="cbi-section">
|
||||
<h3><%:访问记录%></h3>
|
||||
<div class="table" id="user_status_table">
|
||||
<div class="tr table-titles">
|
||||
<div class="th"><%:Hostname%></div>
|
||||
<div class="th"><%:mac地址%></div>
|
||||
<div class="th"><%:ip地址%></div>
|
||||
<div class="th"><%:应用名称%></div>
|
||||
<div class="th"><%:丢包次数%></div>
|
||||
<div class="th"><%:总访问次数%></div>
|
||||
<div class="th"><%:最后访问时间%></div>
|
||||
<div class="th"><%:过滤状态%></div>
|
||||
|
||||
</div>
|
||||
<div class="tr placeholder">
|
||||
<div class="td"><em><%:Collecting data...%></em></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,7 @@
|
||||
|
||||
msgid "website"
|
||||
msgstr "常用网站"
|
||||
|
||||
msgid "appfilter"
|
||||
msgstr "应用过滤"
|
||||
|
||||
@ -39,4 +42,7 @@ msgid "App Filter Rules"
|
||||
msgstr "应用过滤规则"
|
||||
|
||||
msgid "Enable App Filter"
|
||||
msgstr "开启应用过滤"
|
||||
msgstr "开启应用过滤"
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
277
oaf/src/af_client.c
Executable file
277
oaf/src/af_client.c
Executable file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
Author:Derry
|
||||
Date: 2019/11/12
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_acct.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/ip.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "af_client.h"
|
||||
#include "af_client_fs.h"
|
||||
#include "af_log.h"
|
||||
|
||||
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 ;
|
||||
}
|
||||
|
||||
|
65
oaf/src/af_client.h
Executable file
65
oaf/src/af_client.h
Executable file
@ -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
|
222
oaf/src/af_client_fs.c
Executable file
222
oaf/src/af_client_fs.c
Executable file
@ -0,0 +1,222 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "af_log.h"
|
||||
#include "af_client.h"
|
||||
|
||||
extern struct list_head af_client_list_table[MAX_AF_CLIENT_HASH_SIZE];
|
||||
struct af_client_iter_state {
|
||||
unsigned int bucket;
|
||||
void *head;
|
||||
};
|
||||
|
||||
static void *af_client_get_first(struct seq_file *seq)
|
||||
{
|
||||
struct af_client_iter_state *st = seq->private;
|
||||
for (st->bucket = 0;st->bucket < MAX_AF_CLIENT_HASH_SIZE;st->bucket++){
|
||||
if(!list_empty(&(af_client_list_table[st->bucket]))){
|
||||
st->head = &(af_client_list_table[st->bucket]);
|
||||
return af_client_list_table[st->bucket].next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *af_client_get_next(struct seq_file *seq,
|
||||
void *head)
|
||||
{
|
||||
struct af_client_iter_state *st = seq->private;
|
||||
struct hlist_node * node = (struct hlist_node *)head;
|
||||
|
||||
node = node->next;
|
||||
if (node != st->head){
|
||||
return node;
|
||||
}
|
||||
else{
|
||||
st->bucket++;
|
||||
for (;st->bucket < MAX_AF_CLIENT_HASH_SIZE;st->bucket++) {
|
||||
if(!list_empty(&(af_client_list_table[st->bucket]))){
|
||||
st->head = &(af_client_list_table[st->bucket]);
|
||||
return af_client_list_table[st->bucket].next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void *af_client_get_idx(struct seq_file *seq, loff_t pos)
|
||||
{
|
||||
void *head = af_client_get_first(seq);
|
||||
|
||||
if (head)
|
||||
while (pos && (head = af_client_get_next(seq, head)))
|
||||
pos--;
|
||||
|
||||
return pos ? NULL : head;
|
||||
}
|
||||
|
||||
static void *af_client_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
AF_CLIENT_LOCK_R();
|
||||
if (*pos == 0){
|
||||
return SEQ_START_TOKEN;
|
||||
}
|
||||
|
||||
return af_client_get_idx(s, *pos - 1);
|
||||
}
|
||||
|
||||
static void *af_client_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
(*pos)++;
|
||||
if (v == SEQ_START_TOKEN)
|
||||
return af_client_get_idx(s, 0);
|
||||
|
||||
return af_client_get_next(s, v);
|
||||
}
|
||||
|
||||
static void af_client_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
7
oaf/src/af_client_fs.h
Executable file
7
oaf/src/af_client_fs.h
Executable file
@ -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
|
@ -7,7 +7,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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;}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;;]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user