🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot] committed 2026-03-05 23:51:42 +08:00
1 parent 0d155c70be
commit 32600acc60
14258 files changed
+3954570

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
oaf-objs := app_filter.o af_utils.o af_config.o regexp.o cJSON.o af_log.o af_client.o af_client_fs.o af_conntrack.o af_rule_config.o af_user_config.o af_whitelist_config.o
obj-m += oaf.o
+663
View File
@@ -0,0 +1,663 @@
/*
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 <linux/netfilter_ipv6.h>
#include <linux/ipv6.h>
#include <linux/in6.h>
#include <linux/timer.h>
#include "af_client.h"
#include "af_client_fs.h"
#include "af_log.h"
#include "af_utils.h"
#include "app_filter.h"
#include "cJSON.h"
DEFINE_RWLOCK(af_client_lock);
u32 total_client = 0;
struct list_head af_client_list_table[MAX_AF_CLIENT_HASH_SIZE];
int af_send_msg_to_user(char *pbuf, uint16_t len);
extern char *ipv6_to_str(const struct in6_addr *addr, char *str);
static void init_client_timer(af_client_info_t *client);
static void stop_client_timer(af_client_info_t *client);
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);
stop_client_timer(p);
list_del(&(p->hlist));
kfree(p);
}
}
AF_CLIENT_UNLOCK_W();
}
void af_client_list_reset_report_num(void)
{
int i;
af_client_info_t *node = NULL;
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)
{
node->report_count = 0;
}
}
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))
{
return node;
}
}
return NULL;
}
af_client_info_t *find_and_add_af_client(unsigned char *mac)
{
af_client_info_t *nfc;
nfc = find_af_client(mac);
if (!nfc){
nfc = nf_client_add(mac);
}
return nfc;
}
af_client_info_t *find_af_client_by_ip(unsigned int ip)
{
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;
}
af_client_info_t *find_af_client_by_ipv6(struct in6_addr *ipv6)
{
af_client_info_t *node;
int i;
char addr_str[64] = {0};
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++)
{
list_for_each_entry(node, &af_client_list_table[i], hlist)
{
if (ipv6_addr_equal(&node->ipv6, ipv6))
{
AF_INFO("match node->ipv6=%s\n", ipv6_to_str(&node->ipv6, addr_str));
return node;
}
}
}
return NULL;
}
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++;
init_client_timer(node);
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));
stop_client_timer(node);
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)
{
// 3?��o?��??3y????
memset(&node->visit_info[i], 0x0, sizeof(app_visit_info_t));
count++;
}
}
}
int __af_visit_info_report(af_client_info_t *node)
{
unsigned char mac_str[32] = {0};
unsigned char ip_str[32] = {0};
int i;
int count = 0;
char *out = NULL;
cJSON *visit_obj = NULL;
cJSON *visit_info_array = NULL;
cJSON *root_obj = NULL;
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_AddNumberToObject(root_obj, "up_flow", (u32)(node->period_flow.up_bytes >> 10));
cJSON_AddNumberToObject(root_obj, "down_flow", (u32)(node->period_flow.down_bytes >> 10));
cJSON_AddNumberToObject(root_obj, "active", node->active);
visit_info_array = cJSON_CreateArray();
for (i = 0; i < MAX_RECORD_APP_NUM; i++)
{
if (node->visit_info[i].app_id == 0)
continue;
count++;
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);
memset((char *)&node->visit_info[i], 0x0, sizeof(app_visit_info_t));
cJSON_AddItemToArray(visit_info_array, visit_obj);
}
cJSON_AddItemToObject(root_obj, "visit_info", visit_info_array);
out = cJSON_Print(root_obj);
if (!out) {
cJSON_Delete(root_obj);
return 0;
}
cJSON_Minify(out);
AF_INFO("report:%s count=%d\n", out, node->report_count);
node->report_count++;
af_send_msg_to_user(out, strlen(out));
cJSON_Delete(root_obj);
memset(&node->period_flow, 0x0, sizeof(node->period_flow));
kfree(out);
return 0;
}
static inline int get_packet_dir(struct net_device *in)
{
if (strstr(in->name, g_lan_ifname))
{
return PKT_DIR_UP;
}
else
{
return PKT_DIR_DOWN;
}
}
void af_update_client_status(af_client_info_t *node)
{
if (node->last_flow.down_bytes > 0){
node->period_flow.down_bytes += (node->flow.down_bytes - node->last_flow.down_bytes);
}
if (node->last_flow.up_bytes > 0){
node->period_flow.up_bytes += (node->flow.up_bytes - node->last_flow.up_bytes);
}
AF_LMT_DEBUG("period flow down:%llu up: %llu pkg up %d\n", node->period_flow.down_bytes,
node->period_flow.up_bytes, node->rate.pkt_up_rate);
// 2s
node->rate.up_rate = (node->flow.up_bytes - node->last_flow.up_bytes) >> 1;
node->rate.down_rate = (node->flow.down_bytes - node->last_flow.down_bytes) >> 1;
node->rate.pkt_up_rate = (node->flow.up_pkts - node->last_flow.up_pkts) >> 1;
node->rate.pkt_down_rate = (node->flow.down_pkts - node->last_flow.down_pkts) >> 1;
node->last_flow.up_bytes = node->flow.up_bytes;
node->last_flow.down_bytes = node->flow.down_bytes;
node->last_flow.up_pkts = node->flow.up_pkts;
node->last_flow.down_pkts = node->flow.down_pkts;
if (node->rate.pkt_down_rate > 10 || node->rate.pkt_up_rate > 5){
node->active_time++;
node->inactive_time = 0;
node->active = 1;
}
else{
node->inactive_time++;
node->active_time = 0;
if (node->active && node->inactive_time > 30){
node->active = 0;
}
}
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
static u_int32_t af_client_hook(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
#else
static u_int32_t af_client_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;
struct iphdr *iph = NULL;
unsigned int ip = 0;
struct ipv6hdr *ip6h = NULL;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (NULL == ct)
return NF_ACCEPT;
if (skb->protocol == htons(ETH_P_IPV6) && AF_MODE_GATEWAY != af_work_mode){
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);
}
AF_CLIENT_LOCK_W();
nfc = find_af_client(smac);
if (!nfc)
{
if (skb->dev)
AF_DEBUG("from dev:%s %pI4", skb->dev->name, &ip);
nfc = nf_client_add(smac);
}
if (nfc) {
if (skb->protocol == htons(ETH_P_IP)) {
iph = ip_hdr(skb);
if (iph && nfc->ip != iph->saddr) {
AF_DEBUG("update node " MAC_FMT " ipv4 %pI4--->%pI4\n",
MAC_ARRAY(nfc->mac), &nfc->ip, &iph->saddr);
nfc->ip = iph->saddr;
}
}
else if (skb->protocol == htons(ETH_P_IPV6)) {
ip6h = ipv6_hdr(skb);
if (ip6h && !ipv6_addr_equal(&nfc->ipv6, &ip6h->saddr)) {
nfc->ipv6 = ip6h->saddr;
}
}
nfc->flow.up_bytes += skb->len;
nfc->flow.up_pkts++;
}
AF_CLIENT_UNLOCK_W();
return NF_ACCEPT;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
static u_int32_t af_client_hook2(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
#else
static u_int32_t af_client_hook2(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;
struct iphdr *iph = NULL;
struct ipv6hdr *ip6h = NULL;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
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 (!skb->dev)
{
return NF_ACCEPT;
}
if (PKT_DIR_DOWN != pkt_dir)
return NF_ACCEPT;
AF_CLIENT_LOCK_R();
if (skb->protocol == htons(ETH_P_IP)) {
iph = ip_hdr(skb);
nfc = find_af_client_by_ip(iph->daddr);
}
else if (skb->protocol == htons(ETH_P_IPV6)) {
ip6h = ipv6_hdr(skb);
nfc = find_af_client_by_ipv6(&ip6h->daddr);
if (nfc){
AF_LMT_DEBUG("found ipv6 %pI6 client\n", &ip6h->daddr);
}
else{
AF_LMT_DEBUG("not found ipv6 %pI6 client\n", &ip6h->daddr);
}
}
if (nfc){
nfc->flow.down_bytes += skb->len;
nfc->flow.down_pkts++;
}
AF_CLIENT_UNLOCK_R();
return NF_ACCEPT;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
static struct nf_hook_ops af_client_ops[] = {
{
.hook = af_client_hook,
.pf = NFPROTO_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FIRST + 1,
},
{
.hook = af_client_hook2,
.pf = NFPROTO_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_LAST - 1,
},
};
#else
static struct nf_hook_ops af_client_ops[] = {
{
.hook = af_client_hook,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
.owner = THIS_MODULE,
#endif
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FIRST + 1,
},
{
.hook = af_client_hook,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
.owner = THIS_MODULE,
#endif
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FIRST + 1,
},
};
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
static void client_timer_handler(struct timer_list *t)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 16, 0)
af_client_info_t *client = from_timer(client, t, client_timer);
#else
af_client_info_t *client = timer_container_of(client, t, client_timer);
#endif
#else
static void client_timer_handler(unsigned long data)
{
af_client_info_t *client = (af_client_info_t *)data;
#endif
if (!client) {
AF_ERROR("client timer handler: invalid client\n");
return;
}
if (client->timer_count >= 30) {
__af_visit_info_report(client);
client->timer_count = 0;
}
af_update_client_status(client);
client->timer_count++;
mod_timer(&client->client_timer, jiffies + HZ * 2);
}
void init_client_timer(af_client_info_t *client)
{
if (!client) {
AF_ERROR("init_client_timer: invalid client\n");
return;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
timer_setup(&client->client_timer, client_timer_handler, 0);
#else
setup_timer(&client->client_timer, client_timer_handler, (unsigned long)client);
#endif
mod_timer(&client->client_timer, jiffies + HZ * 1);
}
void stop_client_timer(af_client_info_t *client)
{
if (!client) {
AF_ERROR("stop_client_timer: invalid client\n");
return;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 16, 0)
del_timer_sync(&client->client_timer);
#else
timer_delete_sync(&client->client_timer);
#endif
}
int af_client_init(void)
{
int err;
nf_client_list_init();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
err = nf_register_net_hooks(&init_net, af_client_ops, ARRAY_SIZE(af_client_ops));
#else
err = nf_register_hooks(af_client_ops, ARRAY_SIZE(af_client_ops));
#endif
if (err) {
AF_ERROR("oaf register client hooks failed!\n");
}
AF_INFO("init app afclient ........ok\n");
return 0;
}
void af_client_exit(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 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;
}
+106
View File
@@ -0,0 +1,106 @@
#ifndef __AF_CLIENT_H__
#define __AF_CLIENT_H__
#include "app_filter.h"
extern rwlock_t af_client_lock;
extern u32 nfc_debug_level;
#define MAX_AF_CLIENT_HASH_SIZE 64
#define 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
#define MIN_REPORT_URL_LEN 4
#define MAX_REPORT_URL_LEN 64
typedef struct flow_stat
{
long long up_bytes;
long long down_bytes;
long long up_pkts;
long long down_pkts;
} flow_stat_t;
typedef struct flow_rate
{
unsigned int up_rate;
unsigned int down_rate;
unsigned int pkt_up_rate;
unsigned int pkt_down_rate;
}flow_rate_t;
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;
} app_visit_info_t;
typedef struct visiting_info{
int visiting_app;
int app_time;
char visiting_url[MAX_REPORT_URL_LEN];
int url_time;
}visiting_info_t;
typedef struct af_client_info
{
struct list_head hlist;
unsigned char mac[MAC_ADDR_LEN];
unsigned int ip;
struct in6_addr ipv6;
unsigned long create_jiffies;
unsigned long update_jiffies;
flow_stat_t flow;
flow_stat_t last_flow;
flow_stat_t period_flow;
flow_rate_t rate;
struct timer_list client_timer;
unsigned int visit_app_num;
int active_time;
int inactive_time;
int active;
visiting_info_t visiting;
int timer_count;
int report_count;
app_visit_info_t visit_info[MAX_RECORD_APP_NUM];
} af_client_info_t;
int af_client_init(void);
void af_client_exit(void);
af_client_info_t *find_af_client_by_ip(unsigned int ip);
af_client_info_t *find_af_client_by_ipv6(struct in6_addr *addr);
af_client_info_t *find_af_client(unsigned char *mac);
void check_client_expire(void);
void af_visit_info_report(void);
void af_client_list_reset_report_num(void);
af_client_info_t *nf_client_add(unsigned char *mac);
af_client_info_t *find_and_add_af_client(unsigned char *mac);
#endif
+296
View File
@@ -0,0 +1,296 @@
#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 "af_utils.h"
#include "cJSON.h"
#include "af_log.h"
#include "af_client.h"
extern char *ipv6_to_str(const struct in6_addr *addr, char *str);
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)
{
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};
unsigned char ipv6_str[128];
static int index = 0;
af_client_info_t *node = (af_client_info_t *)v;
if (v == SEQ_START_TOKEN)
{
index = 0;
seq_printf(s, "%-4s %-20s %-20s %-32s %-16s %-16s\n", "Id", "Mac", "IP", "IPv6", "UpRate", "DownRate");
return 0;
}
index++;
sprintf(mac_str, MAC_FMT, MAC_ARRAY(node->mac));
sprintf(ip_str, "%pI4", &node->ip);
ipv6_to_str(&node->ipv6, ipv6_str);
seq_printf(s, "%-4d %-20s %-20s %-32s %-16d %-16d\n", index, mac_str, ip_str, ipv6_str, node->rate.up_rate, node->rate.down_rate);
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;
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 5, 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,
};
#else
static const struct proc_ops af_client_fops = {
.proc_flags = PROC_ENTRY_PERMANENT,
.proc_read = seq_read,
.proc_open = af_client_open,
.proc_lseek = seq_lseek,
.proc_release = seq_release_private,
};
#endif
#define AF_CLIENT_PROC_STR "af_client"
static int af_visiting_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;
af_client_info_t *node = (af_client_info_t *)v;
if (v == SEQ_START_TOKEN)
{
index = 0;
seq_printf(s, "%-20s %-12s %-32s\n", "Mac", "Appid", "Url");
return 0;
}
index++;
sprintf(mac_str, MAC_FMT, MAC_ARRAY(node->mac));
int visiting_app = 0;
char visiting_url[64] = {0};
if (af_get_timestamp_sec() - node->visiting.app_time < 120){
visiting_app = node->visiting.visiting_app;
}
if ( af_get_timestamp_sec() - node->visiting.url_time < 120 ){
strncpy(visiting_url, node->visiting.visiting_url, sizeof(visiting_url));
}
else{
strcpy(visiting_url, "none");
}
seq_printf(s, "%-20s %-12d %-32s\n", mac_str, visiting_app, visiting_url);
return 0;
}
static const struct seq_operations nf_visiting_seq_ops = {
.start = af_client_seq_start,
.next = af_client_seq_next,
.stop = af_client_seq_stop,
.show = af_visiting_seq_show
};
static int af_visiting_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_visiting_seq_ops);
if (err)
{
kfree(iter);
return err;
}
seq = file->private_data;
seq->private = iter;
return 0;
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 5, 0)
static const struct file_operations af_visiting_fops = {
.owner = THIS_MODULE,
.open = af_visiting_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
#else
static const struct proc_ops af_visiting_fops = {
.proc_flags = PROC_ENTRY_PERMANENT,
.proc_read = seq_read,
.proc_open = af_visiting_open,
.proc_lseek = seq_lseek,
.proc_release = seq_release_private,
};
#endif
#define AF_VISIT_INFO "af_visit"
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;
}
pde = proc_create(AF_VISIT_INFO, 0440, net->proc_net, &af_visiting_fops);
if (!pde)
{
AF_ERROR("client visiting 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);
remove_proc_entry(AF_VISIT_INFO, net->proc_net);
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef __AF_CLIENT_FS_H__
#define __AF_CLIENT_FS_H__
int init_af_client_procfs(void);
void finit_af_client_procfs(void);
#endif
+234
View File
@@ -0,0 +1,234 @@
#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 <linux/version.h>
#include "cJSON.h"
#include "app_filter.h"
#include "af_config.h"
#include "af_utils.h"
#include "af_log.h"
#include "af_rule_config.h"
#include "af_user_config.h"
#include "af_whitelist_config.h"
#define AF_DEV_NAME "appfilter"
extern u_int32_t g_update_jiffies;
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];
};
static struct af_config_interface af_config_interfaces[] = {
{AF_CMD_ADD_APPID, af_config_add_appid, "Add App ID"},
{AF_CMD_DEL_APPID, af_config_del_appid, "Delete App ID"},
{AF_CMD_CLEAN_APPID, af_config_clean_appid, "Clean App ID"},
{AF_CMD_SET_MAC_LIST, af_config_set_mac_list, "Set MAC List"},
{AF_CMD_SET_WHITELIST_MAC_LIST, af_config_set_whitelist_mac_list, "Set Whitelist MAC List"},
{0, NULL, NULL}
};
static af_config_handler_t af_find_handler(enum AF_CONFIG_CMD cmd)
{
struct af_config_interface *interface = af_config_interfaces;
while (interface->handler != NULL) {
if (interface->cmd == cmd) {
return interface->handler;
}
interface++;
}
return NULL;
}
/*
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;
int ret = 0;
af_config_handler_t handler = NULL;
if (!config || len == 0)
{
AF_ERROR("config or len is invalid\n");
return -1;
}
AF_DEBUG("config = %s\n", config);
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");
cJSON_Delete(config_obj);
return -1;
}
data_obj = cJSON_GetObjectItem(config_obj, "data");
handler = af_find_handler(cmd_obj->valueint);
if (handler) {
ret = handler(data_obj);
g_update_jiffies = jiffies;
cJSON_Delete(config_obj);
return ret;
} else {
AF_ERROR("invalid cmd %d\n", cmd_obj->valueint);
cJSON_Delete(config_obj);
return -1;
}
}
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;
AF_DEBUG("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))
{
AF_ERROR("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;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
g_af_dev.c = class_create(THIS_MODULE, AF_DEV_NAME);
#else
g_af_dev.c = class_create(AF_DEV_NAME);
#endif
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;
}
AF_INFO("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);
AF_ERROR("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);
AF_INFO("unregister char dev....ok\n");
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef __AF_CONFIG_H__
#define __AF_CONFIG_H__
#include "app_filter.h"
enum AF_CONFIG_CMD
{
AF_CMD_ADD_APPID = 1,
AF_CMD_DEL_APPID,
AF_CMD_CLEAN_APPID,
AF_CMD_SET_MAC_LIST,
AF_CMD_SET_WHITELIST_MAC_LIST,
};
typedef int (*af_config_handler_t)(cJSON *data);
struct af_config_interface
{
enum AF_CONFIG_CMD cmd;
af_config_handler_t handler;
const char *description;
};
int af_register_dev(void);
void af_unregister_dev(void);
int af_config_add_appid(cJSON *data);
int af_config_del_appid(cJSON *data);
int af_config_clean_appid(cJSON *data);
int af_config_set_mac_list(cJSON *data);
int af_config_set_whitelist_mac_list(cJSON *data);
#endif
+302
View File
@@ -0,0 +1,302 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/jhash.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <net/ip.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/etherdevice.h>
#include <linux/cdev.h>
#include "af_conntrack.h"
#include "af_log.h"
struct hlist_head af_conn_table[AF_CONN_HASH_SIZE];
DEFINE_SPINLOCK(af_conn_lock);
static u32 af_conn_hash(u32 src_ip, u32 dst_ip,
u16 src_port, u16 dst_port,
u8 protocol)
{
return jhash_3words(src_ip, dst_ip,
((u32)protocol << 16) | src_port,
dst_port) % AF_CONN_HASH_SIZE;
}
void af_conn_cleanup(void)
{
int i;
spin_lock(&af_conn_lock);
af_conn_t *p = NULL;
struct hlist_node *n;
for (i = 0; i < AF_CONN_HASH_SIZE; i++)
{
hlist_for_each_entry_safe(p, n, &af_conn_table[i], node)
{
hlist_del(&p->node);
kfree(p);
}
}
spin_unlock(&af_conn_lock);
}
af_conn_t *af_conn_add(u32 src_ip, u32 dst_ip, u16 src_port, u16 dst_port, u8 protocol)
{
u32 hash;
af_conn_t *conn;
hash = af_conn_hash(src_ip, dst_ip, src_port, dst_port, protocol);
conn = kmalloc(sizeof(af_conn_t), GFP_ATOMIC);
if (!conn) {
return NULL;
}
conn->src_ip = src_ip;
conn->dst_ip = dst_ip;
conn->src_port = src_port;
conn->dst_port = dst_port;
conn->protocol = protocol;
conn->total_pkts = 0;
conn->app_id = 0;
conn->client_hello = 0;
conn->drop = 0;
conn->state = AF_CONN_NEW;
conn->last_jiffies = jiffies;
hlist_add_head(&conn->node, &af_conn_table[hash]);
AF_LMT_INFO("add new conn ok...%pI4:%d->%pI4:%d %d\n",
&conn->src_ip, conn->src_port, &conn->dst_ip, conn->dst_port, conn->protocol);
return conn;
}
af_conn_t* af_conn_find(u32 src_ip, u32 dst_ip, u16 src_port, u16 dst_port, u8 protocol)
{
u32 hash;
af_conn_t *conn;
hash = af_conn_hash(src_ip, dst_ip, src_port, dst_port, protocol);
hlist_for_each_entry(conn, &af_conn_table[hash], node)
{
if (conn->src_ip == src_ip && conn->dst_ip == dst_ip &&
conn->src_port == src_port && conn->dst_port == dst_port &&
conn->protocol == protocol) {
return conn;
}
}
return NULL;
}
af_conn_t* af_conn_find_and_add(u32 src_ip, u32 dst_ip, u16 src_port, u16 dst_port, u8 protocol)
{
af_conn_t *conn;
conn = af_conn_find(src_ip, dst_ip, src_port, dst_port, protocol);
if (!conn)
{
conn = af_conn_add(src_ip, dst_ip, src_port, dst_port, protocol);
}
return conn;
}
void af_conn_update(af_conn_t *conn, u32 app_id, u8 drop)
{
spin_lock(&af_conn_lock);
conn->app_id = app_id;
conn->drop = drop;
conn->last_jiffies = jiffies;
spin_unlock(&af_conn_lock);
}
#define MAX_AF_CONN_CHECK_COUNT 5
void af_conn_clean_timeout(void)
{
int i;
af_conn_t *conn;
struct hlist_node *n;
unsigned long timeout = AF_CONN_TIMEOUT * HZ;
static int last_bucket = 0;
int count = 0;
spin_lock(&af_conn_lock);
for (i = last_bucket; i < AF_CONN_HASH_SIZE; i++)
{
hlist_for_each_entry_safe(conn, n, &af_conn_table[i], node)
{
if (time_after(jiffies, conn->last_jiffies + timeout)) {
AF_LMT_INFO("clean timeout conn ok...%pI4:%d->%pI4:%d %d\n",
&conn->src_ip, conn->src_port, &conn->dst_ip, conn->dst_port, conn->protocol);
hlist_del(&(conn->node));
kfree(conn);
}
}
last_bucket = i;
count++;
if (count > MAX_AF_CONN_CHECK_COUNT)
break;
}
if (last_bucket == AF_CONN_HASH_SIZE - 1)
{
last_bucket = 0;
}
spin_unlock(&af_conn_lock);
}
struct af_conn_iter_state
{
unsigned int bucket;
};
static void *af_conn_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos == 0)
{
return SEQ_START_TOKEN;
}
struct af_conn_iter_state *st = s->private;
while (st->bucket < AF_CONN_HASH_SIZE){
if (!hlist_empty(&(af_conn_table[st->bucket])))
{
return &af_conn_table[st->bucket++].first->next;
}
st->bucket++;
}
return NULL;
}
static void *af_conn_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
if (v == SEQ_START_TOKEN){
return NULL;
}
struct hlist_node *node = (struct hlist_node *)v;
node = node->next;
if (node != NULL)
return node;
return NULL;
}
static void af_conn_seq_stop(struct seq_file *s, void *v)
{
}
static int af_conn_seq_show(struct seq_file *s, void *v)
{
unsigned char src_ip_str[32] = {0};
unsigned char dst_ip_str[32] = {0};
static int index = 0;
af_conn_t *node = (af_conn_t *)v;
if (v == SEQ_START_TOKEN)
{
index = 0;
seq_printf(s, "%-4s %-20s %-20s %-12s %-12s %-12s %-12s %-12s %-12s %-12s\n",
"Id", "src_ip", "dst_ip", "src_port", "dst_port", "protocol", "app_id", "drop", "inactive", "total_pkts");
return 0;
}
index++;
sprintf(src_ip_str, "%pI4", &node->src_ip);
sprintf(dst_ip_str, "%pI4", &node->dst_ip);
u_int32_t inactive_time = jiffies - node->last_jiffies;
seq_printf(s, "%-4d %-20s %-20s %-12d %-12d %-12d %-12d %-12d %-12d %-12d\n", index, src_ip_str, dst_ip_str,
node->src_port, node->dst_port, node->protocol, node->app_id, node->drop, inactive_time, node->total_pkts);
return 0;
}
static const struct seq_operations af_conn_seq_ops = {
.start = af_conn_seq_start,
.next = af_conn_seq_next,
.stop = af_conn_seq_stop,
.show = af_conn_seq_show
};
static int af_conn_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
struct af_conn_iter_state *iter;
int err;
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
if (!iter)
return -ENOMEM;
err = seq_open(file, &af_conn_seq_ops);
if (err)
{
kfree(iter);
return err;
}
seq = file->private_data;
seq->private = iter;
return 0;
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 5, 0)
static const struct file_operations af_conn_fops = {
.owner = THIS_MODULE,
.open = af_conn_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
#else
static const struct proc_ops af_conn_fops = {
.proc_flags = PROC_ENTRY_PERMANENT,
.proc_read = seq_read,
.proc_open = af_conn_open,
.proc_lseek = seq_lseek,
.proc_release = seq_release_private,
};
#endif
#define AF_CONN_PROC_STR "af_conn"
int af_conn_init_procfs(void)
{
struct proc_dir_entry *pde;
struct net *net = &init_net;
pde = proc_create(AF_CONN_PROC_STR, 0644, net->proc_net, &af_conn_fops);
if (!pde)
{
printk("af_conn seq file created error\n");
return -1;
}
return 0;
}
void af_conn_remove_procfs(void)
{
struct net *net = &init_net;
remove_proc_entry(AF_CONN_PROC_STR, net->proc_net);
}
int af_conn_init(void)
{
int i;
for (i = 0; i < AF_CONN_HASH_SIZE; i++)
{
INIT_HLIST_HEAD(&af_conn_table[i]);
}
af_conn_init_procfs();
return 0;
}
void af_conn_exit(void){
af_conn_remove_procfs();
af_conn_cleanup();
}
+53
View File
@@ -0,0 +1,53 @@
#ifndef __AF_SIMPLE_CONNTRACK_H__
#define __AF_SIMPLE_CONNTRACK_H__
#include <linux/types.h>
#include <linux/list.h>
#define AF_CONN_TIMEOUT 30
#define AF_CONN_HASH_SIZE 256
extern spinlock_t af_conn_lock;
typedef enum {
AF_CONN_NEW = 0,
AF_CONN_ESTABLISHED,
AF_CONN_DPI_FINISHED,
} af_conn_state_t;
typedef struct {
struct hlist_node node;
u32 src_ip;
u32 dst_ip;
u16 src_port;
u16 dst_port;
u8 protocol;
u32 total_pkts;
u32 app_id;
u8 client_hello;
u8 drop;
u8 ignore;
af_conn_state_t state;
unsigned long last_jiffies;
} af_conn_t;
int af_conn_init(void);
void af_conn_cleanup(void);
af_conn_t* af_conn_add(u32 src_ip, u32 dst_ip,
u16 src_port, u16 dst_port,
u8 protocol);
af_conn_t* af_conn_find(u32 src_ip, u32 dst_ip,
u16 src_port, u16 dst_port,
u8 protocol);
af_conn_t* af_conn_find_and_add(u32 src_ip, u32 dst_ip,
u16 src_port, u16 dst_port,
u8 protocol);
void af_conn_update(af_conn_t *conn, u32 app_id, u8 drop);
void af_conn_clean_timeout(void);
void af_conn_exit(void);
#endif
+183
View File
@@ -0,0 +1,183 @@
#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 "app_filter.h"
#include "af_log.h"
int af_log_lvl = 1;
int af_test_mode = 0;
// todo: rename af_log.c
int g_oaf_filter_enable __read_mostly = 0;
int g_oaf_record_enable __read_mostly = 0;
int g_by_pass_accl = 1;
int g_user_mode = 0;
int af_work_mode = AF_MODE_GATEWAY;
unsigned int af_lan_ip = 0;
unsigned int af_lan_mask = 0;
char g_lan_ifname[64] = "br-lan";
int g_tcp_rst = 1;
int g_feature_init = 0;
char g_oaf_version[64] = AF_VERSION;
int g_disable_quic = 0;
int g_app_filter_mode = 0; // 0 = specified apps, 1 = all apps
/*
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 = "feature_init",
.data = &g_feature_init,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "version",
.data = g_oaf_version,
.maxlen = 64,
.mode = 0444,
.proc_handler = proc_dostring,
},
{
.procname = "test_mode",
.data = &af_test_mode,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "enable",
.data = &g_oaf_filter_enable,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "by_pass_accl",
.data = &g_by_pass_accl,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "tcp_rst",
.data = &g_tcp_rst,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "lan_ifname",
.data = g_lan_ifname,
.maxlen = 64,
.mode = 0666,
.proc_handler = proc_dostring,
},
{
.procname = "record_enable",
.data = &g_oaf_record_enable,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "user_mode",
.data = &g_user_mode,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "work_mode",
.data = &af_work_mode,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "lan_ip",
.data = &af_lan_ip,
.maxlen = sizeof(unsigned int),
.mode = 0666,
.proc_handler = proc_douintvec,
},
{
.procname = "lan_mask",
.data = &af_lan_mask,
.maxlen = sizeof(unsigned int),
.mode = 0666,
.proc_handler = proc_douintvec,
},
{
.procname = "disable_quic",
.data = &g_disable_quic,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "app_filter_mode",
.data = &g_app_filter_mode,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0))
{
}
#endif
};
#define OAF_SYS_PROC_DIR "oaf"
static struct ctl_table oaf_root_table[] = {
{
.procname = OAF_SYS_PROC_DIR,
.mode = 0555,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0))
.child = oaf_table,
#endif
},
{}
};
static struct ctl_table_header *oaf_table_header;
static int af_init_log_sysctl(void)
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0))
oaf_table_header = register_sysctl_table(oaf_root_table);
#else
oaf_table_header = register_sysctl(OAF_SYS_PROC_DIR, oaf_table);
#endif
if (oaf_table_header == NULL){
printk("init log sysctl...failed\n");
return -ENOMEM;
}
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();
return 0;
}
int af_log_exit(void){
af_fini_log_sysctl();
return 0;
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef __AF_DEBUG_H__
#define __AF_DEBUG_H__
extern int af_log_lvl;
extern int af_test_mode;
extern int af_work_mode;
extern int g_oaf_filter_enable;
extern int g_oaf_record_enable;
extern int g_by_pass_accl;
extern unsigned int af_lan_ip;
extern unsigned int af_lan_mask;
extern int g_feature_init;
extern int g_user_mode;
extern int g_disable_quic;
extern int g_app_filter_mode;
extern char g_lan_ifname[64];
extern int g_tcp_rst;
#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
+116
View File
@@ -0,0 +1,116 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/version.h>
#include "cJSON.h"
#include "app_filter.h"
#include "af_utils.h"
#include "af_log.h"
#define AF_MAX_APP_TYPE_NUM 32
#define AF_MAX_APP_NUM 512
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);
extern u_int32_t g_update_jiffies;
char g_app_id_array[AF_MAX_APP_TYPE_NUM][AF_MAX_APP_NUM] = {0};
void af_show_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_read_lock();
if (g_app_id_array[i][j] == AF_TRUE)
{
AF_DEBUG("%d, %d\n", i, j);
}
af_rule_read_unlock();
}
}
AF_DEBUG("\n\n\n");
}
int af_change_app_status(cJSON *data_obj, int status)
{
int i;
int id;
int type;
cJSON *appid_arr = NULL;
if (!data_obj)
{
AF_ERROR("data obj is null\n");
return -1;
}
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)
return -1;
id = AF_APP_ID(appid_obj->valueint);
type = AF_APP_TYPE(appid_obj->valueint);
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;
}
int af_config_add_appid(cJSON *data)
{
return af_change_app_status(data, 1);
}
int af_config_del_appid(cJSON *data)
{
return af_change_app_status(data, 0);
}
int af_config_clean_appid(cJSON *data)
{
af_init_app_status();
return 0;
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef __AF_RULE_CONFIG_H__
#define __AF_RULE_CONFIG_H__
#include "app_filter.h"
#include "af_utils.h"
#include "af_log.h"
void af_init_app_status(void);
int af_get_app_status(int appid);
#endif
+132
View File
@@ -0,0 +1,132 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#include "app_filter.h"
#include "af_utils.h"
#include "af_log.h"
#include "cJSON.h"
#include "af_whitelist_config.h"
#include "af_user_config.h"
DEFINE_RWLOCK(af_mac_lock);
u32 total_mac = 0;
struct list_head af_mac_htable[MAX_AF_MAC_HASH_SIZE];
void af_mac_list_init(void)
{
int i;
write_lock_bh(&af_mac_lock);
for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
{
INIT_LIST_HEAD(&af_mac_htable[i]);
}
write_unlock_bh(&af_mac_lock);
}
void af_mac_list_flush(void)
{
int i;
af_mac_node_t *p = NULL;
char mac_str[32] = {0};
write_lock_bh(&af_mac_lock);
for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
{
while (!list_empty(&af_mac_htable[i]))
{
p = list_first_entry(&af_mac_htable[i], af_mac_node_t, list);
memset(mac_str, 0x0, sizeof(mac_str));
sprintf(mac_str, MAC_FMT, MAC_ARRAY(p->mac));
list_del(&(p->list));
kfree(p);
}
}
total_mac = 0;
write_unlock_bh(&af_mac_lock);
}
af_mac_node_t *af_mac_find(unsigned char *mac)
{
af_mac_node_t *node;
unsigned int index;
index = hash_mac(mac);
read_lock_bh(&af_mac_lock);
list_for_each_entry(node, &af_mac_htable[index], list)
{
if (0 == memcmp(node->mac, mac, 6))
{
read_unlock_bh(&af_mac_lock);
return node;
}
}
read_unlock_bh(&af_mac_lock);
return NULL;
}
af_mac_node_t *af_mac_add(unsigned char *mac)
{
af_mac_node_t *node;
int index = 0;
node = (af_mac_node_t *)kmalloc(sizeof(af_mac_node_t), GFP_ATOMIC);
if (node == NULL)
{
return NULL;
}
memset(node, 0, sizeof(af_mac_node_t));
memcpy(node->mac, mac, MAC_ADDR_LEN);
index = hash_mac(mac);
printk("add user mac=" MAC_FMT "\n", MAC_ARRAY(node->mac));
total_mac++;
write_lock_bh(&af_mac_lock);
list_add(&(node->list), &af_mac_htable[index]);
write_unlock_bh(&af_mac_lock);
return node;
}
int is_user_match_enable(void)
{
return total_mac > 0;
}
int af_config_set_mac_list(cJSON *data_obj)
{
int i;
cJSON *mac_arr = NULL;
u8 mac_hex[MAC_ADDR_LEN] = {0};
if (!data_obj)
{
AF_ERROR("data obj is null\n");
return -1;
}
mac_arr = cJSON_GetObjectItem(data_obj, "mac_list");
if (!mac_arr)
{
AF_ERROR("mac_list obj is null\n");
return -1;
}
af_mac_list_flush();
for (i = 0; i < cJSON_GetArraySize(mac_arr); i++)
{
cJSON *mac_obj = cJSON_GetArrayItem(mac_arr, i);
if (!mac_obj)
{
AF_ERROR("mac obj is null\n");
return -1;
}
if (-1 == mac_to_hex(mac_obj->valuestring, mac_hex))
{
continue;
}
af_mac_add(mac_hex);
}
AF_DEBUG("## mac num = %d\n", total_mac);
return 0;
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef __AF_USER_CONFIG_H__
#define __AF_USER_CONFIG_H__
#include "app_filter.h"
#include "af_utils.h"
typedef struct af_mac_node {
struct list_head list;
unsigned char mac[MAC_ADDR_LEN];
}af_mac_node_t;
void af_mac_list_init(void);
void af_mac_list_flush(void);
af_mac_node_t *af_mac_find(unsigned char *mac);
af_mac_node_t *af_mac_add(unsigned char *mac);
#endif
+402
View File
@@ -0,0 +1,402 @@
#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"
#define MAX_DUMP_STR_LEN 256
u_int32_t af_get_timestamp_sec(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
struct timespec64 ts;
ktime_get_real_ts64(&ts);
return (u_int32_t)ts.tv_sec;
#else
struct timespec ts;
ts = current_kernel_time();
return ts.tv_sec;
#endif
}
int k_atoi(const char *str) {
int result = 0;
// Skip whitespace
while (*str == ' ' || *str == '\t') {
str++;
}
// Convert characters to integer
while (*str >= '0' && *str <= '9') {
result = result * 10 + (*str - '0');
str++;
}
return result;
}
char *k_trim(char *s)
{
char *start, *last, *bk;
int len;
start = s;
while (isspace(*start))
start++;
bk = last = s + strlen(s) - 1;
while (last > start && isspace(*last))
last--;
if ((s != start) || (bk != last))
{
len = last - start + 1;
strncpy(s, start, len);
s[len] = '\0';
}
return s;
}
int check_local_network_ip(unsigned int ip)
{
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)
{
char buf[MAX_DUMP_STR_LEN] = {0};
if (len > MAX_DUMP_STR_LEN) {
len = MAX_DUMP_STR_LEN - 1;
}
printk("%s: ",name);
strncpy(buf, p, len);
printk("[%s]\n", buf);
}
int isprint_char(unsigned char c)
{
if (c >= 0x20 && c <= 0x7e)
return 1;
else
return 0;
}
void print_hex_ascii(const unsigned char *data, size_t size) {
size_t i, j;
for (i = 0; i < size; i += 16) {
printk(KERN_CONT"%08lx ", (unsigned long)i);
for (j = 0; j < 16; ++j) {
if (i + j < size) {
printk(KERN_CONT"%02x ", data[i + j]);
} else {
printk(KERN_CONT" ");
}
}
printk(KERN_CONT" ");
for (j = 0; j < 16; ++j) {
if (i + j < size) {
unsigned char c = data[i + j];
printk(KERN_CONT"%c", isprint_char(c) ? c : '.');
}
}
printk(KERN_CONT"\n");
}
printk(KERN_CONT"---------------------------------------\n");
}
void dump_hex(char *name, unsigned char *p, int len)
{
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(KERN_CONT "\n");
printk(KERN_CONT "%02X ",*(p + i));
}
printk(KERN_CONT "\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;
}
int mac_to_hex(u8 *mac, u8 *mac_hex)
{
u32 mac_tmp[6];
int ret = 0, i = 0;
ret = sscanf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned int *)&mac_tmp[0],
(unsigned int *)&mac_tmp[1],
(unsigned int *)&mac_tmp[2],
(unsigned int *)&mac_tmp[3],
(unsigned int *)&mac_tmp[4],
(unsigned int *)&mac_tmp[5]);
if (6 != ret)
return -1;
for (i = 0; i < 6; i++)
{
mac_hex[i] = mac_tmp[i];
}
return 0;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef AF_UTILS_H
#define AF_UTILS_H
u_int32_t af_get_timestamp_sec(void);
char *k_trim(char *s);
int check_local_network_ip(unsigned int ip);
void dump_str(char *name, unsigned char *p, int len);
void dump_hex(char *name, unsigned char *p, int len);
int k_sscanf(const char *buf, const char *fmt, ...);
int k_atoi(const char *str);
void print_hex_ascii(const unsigned char *data, size_t size);
int hash_mac(unsigned char *mac);
int mac_to_hex(u8 *mac, u8 *mac_hex);
#endif
+122
View File
@@ -0,0 +1,122 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#include "app_filter.h"
#include "af_utils.h"
#include "af_log.h"
#include "cJSON.h"
#include "af_whitelist_config.h"
DEFINE_RWLOCK(af_whitelist_mac_lock);
struct list_head af_whitelist_mac_htable[MAX_AF_MAC_HASH_SIZE];
void af_whitelist_mac_init(void)
{
int i;
write_lock_bh(&af_whitelist_mac_lock);
for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
{
INIT_LIST_HEAD(&af_whitelist_mac_htable[i]);
}
write_unlock_bh(&af_whitelist_mac_lock);
}
void af_whitelist_mac_flush(void)
{
int i;
af_whitelist_mac_node_t *p = NULL;
char mac_str[32] = {0};
write_lock_bh(&af_whitelist_mac_lock);
for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
{
while (!list_empty(&af_whitelist_mac_htable[i]))
{
p = list_first_entry(&af_whitelist_mac_htable[i], af_whitelist_mac_node_t, list);
memset(mac_str, 0x0, sizeof(mac_str));
sprintf(mac_str, MAC_FMT, MAC_ARRAY(p->mac));
list_del(&(p->list));
kfree(p);
}
}
write_unlock_bh(&af_whitelist_mac_lock);
}
af_whitelist_mac_node_t *af_whitelist_mac_find(unsigned char *mac)
{
af_whitelist_mac_node_t *node = NULL;
unsigned int index = 0;
index = hash_mac(mac);
read_lock_bh(&af_whitelist_mac_lock);
list_for_each_entry(node, &af_whitelist_mac_htable[index], list)
{
if (0 == memcmp(node->mac, mac, 6))
{
read_unlock_bh(&af_whitelist_mac_lock);
return node;
}
}
read_unlock_bh(&af_whitelist_mac_lock);
return NULL;
}
af_whitelist_mac_node_t *af_whitelist_mac_add(unsigned char *mac)
{
af_whitelist_mac_node_t *node = NULL;
int index = 0;
node = (af_whitelist_mac_node_t *)kmalloc(sizeof(af_whitelist_mac_node_t), GFP_ATOMIC);
if (node == NULL)
{
return NULL;
}
memset(node, 0, sizeof(af_whitelist_mac_node_t));
memcpy(node->mac, mac, MAC_ADDR_LEN);
index = hash_mac(mac);
AF_DEBUG("add whitelist mac=" MAC_FMT "\n", MAC_ARRAY(node->mac));
write_lock_bh(&af_whitelist_mac_lock);
list_add(&(node->list), &af_whitelist_mac_htable[index]);
write_unlock_bh(&af_whitelist_mac_lock);
return node;
}
int af_config_set_whitelist_mac_list(cJSON *data_obj)
{
int i;
cJSON *mac_arr = NULL;
u8 mac_hex[MAC_ADDR_LEN] = {0};
if (!data_obj)
{
AF_ERROR("data obj is null\n");
return -1;
}
mac_arr = cJSON_GetObjectItem(data_obj, "mac_list");
if (!mac_arr)
{
AF_ERROR("mac_list obj is null\n");
return -1;
}
af_whitelist_mac_flush();
for (i = 0; i < cJSON_GetArraySize(mac_arr); i++)
{
cJSON *mac_obj = cJSON_GetArrayItem(mac_arr, i);
if (!mac_obj)
{
AF_ERROR("mac obj is null\n");
return -1;
}
if (-1 == mac_to_hex(mac_obj->valuestring, mac_hex))
{
continue;
}
af_whitelist_mac_add(mac_hex);
}
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef __AF_WHITELIST_CONFIG_H__
#define __AF_WHITELIST_CONFIG_H__
#include "app_filter.h"
#include "af_utils.h"
#define MAX_AF_WHITELIST_MAC_HASH_SIZE 64
typedef struct af_whitelist_mac_node{
struct list_head list;
unsigned char mac[MAC_ADDR_LEN];
}af_whitelist_mac_node_t;
void af_whitelist_mac_init(void);
void af_whitelist_mac_flush(void);
af_whitelist_mac_node_t *af_whitelist_mac_find(unsigned char *mac);
af_whitelist_mac_node_t *af_whitelist_mac_add(unsigned char *mac);
int af_config_set_whitelist_mac_list(cJSON *data_obj);
#endif
+1961
View File
File diff suppressed because it is too large. Load diff
+176
View File
@@ -0,0 +1,176 @@
#ifndef APP_FILTER_H
#define APP_FILTER_H
#define AF_VERSION "5.3.3"
#define AF_FEATURE_CONFIG_FILE "/tmp/feature.cfg"
#define MAX_DPI_PKT_NUM 64
#define MIN_HTTP_DATA_LEN 16
#define MAX_APP_NAME_LEN 64
#define MAX_FEATURE_NUM_PER_APP 16
#define MIN_FEATURE_STR_LEN 8
#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 600
#define MIN_FEATURE_LINE_LEN 16
#define MAX_URL_MATCH_LEN 64
#define MAX_BYPASS_DPI_PKT_LEN 600
#define MAX_AF_MAC_HASH_SIZE 64
#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 MAC_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define AF_TRUE 1
#define AF_FALSE 0
#define AF_APP_TYPE(a) (a) / 1000
#define AF_APP_ID(a) (a) % 1000
#define MAC_ADDR_LEN 6
#define HTTPS_URL_OFFSET 9
#define HTTPS_LEN_OFFSET 7
#define MAX_SEARCH_STR_LEN 32
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,
AF_STR_PARAM_INDEX,
AF_IGNORE_PARAM_INDEX,
};
#define OAF_NETLINK_ID 29
#define MAX_OAF_NL_MSG_LEN 1024
enum E_MSG_TYPE{
AF_MSG_INIT,
AF_MSG_ADD_FEATURE,
AF_MSG_CLEAN_FEATURE,
AF_MSG_MAX
};
enum AF_WORK_MODE {
AF_MODE_GATEWAY,
AF_MODE_BYPASS,
AF_MODE_BRIDGE,
};
#define MAX_AF_MSG_DATA_LEN 800
typedef struct af_msg{
int action;
}af_msg_t;
struct af_msg_hdr{
int magic;
int len;
};
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 af_pos_info{
int pos;
unsigned char value;
}af_pos_info_t;
#define MAX_PORT_RANGE_NUM 5
typedef struct range_value
{
int not ;
int start;
int end;
} range_value_t;
typedef struct port_info
{
u_int8_t mode; // 0: match, 1: not match
int num;
range_value_t range_list[MAX_PORT_RANGE_NUM];
} port_info_t;
typedef struct af_feature_node{
struct list_head head;
u_int32_t app_id;
char app_name[MAX_APP_NAME_LEN];
char feature[MAX_FEATURE_STR_LEN];
u_int32_t proto;
u_int32_t sport;
u_int32_t dport;
port_info_t dport_info;
char host_url[MAX_HOST_URL_LEN];
char request_url[MAX_REQUEST_URL_LEN];
int pos_num;
char search_str[MAX_SEARCH_STR_LEN];
int ignore;
af_pos_info_t pos_info[MAX_POS_INFO_PER_FEATURE];
}af_feature_node_t;
typedef struct flow_info{
struct nf_conn *ct;
u_int32_t src;
u_int32_t dst;
struct in6_addr *src6;
struct in6_addr *dst6;
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 app_name[MAX_APP_NAME_LEN];
u_int8_t drop;
u_int8_t ignore;
u_int8_t dir;
u_int16_t total_len;
u_int8_t client_hello;
af_feature_node_t *feature;
}flow_info_t;
int regexp_match(char *reg, char *text);
int hash_mac(unsigned char *mac);
#endif
+519
View File
@@ -0,0 +1,519 @@
/*
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;
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;}
+94
View File
@@ -0,0 +1,94 @@
/*
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
+302
View File
@@ -0,0 +1,302 @@
#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;
}
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);
}