secgateway/Platform/user/kernel_hook/lkh_hook_fwd.c

149 lines
3.6 KiB
C
Raw Normal View History

#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);