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

2024-03-18

我正在编写一个内核模块(更具体地说,一个网络过滤器模块)适用于 Linux。我试图使其与各种内核兼容,但入口功能给我带来了麻烦。

从 LXR 中,我可以看到nf_hookfntypedef 在内核 3.13 中发生了变化。

Linux 3.12 及之前版本 http://lxr.free-electrons.com/source/include/linux/netfilter.h?v=3.12#L45:

typedef unsigned int nf_hookfn(unsigned int hooknum, (...));

3.13 起: http://lxr.free-electrons.com/source/include/linux/netfilter.h?v=3.13#L46

typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, (...));

然而,我们有一台 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 模块的入口点;你可能会认为他们通过改变它破坏了数千个驱动程序。


最后我只是做了一个整个模块 https://github.com/NICMx/Jool/blob/5f60dcda5944b01cc43c3be342aad26af8161bcb/include/nat64/mod/common/nf_wrapper.h致力于此:

/**
 * 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);
}

Do this:

static NF_CALLBACK(function_name, skb)
{
    return do_something_with_skb(skb);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

定义 Netfilter 挂钩函数的正确方法是什么? 的相关文章

随机推荐

  • 电子邮件中的 Message-ID 有什么用?

    据我所知 每个消息 ID 都必须是唯一的 但是如果我们强制标头具有固定值 则可能会创建重复的消息 ID 所以我不明白他们说 Message ID 应该是唯一的有什么意义 但他们很容易创建重复项 如果任何有一点阅读和基本编程知识的人都可以轻松
  • 使用 Keras 加载之前保存的重新训练的 VGG16 模型时出现 ValueError

    我在 Keras 中使用 VGG16 架构 我通过以下方式对其进行了重新训练以满足我的需求 vgg16 model keras applications vgg16 VGG16 model Sequential for layer in v
  • CUDA:如何直接在GPU上使用thrust::sort_by_key? [复制]

    这个问题在这里已经有答案了 Thrust 库可用于对数据进行排序 该调用可能如下所示 带有键和值向量 thrust sort by key d keys begin d keys end d values begin 在 CPU 上调用 d
  • Azure DevOps 服务连接到 B2C 租户?

    我正在尝试建立从 Azure DevOps 到我的 Azure B2C 租户的服务连接 但遇到了问题 我开始认为这是不可能的 我与主 Azure 订阅 租户有多个服务连接 但特别想要与我的 B2C 租户建立连接 以便我可以使用 Terraf
  • 禁用复制构造函数

    我有一堂课 class SymbolIndexer protected SymbolIndexer public static inline SymbolIndexer GetUniqueInstance static SymbolInde
  • 如何从javascript中的回调函数中获取完整数据

    我编写了以下函数 它从 url 获取 json 数据 function getWeatherDataForCities cityArray var arrAllrecords var toDaysTimestamp Math round n
  • 将(可选)参数传递给 HTTP 参数(Python、请求)

    我目前正在开发 API 包装器 并且在将参数从函数传递到请求的有效负载中时遇到问题 参数可以是 blockId senderId recipientId limit offset orderBy 所有参数均通过 OR 连接 一个可能的解决方
  • 在 Rails 中使用 Turbolinks link_to

    只是想知道是否有一种方法可以直接在 Rails link to 帮助程序中使用 Turbolinks 快速的谷歌搜索没有发现任何值得注意的东西 这是我尝试过但无济于事的类型 我知道你可以通过像这样的常规链接来做到这一点 a href gir
  • 为什么使用 twitter bootstrap 的多模式会出现过多递归错误?

    我尝试在另一个模态中包含一个模态 但是 我收到了类似的错误too much recursion在火狐浏览器中 我使用了最新的 jQuery 和 Twitter bootstrap 但仍然有这个问题 这里是plunker http plnkr
  • Windows 服务托管 TCP WCF 服务

    我正在尝试在 Windows 2008 R2 服务器上托管 WCF 服务作为 Windows 服务 我按照 msdn 提供的指示进行操作 在这里找到 http msdn microsoft com en us library ff64981
  • 如何在不创建用户帐户的情况下只允许每人(电脑/手机)对网站上的 1 个帖子投 1 票?

    在学习 Meteor 框架的过程中 我正在将 Yik Yak 移动应用程序重新创建为 Web 应用程序 但该应用程序是完全匿名的 没有用户帐户 但您仍然只能对帖子投赞成票或反对票一次 如何使这项工作有效 您想要的可能不仅仅需要 JavaSc
  • 网格视图数据绑定事件

    如何使用网格视图的数据绑定事件以及如何调用它有人可以详细说明一下吗 我像这样在按钮上绑定 gridview DataTable dt placedStudentManager GetPlacedStudentList sb passoutY
  • set.pop() 是确定性的吗?

    我知道 python 集合的元素是没有顺序的 调用pop方法返回任意元素 我对此很满意 我想知道当集合具有相同的历史记录时 pop 是否总是返回相同的元素 当然 在一个版本的 python 中 我不介意 python 的不同版本 实现是否做
  • 在 Android 密钥库中存储 hmac 密钥

    我使用下面的代码创建 hmac 密钥并将其作为字符串返回 KeyGenerator keyGen null try keyGen KeyGenerator getInstance HmacSHA256 catch NoSuchAlgorit
  • 如何使用目标接口将编译选项添加到 CMake FetchContent 依赖项

    我有一个使用 CMake 的依赖项FetchContent需要使用一些构建标志来构建 cmake DFLAG ON 这个问题也被问到here https stackoverflow com questions 68708076 how to
  • 在 Elastic Beanstalk 上运行 .config 文件?

    我正在尝试在我的弹性豆茎上运行自定义 config 文件 我正在按照以下说明进行操作这个链接 http www tonmoygoswami com 2013 05 how to enable gzip on amazon elastic h
  • 在 C# 中使用 RSA

    如何在 C 中使用 RSA 加密技术加密文本或任何其他媒体 我需要使用任何外部库还是有任何内置的东西 一个小示例代码会有所帮助 Use 系统 安全 加密 RSACryptoServiceProvider http msdn microsof
  • OpenShift action_hooks 不可执行

    当我在 OpenShift 中创建测试 DIY 应用程序时 action hooks工作正常 但现在我创建了一个实际的应用程序 当我推送更改时它们不会触发 我做了一些调查 发现了问题 由于某种原因 操作挂钩无法执行 我检查过 它们在测试应用
  • 在 C# 中无法获得与 Python 中相同的哈希值

    我有一个字符串 需要对其进行哈希处理才能访问 API API 创建者在 Python 中提供了一个 codenippet 它对代码进行哈希处理 如下所示 hashed string hashlib sha1 string to hash h
  • 定义 Netfilter 挂钩函数的正确方法是什么?

    我正在编写一个内核模块 更具体地说 一个网络过滤器模块 适用于 Linux 我试图使其与各种内核兼容 但入口功能给我带来了麻烦 从 LXR 中 我可以看到nf hookfntypedef 在内核 3 13 中发生了变化 Linux 3 12