Linux 定义Netfilter挂钩函数的正确方法是什么?

Linux 定义Netfilter挂钩函数的正确方法是什么?,linux,linux-kernel,netfilter,Linux,Linux Kernel,Netfilter,我正在为Linux编写一个内核模块(更具体地说,是一个Netfilter模块)。我正试图使它与广泛的内核兼容,但entry函数给我带来了麻烦 从LXR中,我可以看到内核3.13中的nf\uhookfntypedef发生了变化 : 然而,我们有一台Red Hat机器声称正在使用内核3.10.0-123.4.4.el7.x86_64,但它的netlink.h读取 typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, (...))

我正在为Linux编写一个内核模块(更具体地说,是一个Netfilter模块)。我正试图使它与广泛的内核兼容,但entry函数给我带来了麻烦

从LXR中,我可以看到内核3.13中的
nf\uhookfn
typedef发生了变化

:

然而,我们有一台Red Hat机器声称正在使用内核3.10.0-123.4.4.el7.x86_64,但它的netlink.h读取

typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, (...));
好像是3.13+代码

它在我的模块上引起警告,因为它完全破坏了我根据内核版本以不同方式定义函数的尝试:

#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同时依赖于内核版本和发行版,这毫无意义

更重要的是,我如何解决这个问题
nf_hookfn
是一个typedef,不是一个宏,所以我不能把它放在我的函数定义中。 有一件事可能会让事情变得更容易,那就是我从不使用那个论点


我肯定不是第一个经历这种情况的人?我的意思是
nf_hookfn
是任何Netfilter模块的入口点;你可能会认为他们改变了数千个驱动程序。

这可能是因为你使用的是ko,它是为新版本的内核编译的。如果模块未作为RH发货,则您可能需要与供应商合作解决此问题

最后,我对这个问题做了一个专门的讨论:

/**
 * 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 NF_CALLBACK(function_name, skb)
{
    return do_something_with_skb(skb);
}
我实际上正在尝试编写一个内核模块,并使其与广泛的内核兼容。呃。。。我想我的问题不清楚。我会编辑它。
/**
 * 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);
}