====================以下为hook函数执行大致流程============================
/* Respones from hook functions. */
#define NF_DROP 0
#define NF_ACCEPT 1
#define NF_STOLEN 2
#define NF_QUEUE 3
#define NF_REPEAT 4
#define NF_STOP 5
#define NF_MAX_VERDICT NF_STOP
struct nf_hook_state {
unsigned int hook;
int thresh;
u_int8_t pf;
struct net_device *in;
struct net_device *out;
struct sock *sk;
struct net *net;
// 根据list_entry_rcu函数返回值的类型为nf_hook_ops得知,该list为nf_hook_ops类型的list
struct list_head *hook_list;
int (*okfn)(struct net *, struct sock *, struct sk_buff *);
}
/* Returns 1 if okfn() needs to be executed by the caller,
* -EPERM for NF_DROP, 0 otherwise. */
int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
{
struct nf_hook_ops *elem;
unsigned int verdict;
int ret = 0;
/* We may already have this, but read-locks nest anyway */
rcu_read_lock();
elem = list_entry_rcu(state->hook_list, struct nf_hook_ops, list);
next_hook:
verdict = nf_iterate(state->hook_list, skb, state, &elem);
if (verdict == NF_ACCEPT || verdict == NF_STOP) {
ret = 1;
} else if ((verdict & NF_VERDICT_MASK) == NF_DROP) {
kfree_skb(skb);
ret = NF_DROP_GETERR(verdict);
if (ret == 0)
ret = -EPERM;
} else if ((verdict & NF_VERDICT_MASK) == NF_DUEUE) {
int err = nf_queue(skb, elem, state,
verdict >> NF_VERDICT_QBITS);
if (err < 0) {
if (err == -ESRCH &&
(verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
goto next_hook;
kfree_skb(skb);
}
}
rcu_read_unlock();
return ret;
}
// include/linux/netfilter.h
typedef unsigned int nf_hookfn(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state);
struct nf_hook_ops {
struct list_head list;
/* User fill in from here down */
nf_hookfn *hook;
struct net_device *dev;
void *priv;
u_int8_t pf; // protocol family
unsigned int hooknum; // hook point
/* Hooks are ordered in ascending priority */
int priority;
}
struct nf_hook_ops *list_entry_rcu(struct list_head *list, )
/* Any packet that leave via this function must come back
* through nf_reinject(). */
/* nf_queue 是netfilter的基本机制 - 队列模型
可以经内核数据包递交给用户层处理,并根据用户态的处理结果,进行相应的处理操作*/
nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem,
struct nf_hook_state *state, unsigned int queuenum)
unsigned int nf_iterate(struct list_head *head, struct sk_buff,
struct nf_hook_state *state, struct nf_hook_ops **elemp)
{
unsigned int verdict;
/*
* The caller must not block between calls to this
* function because of risk of continuing form deleted element.
*/
list_for_each_entry_continue_rcu((*elemp), head, list) {
if (state->thresh > (*elemp)->priority)
continue;
repeat:
verdict = (*elemp)->hook((*elemp)->priv, skb, state);
if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG
if (unlikely((verdict & NF_VERDICT_MASK)
> MF_MAX_VERDICT)){
NFDEBUG("Evil return form %p(%u).\n",
(*elemp)->hook, state->hook);
continue;
}
#endif
if (verdict != NF_REPEAT)
return verdict
goto repeat;
}
}
return NF_ACCEPT;
}
==================以下为hook函数注册的大致流程==============================
struct nf_hook_entry {
const struct nf_hook_ops *orig_ops;
struct nf_hook_ops ops;
};
struct net {
...
struct netns_nf nf;
struct netns_xt xt;
...
};
struct netns_nf {
#if defined CONFIG_PROC_FS
struct proc_dir_entry *proc_netfilter;
#endif
const struct nf_queue_handler __rcu *queue_handler;
const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
#ifdef CONFIG_SYSCTL
struct ctl_table_header *nf_log_dir_header;
#endif
struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
};
int nf_register_hook(struct nf_hook_ops *reg)
{
struct net *net, *last;
int ret;
rtnl_lock();
for_each_net(net) {
ret = nf_register_net_hook(net, reg);
if (ret && ret != -ENOENT)
return rollback;
}
list_add_tail(®->list, &nf_hook_list);
rtnl_unlock();
return 0;
rollback:
last = net;
for_each_net(net) {
if (net == last)
break;
nf_unregister_net_hook(net, reg);
}
rtnl_unlock();
return ret;
}
int nf_register_net_hook(struct net *net, struct nf_hook_ops *reg)
{
struct list_head *hook_list;
struct nf_hook_entry *entry;
struct nf_hook_ops *elem;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->orig_ops = reg;
entry->ops = *reg;
hook_list = nf_find_hook_list(net, reg);
if (!hook_llist) {
kfree(entry);
return -ENOENT;
}
mutex_lock(&nf_hook_mutex);
list_for_each_entry(elem, hook_list, list) {
if (reg->priority < elem->priority)
break;
}
list_add_rcu(&enry->ops.list, elem->list.prev);
mutex_unlock(&nf_hook_mutex);
#ifdef CONFIG_NETFILTER_INGRESS
if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETdEV_INGRESS)
net_dec_ingress_queue();
#endif
#ifdef HAVE_JUMP_LABEL
static_key_slow_cec(&nf_hooks_needed[reg-pf][reg->hooknum]);
#endif
synchronize_net();
nf_queue_nf_hook_drop(net, &entry->ops);
/* other cpu might sill process nfqueue verdict that used reg */
synchronize_net();
kfree(entry);
}
static struct list_head *nf_find_hook_list(struct net *net, struct nf_hook_ops *reg)
{
struct list_head *hook_list = NULL;
if (reg->pf != NFPROTO_NETDEV)
hook_list = &net->nf.hooks[reg->pf][reg->hooknum];
else if (reg->hooknum == NF_NETDEV_INGRESS) {
#ifdef CONFIG_NETFILTER_NIGRESS
if (reg->dev && dev_net(reg->dev) == net)
hook_list = ®->dev->nf_hooks_ingress;
#endif
}
return hook_list;
}
nf_register_hooks()
nf_register_net_hooks()
本文深入探讨了Linux内核中Netfilter框架的钩子函数执行流程与注册机制。详细解释了nf_hook_state结构体的功能,nf_hook_slow函数如何处理数据包以及nf_hook_ops结构体在钩子注册中的作用。此外,还介绍了nf_queue机制和数据包队列模型的基本原理。
7215

被折叠的 条评论
为什么被折叠?



