149 lines
3.6 KiB
C
149 lines
3.6 KiB
C
|
#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);
|
|||
|
|
|||
|
|