parent
ff08ddb462
commit
a75a413208
|
@ -0,0 +1,12 @@
|
|||
#CONFIG_TOUCHSCREEN_FOCALTECH=m
|
||||
obj-m+=eg_hk_hook.o
|
||||
eg_hk_hook-objs:=lkh_hook.o
|
||||
eg_hk_hook-objs+=lkh_hook_fwd.o
|
||||
eg_hk_hook-objs+=lkh_hook_init.o
|
||||
#mymodule-objs:=module
|
||||
KDIR:=/lib/modules/4.18.12-1.el7.elrepo.x86_64/build
|
||||
MAKE:=make
|
||||
default:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
|
|
@ -0,0 +1,530 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include "lkh_hook.h"
|
||||
|
||||
|
||||
struct lkh_hook_handle g_lkh_hook_handle;
|
||||
|
||||
static unsigned int lkh_accept_all(void *priv, struct sk_buff *skb, const struct lkh_hook_state *state)
|
||||
{
|
||||
return LKH_ACCEPT; /* ACCEPT makes nf_hook_slow call next hook */
|
||||
}
|
||||
|
||||
|
||||
static const struct lkh_hook_ops dummy_ops = {
|
||||
.hook = lkh_accept_all,
|
||||
.priority = INT_MIN,
|
||||
};
|
||||
|
||||
|
||||
static inline struct lkh_hook_ops **lkh_hook_entries_get_hook_ops(const struct lkh_hook_entries *e)
|
||||
{
|
||||
unsigned int n = e->num_hook_entries;
|
||||
const void *hook_end;
|
||||
|
||||
hook_end = &e->hooks[n]; /* this is *past* ->hooks[]! */
|
||||
|
||||
return (struct lkh_hook_ops **)hook_end;
|
||||
}
|
||||
|
||||
|
||||
/* 注册流程 */
|
||||
static void __lkh_hook_entries_free(struct rcu_head *h)
|
||||
{
|
||||
struct lkh_hook_entries_rcu_head *head;
|
||||
|
||||
head = container_of(h, struct lkh_hook_entries_rcu_head, head);
|
||||
kvfree(head->allocation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void lkh_hook_entries_free(struct lkh_hook_entries *e)
|
||||
{
|
||||
struct lkh_hook_entries_rcu_head *head;
|
||||
struct lkh_hook_ops **ops;
|
||||
unsigned int num;
|
||||
|
||||
if (NULL == e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
num = e->num_hook_entries;
|
||||
ops = lkh_hook_entries_get_hook_ops(e);
|
||||
head = (void *)&ops[num];
|
||||
head->allocation = e;
|
||||
call_rcu(&head->head, __lkh_hook_entries_free);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void lkh_hooks_validate(const struct lkh_hook_entries *hooks)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_KERNEL
|
||||
struct lkh_hook_ops **orig_ops;
|
||||
int prio = INT_MIN;
|
||||
size_t i = 0;
|
||||
|
||||
orig_ops = lkh_hook_entries_get_hook_ops(hooks);
|
||||
|
||||
for (i = 0; i < hooks->num_hook_entries; i++)
|
||||
{
|
||||
if (orig_ops[i] == &dummy_ops)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (orig_ops[i]->priority > prio)
|
||||
{
|
||||
prio = orig_ops[i]->priority;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 申请新的存储结构 */
|
||||
static struct lkh_hook_entries * lkh_allocate_hook_entries_size(u16 num)
|
||||
{
|
||||
struct lkh_hook_entries *e;
|
||||
size_t alloc = sizeof(*e) +
|
||||
sizeof(struct lkh_hook_entry) * num +
|
||||
sizeof(struct lkh_hook_ops *) * num +
|
||||
sizeof(struct lkh_hook_entries_rcu_head);
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e = kvzalloc(alloc, GFP_KERNEL);
|
||||
if (e)
|
||||
{
|
||||
e->num_hook_entries = num;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static struct lkh_hook_entries * lkh_hook_entries_grow(const struct lkh_hook_entries *old, const struct lkh_hook_ops *reg)
|
||||
{
|
||||
unsigned int i, alloc_entries, nhooks, old_entries;
|
||||
struct lkh_hook_ops **orig_ops = NULL;
|
||||
struct lkh_hook_ops **new_ops;
|
||||
struct lkh_hook_entries *new;
|
||||
bool inserted = false;
|
||||
|
||||
alloc_entries = 1;
|
||||
old_entries = old ? old->num_hook_entries : 0;
|
||||
|
||||
if (old != NULL)
|
||||
{
|
||||
orig_ops = lkh_hook_entries_get_hook_ops(old);
|
||||
|
||||
for (i = 0; i < old_entries; i++)
|
||||
{
|
||||
if (orig_ops[i] != &dummy_ops)
|
||||
{
|
||||
alloc_entries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_entries > MAX_HOOK_COUNT)
|
||||
{
|
||||
return ERR_PTR(-E2BIG);
|
||||
}
|
||||
|
||||
new = lkh_allocate_hook_entries_size(alloc_entries);
|
||||
if (NULL == new)
|
||||
{
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
new_ops = lkh_hook_entries_get_hook_ops(new);
|
||||
|
||||
i = 0;
|
||||
nhooks = 0;
|
||||
while (i < old_entries)
|
||||
{
|
||||
if (orig_ops[i] == &dummy_ops)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inserted || (reg->priority > orig_ops[i]->priority))
|
||||
{
|
||||
new_ops[nhooks] = (void *)orig_ops[i];
|
||||
new->hooks[nhooks] = old->hooks[i];
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_ops[nhooks] = (void *)reg;
|
||||
new->hooks[nhooks].hook = reg->hook;
|
||||
new->hooks[nhooks].priv = reg->priv;
|
||||
inserted = true;
|
||||
}
|
||||
|
||||
nhooks++;
|
||||
}
|
||||
|
||||
if (!inserted)
|
||||
{
|
||||
new_ops[nhooks] = (void *)reg;
|
||||
new->hooks[nhooks].hook = reg->hook;
|
||||
new->hooks[nhooks].priv = reg->priv;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct lkh_hook_entries __rcu ** lkh_hook_entry_head(struct net *net, int pf, unsigned int hook_stage)
|
||||
{
|
||||
struct lkh_hook * hook;
|
||||
|
||||
list_for_each_entry(hook, &g_lkh_hook_handle.list, list)
|
||||
{
|
||||
if (hook->net_ptr == net)
|
||||
{
|
||||
switch (pf)
|
||||
{
|
||||
case LKH_PROTO_IPV4:
|
||||
if ((ARRAY_SIZE(hook->hooks_ipv4) <= hook_stage))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return hook->hooks_ipv4 + hook_stage;
|
||||
case LKH_PROTO_IPV6:
|
||||
if ((ARRAY_SIZE(hook->hooks_ipv6) <= hook_stage))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return hook->hooks_ipv6 + hook_stage;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __lkh_register_net_hook(struct net *net, int pf, const struct lkh_hook_ops *reg)
|
||||
{
|
||||
struct lkh_hook_entries *p, *new_hooks;
|
||||
struct lkh_hook_entries __rcu **pp;
|
||||
|
||||
pp = lkh_hook_entry_head(net, pf, reg->hook_stage);
|
||||
if (NULL == pp)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&lkh_hook_mutex);
|
||||
|
||||
/* 多核信号量保护处理 RCU */
|
||||
p = lkh_entry_dereference(*pp);
|
||||
|
||||
new_hooks = lkh_hook_entries_grow(p, reg);
|
||||
|
||||
if (!IS_ERR(new_hooks))
|
||||
{
|
||||
/*
|
||||
* 该接口被writer用来进行removal的操作,在witer完成新版本数据分配和更新之后,
|
||||
* 调用这个接口可以让RCU protected pointer指向RCU protected data
|
||||
*/
|
||||
rcu_assign_pointer(*pp, new_hooks);
|
||||
}
|
||||
|
||||
mutex_unlock(&lkh_hook_mutex);
|
||||
|
||||
if (IS_ERR(new_hooks))
|
||||
{
|
||||
return PTR_ERR(new_hooks);
|
||||
}
|
||||
|
||||
lkh_hooks_validate(new_hooks);
|
||||
|
||||
/* 释放旧的指针内存 */
|
||||
lkh_hook_entries_free(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lkh_register_net_hook(struct net *net, const struct lkh_hook_ops *reg)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __lkh_register_net_hook(net, reg->pf, reg);
|
||||
if (err < 0)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *__lkh_hook_entries_try_shrink(struct lkh_hook_entries *old, struct lkh_hook_entries __rcu **pp)
|
||||
{
|
||||
unsigned int i, j, skip = 0, hook_entries;
|
||||
struct lkh_hook_entries *new = NULL;
|
||||
struct lkh_hook_ops **orig_ops;
|
||||
struct lkh_hook_ops **new_ops;
|
||||
|
||||
if (NULL == old)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
orig_ops = lkh_hook_entries_get_hook_ops(old);
|
||||
|
||||
for (i = 0; i < old->num_hook_entries; i++)
|
||||
{
|
||||
if (orig_ops[i] == &dummy_ops)
|
||||
{
|
||||
skip++;
|
||||
}
|
||||
}
|
||||
|
||||
hook_entries = old->num_hook_entries;
|
||||
if (skip == hook_entries)
|
||||
{
|
||||
goto out_assign;
|
||||
}
|
||||
|
||||
if (skip == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hook_entries -= skip;
|
||||
new = lkh_allocate_hook_entries_size(hook_entries);
|
||||
|
||||
if (NULL == new)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_ops = lkh_hook_entries_get_hook_ops(new);
|
||||
for (i = 0, j = 0; i < old->num_hook_entries; i++)
|
||||
{
|
||||
if (orig_ops[i] == &dummy_ops)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
new->hooks[j] = old->hooks[i];
|
||||
new_ops[j] = (void *)orig_ops[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
lkh_hooks_validate(new);
|
||||
|
||||
out_assign:
|
||||
rcu_assign_pointer(*pp, new);
|
||||
return old;
|
||||
}
|
||||
|
||||
static bool lkh_remove_net_hook(struct lkh_hook_entries *old, const struct lkh_hook_ops *unreg)
|
||||
{
|
||||
struct lkh_hook_ops **orig_ops;
|
||||
unsigned int i;
|
||||
|
||||
orig_ops = lkh_hook_entries_get_hook_ops(old);
|
||||
for (i = 0; i < old->num_hook_entries; i++)
|
||||
{
|
||||
if (orig_ops[i] != unreg)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
WRITE_ONCE(old->hooks[i].hook, lkh_accept_all);
|
||||
WRITE_ONCE(orig_ops[i], &dummy_ops);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __lkh_unregister_net_hook(struct net *net, int pf, const struct lkh_hook_ops *reg)
|
||||
{
|
||||
struct lkh_hook_entries __rcu **pp;
|
||||
struct lkh_hook_entries *p;
|
||||
|
||||
pp = lkh_hook_entry_head(net, pf, reg->hook_stage);
|
||||
if (NULL == pp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&lkh_hook_mutex);
|
||||
|
||||
p = lkh_entry_dereference(*pp);
|
||||
if (NULL == p)
|
||||
{
|
||||
mutex_unlock(&lkh_hook_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
lkh_remove_net_hook(p, reg);
|
||||
|
||||
p = __lkh_hook_entries_try_shrink(p, pp);
|
||||
|
||||
mutex_unlock(&lkh_hook_mutex);
|
||||
|
||||
if (NULL == p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lkh_hook_entries_free(p);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void lkh_unregister_net_hook(struct net *net, const struct lkh_hook_ops *reg)
|
||||
{
|
||||
__lkh_unregister_net_hook(net, reg->pf, reg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* Description:
|
||||
* 指定协议、阶段、优先级解除注册钩子处理函数
|
||||
* Input:
|
||||
* net - 网络命名空间指针
|
||||
* reg - 协议、阶段、优先级、钩子函数指针等信息保存结构
|
||||
* n - 一次注册的钩子函数数量
|
||||
* Output:
|
||||
* 无
|
||||
* Return:
|
||||
* 无
|
||||
* Others:
|
||||
* 无
|
||||
**********************************************************************************/
|
||||
|
||||
void lkh_unregister_net_hooks(struct net *net, const struct lkh_hook_ops *reg, unsigned int hookcount)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < hookcount; i++)
|
||||
{
|
||||
lkh_unregister_net_hook(net, ®[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* Description:
|
||||
* 指定协议、阶段、优先级注册钩子处理函数
|
||||
* Input:
|
||||
* net - 网络命名空间指针
|
||||
* reg - 协议、阶段、优先级、钩子函数指针等信息保存结构
|
||||
* hookcount - 一次注册的钩子函数数量
|
||||
* Output:
|
||||
* 无
|
||||
* Return:
|
||||
* 0 - 成功
|
||||
* 非0 - 失败
|
||||
* Others:
|
||||
* 入参的reg结构需要调用者确认是否需要保存,因为HOOK管理结构不会记录reg的内容,而是记录reg的指针, netfilter就是这样实现
|
||||
* 当前按照netfilter的方式实现。
|
||||
**********************************************************************************/
|
||||
int lkh_register_net_hooks(struct net *net, const struct lkh_hook_ops *reg, unsigned int hookcount)
|
||||
{
|
||||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < hookcount; i++)
|
||||
{
|
||||
err = lkh_register_net_hook(net, ®[i]);
|
||||
if (err != 0)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
err:
|
||||
if (i > 0)
|
||||
{
|
||||
lkh_unregister_net_hooks(net, reg, i);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void lkh_hash_struct_show(void)
|
||||
{
|
||||
struct lkh_hook * hook;
|
||||
struct lkh_hook_entries * hook_entries= NULL;
|
||||
struct lkh_hook_ops **new_ops;
|
||||
struct lkh_hook_ops * ops = NULL;
|
||||
struct lkh_hook_entry * entry = NULL;
|
||||
|
||||
list_for_each_entry(hook, &g_lkh_hook_handle.list, list)
|
||||
{
|
||||
|
||||
if (hook->net_ptr != NULL)
|
||||
{
|
||||
printk(KERN_EMERG "------------------------------ net hook begin-----------------------------");
|
||||
printk(KERN_EMERG "hook->net_ptr %p", hook->net_ptr);
|
||||
printk(KERN_EMERG "------------------------------ net hook ipv4-----------------------------");
|
||||
printk(KERN_EMERG "hook->hooks_ipv4 %p", hook->hooks_ipv4);
|
||||
printk(KERN_EMERG "------------------------- LKH_INET_PRE_FORWARD------------------------");
|
||||
printk(KERN_EMERG "hook_entries %p", hook->hooks_ipv4[LKH_INET_PRE_FORWARD]);
|
||||
hook_entries = hook->hooks_ipv4[LKH_INET_PRE_FORWARD];
|
||||
if (hook_entries != NULL)
|
||||
{
|
||||
int i = 0;
|
||||
new_ops = lkh_hook_entries_get_hook_ops(hook_entries);
|
||||
printk(KERN_EMERG "hook_entries num_hook_entries %d new_ops: %p", hook_entries->num_hook_entries, new_ops);
|
||||
for (; i < hook_entries->num_hook_entries; i++)
|
||||
{
|
||||
entry = &(hook_entries->hooks[i]);
|
||||
ops = new_ops[i];
|
||||
printk(KERN_EMERG "----------- hook [%d]------------", i);
|
||||
printk(KERN_EMERG "hook entry [%d] entry ptr: %p new_ops: %p", i, entry, ops);
|
||||
printk(KERN_EMERG "entry hook: %p", entry->hook);
|
||||
printk(KERN_EMERG "ops pf: %d hook_stage: %d priority: %d hook: %p", ops->pf, ops->hook_stage, ops->priority, ops->hook);
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_EMERG "------------------------------ net hook end-----------------------------");
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_EMERG "------------------------------ net hook begin-----------------------------");
|
||||
printk(KERN_EMERG "hook->net_ptr is NULL");
|
||||
printk(KERN_EMERG "------------------------------ net hook end-----------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(lkh_register_net_hooks);
|
||||
EXPORT_SYMBOL(lkh_unregister_net_hooks);
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
#ifndef LKH_HOOK_H
|
||||
#define LKH_HOOK_H
|
||||
|
||||
static DEFINE_MUTEX(lkh_hook_mutex);
|
||||
|
||||
#define MAX_HOOK_COUNT 1024
|
||||
|
||||
/* 多核信息同步处理 */
|
||||
#define lkh_entry_dereference(e) rcu_dereference_protected(e, lockdep_is_held(&lkh_hook_mutex))
|
||||
|
||||
/* 执行HOOK处理后的返回值 */
|
||||
#define LKH_DROP 0
|
||||
#define LKH_ACCEPT 1
|
||||
#define LKH_STOLEN 2
|
||||
#define LKH_QUEUE 3
|
||||
#define LKH_REPEAT 4
|
||||
#define LKH_STOP 5 /* Deprecated, for userspace nf_queue compatibility. */
|
||||
|
||||
/* 钩子函数调用位置 */
|
||||
enum lkh_inet_hooks
|
||||
{
|
||||
LKH_INET_PRE_FORWARD,
|
||||
LKH_INET_NUMHOOKS
|
||||
};
|
||||
|
||||
|
||||
/* 支持的协议类型 */
|
||||
enum
|
||||
{
|
||||
LKH_PROTO_UNSPEC = 0,
|
||||
LKH_PROTO_IPV4 = 1,
|
||||
LKH_PROTO_IPV6 = 2,
|
||||
LKH_PROTO_NUMPROTO,
|
||||
};
|
||||
|
||||
struct lkh_hook_entries_rcu_head
|
||||
{
|
||||
struct rcu_head head;
|
||||
void *allocation;
|
||||
};
|
||||
|
||||
struct lkh_hook_state
|
||||
{
|
||||
unsigned int hook_stage;
|
||||
u_int8_t pf;
|
||||
struct net_device *in;
|
||||
struct net_device *out;
|
||||
struct sock *sk;
|
||||
struct net *net;
|
||||
};
|
||||
|
||||
typedef unsigned int lkh_hookfn(void *priv, struct sk_buff *skb, const struct lkh_hook_state *state);
|
||||
|
||||
struct lkh_hook_ops
|
||||
{
|
||||
/* User fills in from here down. */
|
||||
lkh_hookfn *hook; /* 钩子函数 */
|
||||
void *priv;
|
||||
u_int8_t pf; /* 协议类型 IPv4、IPv6、brigde等 */
|
||||
unsigned int hook_stage; /* 阶段ID,比如PRE_FORWARD等*/
|
||||
int priority; /* 优先级 */
|
||||
};
|
||||
|
||||
struct lkh_hook_entry
|
||||
{
|
||||
lkh_hookfn *hook;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* 一种协议类型的hook集合,包括多个处理阶段 */
|
||||
struct lkh_hook_entries
|
||||
{
|
||||
u_int8_t num_hook_entries;
|
||||
struct lkh_hook_entry hooks[];
|
||||
};
|
||||
|
||||
struct lkh_hook
|
||||
{
|
||||
struct list_head list;
|
||||
void * net_ptr; /* 记录struct net 结构指针,用来查找对应的hook */
|
||||
struct lkh_hook_entries __rcu *hooks_ipv4[LKH_INET_NUMHOOKS];
|
||||
struct lkh_hook_entries __rcu *hooks_ipv6[LKH_INET_NUMHOOKS];
|
||||
};
|
||||
|
||||
|
||||
/* 句柄 */
|
||||
struct lkh_hook_handle
|
||||
{
|
||||
struct list_head list;
|
||||
unsigned int net_num; /* 网络命名空间数量 */
|
||||
};
|
||||
|
||||
extern struct lkh_hook_handle g_lkh_hook_handle;
|
||||
extern void lkh_hash_struct_show(void);
|
||||
extern int lkh_register_net_hooks(struct net *net, const struct lkh_hook_ops *reg, unsigned int hookcount);
|
||||
extern void lkh_unregister_net_hooks(struct net *net, const struct lkh_hook_ops *reg, unsigned int hookcount);
|
||||
extern int lkh_hook(u_int8_t pf,
|
||||
unsigned int hook_stage,
|
||||
struct net *net,
|
||||
struct sock *sk,
|
||||
struct sk_buff *skb,
|
||||
struct net_device *indev,
|
||||
struct net_device *outdev);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include "lkh_hook.h"
|
||||
|
||||
|
||||
#define LKH_VERDICT_MASK 0x000000ff
|
||||
#define LKH_VERDICT_QBITS 16
|
||||
|
||||
static inline int LKH_DROP_GETERR(int verdict)
|
||||
{
|
||||
return -(verdict >> LKH_VERDICT_QBITS);
|
||||
}
|
||||
|
||||
static inline int lkh_hook_entry_hookfn(const struct lkh_hook_entry *entry, struct sk_buff *skb, struct lkh_hook_state *state)
|
||||
{
|
||||
return entry->hook(entry->priv, skb, state);
|
||||
}
|
||||
|
||||
static inline void lkh_hook_state_init(struct lkh_hook_state *p,
|
||||
unsigned int hook,
|
||||
u_int8_t pf,
|
||||
struct net_device *indev,
|
||||
struct net_device *outdev,
|
||||
struct sock *sk,
|
||||
struct net *net)
|
||||
{
|
||||
p->hook_stage = hook;
|
||||
p->pf = pf;
|
||||
p->in = indev;
|
||||
p->out = outdev;
|
||||
p->sk = sk;
|
||||
p->net = net;
|
||||
}
|
||||
|
||||
int lkh_hook_slow(struct sk_buff *skb, struct lkh_hook_state *state,
|
||||
const struct lkh_hook_entries *e, unsigned int s)
|
||||
{
|
||||
unsigned int verdict;
|
||||
int ret;
|
||||
|
||||
for (; s < e->num_hook_entries; s++)
|
||||
{
|
||||
verdict = lkh_hook_entry_hookfn(&e->hooks[s], skb, state);
|
||||
|
||||
switch (verdict & LKH_VERDICT_MASK)
|
||||
{
|
||||
case LKH_ACCEPT:
|
||||
break;
|
||||
case LKH_DROP:
|
||||
kfree_skb(skb);
|
||||
ret = LKH_DROP_GETERR(verdict);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = -EPERM;
|
||||
}
|
||||
return ret;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* Description:
|
||||
* 转发流程调用钩子函数的处理报文的入口函数
|
||||
* Input:
|
||||
* pf - 优先级
|
||||
* hook_stage - 钩子函数调用阶段
|
||||
* sk - socket
|
||||
* skb - 报文描述符
|
||||
* indev - 入设备信息
|
||||
* outdev - 出设备信息
|
||||
* Output:
|
||||
* 无
|
||||
* Return:
|
||||
* 无
|
||||
* Others:
|
||||
* 入口参数的定义和使用方法同netfilter一样
|
||||
**********************************************************************************/
|
||||
int lkh_hook(u_int8_t pf,
|
||||
unsigned int hook_stage,
|
||||
struct net *net,
|
||||
struct sock *sk,
|
||||
struct sk_buff *skb,
|
||||
struct net_device *indev,
|
||||
struct net_device *outdev)
|
||||
{
|
||||
struct lkh_hook_entries * hook_entrise;
|
||||
int ret = 1;
|
||||
bool find_flag = false;
|
||||
struct lkh_hook * hook_head;
|
||||
|
||||
/* 查找对应网络空间的hook结构 */
|
||||
list_for_each_entry(hook_head, &g_lkh_hook_handle.list, list)
|
||||
{
|
||||
if (hook_head->net_ptr == net)
|
||||
{
|
||||
find_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!find_flag)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
switch (pf)
|
||||
{
|
||||
case LKH_PROTO_IPV4:
|
||||
hook_entrise = rcu_dereference(hook_head->hooks_ipv4[hook_stage]);
|
||||
break;
|
||||
case LKH_PROTO_IPV6:
|
||||
hook_entrise = rcu_dereference(hook_head->hooks_ipv6[hook_stage]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (hook_entrise != NULL)
|
||||
{
|
||||
struct lkh_hook_state state;
|
||||
|
||||
lkh_hook_state_init(&state, hook_stage, pf, indev, outdev, sk, net);
|
||||
|
||||
ret = lkh_hook_slow(skb, &state, hook_entrise, 0);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(lkh_hook);
|
||||
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include "lkh_hook.h"
|
||||
|
||||
static void __net_init __lkh_net_init(struct lkh_hook_entries __rcu **e, int max)
|
||||
{
|
||||
int h;
|
||||
|
||||
for (h = 0; h < max; h++)
|
||||
{
|
||||
RCU_INIT_POINTER(e[h], NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* Description:
|
||||
* 为指定的网络命名空间卸载对应的HOOK数据结构
|
||||
* Input:
|
||||
* net - 网络命名空间指针
|
||||
* Output:
|
||||
* 无
|
||||
* Return:
|
||||
* 无
|
||||
* Others:
|
||||
* 无
|
||||
**********************************************************************************/
|
||||
static void __net_exit lkh_net_exit(struct net *net)
|
||||
{
|
||||
struct list_head * temp_del;
|
||||
struct list_head * temp_node;
|
||||
struct lkh_hook * hook;
|
||||
|
||||
if (NULL == net)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_safe(temp_del, temp_node, &g_lkh_hook_handle.list)
|
||||
{
|
||||
hook = list_entry(temp_del, struct lkh_hook, list);
|
||||
if (hook != NULL)
|
||||
{
|
||||
if (hook->net_ptr == net)
|
||||
{
|
||||
g_lkh_hook_handle.net_num--;
|
||||
|
||||
list_del(&hook->list);
|
||||
|
||||
/* 释放内存,还需要释放hook_ptr内申请的内存,之后补充 */
|
||||
kvfree(hook);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* Description:
|
||||
* 为指定的网络命名空间初始化对应的HOOK数据结构
|
||||
* Input:
|
||||
* net - 网络命名空间指针
|
||||
* Output:
|
||||
* 1 - 处理失败
|
||||
* 0 - 处理成功
|
||||
* Return:
|
||||
* 无
|
||||
* Others:
|
||||
* 无
|
||||
**********************************************************************************/
|
||||
static int __net_init lkh_net_init(struct net *net)
|
||||
{
|
||||
struct lkh_hook * hook_ptr;
|
||||
size_t alloc;
|
||||
|
||||
if (NULL == net)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
hook_ptr = kvzalloc(sizeof(struct lkh_hook), GFP_KERNEL);
|
||||
if (NULL == hook_ptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 记录net指针,用来作为标识命名空间的关键字 */
|
||||
hook_ptr->net_ptr = net;
|
||||
|
||||
list_add(&hook_ptr->list, &g_lkh_hook_handle.list);
|
||||
g_lkh_hook_handle.net_num++;
|
||||
|
||||
alloc = sizeof(struct lkh_hook_entries __rcu *) * LKH_INET_NUMHOOKS;
|
||||
|
||||
hook_ptr->hooks_ipv4[0] = (struct lkh_hook_entries __rcu *)kvzalloc(alloc, GFP_KERNEL);
|
||||
__lkh_net_init(hook_ptr->hooks_ipv4, ARRAY_SIZE(hook_ptr->hooks_ipv4));
|
||||
|
||||
hook_ptr->hooks_ipv6[0] = (struct lkh_hook_entries __rcu *)kvzalloc(alloc, GFP_KERNEL);
|
||||
__lkh_net_init(hook_ptr->hooks_ipv6, ARRAY_SIZE(hook_ptr->hooks_ipv6));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct pernet_operations lkh_net_ops = {
|
||||
.init = lkh_net_init,
|
||||
.exit = lkh_net_exit,
|
||||
};
|
||||
|
||||
/*********************************************************************************
|
||||
* Description:
|
||||
* 内核钩子.KO insmod处理函数
|
||||
* Input:
|
||||
* 无
|
||||
* Output:
|
||||
* 无
|
||||
* Return:
|
||||
* 无
|
||||
* Others:
|
||||
* 无
|
||||
**********************************************************************************/
|
||||
static int lkh_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&g_lkh_hook_handle.list);
|
||||
|
||||
/* 网络空间模块注册函数 */
|
||||
ret = register_pernet_subsys(&lkh_net_ops);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* Description:
|
||||
* 内核钩子.KO rmmod处理函数
|
||||
* Input:
|
||||
* 无
|
||||
* Output:
|
||||
* 无
|
||||
* Return:
|
||||
* 无
|
||||
* Others:
|
||||
* 无
|
||||
**********************************************************************************/
|
||||
static void lkh_exit(void)
|
||||
{
|
||||
/* 解除网络空间模块注册函数 */
|
||||
unregister_pernet_subsys(&lkh_net_ops);
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(lkh_init);
|
||||
module_exit(lkh_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("meng");
|
||||
MODULE_DESCRIPTION("LINUX HOOK");
|
||||
|
Loading…
Reference in New Issue