定义Netfilter挂钩函数的正确方法是什么? [英] What is the correct way to define a Netfilter hook function?
问题描述
我正在为Linux编码一个内核模块(更具体地说,是一个 Netfilter 模块).我正在尝试使其与各种内核兼容,但是入口函数给我带来了麻烦.
I'm coding a kernel module (more specifically, a Netfilter module) for Linux. I'm trying to make it compatible with a wide range of kernels, but the entry function is giving me trouble.
从LXR,我可以看到nf_hookfn
typedef在内核3.13中已更改.
From LXR, I can see that the nf_hookfn
typedef changed in kernel 3.13.
typedef unsigned int nf_hookfn(unsigned int hooknum, (...));
typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, (...));
但是,我们有一台Red Hat机器声称正在使用内核3.10.0-123.4.4.el7.x86_64,但其netlink.h读取
However, we have a Red Hat machine claiming to be using kernel 3.10.0-123.4.4.el7.x86_64, yet its netlink.h reads
typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, (...));
好像是3.13+代码.
as if it were 3.13+ code.
它在我的模块上引起警告,因为它完全破坏了我根据内核版本以不同的方式定义函数的尝试:
It's causing warnings on my module because it completely trainwrecks my attempt to define the function differently based on kernel version:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
#define HOOK_ARG_TYPE const struct nf_hook_ops *
#else
#define HOOK_ARG_TYPE unsigned int
#endif
我错过了哪些文档?从来没有向我建议过内核API依赖于内核版本和发行版,而且没有任何意义.
What piece of documentation did I miss? Nothing ever suggested to me that kernel API depends on BOTH kernel version AND distro, and it makes no sense.
更重要的是,我该如何解决? nf_hookfn
是typedef,而不是宏,因此我不能只是将其放在函数定义中.
使事情变得更容易的一件事是,我从不使用该参数.
And more to the point, how can I fix this? nf_hookfn
is a typedef, not a macro, so I can't just drop it on my function definition.
One thing that might make things easier is that I never use that one argument.
我当然不是第一个遇到这种情况的人吗?我的意思是nf_hookfn
是任何Netfilter模块的入口点;您会认为他们通过更改来破坏了成千上万的驱动程序.
Surely I'm not the first person ever experiencing this? I mean nf_hookfn
is the entry point for any Netfilter module; you'd think they broke thousands of drivers by changing it.
推荐答案
In the end I just made an entire module dedicated to this:
/**
* The kernel API is far from static. In particular, the Netfilter packet entry
* function keeps changing. nf_hook.c, the file where we declare our packet
* entry function, has been quite difficult to read for a while now. It's pretty
* amusing, because we don't even use any of the noisy arguments.
*
* This file declares a usable function header that abstracts away all those
* useless arguments.
*/
#include <linux/version.h>
/* If this is a Red Hat-based kernel (Red Hat, CentOS, Fedora, etc)... */
#ifdef RHEL_RELEASE_CODE
#if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 2)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
const struct nf_hook_state *state) \
#elif RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#else
/*
* Sorry, I don't have headers for RHEL 6 and below because I'm in a bit of a
* deadline right now.
* If this is causing you trouble, find `nf_hookfn` in your kernel headers
* (typically in include/linux/netfilter.h) and add your version of the
* NF_CALLBACK macro here.
* Also, kernel headers per version can be found here: http://vault.centos.org/
*/
#error "Sorry; this version of RHEL is not supported because it's kind of old."
#endif /* RHEL_RELEASE_CODE >= x */
/* If this NOT a RedHat-based kernel (Ubuntu, Debian, SuSE, etc)... */
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
void *priv, \
struct sk_buff *skb, \
const struct nf_hook_state *state)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct nf_hook_state *state)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
unsigned int hooknum, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#else
#error "Linux < 3.0 isn't supported at all."
#endif /* LINUX_VERSION_CODE > n */
#endif /* RHEL or not RHEL */
所以代替这个:
static unsigned int function_name((...), struct sk_buff *skb, (...))
{
return do_something_with_skb(skb);
}
执行此操作:
static NF_CALLBACK(function_name, skb)
{
return do_something_with_skb(skb);
}
这篇关于定义Netfilter挂钩函数的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!