diff --git a/Platform/user/kernel_hook/Makefile b/Platform/user/kernel_hook/Makefile new file mode 100644 index 000000000..2504a3fad --- /dev/null +++ b/Platform/user/kernel_hook/Makefile @@ -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 diff --git a/Platform/user/kernel_hook/lkh_hook.c b/Platform/user/kernel_hook/lkh_hook.c new file mode 100644 index 000000000..ef0579d5e --- /dev/null +++ b/Platform/user/kernel_hook/lkh_hook.c @@ -0,0 +1,530 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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); + + + diff --git a/Platform/user/kernel_hook/lkh_hook.h b/Platform/user/kernel_hook/lkh_hook.h new file mode 100644 index 000000000..b79e9df3d --- /dev/null +++ b/Platform/user/kernel_hook/lkh_hook.h @@ -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 + diff --git a/Platform/user/kernel_hook/lkh_hook_fwd.c b/Platform/user/kernel_hook/lkh_hook_fwd.c new file mode 100644 index 000000000..cfa2b211c --- /dev/null +++ b/Platform/user/kernel_hook/lkh_hook_fwd.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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); + + diff --git a/Platform/user/kernel_hook/lkh_hook_init.c b/Platform/user/kernel_hook/lkh_hook_init.c new file mode 100644 index 000000000..79581657b --- /dev/null +++ b/Platform/user/kernel_hook/lkh_hook_init.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); +