Merge Mainline
This commit is contained in:
commit
2a12903b64
@ -6,81 +6,82 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gq-client
|
||||
PKG_NAME:=GoQuiet
|
||||
PKG_VERSION:=1.2.2
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/cbeuw/GoQuiet.git
|
||||
PKG_SOURCE_VERSION:=013cdfdf72000dcd4691799c37a0cf960ab4c82f
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
|
||||
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
|
||||
|
||||
PKG_BUILD_DEPENDS:=golang/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
|
||||
GO_PKG:=github.com/cbeuw/GoQuiet
|
||||
GO_PKG_LDFLAGS:=-s -w
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||
|
||||
define Package/$(PKG_NAME)/temple
|
||||
define Package/gq-client
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=GoQuiet
|
||||
DEPENDS:=+libpthread
|
||||
TITLE:=GoQuiet Client
|
||||
DEPENDS:=$(GO_ARCH_DEPENDS) +libpthread
|
||||
URL:=https://github.com/cbeuw/GoQuiet
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
$(call Package/$(PKG_NAME)/temple)
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
endef
|
||||
|
||||
define Package/gq-server
|
||||
$(call Package/$(PKG_NAME)/temple)
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=GoQuiet Server
|
||||
DEPENDS:=$(GO_ARCH_DEPENDS) +libpthread
|
||||
URL:=https://github.com/cbeuw/GoQuiet
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
GoQuiet-client
|
||||
define Package/gq-client/description
|
||||
GoQuiet-Client
|
||||
endef
|
||||
|
||||
define Package/gq-server/description
|
||||
GoQuiet-server
|
||||
GoQuiet-Server
|
||||
endef
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
GOQUIET_NAME:=gq-client-linux-amd64-$(PKG_VERSION)
|
||||
GOQUIETSERVER_NAME:=gq-server-linux-amd64-$(PKG_VERSION)
|
||||
endif
|
||||
ifeq ($(ARCH),i386)
|
||||
GOQUIET_NAME:=gq-client-linux-386-$(PKG_VERSION)
|
||||
GOQUIETSERVER_NAME:=gq-server-linux-386-$(PKG_VERSION)
|
||||
endif
|
||||
ifeq ($(ARCH),mipsel)
|
||||
GOQUIET_NAME:=gq-client-linux-mips64-$(PKG_VERSION)
|
||||
endif
|
||||
ifeq ($(ARCH),mips)
|
||||
GOQUIET_NAME:=gq-client-linux-mips-$(PKG_VERSION)
|
||||
endif
|
||||
ifeq ($(ARCH),arm)
|
||||
GOQUIET_NAME:=gq-client-linux-arm-$(PKG_VERSION)
|
||||
GOQUIETSERVER_NAME:=gq-server-linux-arm-$(PKG_VERSION)
|
||||
endif
|
||||
ifeq ($(ARCH),aarch64)
|
||||
GOQUIET_NAME:=gq-client-linux-arm64-$(PKG_VERSION)
|
||||
GOQUIETSERVER_NAME:=gq-server-linux-arm64-$(PKG_VERSION)
|
||||
endif
|
||||
|
||||
define Build/Prepare
|
||||
[ ! -f $(PKG_BUILD_DIR)/gq-client ] && wget -O $(PKG_BUILD_DIR)/gq-client https://github.com/cbeuw/GoQuiet/releases/download/v$(PKG_VERSION)/$(GOQUIET_NAME)
|
||||
[ ! -f $(PKG_BUILD_DIR)/gq-server ] && wget -O $(PKG_BUILD_DIR)/gq-server https://github.com/cbeuw/GoQuiet/releases/download/v$(PKG_VERSION)/$(GOQUIETSERVER_NAME)
|
||||
tar -zxf $(DL_DIR)/$(PKG_SOURCE) -C $(PKG_BUILD_DIR) --strip-components 1
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
chmod +x $(PKG_BUILD_DIR)/gq-client && upx --ultra-brute $(PKG_BUILD_DIR)/gq-client
|
||||
chmod +x $(PKG_BUILD_DIR)/gq-server && upx --ultra-brute $(PKG_BUILD_DIR)/gq-server
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(eval GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/gq-client)
|
||||
$(call GoPackage/Build/Configure)
|
||||
$(call GoPackage/Build/Compile)
|
||||
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(GO_PKG_BUILD_BIN_DIR)/gq-client
|
||||
$(eval GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/gq-server)
|
||||
$(call GoPackage/Build/Configure)
|
||||
$(call GoPackage/Build/Compile)
|
||||
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(GO_PKG_BUILD_BIN_DIR)/gq-server
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/install
|
||||
define Package/gq-client/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gq-client $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(GO_PKG_BUILD_BIN_DIR)/gq-client $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
define Package/gq-server/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gq-server $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(GO_PKG_BUILD_BIN_DIR)/gq-server $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
$(eval $(call GoBinPackage,gq-client))
|
||||
$(eval $(call GoBinPackage,gq-server))
|
||||
$(eval $(call BuildPackage,gq-client))
|
||||
$(eval $(call BuildPackage,gq-server))
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=oaf
|
||||
PKG_VERSION:=3.0
|
||||
PKG_RELEASE:=2
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/destan19/OpenAppFilter.git
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2020-05-26
|
||||
PKG_SOURCE_VERSION:=bba08ecedaf97bd4bbb991e32b89eb81ad017da6
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
PKG_AUTOLOAD:=oaf
|
||||
RSTRIP:=:
|
||||
|
||||
define KernelPackage/oaf
|
||||
@ -19,13 +22,18 @@ define KernelPackage/oaf
|
||||
FILES:=$(PKG_BUILD_DIR)/oaf.ko
|
||||
DEPENDS:=+kmod-ipt-conntrack
|
||||
KCONFIG:=
|
||||
AUTOLOAD:=$(call AutoLoad,0,$(PKG_AUTOLOAD))
|
||||
endef
|
||||
|
||||
define KernelPackage/oaf/description
|
||||
open appfilter kernel module
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
tar xJf $(DL_DIR)/$(PKG_SOURCE) -C $(TMP_DIR)
|
||||
$(CP) $(TMP_DIR)/$(PKG_NAME)-$(PKG_VERSION)/oaf/src/* $(PKG_BUILD_DIR)
|
||||
rm -rf $(TMP_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
endef
|
||||
|
||||
MAKE_OPTS:= \
|
||||
$(KERNEL_MAKE_FLAGS) \
|
||||
@ -40,4 +48,3 @@ define Build/Compile
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,oaf))
|
||||
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
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
|
||||
@ -1,323 +0,0 @@
|
||||
/*
|
||||
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"
|
||||
#include "af_utils.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:%lu interval:%lu\n", MAC_ARRAY(node->mac),
|
||||
node->update_jiffies, (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();
|
||||
}
|
||||
|
||||
#define MAX_EXPIRED_VISIT_INFO_COUNT 10
|
||||
void flush_expired_visit_info(af_client_info_t *node)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
u_int32_t cur_timep = 0;
|
||||
int timeout = 0;
|
||||
cur_timep = af_get_timestamp_sec();
|
||||
for (i = 0; i < MAX_RECORD_APP_NUM; i++){
|
||||
if (node->visit_info[i].app_id == 0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_RECORD_APP_NUM; i++){
|
||||
if (count >= MAX_EXPIRED_VISIT_INFO_COUNT)
|
||||
break;
|
||||
|
||||
if (node->visit_info[i].total_num > 3){
|
||||
timeout = 180;
|
||||
}
|
||||
else{
|
||||
timeout = 60;
|
||||
}
|
||||
|
||||
if (cur_timep - node->visit_info[i].latest_time > timeout){
|
||||
// ³¬Ê±Çå³ý¼Ç¼
|
||||
memset(&node->visit_info[i], 0x0, sizeof(app_visit_info_t));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void af_visit_info_timer_handle(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) {
|
||||
flush_expired_visit_info(node);
|
||||
}
|
||||
}
|
||||
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){
|
||||
if (skb->dev)
|
||||
AF_DEBUG("from dev:%s [%s] %pI4--->%pI4", skb->dev->name, (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 ;
|
||||
}
|
||||
|
||||
|
||||
@ -1,69 +0,0 @@
|
||||
#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 64
|
||||
|
||||
|
||||
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);
|
||||
|
||||
void check_client_expire(void);
|
||||
|
||||
void af_visit_info_timer_handle(void);
|
||||
|
||||
#endif
|
||||
@ -1,224 +0,0 @@
|
||||
#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)
|
||||
continue;
|
||||
if(node->visit_info[i].total_num < 3)
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
#ifndef __AF_CLIENT_FS_H__
|
||||
#define __AF_CLIENT_FS_H__
|
||||
|
||||
int init_af_client_procfs(void);
|
||||
void finit_af_client_procfs(void);
|
||||
|
||||
#endif
|
||||
@ -1,79 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sysctl.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;
|
||||
|
||||
/*
|
||||
cat /proc/sys/oaf/debug
|
||||
*/
|
||||
static struct ctl_table oaf_table[] = {
|
||||
{
|
||||
.procname = "debug",
|
||||
.data = &af_log_lvl,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0666,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "test_mode",
|
||||
.data = &af_test_mode,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0666,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "enable",
|
||||
.data = &g_oaf_enable,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0666,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static struct ctl_table oaf_root_table[] = {
|
||||
{
|
||||
.procname = "oaf",
|
||||
.mode = 0555,
|
||||
.child = oaf_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
static struct ctl_table_header *oaf_table_header;
|
||||
|
||||
|
||||
static int af_init_log_sysctl(void)
|
||||
{
|
||||
struct ctl_table_header *hdr;
|
||||
oaf_table_header = register_sysctl_table(oaf_root_table);
|
||||
if (oaf_table_header == NULL){
|
||||
printk("init log sysctl...failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
printk("init oaf sysctl...ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_fini_log_sysctl(void)
|
||||
{
|
||||
if (oaf_table_header)
|
||||
unregister_sysctl_table(oaf_table_header);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int af_log_init(void){
|
||||
af_init_log_sysctl();
|
||||
}
|
||||
|
||||
int af_log_exit(void){
|
||||
af_fini_log_sysctl();
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
#ifndef __AF_DEBUG_H__
|
||||
#define __AF_DEBUG_H__
|
||||
extern int af_log_lvl;
|
||||
extern int af_test_mode;
|
||||
#define LOG(level, fmt, ...) do { \
|
||||
if ((level) <= af_log_lvl) { \
|
||||
printk(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LLOG(level, fmt, ...) do { \
|
||||
if ((level) <= af_log_lvl) { \
|
||||
pr_info_ratelimited(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define AF_ERROR(...) LOG(0, ##__VA_ARGS__)
|
||||
#define AF_WARN(...) LOG(1, ##__VA_ARGS__)
|
||||
#define AF_INFO(...) LOG(2, ##__VA_ARGS__)
|
||||
#define AF_DEBUG(...) LOG(3, ##__VA_ARGS__)
|
||||
|
||||
#define AF_LMT_ERROR(...) LLOG(0, ##__VA_ARGS__)
|
||||
#define AF_LMT_WARN(...) LLOG(1, ##__VA_ARGS__)
|
||||
#define AF_LMT_INFO(...) LLOG(2, ##__VA_ARGS__)
|
||||
#define AF_LMT_DEBUG(...) LLOG(3, ##__VA_ARGS__)
|
||||
|
||||
|
||||
#define TEST_MODE() (af_test_mode)
|
||||
int af_log_init(void);
|
||||
int af_log_exit(void);
|
||||
#endif
|
||||
@ -1,309 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/version.h>
|
||||
#include "af_utils.h"
|
||||
u_int32_t af_get_timestamp_sec(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
|
||||
struct timespec64 ts;
|
||||
ktime_get_ts64(&ts);
|
||||
return (u_int32_t)ts.tv_sec;
|
||||
#else
|
||||
struct timespec ts;
|
||||
ts = current_kernel_time();
|
||||
return ts.tv_sec;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int check_local_network_ip(unsigned int ip)
|
||||
{
|
||||
if ((ip & 0xffff0000) == 0xc0a80000)
|
||||
return 1;
|
||||
else if ((ip & 0xfff00000) == 0xac100000)
|
||||
return 1;
|
||||
else if ((ip & 0xff000000) == 0x0a000000)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_str(char *name, unsigned char *p, int len)
|
||||
{
|
||||
#define MAX_DUMP_STR_LEN 64
|
||||
char buf[MAX_DUMP_STR_LEN] = {0};
|
||||
int i;
|
||||
if (len > MAX_DUMP_STR_LEN) {
|
||||
len = MAX_DUMP_STR_LEN - 1;
|
||||
}
|
||||
printk("%s: ",name);
|
||||
strncpy(buf, p, len);
|
||||
printk("[%s]\n", buf);
|
||||
}
|
||||
|
||||
void dump_hex(char *name, unsigned char *p, int len)
|
||||
{
|
||||
#define MAX_DUMP_STR_LEN 64
|
||||
int i;
|
||||
if (len > MAX_DUMP_STR_LEN) {
|
||||
len = MAX_DUMP_STR_LEN - 1;
|
||||
}
|
||||
printk("%s: ",name);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i % 16 == 0)
|
||||
printk("\n");
|
||||
printk("%02X ",*(p + i));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
#ifndef va_arg
|
||||
typedef signed int acpi_native_int;
|
||||
#ifndef _VALIST
|
||||
#define _VALIST
|
||||
typedef char *va_list;
|
||||
#endif
|
||||
|
||||
#define _AUPBND (sizeof (acpi_native_int) - 1)
|
||||
#define _ADNBND (sizeof (acpi_native_int) - 1)
|
||||
|
||||
|
||||
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
|
||||
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
|
||||
#define va_end(ap) (void) 0
|
||||
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TOLOWER
|
||||
#define TOLOWER(x) ((x) | 0x20)
|
||||
#endif
|
||||
|
||||
|
||||
static long long k_simple_strtoll(const char *cp, char **endp, unsigned int base)
|
||||
{
|
||||
if (*cp == '-')
|
||||
return -simple_strtoull(cp + 1, endp, base);
|
||||
|
||||
return simple_strtoull(cp, endp, base);
|
||||
}
|
||||
|
||||
static int skip_atoi(const char **s)
|
||||
{
|
||||
int i=0;
|
||||
while (isdigit(**s))
|
||||
i = i*10 + *((*s)++) - '0';
|
||||
return i;
|
||||
}
|
||||
|
||||
char *skip_spaces(const char *str)
|
||||
{
|
||||
while (isspace(*str) && ((unsigned char )*str != 0xa0))
|
||||
++str;
|
||||
return (char *)str;
|
||||
}
|
||||
static int k_vsscanf(const char *buf, const char *fmt, va_list args)
|
||||
{
|
||||
const char *str = buf;
|
||||
char *next;
|
||||
char digit;
|
||||
int num = 0;
|
||||
u8 qualifier;
|
||||
u8 base;
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
|
||||
int field_width;
|
||||
#else
|
||||
s16 field_width;
|
||||
#endif
|
||||
bool is_sign;
|
||||
while (*fmt && *str) {
|
||||
if (isspace(*fmt)) {
|
||||
fmt = skip_spaces(++fmt);
|
||||
str = skip_spaces(str);
|
||||
}
|
||||
|
||||
if (*fmt != '%' && *fmt) {
|
||||
if (*fmt++ != *str++)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!*fmt)
|
||||
break;
|
||||
++fmt;
|
||||
|
||||
if (*fmt == '*') {
|
||||
while (!isspace(*fmt) && *fmt != '%' && *fmt)
|
||||
fmt++;
|
||||
while (!isspace(*str) && *str)
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
field_width = -1;
|
||||
if (isdigit(*fmt))
|
||||
field_width = skip_atoi(&fmt);
|
||||
qualifier = -1;
|
||||
if (*fmt == 'h' || TOLOWER(*fmt) == 'l' ||
|
||||
TOLOWER(*fmt) == 'z') {
|
||||
qualifier = *fmt++;
|
||||
if (unlikely(qualifier == *fmt)) {
|
||||
if (qualifier == 'h') {
|
||||
qualifier = 'H';
|
||||
fmt++;
|
||||
} else if (qualifier == 'l') {
|
||||
qualifier = 'L';
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!*fmt || !*str)
|
||||
break;
|
||||
base = 10;
|
||||
is_sign = 0;
|
||||
switch (*fmt++) {
|
||||
case 'c':
|
||||
{
|
||||
char *s = (char *)va_arg(args, char*);
|
||||
if (field_width == -1)
|
||||
field_width = 1;
|
||||
do {
|
||||
*s++ = *str++;
|
||||
} while (--field_width > 0 && *str);
|
||||
num++;
|
||||
}
|
||||
continue;
|
||||
case 's':
|
||||
{
|
||||
char *s = (char *)va_arg(args, char *);
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
|
||||
if(field_width == -1)
|
||||
field_width = INT_MAX;
|
||||
#else
|
||||
if (field_width == -1)
|
||||
field_width = SHRT_MAX;
|
||||
#endif
|
||||
str = skip_spaces(str);
|
||||
|
||||
while (*str && (!isspace(*str) || ((unsigned char )*str == 0xA0) )&& field_width--)
|
||||
*s++ = *str++;
|
||||
*s = '\0';
|
||||
num++;
|
||||
}
|
||||
continue;
|
||||
case 'n':
|
||||
{
|
||||
int *i = (int *)va_arg(args, int*);
|
||||
*i = str - buf;
|
||||
}
|
||||
continue;
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
break;
|
||||
case 'i':
|
||||
base = 0;
|
||||
case 'd':
|
||||
is_sign = 1;
|
||||
case 'u':
|
||||
break;
|
||||
case '%':
|
||||
if (*str++ != '%')
|
||||
return num;
|
||||
continue;
|
||||
default:
|
||||
return num;
|
||||
}
|
||||
str = skip_spaces(str);
|
||||
digit = *str;
|
||||
if (is_sign && digit == '-')
|
||||
digit = *(str + 1);
|
||||
if (!digit
|
||||
|| (base == 16 && !isxdigit(digit))
|
||||
|| (base == 10 && !isdigit(digit))
|
||||
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|
||||
|| (base == 0 && !isdigit(digit)))
|
||||
break;
|
||||
|
||||
switch (qualifier) {
|
||||
case 'H':
|
||||
if (is_sign) {
|
||||
signed char *s = (signed char *)va_arg(args, signed char *);
|
||||
*s = (signed char)simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned char *s = (unsigned char *)va_arg(args, unsigned char *);
|
||||
*s = (unsigned char)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (is_sign) {
|
||||
short *s = (short *)va_arg(args, short *);
|
||||
*s = (short)simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned short *s = (unsigned short *)va_arg(args, unsigned short *);
|
||||
*s = (unsigned short)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (is_sign) {
|
||||
long *l = (long *)va_arg(args, long *);
|
||||
*l = simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned long *l = (unsigned long *)va_arg(args, unsigned long *);
|
||||
*l = simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if (is_sign) {
|
||||
long long *l = (long long *)va_arg(args, long long *);
|
||||
*l = k_simple_strtoll(str, &next, base);
|
||||
} else {
|
||||
unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *);
|
||||
*l = simple_strtoull(str, &next, base);
|
||||
}
|
||||
break;
|
||||
case 'Z':
|
||||
case 'z':
|
||||
{
|
||||
size_t *s = (size_t *)va_arg(args, size_t *);
|
||||
*s = (size_t)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (is_sign) {
|
||||
int *i = (int *)va_arg(args, int *);
|
||||
*i = (int)simple_strtol(str, &next, base);
|
||||
} else {
|
||||
unsigned int *i = (unsigned int *)va_arg(args, unsigned int*);
|
||||
*i = (unsigned int)simple_strtoul(str, &next, base);
|
||||
}
|
||||
break;
|
||||
}
|
||||
num++;
|
||||
if (!next)
|
||||
break;
|
||||
str = next;
|
||||
}
|
||||
if (*fmt == '%' && *(fmt + 1) == 'n') {
|
||||
int *p = (int *)va_arg(args, int *);
|
||||
*p = str - buf;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
int k_sscanf(const char *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
va_start(args, fmt);
|
||||
i = k_vsscanf(buf, fmt, args);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
#ifndef AF_UTILS_H
|
||||
#define AF_UTILS_H
|
||||
u_int32_t af_get_timestamp_sec(void);
|
||||
|
||||
int check_local_network_ip(unsigned int ip);
|
||||
|
||||
void dump_str(char *name, unsigned char *p, int len);
|
||||
|
||||
void dump_hex(char *name, unsigned char *p, int len);
|
||||
|
||||
int k_sscanf(const char *buf, const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,983 +0,0 @@
|
||||
|
||||
/*
|
||||
author: destan19@126.com
|
||||
微信公众号: OpenWrt
|
||||
date:2019/1/10
|
||||
*/
|
||||
#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 "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("3.0.1");
|
||||
struct list_head af_feature_head = LIST_HEAD_INIT(af_feature_head);
|
||||
|
||||
DEFINE_RWLOCK(af_feature_lock);
|
||||
|
||||
#define feature_list_read_lock() read_lock_bh(&af_feature_lock);
|
||||
#define feature_list_read_unlock() read_unlock_bh(&af_feature_lock);
|
||||
#define feature_list_write_lock() write_lock_bh(&af_feature_lock);
|
||||
#define feature_list_write_unlock() write_unlock_bh(&af_feature_lock);
|
||||
|
||||
#if 0
|
||||
static void show_feature_list(void)
|
||||
{
|
||||
af_feature_node_t *n,*node;
|
||||
unsigned int count = 0;
|
||||
feature_list_read_lock();
|
||||
if(!list_empty(&af_feature_head)) { // handle qos
|
||||
list_for_each_entry_safe(node, n, &af_feature_head, head) {
|
||||
count ++;
|
||||
printk("[%d] id=%d appname:%s, dport:%d, host:%s, request:%s\n",
|
||||
count,
|
||||
node->app_id, node->app_name,
|
||||
node->dport,node->host_url, node->request_url);
|
||||
int i;
|
||||
for (i = 0;i < node->pos_num;i++){
|
||||
printk("(%d:%x)-->",
|
||||
node->pos_info[i].pos,
|
||||
node->pos_info[i].value);
|
||||
|
||||
}
|
||||
printk("\n----------------------------------------\n\n\n");
|
||||
}
|
||||
}
|
||||
feature_list_read_unlock();
|
||||
}
|
||||
static af_feature_node_t* af_find_feature(char *app_id)
|
||||
{
|
||||
af_feature_node_t *node;
|
||||
feature_list_read_lock();
|
||||
|
||||
if (!list_empty(&af_feature_head)) {
|
||||
list_for_each_entry(node, &af_feature_head, head) {
|
||||
if (node->app_id == app_id){
|
||||
feature_list_read_unlock();
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
feature_list_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int __add_app_feature(int appid,
|
||||
char *name,
|
||||
int proto,
|
||||
int src_port,
|
||||
int dst_port,
|
||||
char *host_url,
|
||||
char *request_url,
|
||||
char *dict)
|
||||
{
|
||||
af_feature_node_t *node = NULL;
|
||||
node = kzalloc(sizeof(af_feature_node_t), GFP_KERNEL);
|
||||
if (node == NULL) {
|
||||
printk("malloc feature memory error\n");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
node->app_id = appid;
|
||||
strcpy(node->app_name, name);
|
||||
node->proto = proto;
|
||||
node->dport = dst_port;
|
||||
node->sport = src_port;
|
||||
strcpy(node->host_url, host_url);
|
||||
strcpy(node->request_url, request_url);
|
||||
// 00:0a-01:11
|
||||
char *p = dict;
|
||||
char *begin = dict;
|
||||
char pos[32] = {0};
|
||||
int index = 0;
|
||||
int value = 0;
|
||||
|
||||
while (*p++) {
|
||||
if (*p == '|'){
|
||||
memset(pos, 0x0, sizeof(pos));
|
||||
strncpy(pos, begin, p - begin);
|
||||
k_sscanf(pos, "%d:%x",&index, &value);
|
||||
begin = p + 1;
|
||||
node->pos_info[node->pos_num].pos = index;
|
||||
node->pos_info[node->pos_num].value = value;
|
||||
node->pos_num++;
|
||||
}
|
||||
}
|
||||
|
||||
if (begin != dict) {
|
||||
strncpy(pos, begin, p - begin);
|
||||
k_sscanf(pos, "%d:%x",&index, &value);
|
||||
node->pos_info[node->pos_num].pos = index;
|
||||
node->pos_info[node->pos_num].value = value;
|
||||
node->pos_num++;
|
||||
}
|
||||
feature_list_write_lock();
|
||||
list_add(&(node->head), &af_feature_head);
|
||||
feature_list_write_unlock();
|
||||
}
|
||||
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};
|
||||
|
||||
char dst_port_str[16] = {0};
|
||||
char host_url[32] = {0};
|
||||
char request_url[128] = {0};
|
||||
char dict[128] = {0};
|
||||
int proto = IPPROTO_TCP;
|
||||
if (!name || !feature) {
|
||||
AF_ERROR("error, name or feature is null\n");
|
||||
return -1;
|
||||
}
|
||||
// tcp;8000;www.sina.com;0:get_name;00:0a-01:11
|
||||
|
||||
char *p = feature;
|
||||
char *begin = feature;
|
||||
int param_num = 0;
|
||||
while(*p++) {
|
||||
if (*p != ';')
|
||||
continue;
|
||||
|
||||
switch(param_num){
|
||||
|
||||
case AF_PROTO_PARAM_INDEX:
|
||||
strncpy(proto_str, begin, p - begin);
|
||||
break;
|
||||
case AF_SRC_PORT_PARAM_INDEX:
|
||||
strncpy(src_port_str, begin, p - begin);
|
||||
break;
|
||||
case AF_DST_PORT_PARAM_INDEX:
|
||||
strncpy(dst_port_str, begin, p - begin);
|
||||
break;
|
||||
|
||||
case AF_HOST_URL_PARAM_INDEX:
|
||||
strncpy(host_url, begin, p - begin);
|
||||
break;
|
||||
|
||||
case AF_REQUEST_URL_PARAM_INDEX:
|
||||
strncpy(request_url, begin, p - begin);
|
||||
break;
|
||||
}
|
||||
param_num ++;
|
||||
begin = p + 1;
|
||||
}
|
||||
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);
|
||||
|
||||
if (0 == strcmp(proto_str, "tcp"))
|
||||
proto = IPPROTO_TCP;
|
||||
else if (0 == strcmp(proto_str, "udp"))
|
||||
proto = IPPROTO_UDP;
|
||||
else {
|
||||
AF_DEBUG("proto %s is not support\n", proto_str);
|
||||
return -1;
|
||||
}
|
||||
int dst_port = 0;
|
||||
|
||||
int src_port = 0;
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void af_init_feature(char *feature_str)
|
||||
{
|
||||
int app_id;
|
||||
char app_name[128] = {0};
|
||||
char feature_buf[MAX_FEATURE_LINE_LEN] = {0};
|
||||
if (strstr(feature_str,"#"))
|
||||
return;
|
||||
|
||||
k_sscanf(feature_str, "%d%[^:]", &app_id, app_name);
|
||||
|
||||
char *p = feature_str;
|
||||
char *pos = NULL;
|
||||
int len = 0;
|
||||
while(*p++) {
|
||||
if (*p == '['){
|
||||
pos = p + 1;
|
||||
continue;
|
||||
}
|
||||
if (*p == ']' && pos != NULL) {
|
||||
len = p - pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos && len)
|
||||
strncpy(feature_buf, pos, len);
|
||||
char feature[MAX_FEATURE_STR_LEN];;
|
||||
int i;
|
||||
memset(feature, 0x0, sizeof(feature));
|
||||
p = feature_buf;
|
||||
char *begin = feature_buf;
|
||||
|
||||
while(*p++){
|
||||
if (*p == ',') {
|
||||
memset(feature, 0x0, sizeof(feature));
|
||||
strncpy((char *)feature, begin, p - begin);
|
||||
|
||||
add_app_feature(app_id, app_name, feature);
|
||||
begin = p + 1;
|
||||
}
|
||||
}
|
||||
if (p != begin){
|
||||
memset(feature, 0x0, sizeof(feature));
|
||||
strncpy((char *)feature, begin, p - begin);
|
||||
add_app_feature(app_id, app_name, feature);
|
||||
}
|
||||
}
|
||||
|
||||
void load_feature_buf_from_file(char **config_buf)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct file *fp = NULL;
|
||||
mm_segment_t fs;
|
||||
off_t size;
|
||||
fp = filp_open(AF_FEATURE_CONFIG_FILE, O_RDONLY, 0);
|
||||
|
||||
if(IS_ERR(fp)) {
|
||||
printk("open feature file failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
inode = fp->f_inode;
|
||||
size = inode->i_size;
|
||||
AF_INFO("feature file size: %u\n", size);
|
||||
if (size == 0) {
|
||||
AF_WARN("warning, file size = %u\n", size);
|
||||
return;
|
||||
}
|
||||
*config_buf = (char *) kzalloc( sizeof(char) * size, GFP_KERNEL);
|
||||
if(NULL == *config_buf ) {
|
||||
AF_ERROR("alloc buf fail\n");
|
||||
filp_close(fp, NULL);
|
||||
return -1;
|
||||
}
|
||||
fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
// 4.14rc3 vfs_read-->kernel_read
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
|
||||
kernel_read(fp, *config_buf, size, &(fp->f_pos));
|
||||
#else
|
||||
vfs_read(fp, *config_buf, size, &(fp->f_pos));
|
||||
#endif
|
||||
set_fs(fs);
|
||||
filp_close(fp, NULL);
|
||||
return size;
|
||||
}
|
||||
|
||||
void load_feature_config(void)
|
||||
{
|
||||
AF_INFO("begin load feature config.....\n");
|
||||
char *feature_buf = NULL;
|
||||
load_feature_buf_from_file(&feature_buf);
|
||||
if (!feature_buf) {
|
||||
AF_ERROR("error, feature buf is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *p;
|
||||
char *begin;
|
||||
p = begin = feature_buf;
|
||||
char line[MAX_FEATURE_LINE_LEN] = {0};
|
||||
while(*p++) {
|
||||
if (*p == '\n'){
|
||||
if (p - begin < MIN_FEATURE_LINE_LEN || p - begin > MAX_FEATURE_LINE_LEN ) {
|
||||
begin = p + 1;
|
||||
continue;
|
||||
}
|
||||
memset(line, 0x0, sizeof(line));
|
||||
strncpy(line, begin, p - begin);
|
||||
af_init_feature(line);
|
||||
begin = p + 1;
|
||||
}
|
||||
}
|
||||
if (p != begin) {
|
||||
if (p - begin < MIN_FEATURE_LINE_LEN || p - begin > MAX_FEATURE_LINE_LEN )
|
||||
return;
|
||||
memset(line, 0x0, sizeof(line));
|
||||
strncpy(line, begin, p - begin);
|
||||
af_init_feature(line);
|
||||
begin = p + 1;
|
||||
}
|
||||
if (feature_buf)
|
||||
kfree(feature_buf);
|
||||
}
|
||||
|
||||
static void af_clean_feature_list(void)
|
||||
{
|
||||
af_feature_node_t *n,*node;
|
||||
feature_list_write_lock();
|
||||
while(!list_empty(&af_feature_head)) {
|
||||
node = list_first_entry(&af_feature_head, af_feature_node_t, head);
|
||||
list_del(&(node->head));
|
||||
kfree(node);
|
||||
}
|
||||
feature_list_write_unlock();
|
||||
}
|
||||
|
||||
|
||||
int parse_flow_base(struct sk_buff *skb, flow_info_t *flow)
|
||||
{
|
||||
struct tcphdr * tcph = NULL;
|
||||
struct udphdr * udph = NULL;
|
||||
struct nf_conn *ct = NULL;
|
||||
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;
|
||||
switch (iph->protocol) {
|
||||
case IPPROTO_TCP:
|
||||
tcph = (struct tcphdr *)(iph + 1);
|
||||
flow->l4_data = skb->data + iph->ihl * 4 + tcph->doff * 4;
|
||||
flow->l4_len = ntohs(iph->tot_len) - iph->ihl * 4 - tcph->doff * 4;
|
||||
flow->dport = htons(tcph->dest);
|
||||
flow->sport = htons(tcph->source);
|
||||
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);
|
||||
return 0;
|
||||
case IPPROTO_ICMP:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
desc: 解析https url信息,保存到flow中
|
||||
return:
|
||||
-1: error
|
||||
0: match
|
||||
author: Derry
|
||||
Date:2018/12/19
|
||||
*/
|
||||
int parse_https_proto(flow_info_t *flow) {
|
||||
int i ;
|
||||
short url_len = 0 ;
|
||||
char * p = flow->l4_data;
|
||||
int data_len = flow->l4_len;
|
||||
|
||||
if (NULL == flow) {
|
||||
AF_ERROR("flow is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
if (NULL == p || data_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
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) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(p[i] == 0x0 && p[i + 1] == 0x0 && p[i + 2] == 0x0 && p[i + 3] != 0x0) {
|
||||
// 2 bytes
|
||||
memcpy(&url_len , p + i + HTTPS_LEN_OFFSET, 2);
|
||||
if(ntohs(url_len) <= 0 || ntohs(url_len) > data_len) {
|
||||
continue ;
|
||||
}
|
||||
|
||||
if(i + HTTPS_URL_OFFSET + ntohs(url_len) < data_len) {
|
||||
//dump_hex("https hex", p, data_len);
|
||||
flow->https.match = AF_TRUE;
|
||||
flow->https.url_pos = p + i + HTTPS_URL_OFFSET;
|
||||
//dump_str("https url", flow->https.url_pos, 5);
|
||||
flow->https.url_len = ntohs(url_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void parse_http_proto(flow_info_t *flow)
|
||||
{
|
||||
if (!flow) {
|
||||
AF_ERROR("flow is null\n");
|
||||
return;
|
||||
}
|
||||
if (flow->l4_protocol != IPPROTO_TCP) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int start = 0;
|
||||
char *data = flow->l4_data;
|
||||
int data_len = flow->l4_len;
|
||||
if (data_len < MIN_HTTP_DATA_LEN) {
|
||||
return;
|
||||
}
|
||||
if (flow->sport != 80 && flow->dport != 80)
|
||||
return;
|
||||
for (i = 0; i < data_len; i++) {
|
||||
if (data[i] == 0x0d && data[i + 1] == 0x0a){
|
||||
if (0 == memcmp(&data[start], "POST ", 5)) {
|
||||
flow->http.match = AF_TRUE;
|
||||
flow->http.method = HTTP_METHOD_POST;
|
||||
flow->http.url_pos = data + start + 5;
|
||||
flow->http.url_len = i - start - 5;
|
||||
//dump_str("get request", flow->http.url_pos, flow->http.url_len);
|
||||
}
|
||||
else if(0 == memcmp(&data[start], "GET ", 4)) {
|
||||
flow->http.match = AF_TRUE;
|
||||
flow->http.method = HTTP_METHOD_GET;
|
||||
flow->http.url_pos = data + start + 4;
|
||||
flow->http.url_len = i - start - 4;
|
||||
//dump_str("post request", flow->http.url_pos, flow->http.url_len);
|
||||
}
|
||||
else if (0 == memcmp(&data[start], "Host:", 5) ){
|
||||
flow->http.host_pos = data + start + 6;
|
||||
flow->http.host_len = i - start - 6;
|
||||
//dump_str("host ", flow->http.host_pos, flow->http.host_len);
|
||||
}
|
||||
// 判断http头部结束
|
||||
if (data[i + 2] == 0x0d && data[i + 3] == 0x0a){
|
||||
flow->http.data_pos = data + i + 4;
|
||||
flow->http.data_len = data_len - i - 4;
|
||||
break;
|
||||
}
|
||||
// 0x0d 0x0a
|
||||
start = i + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_http_flow_info(http_proto_t *http) {
|
||||
if (!http) {
|
||||
AF_ERROR("http ptr is NULL\n");
|
||||
return ;
|
||||
}
|
||||
if (!http->match)
|
||||
return;
|
||||
if (http->method == HTTP_METHOD_GET){
|
||||
printk("Http method: "HTTP_GET_METHOD_STR"\n");
|
||||
}
|
||||
else if (http->method == HTTP_METHOD_POST) {
|
||||
printk("Http method: "HTTP_POST_METHOD_STR"\n");
|
||||
}
|
||||
if (http->url_len > 0 && http->url_pos){
|
||||
dump_str("Request url", http->url_pos, http->url_len);
|
||||
}
|
||||
|
||||
if (http->host_len > 0 && http->host_pos){
|
||||
dump_str("Host", http->host_pos, http->host_len);
|
||||
}
|
||||
|
||||
printk("--------------------------------------------------------\n\n\n");
|
||||
}
|
||||
|
||||
static void dump_https_flow_info(https_proto_t *https) {
|
||||
if (!https) {
|
||||
AF_ERROR("https ptr is NULL\n");
|
||||
return ;
|
||||
}
|
||||
if (!https->match)
|
||||
return;
|
||||
|
||||
|
||||
if (https->url_len > 0 && https->url_pos){
|
||||
dump_str("https server name", https->url_pos, https->url_len);
|
||||
}
|
||||
|
||||
printk("--------------------------------------------------------\n\n\n");
|
||||
}
|
||||
static void dump_flow_info(flow_info_t *flow)
|
||||
{
|
||||
if (!flow) {
|
||||
AF_ERROR("flow is null\n");
|
||||
return;
|
||||
}
|
||||
if (flow->l4_len > 0){
|
||||
AF_LMT_INFO("src="NIPQUAD_FMT",dst="NIPQUAD_FMT",sport: %d, dport: %d, data_len: %d\n",
|
||||
NIPQUAD(flow->src), NIPQUAD(flow->dst), flow->sport, flow->dport, flow->l4_len);
|
||||
}
|
||||
|
||||
if (flow->l4_protocol == IPPROTO_TCP) {
|
||||
if (AF_TRUE == flow->http.match) {
|
||||
printk("-------------------http protocol-------------------------\n");
|
||||
printk("protocol:TCP , sport: %-8d, dport: %-8d, data_len: %-8d\n",
|
||||
flow->sport, flow->dport, flow->l4_len);
|
||||
dump_http_flow_info(&flow->http);
|
||||
}
|
||||
if (AF_TRUE == flow->https.match) {
|
||||
printk("-------------------https protocol-------------------------\n");
|
||||
dump_https_flow_info(&flow->https);
|
||||
}
|
||||
}
|
||||
}
|
||||
int af_match_by_pos(flow_info_t *flow, af_feature_node_t *node)
|
||||
{
|
||||
int i;
|
||||
unsigned int pos = 0;
|
||||
|
||||
if (!flow || !node)
|
||||
return AF_FALSE;
|
||||
if (node->pos_num > 0) {
|
||||
for (i = 0;i < node->pos_num; i++){
|
||||
// -1
|
||||
if(node->pos_info[i].pos < 0) {
|
||||
pos = flow->l4_len + node->pos_info[i].pos;
|
||||
}
|
||||
else{
|
||||
pos = node->pos_info[i].pos;
|
||||
}
|
||||
if (pos >= flow->l4_len){
|
||||
return AF_FALSE;
|
||||
}
|
||||
if (flow->l4_data[pos] != node->pos_info[i].value){
|
||||
return AF_FALSE;
|
||||
}
|
||||
}
|
||||
AF_DEBUG("match by pos, appid=%d\n", node->app_id);
|
||||
return AF_TRUE;
|
||||
}
|
||||
return AF_FALSE;
|
||||
}
|
||||
|
||||
int af_match_by_url(flow_info_t *flow, af_feature_node_t *node)
|
||||
{
|
||||
char reg_url_buf[MAX_URL_MATCH_LEN] = {0};
|
||||
|
||||
if (!flow || !node)
|
||||
return AF_FALSE;
|
||||
// match host or https url
|
||||
if (flow->https.match == AF_TRUE && flow->https.url_pos) {
|
||||
if (flow->https.url_len >= MAX_URL_MATCH_LEN)
|
||||
strncpy(reg_url_buf, flow->https.url_pos, MAX_URL_MATCH_LEN - 1);
|
||||
else
|
||||
strncpy(reg_url_buf, flow->https.url_pos, flow->https.url_len);
|
||||
}
|
||||
else if (flow->http.match == AF_TRUE && flow->http.host_pos) {
|
||||
if (flow->http.host_len >= MAX_URL_MATCH_LEN)
|
||||
strncpy(reg_url_buf, flow->http.host_pos, MAX_URL_MATCH_LEN - 1);
|
||||
else
|
||||
strncpy(reg_url_buf, flow->http.host_pos, flow->http.host_len);
|
||||
}
|
||||
if (strlen(reg_url_buf) > 0 && strlen(node->host_url) > 0
|
||||
&& regexp_match(node->host_url, reg_url_buf)){
|
||||
AF_DEBUG("match url:%s reg = %s, appid=%d\n",
|
||||
reg_url_buf, node->host_url, node->app_id);
|
||||
return AF_TRUE;
|
||||
}
|
||||
|
||||
// match request url
|
||||
if (flow->http.match == AF_TRUE && flow->http.url_pos) {
|
||||
memset(reg_url_buf, 0x0, sizeof(reg_url_buf));
|
||||
if (flow->http.url_len >= MAX_URL_MATCH_LEN)
|
||||
strncpy(reg_url_buf, flow->http.url_pos, MAX_URL_MATCH_LEN - 1);
|
||||
else
|
||||
strncpy(reg_url_buf, flow->http.url_pos, flow->http.url_len);
|
||||
if(strlen(reg_url_buf) > 0 && strlen(node->request_url)
|
||||
&& regexp_match(node->request_url, reg_url_buf)){
|
||||
AF_DEBUG("match request:%s reg:%s appid=%d\n",
|
||||
reg_url_buf, node->request_url, node->app_id);
|
||||
return AF_TRUE;
|
||||
}
|
||||
}
|
||||
return AF_FALSE;
|
||||
}
|
||||
|
||||
int af_match_one(flow_info_t *flow, af_feature_node_t *node)
|
||||
{
|
||||
int ret = AF_FALSE;
|
||||
if (!flow || !node){
|
||||
AF_ERROR("node or flow is NULL\n");
|
||||
return AF_FALSE;
|
||||
}
|
||||
|
||||
if (flow->l4_len == 0)
|
||||
return AF_FALSE;
|
||||
|
||||
// 匹配端口
|
||||
if (node->sport != 0 && flow->sport != node->sport ){
|
||||
return AF_FALSE;
|
||||
}
|
||||
|
||||
if (node->dport != 0 && flow->dport != node->dport) {
|
||||
return AF_FALSE;
|
||||
}
|
||||
|
||||
if (strlen(node->request_url) > 0 ||
|
||||
strlen(node->host_url) > 0){
|
||||
ret = af_match_by_url(flow, node);
|
||||
}
|
||||
else if (node->pos_num > 0){
|
||||
ret = af_match_by_pos(flow, node);
|
||||
}
|
||||
else{
|
||||
AF_DEBUG("node is empty, match sport:%d,dport:%d, appid = %d\n",
|
||||
node->sport, node->dport, node->app_id);
|
||||
return AF_TRUE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int app_filter_match(flow_info_t *flow)
|
||||
{
|
||||
af_feature_node_t *n,*node;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
feature_list_read_unlock();
|
||||
return AF_FALSE;
|
||||
}
|
||||
|
||||
#define APP_FILTER_DROP_BITS 0xf0000000
|
||||
|
||||
|
||||
|
||||
static int af_get_visit_index(af_client_info_t *node, int app_id){
|
||||
int i;
|
||||
for(i = 0; i < MAX_RECORD_APP_NUM; i++){
|
||||
if(node->visit_info[i].app_id == app_id || node->visit_info[i].app_id == 0){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// default 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
index = af_get_visit_index(node, flow->app_id);
|
||||
|
||||
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框架注册的钩子 */
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
|
||||
static u_int32_t app_filter_hook(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state) {
|
||||
#else
|
||||
static u_int32_t app_filter_hook(unsigned int hook,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *)){
|
||||
#endif
|
||||
unsigned long long total_packets = 0;
|
||||
flow_info_t flow;
|
||||
// 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 (!g_oaf_enable){
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
if(ct == NULL) {
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
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)){
|
||||
return NF_DROP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// 3.12.74-->3.13-rc1
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
|
||||
struct nf_conn_acct *acct;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
af_update_client_app_info(&flow);
|
||||
|
||||
if(flow.drop){
|
||||
#if defined(CONFIG_NF_CONNTRACK_MARK)
|
||||
ct->mark |= APP_FILTER_DROP_BITS;
|
||||
#endif
|
||||
AF_LMT_INFO("##drop appid = %d\n\n\n", flow.app_id);
|
||||
return NF_DROP;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
|
||||
static struct nf_hook_ops app_filter_ops[] __read_mostly = {
|
||||
{
|
||||
.hook = app_filter_hook,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_INET_FORWARD,
|
||||
.priority = NF_IP_PRI_MANGLE + 1,
|
||||
},
|
||||
};
|
||||
#else
|
||||
static struct nf_hook_ops app_filter_ops[] __read_mostly = {
|
||||
{
|
||||
.hook = app_filter_hook,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_INET_FORWARD,
|
||||
.priority = NF_IP_PRI_MANGLE + 1,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#include "cJSON.h"
|
||||
void TEST_cJSON(void)
|
||||
{
|
||||
cJSON * root = NULL;
|
||||
char *out = NULL;
|
||||
root = cJSON_CreateObject();
|
||||
if (!root) {
|
||||
AF_ERROR("create obj failed\n");
|
||||
return;
|
||||
}
|
||||
cJSON_AddNumberToObject(root, "id", 123);
|
||||
cJSON_AddStringToObject(root, "name", "derry");
|
||||
out = cJSON_Print(root);
|
||||
printk("out = %s\n", out);
|
||||
cJSON_Delete(root);
|
||||
kfree(out);
|
||||
}
|
||||
|
||||
|
||||
struct timer_list oaf_timer;
|
||||
|
||||
#define OAF_TIMER_INTERVAL 15
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
|
||||
static void oaf_timer_func(struct timer_list *t)
|
||||
#else
|
||||
static void oaf_timer_func(unsigned long ptr)
|
||||
#endif
|
||||
{
|
||||
// check_client_expire();
|
||||
af_visit_info_timer_handle();
|
||||
mod_timer(&oaf_timer, jiffies + OAF_TIMER_INTERVAL * HZ);
|
||||
}
|
||||
|
||||
|
||||
void init_oaf_timer(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
|
||||
timer_setup(&oaf_timer, oaf_timer_func, 0);
|
||||
#else
|
||||
setup_timer(&oaf_timer, oaf_timer_func, OAF_TIMER_INTERVAL * HZ);
|
||||
#endif
|
||||
mod_timer(&oaf_timer, jiffies + OAF_TIMER_INTERVAL * HZ);
|
||||
AF_INFO("init oaf timer...ok");
|
||||
}
|
||||
|
||||
void fini_port_timer(void)
|
||||
{
|
||||
del_timer_sync(&oaf_timer);
|
||||
AF_INFO("del oaf timer...ok");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
模块初始化
|
||||
*/
|
||||
static int __init app_filter_init(void)
|
||||
{
|
||||
AF_INFO("appfilter version:"AF_VERSION"\n");
|
||||
af_log_init();
|
||||
af_register_dev();
|
||||
af_init_app_status();
|
||||
load_feature_config();
|
||||
init_af_client_procfs();
|
||||
// show_feature_list();
|
||||
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
|
||||
init_oaf_timer();
|
||||
|
||||
AF_INFO("init app filter ........ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
模块退出
|
||||
*/
|
||||
static void app_filter_fini(void)
|
||||
{
|
||||
AF_INFO("app filter module exit\n");
|
||||
fini_port_timer();
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
nf_unregister_net_hooks(&init_net, app_filter_ops, ARRAY_SIZE(app_filter_ops));
|
||||
#else
|
||||
nf_unregister_hooks(app_filter_ops, ARRAY_SIZE(app_filter_ops));
|
||||
#endif
|
||||
|
||||
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,117 +0,0 @@
|
||||
#ifndef APP_FILTER_H
|
||||
#define APP_FILTER_H
|
||||
|
||||
#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
|
||||
#define MAX_FEATURE_BITS 16
|
||||
#define MAX_POS_INFO_PER_FEATURE 16
|
||||
#define MAX_FEATURE_LINE_LEN 256
|
||||
#define MIN_FEATURE_LINE_LEN 16
|
||||
#define MAX_URL_MATCH_LEN 64
|
||||
|
||||
//#define CONFIG_KERNEL_FUNC_TEST 1
|
||||
|
||||
#define HTTP_GET_METHOD_STR "GET"
|
||||
#define HTTP_POST_METHOD_STR "POST"
|
||||
#define HTTP_HEADER "HTTP"
|
||||
#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"
|
||||
|
||||
#define AF_TRUE 1
|
||||
#define AF_FALSE 0
|
||||
|
||||
#define AF_APP_TYPE(a) (a) / 1000
|
||||
#define AF_APP_ID(a) (a) % 1000
|
||||
|
||||
#define HTTPS_URL_OFFSET 9
|
||||
#define HTTPS_LEN_OFFSET 7
|
||||
|
||||
enum AF_FEATURE_PARAM_INDEX{
|
||||
AF_PROTO_PARAM_INDEX,
|
||||
AF_SRC_PORT_PARAM_INDEX,
|
||||
AF_DST_PORT_PARAM_INDEX,
|
||||
AF_HOST_URL_PARAM_INDEX,
|
||||
AF_REQUEST_URL_PARAM_INDEX,
|
||||
AF_DICT_PARAM_INDEX,
|
||||
};
|
||||
|
||||
enum e_http_method{
|
||||
HTTP_METHOD_GET = 1,
|
||||
HTTP_METHOD_POST,
|
||||
};
|
||||
typedef struct http_proto{
|
||||
int match;
|
||||
int method;
|
||||
char *url_pos;
|
||||
int url_len;
|
||||
char *host_pos;
|
||||
int host_len;
|
||||
char *data_pos;
|
||||
int data_len;
|
||||
}http_proto_t;
|
||||
|
||||
typedef struct https_proto{
|
||||
int match;
|
||||
char *url_pos;
|
||||
int url_len;
|
||||
}https_proto_t;
|
||||
|
||||
typedef struct flow_info{
|
||||
struct nf_conn *ct; // Á¬½Ó¸ú×ÙÖ¸Õë
|
||||
u_int32_t src;
|
||||
u_int32_t dst;
|
||||
int l4_protocol;
|
||||
u_int16_t sport;
|
||||
u_int16_t dport;
|
||||
unsigned char *l4_data;
|
||||
int l4_len;
|
||||
http_proto_t http;
|
||||
https_proto_t https;
|
||||
u_int32_t app_id;
|
||||
u_int8_t drop;
|
||||
}flow_info_t;
|
||||
|
||||
|
||||
|
||||
typedef struct af_pos_info{
|
||||
int pos;
|
||||
unsigned char value;
|
||||
}af_pos_info_t;
|
||||
|
||||
typedef struct af_feature_node{
|
||||
struct list_head head;
|
||||
u_int32_t app_id;
|
||||
char app_name[MAX_APP_NAME_LEN];
|
||||
char feature_str[MAX_FEATURE_NUM_PER_APP][MAX_FEATURE_STR_LEN];
|
||||
u_int32_t proto;
|
||||
u_int32_t sport;
|
||||
u_int32_t dport;
|
||||
char host_url[MAX_HOST_URL_LEN];
|
||||
char request_url[MAX_REQUEST_URL_LEN];
|
||||
int pos_num;
|
||||
af_pos_info_t pos_info[MAX_POS_INFO_PER_FEATURE];
|
||||
}af_feature_node_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);
|
||||
|
||||
extern int g_oaf_enable;
|
||||
|
||||
#endif
|
||||
@ -1,294 +0,0 @@
|
||||
|
||||
/*
|
||||
author: destan19@126.com
|
||||
΢ÐŹ«ÖÚºÅ: OpenWrt
|
||||
date:2019/1/10
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/netfilter/nf_conntrack.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/vmalloc.h>
|
||||
#include <linux/device.h>
|
||||
#include "cJSON.h"
|
||||
#include "app_filter.h"
|
||||
#include "af_utils.h"
|
||||
#include "af_log.h"
|
||||
#define AF_MAX_APP_TYPE_NUM 16
|
||||
#define AF_MAX_APP_NUM 256
|
||||
#define AF_DEV_NAME "appfilter"
|
||||
|
||||
DEFINE_RWLOCK(af_rule_lock);
|
||||
|
||||
#define af_rule_read_lock() read_lock_bh(&af_rule_lock);
|
||||
#define af_rule_read_unlock() read_unlock_bh(&af_rule_lock);
|
||||
#define af_rule_write_lock() write_lock_bh(&af_rule_lock);
|
||||
#define af_rule_write_unlock() write_unlock_bh(&af_rule_lock);
|
||||
|
||||
|
||||
static struct mutex af_cdev_mutex;
|
||||
struct af_config_dev {
|
||||
dev_t id;
|
||||
struct cdev char_dev;
|
||||
struct class *c;
|
||||
};
|
||||
struct af_config_dev g_af_dev;
|
||||
|
||||
struct af_cdev_file {
|
||||
size_t size;
|
||||
char buf[256 << 10];
|
||||
};
|
||||
|
||||
enum AF_CONFIG_CMD{
|
||||
AF_CMD_ADD_APPID = 1,
|
||||
AF_CMD_DEL_APPID,
|
||||
AF_CMD_CLEAN_APPID,
|
||||
};
|
||||
|
||||
char g_app_id_array[AF_MAX_APP_TYPE_NUM][AF_MAX_APP_NUM] = {0};
|
||||
|
||||
|
||||
void af_show_app_status(void)
|
||||
{
|
||||
int i, j;
|
||||
printk("#########show app status##########\n");
|
||||
for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++) {
|
||||
for (j = 0; j < AF_MAX_APP_NUM; j++) {
|
||||
|
||||
af_rule_read_lock();
|
||||
if (g_app_id_array[i][j] == AF_TRUE) {
|
||||
printk("%d, %d\n", i, j);
|
||||
}
|
||||
af_rule_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
printk("\n\n\n");
|
||||
}
|
||||
|
||||
int af_change_app_status(cJSON * data_obj, int status)
|
||||
{
|
||||
int i;
|
||||
int id;
|
||||
int type;
|
||||
if (!data_obj) {
|
||||
AF_ERROR("data obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
cJSON *appid_arr = cJSON_GetObjectItem(data_obj, "apps");
|
||||
if (!appid_arr){
|
||||
AF_ERROR("apps obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < cJSON_GetArraySize(appid_arr); i++) {
|
||||
cJSON *appid_obj = cJSON_GetArrayItem(appid_arr, i);
|
||||
if (!appid_obj){
|
||||
AF_ERROR("appid obj is null\n");
|
||||
return -1;
|
||||
}
|
||||
id = AF_APP_ID(appid_obj->valueint);
|
||||
type = AF_APP_TYPE(appid_obj->valueint);
|
||||
AF_DEBUG("appid:%d, type = %d, id = %d\n", appid_obj->valueint, type, id);
|
||||
|
||||
af_rule_write_lock();
|
||||
g_app_id_array[type][id] = status;
|
||||
af_rule_write_unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void af_init_app_status(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++) {
|
||||
for (j = 0; j < AF_MAX_APP_NUM; j++) {
|
||||
af_rule_write_lock();
|
||||
g_app_id_array[i][j] = AF_FALSE;
|
||||
af_rule_write_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
int af_get_app_status(int appid)
|
||||
{
|
||||
int status = 0;
|
||||
int id = AF_APP_ID(appid);
|
||||
int type = AF_APP_TYPE(appid);
|
||||
af_rule_read_lock();
|
||||
status = g_app_id_array[type][id];
|
||||
af_rule_read_unlock();
|
||||
return status;
|
||||
}
|
||||
/*
|
||||
add:
|
||||
{
|
||||
"op":1,
|
||||
"data"{
|
||||
"apps":[]
|
||||
}
|
||||
}
|
||||
clean
|
||||
{
|
||||
"op":3,
|
||||
}
|
||||
|
||||
*/
|
||||
int af_config_handle(char *config, unsigned int len)
|
||||
{
|
||||
cJSON * config_obj = NULL;
|
||||
cJSON * cmd_obj = NULL;
|
||||
cJSON * data_obj = NULL;
|
||||
if (!config || len == 0) {
|
||||
AF_ERROR("config or len is invalid\n");
|
||||
return -1;
|
||||
}
|
||||
config_obj = cJSON_Parse(config);
|
||||
if (!config_obj){
|
||||
AF_ERROR("config_obj is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
cmd_obj = cJSON_GetObjectItem(config_obj, "op");
|
||||
if (!cmd_obj){
|
||||
AF_ERROR("not find op object\n");
|
||||
return -1;
|
||||
}
|
||||
data_obj = cJSON_GetObjectItem(config_obj, "data");
|
||||
|
||||
switch(cmd_obj->valueint) {
|
||||
case AF_CMD_ADD_APPID:
|
||||
if (!data_obj)
|
||||
break;
|
||||
af_change_app_status(data_obj, AF_TRUE);
|
||||
break;
|
||||
case AF_CMD_DEL_APPID:
|
||||
if (!data_obj)
|
||||
break;
|
||||
af_change_app_status(data_obj, AF_FALSE);
|
||||
break;
|
||||
case AF_CMD_CLEAN_APPID:
|
||||
af_init_app_status();
|
||||
break;
|
||||
default:
|
||||
AF_ERROR("invalid cmd %d\n", cmd_obj->valueint);
|
||||
return -1;
|
||||
}
|
||||
af_show_app_status();
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int af_cdev_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct af_cdev_file *file;
|
||||
file = vzalloc(sizeof(*file));
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&af_cdev_mutex);
|
||||
filp->private_data = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t af_cdev_read(struct file *filp, char *buf, size_t count, loff_t *off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_cdev_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct af_cdev_file *file = filp->private_data;
|
||||
printk("config size: %d,data = %s\n", (int)file->size, file->buf);
|
||||
af_config_handle(file->buf, file->size);
|
||||
filp->private_data = NULL;
|
||||
mutex_unlock(&af_cdev_mutex);
|
||||
vfree(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t af_cdev_write(struct file *filp, const char *buffer, size_t count, loff_t *off)
|
||||
{
|
||||
struct af_cdev_file *file = filp->private_data;
|
||||
int ret;
|
||||
if (file->size + count > sizeof(file->buf)) {
|
||||
printk("config overflow, cur_size: %d, block_size: %d, max_size: %d",
|
||||
(int)file->size, (int)count, (int)sizeof(file->buf));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = copy_from_user(file->buf + file->size, buffer, count);
|
||||
if (ret != 0)
|
||||
return -EINVAL;
|
||||
|
||||
file->size += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations af_cdev_ops = {
|
||||
owner: THIS_MODULE,
|
||||
release: af_cdev_release,
|
||||
open: af_cdev_open,
|
||||
write: af_cdev_write,
|
||||
read: af_cdev_read,
|
||||
};
|
||||
|
||||
int af_register_dev(void)
|
||||
{
|
||||
struct device *dev;
|
||||
int res;
|
||||
mutex_init(&af_cdev_mutex);
|
||||
|
||||
res = alloc_chrdev_region(&g_af_dev.id, 0, 1, AF_DEV_NAME);
|
||||
if (res != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cdev_init(&g_af_dev.char_dev, &af_cdev_ops);
|
||||
res = cdev_add(&g_af_dev.char_dev, g_af_dev.id, 1);
|
||||
if (res < 0) {
|
||||
goto REGION_OUT;
|
||||
}
|
||||
|
||||
g_af_dev.c= class_create(THIS_MODULE, AF_DEV_NAME);
|
||||
if (IS_ERR_OR_NULL(g_af_dev.c)) {
|
||||
goto CDEV_OUT;
|
||||
}
|
||||
|
||||
dev = device_create(g_af_dev.c, NULL, g_af_dev.id, NULL, AF_DEV_NAME);
|
||||
if (IS_ERR_OR_NULL(dev)) {
|
||||
goto CLASS_OUT;
|
||||
}
|
||||
printk("register char dev....ok\n");
|
||||
|
||||
return 0;
|
||||
|
||||
CLASS_OUT:
|
||||
class_destroy(g_af_dev.c);
|
||||
CDEV_OUT:
|
||||
cdev_del(&g_af_dev.char_dev);
|
||||
REGION_OUT:
|
||||
unregister_chrdev_region(g_af_dev.id, 1);
|
||||
|
||||
printk("register char dev....fail\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
void af_unregister_dev(void)
|
||||
{
|
||||
device_destroy(g_af_dev.c, g_af_dev.id);
|
||||
class_destroy(g_af_dev.c);
|
||||
cdev_del(&g_af_dev.char_dev);
|
||||
unregister_chrdev_region(g_af_dev.id, 1);
|
||||
printk("unregister char dev....ok\n");
|
||||
}
|
||||
|
||||
@ -1,519 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// cJSON
|
||||
// JSON parser in C.
|
||||
|
||||
#if 0
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#if 0
|
||||
#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
|
||||
#define strcasecmp stricmp
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static void *(*cJSON_malloc)(size_t sz) = malloc;
|
||||
static void *(*cJSON_realloc)(void *ptr, size_t sz) = realloc;
|
||||
static void (*cJSON_free)(void *ptr) = free;
|
||||
#endif
|
||||
|
||||
static void *cJSON_malloc(size_t sz) {
|
||||
return kmalloc(sz, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void *cJSON_realloc(void *ptr, size_t sz)
|
||||
{
|
||||
return krealloc(ptr, sz, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void cJSON_free(void *ptr)
|
||||
{
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
static char* cJSON_strdup(const char* str)
|
||||
{
|
||||
size_t len;
|
||||
char* copy;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,str,len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_realloc = realloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
||||
cJSON_realloc= (hooks->realloc_fn)?hooks->realloc_fn:realloc;
|
||||
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Internal constructor.
|
||||
static cJSON *cJSON_New_Item(void)
|
||||
{
|
||||
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
||||
if (node) memset(node,0,sizeof(cJSON));
|
||||
return node;
|
||||
}
|
||||
|
||||
// Delete a cJSON structure.
|
||||
void cJSON_Delete(cJSON *c)
|
||||
{
|
||||
cJSON *next;
|
||||
while (c)
|
||||
{
|
||||
next=c->next;
|
||||
if (c->child) cJSON_Delete(c->child);
|
||||
if (c->valuestring) cJSON_free(c->valuestring);
|
||||
if (c->string) cJSON_free(c->string);
|
||||
cJSON_free(c);
|
||||
c=next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static const char *parse_number(cJSON *item,const char *num)
|
||||
{
|
||||
int n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
|
||||
|
||||
if (*num=='-') sign=-1,num++; /* Has sign? */
|
||||
if (*num=='0') num++; /* is zero */
|
||||
if (*num>='1' && *num<='9') do n=(n*10)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
|
||||
item->valueint=(int)n;
|
||||
item->type=cJSON_Number;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static char *print_number(cJSON *item)
|
||||
{
|
||||
char *str;
|
||||
str=(char*)cJSON_malloc(21);
|
||||
if (str)
|
||||
sprintf(str,"%d",item->valueint);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// Parse the input text into an unescaped cstring, and populate item.
|
||||
static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
{
|
||||
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc;
|
||||
if (*str!='\"') return 0; // not a string!
|
||||
|
||||
while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes.
|
||||
|
||||
out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly.
|
||||
if (!out) return 0;
|
||||
|
||||
ptr=str+1;ptr2=out;
|
||||
while (*ptr!='\"' && *ptr>31)
|
||||
{
|
||||
if (*ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
switch (*ptr)
|
||||
{
|
||||
case 'b': *ptr2++='\b'; break;
|
||||
case 'f': *ptr2++='\f'; break;
|
||||
case 'n': *ptr2++='\n'; break;
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
|
||||
sscanf(ptr+1,"%4x",&uc); // get the unicode char.
|
||||
len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;
|
||||
|
||||
switch (len) {
|
||||
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 1: *--ptr2 =(uc | firstByteMark[len]);
|
||||
}
|
||||
ptr2+=len;ptr+=4;
|
||||
break;
|
||||
default: *ptr2++=*ptr; break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
*ptr2=0;
|
||||
if (*ptr=='\"') ptr++;
|
||||
item->valuestring=out;
|
||||
item->type=cJSON_String;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Render the cstring provided to an escaped version that can be printed.
|
||||
static char *print_string_ptr(const char *str)
|
||||
{
|
||||
const char *ptr;char *ptr2,*out;int len=0;
|
||||
|
||||
ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;}
|
||||
|
||||
out=(char*)cJSON_malloc(len+3);
|
||||
ptr2=out;ptr=str;
|
||||
*ptr2++='\"';
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
*ptr2++='\\';
|
||||
switch (*ptr++)
|
||||
{
|
||||
case '\\': *ptr2++='\\'; break;
|
||||
case '\"': *ptr2++='\"'; break;
|
||||
case '\b': *ptr2++='b'; break;
|
||||
case '\f': *ptr2++='f'; break;
|
||||
case '\n': *ptr2++='n'; break;
|
||||
case '\r': *ptr2++='r'; break;
|
||||
case '\t': *ptr2++='t'; break;
|
||||
default: ptr2--; break; // eviscerate with prejudice.
|
||||
}
|
||||
}
|
||||
}
|
||||
*ptr2++='\"';*ptr2++=0;
|
||||
return out;
|
||||
}
|
||||
// Invote print_string_ptr (which is useful) on an item.
|
||||
static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
|
||||
|
||||
// Predeclare these prototypes.
|
||||
static const char *parse_value(cJSON *item,const char *value);
|
||||
static char *print_value(cJSON *item,int depth);
|
||||
static const char *parse_array(cJSON *item,const char *value);
|
||||
static char *print_array(cJSON *item,int depth);
|
||||
static const char *parse_object(cJSON *item,const char *value);
|
||||
static char *print_object(cJSON *item,int depth);
|
||||
|
||||
// Utility to jump whitespace and cr/lf
|
||||
static const char *skip(const char *in) {while (in && *in<=32) in++; return in;}
|
||||
|
||||
// Parse an object - create a new root, and populate.
|
||||
cJSON *cJSON_Parse(const char *value)
|
||||
{
|
||||
cJSON *c=cJSON_New_Item();
|
||||
if (!c) return 0; /* memory fail */
|
||||
|
||||
if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;}
|
||||
return c;
|
||||
}
|
||||
|
||||
// Render a cJSON item/entity/structure to text.
|
||||
char *cJSON_Print(cJSON *item) {return print_value(item,0);}
|
||||
|
||||
// Parser core - when encountering text, process appropriately.
|
||||
static const char *parse_value(cJSON *item,const char *value)
|
||||
{
|
||||
if (!value) return 0; // Fail on null.
|
||||
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
|
||||
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
|
||||
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
|
||||
if (*value=='\"') { return parse_string(item,value); }
|
||||
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
|
||||
if (*value=='[') { return parse_array(item,value); }
|
||||
if (*value=='{') { return parse_object(item,value); }
|
||||
|
||||
return 0; // failure.
|
||||
}
|
||||
|
||||
// Render a value to text.
|
||||
static char *print_value(cJSON *item,int depth)
|
||||
{
|
||||
char *out=0;
|
||||
switch (item->type)
|
||||
{
|
||||
case cJSON_NULL: out=cJSON_strdup("null"); break;
|
||||
case cJSON_False: out=cJSON_strdup("false");break;
|
||||
case cJSON_True: out=cJSON_strdup("true"); break;
|
||||
case cJSON_Number: out=print_number(item);break;
|
||||
case cJSON_String: out=print_string(item);break;
|
||||
case cJSON_Array: out=print_array(item,depth);break;
|
||||
case cJSON_Object: out=print_object(item,depth);break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Build an array from input text.
|
||||
static const char *parse_array(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='[') return 0; // not an array!
|
||||
|
||||
item->type=cJSON_Array;
|
||||
value=skip(value+1);
|
||||
if (*value==']') return value+1; // empty array.
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0; // memory fail
|
||||
value=skip(parse_value(child,skip(value))); // skip any spacing, get the value.
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; // memory fail
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_value(child,skip(value+1)));
|
||||
if (!value) return 0; // memory fail
|
||||
}
|
||||
|
||||
if (*value==']') return value+1; // end of array
|
||||
return 0; // malformed.
|
||||
}
|
||||
|
||||
// Render an array to text
|
||||
static char *print_array(cJSON *item,int depth)
|
||||
{
|
||||
char *out,*ptr,*ret;int len=5;
|
||||
cJSON *child=item->child;
|
||||
|
||||
out=(char*)cJSON_malloc(len);*out='[';
|
||||
ptr=out+1;*ptr=0;
|
||||
while (child)
|
||||
{
|
||||
ret=print_value(child,depth+1);
|
||||
if (!ret) {cJSON_free(out);return 0;} // Check for failure!
|
||||
len+=strlen(ret)+3;
|
||||
out=(char*)cJSON_realloc(out,len);
|
||||
ptr=out+strlen(out);
|
||||
ptr+=sprintf(ptr,ret);
|
||||
if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;}
|
||||
child=child->next;
|
||||
cJSON_free(ret);
|
||||
}
|
||||
*ptr++=']';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Build an object from the text.
|
||||
static const char *parse_object(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='{') return 0; // not an object!
|
||||
|
||||
item->type=cJSON_Object;
|
||||
value=skip(value+1);
|
||||
if (*value=='}') return value+1; // empty array.
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
value=skip(parse_string(child,skip(value)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') return 0; // fail!
|
||||
value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value.
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; // memory fail
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_string(child,skip(value+1)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') return 0; // fail!
|
||||
value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value.
|
||||
if (!value) return 0;
|
||||
}
|
||||
|
||||
if (*value=='}') return value+1; // end of array
|
||||
return 0; // malformed.
|
||||
}
|
||||
|
||||
// Render an object to text.
|
||||
static char *print_object(cJSON *item,int depth)
|
||||
{
|
||||
char *out,*ptr,*ret,*str;int len=7,i;
|
||||
cJSON *child=item->child;
|
||||
|
||||
depth++;len+=depth;out=(char*)cJSON_malloc(len);*out='{';
|
||||
ptr=out+1;*ptr++='\n';*ptr=0;
|
||||
while (child)
|
||||
{
|
||||
str=print_string_ptr(child->string);
|
||||
if (!str) {cJSON_free(out);return 0;}
|
||||
ret=print_value(child,depth);
|
||||
if (!ret) {cJSON_free(str);cJSON_free(out);return 0;} // Check for failure!
|
||||
len+=strlen(ret)+strlen(str)+4+depth;
|
||||
out=(char*)cJSON_realloc(out,len);
|
||||
ptr=out+strlen(out);
|
||||
for (i=0;i<depth;i++) *ptr++='\t';
|
||||
ptr+=sprintf(ptr,str);
|
||||
*ptr++=':';*ptr++='\t';
|
||||
ptr+=sprintf(ptr,ret);
|
||||
if (child->next) *ptr++=',';
|
||||
*ptr++='\n';*ptr=0;
|
||||
child=child->next;
|
||||
cJSON_free(str);cJSON_free(ret);
|
||||
}
|
||||
for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||
*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;}
|
||||
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item) item--,c=c->next; return c;}
|
||||
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
|
||||
// Utility for array list handling.
|
||||
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||
|
||||
// Add item to array/object.
|
||||
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
|
||||
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
|
||||
|
||||
// Create basic types:
|
||||
cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;}
|
||||
cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;}
|
||||
cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateNumber(int num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valueint=(int)num;return item;}
|
||||
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;}
|
||||
cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;}
|
||||
cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;}
|
||||
|
||||
// Create Arrays:
|
||||
cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
@ -1,94 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
#include <linux/slab.h>
|
||||
|
||||
// cJSON Types:
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
|
||||
// The cJSON structure:
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem
|
||||
struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object.
|
||||
|
||||
int type; // The type of the item, as above.
|
||||
|
||||
char *valuestring; // The item's string, if type==cJSON_String
|
||||
int valueint; // The item's number, if type==cJSON_Number
|
||||
char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object.
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void *(*realloc_fn)(void *ptr, size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
// Supply malloc, realloc and free functions to cJSON
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished.
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
// Render a cJSON entity to text for transfer/storage. Free the char* when finished.
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
// Delete a cJSON entity and all subentities.
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
// Returns the number of items in an array (or object).
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
// Get item "string" from object. Case insensitive.
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
// These calls create a cJSON item of the appropriate type.
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
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);
|
||||
|
||||
// Append item to the specified array/object.
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
#endif
|
||||
@ -1,302 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
//#include "regexp.h"
|
||||
|
||||
typedef enum{CHAR, DOT, BEGIN, END, STAR, PLUS, QUES, LIST, TYPENUM}TYPE;
|
||||
|
||||
typedef struct RE{
|
||||
TYPE type;
|
||||
int ch;
|
||||
char *ccl;
|
||||
int nccl;
|
||||
struct RE *next;
|
||||
}RE;
|
||||
|
||||
int match_longest = 0;
|
||||
char *match_first = NULL;
|
||||
|
||||
|
||||
static void * getmem(size_t size)
|
||||
{
|
||||
void *tmp;
|
||||
if((tmp = kmalloc(size, GFP_ATOMIC))==NULL)
|
||||
{
|
||||
printk("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static size_t creat_list(char *str, int start, int end)
|
||||
{
|
||||
size_t cnt = end - start + 1;
|
||||
for(; start <= end ;start++)
|
||||
*str++ = start;
|
||||
return (cnt > 0)?cnt:0;
|
||||
}
|
||||
|
||||
static int in_list(char ch, RE *regexp)
|
||||
{
|
||||
char *str = regexp->ccl;
|
||||
if(regexp->type != LIST)
|
||||
return 0;
|
||||
for(; *str && ch != *str; str++)
|
||||
;
|
||||
return (*str != '\0') ^ regexp->nccl;
|
||||
}
|
||||
|
||||
static void regexp_free(RE *regexp)
|
||||
{
|
||||
RE *tmp;
|
||||
for(; regexp; regexp = tmp)
|
||||
{
|
||||
tmp = regexp->next;
|
||||
kfree(regexp);
|
||||
}
|
||||
}
|
||||
|
||||
static RE* compile(char *regexp)
|
||||
{
|
||||
RE head, *tail, *tmp;
|
||||
char *pstr;
|
||||
int err_flag = 0;
|
||||
|
||||
for(tail = &head; *regexp != '\0' && err_flag == 0; regexp++)
|
||||
{
|
||||
tmp = getmem(sizeof(RE));
|
||||
switch(*regexp){
|
||||
case '\\':
|
||||
regexp++;
|
||||
if(*regexp == 'd')
|
||||
{
|
||||
tmp->type = LIST;
|
||||
tmp->nccl = 0;
|
||||
tmp->ccl = getmem(11);
|
||||
creat_list(tmp->ccl, '0','9');
|
||||
tmp->ccl[11] = '\0';
|
||||
}else if(*regexp == 'D')
|
||||
{
|
||||
tmp->type = LIST;
|
||||
tmp->nccl = 1;
|
||||
tmp->ccl = getmem(11);
|
||||
creat_list(tmp->ccl, '0','9');
|
||||
tmp->ccl[11] = '\0';
|
||||
}else
|
||||
{
|
||||
tmp->type = CHAR;
|
||||
tmp->ch = *(regexp + 1);
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
tmp->type = DOT;
|
||||
break;
|
||||
case '^':
|
||||
tmp->type = BEGIN;
|
||||
tmp->ch = '^';
|
||||
break;
|
||||
case '$':
|
||||
tmp->type = END;
|
||||
tmp->ch = '$';
|
||||
break;
|
||||
case '*':
|
||||
tmp->type = STAR;
|
||||
break;
|
||||
case '+':
|
||||
tmp->type = PLUS;
|
||||
break;
|
||||
case '?':
|
||||
tmp->type = QUES;
|
||||
break;
|
||||
case '[':
|
||||
pstr = tmp->ccl = getmem(256);
|
||||
tmp->nccl = 0;
|
||||
if(*++regexp == '^')
|
||||
{
|
||||
tmp->nccl = 1;
|
||||
regexp++;
|
||||
}
|
||||
while(*regexp != '\0' && *regexp != ']')
|
||||
{
|
||||
if(*regexp != '-')
|
||||
{
|
||||
*pstr++ = *regexp++;
|
||||
continue;
|
||||
}
|
||||
if(pstr == tmp->ccl || *(regexp + 1) == ']')
|
||||
{
|
||||
err_flag = 1;
|
||||
break;
|
||||
}
|
||||
pstr += creat_list(pstr, *(regexp - 1) + 1, *(regexp + 1));
|
||||
regexp += 2;
|
||||
}
|
||||
*pstr = '\0';
|
||||
if(*regexp == '\0')
|
||||
err_flag = 1;
|
||||
tmp->type = LIST;
|
||||
break;
|
||||
default:
|
||||
tmp->type = CHAR;
|
||||
tmp->ch = *regexp;
|
||||
}
|
||||
|
||||
tail->next = tmp;
|
||||
tail = tmp;
|
||||
}
|
||||
|
||||
tail->next = NULL;
|
||||
if(err_flag)
|
||||
{
|
||||
regexp_free(head.next);
|
||||
return NULL;
|
||||
}
|
||||
return head.next;
|
||||
}
|
||||
|
||||
#define MATCH_ONE(reg, text) \
|
||||
(reg->type == DOT || in_list(*text, reg) || *text == reg->ch)
|
||||
#define MATCH_ONE_P(reg, text) \
|
||||
(in_list(*text++, reg) || *(text - 1) == reg->ch || reg->type == DOT)
|
||||
|
||||
static int matchhere(RE *regexp, char *text);
|
||||
|
||||
static int matchstar(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
do{
|
||||
if(matchhere(regexp, text))
|
||||
return 1;
|
||||
}while(*text != '\0' && MATCH_ONE_P(cur, text));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchstar_l(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
char *t;
|
||||
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
|
||||
;
|
||||
do{
|
||||
if(matchhere(regexp, t))
|
||||
return 1;
|
||||
}while(t-- > text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchplus(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
while(*text != '\0' && MATCH_ONE_P(cur, text))
|
||||
{
|
||||
if(matchhere(regexp, text))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchplus_l(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
char *t;
|
||||
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
|
||||
;
|
||||
for(; t > text; t--)
|
||||
{
|
||||
if(matchhere(regexp, t))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int matchques(RE *cur, RE *regexp, char *text)
|
||||
{
|
||||
int cnt = 1;
|
||||
char *t = text;
|
||||
if(*t != '\0' && cnt-- && MATCH_ONE(cur, t))
|
||||
t++;
|
||||
do{
|
||||
if(matchhere(regexp, t))
|
||||
return 1;
|
||||
}while(t-- > text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*matchfun[TYPENUM][2])(RE *, RE *, char *) = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
matchstar, matchstar_l,
|
||||
matchplus, matchplus_l,
|
||||
matchques, matchques,
|
||||
};
|
||||
|
||||
static int matchhere(RE *regexp, char *text)
|
||||
{
|
||||
if(regexp == NULL)
|
||||
return 1;
|
||||
if(regexp->type == END && regexp->next == NULL)
|
||||
return *text == '\0';
|
||||
if(regexp->next && matchfun[regexp->next->type][match_longest])
|
||||
return matchfun[regexp->next->type][match_longest](regexp, regexp->next->next, text);
|
||||
|
||||
if(*text != '\0' && MATCH_ONE(regexp, text))
|
||||
return matchhere(regexp->next, text + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* return value:
|
||||
* -1 error
|
||||
* 0 not match
|
||||
* 1 matched
|
||||
*/
|
||||
int regexp_match(char *reg, char *text)
|
||||
{
|
||||
int ret;
|
||||
RE *regexp = compile(reg);
|
||||
if(regexp == NULL)
|
||||
return -1;
|
||||
|
||||
if(regexp->type == BEGIN)
|
||||
{
|
||||
ret = matchhere(regexp->next, text);
|
||||
goto out;
|
||||
}
|
||||
|
||||
do{
|
||||
if(ret = matchhere(regexp, text))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
}while(*text++ != '\0');
|
||||
|
||||
out:
|
||||
regexp_free(regexp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void TEST_reg_func(char *reg, char * str, int ret)
|
||||
{
|
||||
|
||||
if (ret != regexp_match(reg, str)) {
|
||||
if (reg)
|
||||
printk("reg = %s,", reg);
|
||||
else
|
||||
printk("reg = null");
|
||||
if (str)
|
||||
printk("str = %s ", str);
|
||||
else
|
||||
printk("str= null");
|
||||
printk("error, unit test.... failed, ret = %d\n",ret);
|
||||
}
|
||||
else {
|
||||
if (reg && str)
|
||||
printk("[unit test] %s %s......ok,ret = %d\n", reg, str, ret);
|
||||
}
|
||||
}
|
||||
|
||||
void TEST_regexp(void)
|
||||
{
|
||||
TEST_reg_func(".*baidu.com$", "www.baidu.com", 1);
|
||||
TEST_reg_func("^sina.com", "www.sina.com.cn", 0);
|
||||
TEST_reg_func("^sina.com", "sina.com.cn", 1);
|
||||
TEST_reg_func(".*baidu.com$", "www.baidu.com223", 0);
|
||||
}
|
||||
@ -2,10 +2,12 @@
|
||||
|
||||
START=96
|
||||
start() {
|
||||
lsmod | grep -q oaf 2>/dev/null || modprobe oaf
|
||||
gen_class.sh /etc/appfilter/feature.cfg
|
||||
appfilter.sh
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo "stop appfilter"
|
||||
echo "stop appfilter"
|
||||
rmmod oaf >/dev/null 2>&1
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ UNPACK_CMD=unzip -q -p $(DL_DIR)/$(PKG_SOURCE) $(PKG_SOURCE_UNZIP) | gzip -dc |
|
||||
|
||||
PKG_NAME:=cypress-firmware
|
||||
PKG_VERSION:=v5.4.18-2020_0402
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE_UNZIP:=cypress-firmware-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE:=cypress-fmac-$(PKG_VERSION).zip
|
||||
@ -68,6 +69,7 @@ $(eval $(call BuildPackage,cypress-firmware-43340-sdio))
|
||||
define Package/cypress-firmware-43362-sdio
|
||||
$(Package/cypress-firmware-default)
|
||||
TITLE:=CYW43362 FullMac SDIO firmware
|
||||
PROVIDES:=brcmfmac-firmware-43362-sdio
|
||||
endef
|
||||
|
||||
define Package/cypress-firmware-43362-sdio/install
|
||||
@ -98,6 +100,7 @@ $(eval $(call BuildPackage,cypress-firmware-4339-sdio))
|
||||
define Package/cypress-firmware-43430-sdio
|
||||
$(Package/cypress-firmware-default)
|
||||
TITLE:=CYW43430 FullMac SDIO firmware
|
||||
PROVIDES:=brcmfmac-firmware-43430-sdio
|
||||
endef
|
||||
|
||||
define Package/cypress-firmware-43430-sdio/install
|
||||
@ -116,6 +119,7 @@ $(eval $(call BuildPackage,cypress-firmware-43430-sdio))
|
||||
define Package/cypress-firmware-43455-sdio
|
||||
$(Package/cypress-firmware-default)
|
||||
TITLE:=CYW43455 FullMac SDIO firmware
|
||||
PROVIDES:=brcmfmac-firmware-43455-sdio
|
||||
endef
|
||||
|
||||
define Package/cypress-firmware-43455-sdio/install
|
||||
|
||||
@ -8,12 +8,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=linux-firmware
|
||||
PKG_VERSION:=20191215
|
||||
PKG_VERSION:=20200122
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_URL:=@KERNEL/linux/kernel/firmware
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
|
||||
PKG_HASH:=c2068ff4a797c0f2c3edbb9488f82a48bca8a995855ea21310a8346195c0ae56
|
||||
PKG_HASH:=a30e811b3736a72b874ac27e10662f5e5409b1cadf8aab7ba88e8f8bc8083986
|
||||
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@ include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=bcm27xx-gpu-fw
|
||||
PKG_VERSION:=2020-03-26
|
||||
PKG_RELEASE:=5574077183389cd4c65077ba18b59144ed6ccd6d
|
||||
PKG_VERSION:=2020-05-27
|
||||
PKG_RELEASE:=62fc8c01165a80021054a430182b504f7b877c2d
|
||||
|
||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)/rpi-firmware-$(PKG_RELEASE)
|
||||
|
||||
@ -26,7 +26,7 @@ define Download/bootcode_bin
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-bootcode.bin
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=bootcode.bin
|
||||
HASH:=1e3582640b97f6a1ba77b66181fe698767d205f5d4c4315f56d03b398a7e55d1
|
||||
HASH:=12c6b5fdd893ff60cddbad0fa8aea0ebd5328ed2a9cd39a2a09d7ac99621d5bf
|
||||
endef
|
||||
$(eval $(call Download,bootcode_bin))
|
||||
|
||||
@ -34,7 +34,7 @@ define Download/fixup_dat
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-fixup.dat
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=fixup.dat
|
||||
HASH:=1b90af0c87d5f705b5b6d921b2b47d37f73af81c5c9fb1d683201e619a00d2df
|
||||
HASH:=25d39e703af377ca6412c0ac68e6739d2ffb56634b9a7262140d26d8150fdf23
|
||||
endef
|
||||
$(eval $(call Download,fixup_dat))
|
||||
|
||||
@ -42,7 +42,7 @@ define Download/fixup_cd_dat
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-fixup_cd.dat
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=fixup_cd.dat
|
||||
HASH:=134c5f3db2de3e5fd285bd4073016f074cf4151cdd1bfe3443b9a14700d48a55
|
||||
HASH:=9639f81ad007561048bb3956e88da425a84cef37f307a16734cdcfcdcbd40b4c
|
||||
endef
|
||||
$(eval $(call Download,fixup_cd_dat))
|
||||
|
||||
@ -50,7 +50,7 @@ define Download/fixup_x_dat
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-fixup_x.dat
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=fixup_x.dat
|
||||
HASH:=32fd8182a9a603f41acb7d542cbb15aa4e84c2768816ae48e36b68d0d4e1754c
|
||||
HASH:=538c4d514b55c09670bbc7bdc092e44ff1f572c4f124a47c5b514f120dff6263
|
||||
endef
|
||||
$(eval $(call Download,fixup_x_dat))
|
||||
|
||||
@ -58,7 +58,7 @@ define Download/fixup4_dat
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-fixup4.dat
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=fixup4.dat
|
||||
HASH:=605b28219ba13b73dbf57a45e995e7ea090421ad96a971c950afb34e0d3f7841
|
||||
HASH:=75312421da0e036f9d451facb848bd439247e4322ee2d36bbfe2f7acc9a6d681
|
||||
endef
|
||||
$(eval $(call Download,fixup4_dat))
|
||||
|
||||
@ -66,7 +66,7 @@ define Download/fixup4cd_dat
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-fixup4cd.dat
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=fixup4cd.dat
|
||||
HASH:=a3a4c600472032cd6597e774f0b7be2cebbfa918ccfd7fa1cfecdf853c5f61a9
|
||||
HASH:=9639f81ad007561048bb3956e88da425a84cef37f307a16734cdcfcdcbd40b4c
|
||||
endef
|
||||
$(eval $(call Download,fixup4cd_dat))
|
||||
|
||||
@ -74,7 +74,7 @@ define Download/fixup4x_dat
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-fixup4x.dat
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=fixup4x.dat
|
||||
HASH:=c196692b2cac949fdeb354364eb15da83d192d77ab698cf3fe43142401c5281c
|
||||
HASH:=d3d1a044412a22a7c366d57e79433532e137e9b184ea9ea68b0eb7577e70e4f3
|
||||
endef
|
||||
$(eval $(call Download,fixup4x_dat))
|
||||
|
||||
@ -82,7 +82,7 @@ define Download/start_elf
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-start.elf
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=start.elf
|
||||
HASH:=2364737aade5c6459a0dfd7b5d5070ab6a6139803779d3f94b579744b40731a5
|
||||
HASH:=5980340e652491926f263ac89b7bc2ab513246bd3eb27103bba4780d6e8568f8
|
||||
endef
|
||||
$(eval $(call Download,start_elf))
|
||||
|
||||
@ -90,7 +90,7 @@ define Download/start_cd_elf
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-start_cd.elf
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=start_cd.elf
|
||||
HASH:=12b98b6c5336b4f1ee1a61753bd6471ce7ce8ee2644550dc79c8e41d3ee4e719
|
||||
HASH:=389a44e371802207ed56fe82a3beaf675eb51176112bde7d77546039d7085572
|
||||
endef
|
||||
$(eval $(call Download,start_cd_elf))
|
||||
|
||||
@ -98,7 +98,7 @@ define Download/start_x_elf
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-start_x.elf
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=start_x.elf
|
||||
HASH:=d21ece84f1ac70148787578ec7549a01d5fa7453b46119ab230470f8e403c0f9
|
||||
HASH:=32016c544353b285394f0006d57a785239fee0262ed1b0ff80b8028c918f0ad9
|
||||
endef
|
||||
$(eval $(call Download,start_x_elf))
|
||||
|
||||
@ -106,7 +106,7 @@ define Download/start4_elf
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-start4.elf
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=start4.elf
|
||||
HASH:=98c4cba6bd4ee03a53b02816c645f783becd9f9899787f7b1bcb8a784eeca4c0
|
||||
HASH:=ec26d746ddf76527b1702fbf7e76c7b036545cc43da81361a2887c92e4965dcc
|
||||
endef
|
||||
$(eval $(call Download,start4_elf))
|
||||
|
||||
@ -114,7 +114,7 @@ define Download/start4cd_elf
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-start4cd.elf
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=start4cd.elf
|
||||
HASH:=b9ee5a895563b891a74ac4be3e9e11be553aa69d600a196556328db164735f8a
|
||||
HASH:=ee507a448911a9d82edf632decb160d5712ab43d8d32b1225f1c406d4eb87820
|
||||
endef
|
||||
$(eval $(call Download,start4cd_elf))
|
||||
|
||||
@ -122,7 +122,7 @@ define Download/start4x_elf
|
||||
FILE:=$(RPI_FIRMWARE_FILE)-start4x.elf
|
||||
URL:=$(RPI_FIRMWARE_URL)
|
||||
URL_FILE:=start4x.elf
|
||||
HASH:=bd2741aca11ecface061fd93d6b412d4f2a777165d780f5a2924569c9417ed92
|
||||
HASH:=9a32a06aadeb84649ee03a15f067fa9285791488ffe61b82f9788303a1355614
|
||||
endef
|
||||
$(eval $(call Download,start4x_elf))
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=broadcom-wl
|
||||
PKG_VERSION:=5.10.56.27.3
|
||||
PKG_RELEASE:=8
|
||||
PKG_RELEASE:=9
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(ARCH).tar.bz2
|
||||
PKG_SOURCE_URL:=http://downloads.openwrt.org/sources
|
||||
|
||||
@ -443,7 +443,10 @@ EOF
|
||||
txpower=${txpower:-$vif_txpower}
|
||||
[ -z "$txpower" ] || iwconfig $device txpower ${txpower}dBm
|
||||
|
||||
eval "$nas_cmd"
|
||||
# fd 1000 is an inherited lock file descriptor for preventing concurrent
|
||||
# init script executions. Close it here to prevent the nas daemon from
|
||||
# inheriting it further to avoid holding the lock indefinitely.
|
||||
eval "$nas_cmd 1000>&-"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-clash
|
||||
PKG_VERSION:=1.6.9b
|
||||
PKG_VERSION:=1.6.9c
|
||||
PKG_MAINTAINER:=frainzy1477
|
||||
|
||||
|
||||
@ -101,8 +101,6 @@ define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
|
||||
$(INSTALL_DIR) $(1)/usr/share/
|
||||
$(INSTALL_DIR) $(1)/usr/share/clash
|
||||
$(INSTALL_DIR) $(1)/usr/rpcd
|
||||
$(INSTALL_DIR) $(1)/usr/rpcd/acl.d
|
||||
$(INSTALL_DIR) $(1)/usr/share/clash/rules
|
||||
$(INSTALL_DIR) $(1)/usr/share/clash/rules/g_rules
|
||||
$(INSTALL_DIR) $(1)/usr/share/clash/dashboard
|
||||
@ -139,8 +137,6 @@ define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_BIN) ./root/usr/share/clash/logstatus_check $(1)/usr/share/clash/
|
||||
$(INSTALL_BIN) ./root/usr/share/clash/clash.txt $(1)/usr/share/clash/
|
||||
|
||||
$(INSTALL_BIN) ./root/usr/rpcd/acl.d/luci-app-clash.json $(1)/usr/rpcd/acl.d/
|
||||
|
||||
$(INSTALL_BIN) ./root/usr/share/clash/dashboard/index.html $(1)/usr/share/clash/dashboard/
|
||||
$(INSTALL_BIN) ./root/usr/share/clash/dashboard/main.1560b07adc97ac0ac265.css $(1)/usr/share/clash/dashboard/
|
||||
$(INSTALL_BIN) ./root/usr/share/clash/dashboard/img/ffac0fa1d89f15922b4594863b8b32e9.png $(1)/usr/share/clash/dashboard/img/
|
||||
|
||||
@ -12,8 +12,6 @@ function index()
|
||||
end
|
||||
|
||||
entry({"admin", "services", "clash"},alias("admin", "services", "clash", "overview"), _("Clash"), 5)
|
||||
page.dependent = true
|
||||
page.acl_depends = { "luci-app-openclash" }
|
||||
entry({"admin", "services", "clash", "overview"},cbi("clash/overview"),_("Overview"), 10).leaf = true
|
||||
entry({"admin", "services", "clash", "client"},cbi("clash/client"),_("Client"), 20).leaf = true
|
||||
|
||||
|
||||
@ -8,12 +8,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=bcm27xx-userland
|
||||
PKG_VERSION:=6fb59736b1ae80fc62cddfe3309c800f72e1c07e
|
||||
PKG_VERSION:=f4bccc38f9d0a740aeb7818d33ca1fd551e325de
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/raspberrypi/userland/tar.gz/$(PKG_VERSION)?
|
||||
PKG_HASH:=f81fe28c636178645fb406cc87f543efa828ca896df856536f7b1b4ab54dfe0e
|
||||
PKG_HASH:=3a4ea8788809bf889da9fe61759e4f8daafab3444264c011db9c6b25237fd044
|
||||
|
||||
PKG_FLAGS:=nonshared
|
||||
|
||||
@ -51,10 +51,12 @@ define Package/bcm27xx-userland/install
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dtmerge $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dtparam $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dtoverlay $(1)/usr/bin
|
||||
ifneq ($(ARCH),aarch64)
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspistill $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspivid $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspividyuv $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspiyuv $(1)/usr/bin
|
||||
endif
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/tvservice $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vcgencmd $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vcmailbox $(1)/usr/bin
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
From 39c946b5dfcc38d3b2cd16d9c96f47a8341387cd Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
|
||||
Date: Thu, 28 May 2020 15:19:57 +0200
|
||||
Subject: [PATCH] Revert "Add MMAL and MMAL_APPS to 64bit builds"
|
||||
|
||||
This reverts commit 7d3c6b9f4c3ddeecefdeb2b882bada74a235249b.
|
||||
---
|
||||
CMakeLists.txt | 18 ++++++++++--------
|
||||
host_applications/linux/CMakeLists.txt | 4 ++--
|
||||
interface/mmal/CMakeLists.txt | 6 ++----
|
||||
3 files changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -8,9 +8,13 @@ SET(PROJECT_VER_PATCH 0)
|
||||
SET(PROJECT_VER "${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}.${PROJECT_VER_PATCH}")
|
||||
SET(PROJECT_APIVER "${PROJECT_VER}")
|
||||
|
||||
-set(BUILD_MMAL TRUE)
|
||||
-set(BUILD_MMAL_APPS TRUE)
|
||||
-
|
||||
+if(ARM64)
|
||||
+ set(BUILD_MMAL FALSE)
|
||||
+ set(BUILD_MMAL_APPS FALSE)
|
||||
+else()
|
||||
+ set(BUILD_MMAL TRUE)
|
||||
+ set(BUILD_MMAL_APPS TRUE)
|
||||
+endif()
|
||||
set(vmcs_root ${PROJECT_SOURCE_DIR})
|
||||
get_filename_component(VIDEOCORE_ROOT . ABSOLUTE)
|
||||
|
||||
@@ -74,11 +78,9 @@ if(BUILD_MMAL)
|
||||
endif()
|
||||
|
||||
# VidTex supports Android and Linux
|
||||
-if(NOT ARM64)
|
||||
- if(BUILD_MMAL_APPS)
|
||||
- add_subdirectory(host_applications/android/apps/vidtex)
|
||||
- endif(BUILD_MMAL_APPS)
|
||||
-endif()
|
||||
+if(BUILD_MMAL_APPS)
|
||||
+add_subdirectory(host_applications/android/apps/vidtex)
|
||||
+endif(BUILD_MMAL_APPS)
|
||||
|
||||
if(NOT ARM64)
|
||||
add_subdirectory(middleware/openmaxil)
|
||||
--- a/host_applications/linux/CMakeLists.txt
|
||||
+++ b/host_applications/linux/CMakeLists.txt
|
||||
@@ -4,9 +4,9 @@ add_subdirectory(libs/bcm_host)
|
||||
add_subdirectory(apps/gencmd)
|
||||
add_subdirectory(apps/tvservice)
|
||||
add_subdirectory(apps/vcmailbox)
|
||||
-add_subdirectory(apps/raspicam)
|
||||
-add_subdirectory(libs/sm)
|
||||
if(NOT ARM64)
|
||||
+ add_subdirectory(apps/raspicam)
|
||||
+ add_subdirectory(libs/sm)
|
||||
add_subdirectory(apps/smem)
|
||||
endif()
|
||||
add_subdirectory(libs/debug_sym)
|
||||
--- a/interface/mmal/CMakeLists.txt
|
||||
+++ b/interface/mmal/CMakeLists.txt
|
||||
@@ -11,10 +11,8 @@ add_subdirectory(core)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(vc)
|
||||
add_subdirectory(components)
|
||||
-if(NOT ARM64)
|
||||
- add_subdirectory(openmaxil)
|
||||
- add_subdirectory(client)
|
||||
-endif()
|
||||
+add_subdirectory(openmaxil)
|
||||
+add_subdirectory(client)
|
||||
|
||||
target_link_libraries(mmal mmal_core mmal_util mmal_vc_client vcos mmal_components)
|
||||
|
||||
@ -11,4 +11,4 @@ fbtest: $(OBJS)
|
||||
$(CC) -o $@ $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f rbcfg *.o
|
||||
rm -f fbtest *.o
|
||||
|
||||
@ -8,11 +8,11 @@ include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/target.mk
|
||||
|
||||
PKG_NAME:=ccache
|
||||
PKG_VERSION:=3.7.7
|
||||
PKG_VERSION:=3.7.9
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
|
||||
PKG_SOURCE_URL:=https://github.com/ccache/ccache/releases/download/v$(PKG_VERSION)
|
||||
PKG_HASH:=b7c1d6d6fe42f18e424de92746af863e0bc85794da3d69e44300840c478c98cd
|
||||
PKG_HASH:=f893da7543bfb9172bd55e603fcbdfcd83e6def176a28689c13235695b4cf44b
|
||||
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--- a/src/ccache.c
|
||||
+++ b/src/ccache.c
|
||||
@@ -2220,6 +2220,7 @@ calculate_object_hash(struct args *args,
|
||||
@@ -2227,6 +2227,7 @@ calculate_object_hash(struct args *args,
|
||||
"CPLUS_INCLUDE_PATH",
|
||||
"OBJC_INCLUDE_PATH",
|
||||
"OBJCPLUS_INCLUDE_PATH", // clang
|
||||
|
||||
Loading…
Reference in New Issue
Block a user