nf_conntrack_helper注册未注册端口返回错误

2024-02-11

我有以下代码从内核 3.18 取消注册和注册 sip conntrack

static void __nf_conntrack_sip_fini(void)
{
    int i, j;

    for (i = 0; i < ports_c; i++) {
        for (j = 0; j < ARRAY_SIZE(sip[i]); j++) {
            if (sip[i][j].me == NULL)
                continue;
            nf_conntrack_helper_unregister(&sip[i][j]);
        }
    }
    memset(sip, 0, sizeof(sip));
}

static int __nf_conntrack_sip_init(void)
{
    int i, j, ret;

    if (ports_c == 0)
        ports[ports_c++] = SIP_PORT;

    for (i = 0; i < ports_c; i++) {
        memset(&sip[i], 0, sizeof(sip[i]));

        sip[i][0].tuple.src.l3num = AF_INET;
        sip[i][0].tuple.dst.protonum = IPPROTO_UDP;
        sip[i][0].help = sip_help_udp;
        sip[i][1].tuple.src.l3num = AF_INET;
        sip[i][1].tuple.dst.protonum = IPPROTO_TCP;
        sip[i][1].help = sip_help_tcp;

        sip[i][2].tuple.src.l3num = AF_INET6;
        sip[i][2].tuple.dst.protonum = IPPROTO_UDP;
        sip[i][2].help = sip_help_udp;
        sip[i][3].tuple.src.l3num = AF_INET6;
        sip[i][3].tuple.dst.protonum = IPPROTO_TCP;
        sip[i][3].help = sip_help_tcp;

        for (j = 0; j < ARRAY_SIZE(sip[i]); j++) {
            sip[i][j].data_len = sizeof(struct nf_ct_sip_master);
            sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
            sip[i][j].expect_policy = sip_exp_policy;
            sip[i][j].expect_class_max = SIP_EXPECT_MAX;
            sip[i][j].me = THIS_MODULE;

            if (ports[i] == SIP_PORT)
                sprintf(sip[i][j].name, "sip");
            else
                sprintf(sip[i][j].name, "sip-%u", i);

            pr_debug("port #%u: %u\n", i, ports[i]);

            ret = nf_conntrack_helper_register(&sip[i][j]);
            if (ret) {
                printk(KERN_ERR "nf_ct_sip: failed to register"
                       " helper for pf: %u port: %u i=%d\n",
                       sip[i][j].tuple.src.l3num, ports[i], i);
                __nf_conntrack_sip_fini();
                return ret;
            }
        }
    }
    return 0;
}

我开发了以下代码来使用相同的第一个端口重新启动注册的 sip conntrack

static void nf_conntrack_sip_restart(void)
{
    //here ports[] = {5060, 0}
    __nf_conntrack_sip_fini();
    memcpy(ports,newports,sizeof(ports));
    //here ports[] = {5060, 5555}
    __nf_conntrack_sip_init(); // <---- It fails
}

当我从用户空间触发此重新启动功能时,新端口数组的寄存器失败

如果我使用其他端口,那么它可以工作:

static void nf_conntrack_sip_restart(void)
{
    //here ports[] = {5060, 0}
    __nf_conntrack_sip_fini();
    memcpy(ports,newports,sizeof(ports));
    //here ports[] = {5061, 5555}
    __nf_conntrack_sip_init(); // <---- It works
}

我缺少什么?

下面是经过我修改的 nf_conntrack_sip.c 文件的整个源代码:http://vpaste.net/PgUVD http://vpaste.net/PgUVD

要查看我的修改,您可以与 linux 3.18 的原始源代码进行 diff


您不能调用模块init and exit直接运行并期望它们能够工作,而无需首先确保模块不再以任何方式使用。

我缺少什么?

The init and exit函数以特定方式调用,即它们是安全的 在锁之前做出很多关于持有什么锁等的假设 叫。您的代码绕过了所有这些并假设如果直接调用 他们会工作的。不是这种情况。

如果你看delete_module这不是小事,它正在准备卸载你的 模块,这会检查您的模块是否正在被使用。假设您的代码是 当前正在为请求提供服务,您确实不想要您的模块,并且它是 关联的数据结构在运行时消失,即几乎未定义的行为 肯定会导致内核恐慌或更糟糕的事情......

以下是内核在调用退出例程之前执行的操作的简短摘要

  1. Acquire module_lock,等到可以拿到为止。
  2. 检查是否有依赖该模块的模块。
  3. 检查是否已经有一个正在运行init or exit常规。
  4. 确保有一个exit功能。
  5. 停止模块,即标记为 MODULE_STATE_GOING
  6. Unlock mutex_lock

此时我们有以下评论

/* Final destruction now no one is using it. */

您的代码没有执行上面列出的 6 个步骤中的任何一个。这是 3.16 内核上删除模块的来源,我怀疑它与 3.18 相同...

SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
    unsigned int, flags)
{
  struct module *mod;
  char name[MODULE_NAME_LEN];
  int ret, forced = 0;

  if (!capable(CAP_SYS_MODULE) || modules_disabled)
    return -EPERM;

  if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
    return -EFAULT;
  name[MODULE_NAME_LEN-1] = '\0';

  if (mutex_lock_interruptible(&module_mutex) != 0)
    return -EINTR;

  mod = find_module(name);
  if (!mod) {
    ret = -ENOENT;
    goto out;
  }

  if (!list_empty(&mod->source_list)) {
    /* Other modules depend on us: get rid of them first. */
    ret = -EWOULDBLOCK;
    goto out;
  }

  /* Doing init or already dying? */
  if (mod->state != MODULE_STATE_LIVE) {
    /* FIXME: if (force), slam module count damn the torpedoes */
    pr_debug("%s already dying\n", mod->name);
    ret = -EBUSY;
    goto out;
  }

  /* If it has an init func, it must have an exit func to unload */
  if (mod->init && !mod->exit) {
    forced = try_force_unload(flags);
    if (!forced) {
      /* This module can't be removed */
      ret = -EBUSY;
      goto out;
    }
  }

  /* Stop the machine so refcounts can't move and disable module. */
  ret = try_stop_module(mod, flags, &forced);
  if (ret != 0)
    goto out;

  mutex_unlock(&module_mutex);
  /* Final destruction now no one is using it. */
  if (mod->exit != NULL)
    mod->exit();
  blocking_notifier_call_chain(&module_notify_list,
             MODULE_STATE_GOING, mod);
  async_synchronize_full();

  /* Store the name of the last unloaded module for diagnostic purposes */
  strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));

  free_module(mod);
  return 0;
out:
  mutex_unlock(&module_mutex);
  return ret;
}

接近尾声时,它会运行您的退出函数,但只有在它确保没有人 实际上正在使用它等。能够按照您想要的方式调用函数 需要了解加载和卸载模块。

我看到您已经编辑了问题,现在很清楚代码的来源

如果您提到要剪切并粘贴init and exit来自 nf_conntrack_sip 的函数。这可能会节省很多人很多时间来思考为什么它不起作用。

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

nf_conntrack_helper注册未注册端口返回错误 的相关文章

随机推荐

  • 为什么“a”标签需要“tabindex=0”?

    我正在开发一个网络应用程序 其中一个重复的应用程序a当我通过 Tab 键浏览页面时 锚点 元素没有获得键盘焦点 仅当我添加tabindex 0我可以点击它吗 虽然我的目标是使焦点可见 但我正在使用 jQuery 片段确定元素是否获得焦点 W
  • 是否有一种简洁的方法在 Google Guava 中为 InputStream 创建 InputSupplier?

    Google Guava 中有一些工厂方法来创建 InputSuppliers 例如从一个byte ByteStreams newInputStreamSupplier bytes 或者从一个File Files newInputStrea
  • 为什么在 Alpine Linux 上安装 Pandas 需要很长时间

    我注意到 使用基本操作系统 Alpine 与 CentOS 或 Debian 在 Docker 容器中安装 Pandas 和 Numpy 它的依赖项 需要更长的时间 我在下面创建了一个小测试来演示时差 除了 Alpine 需要几秒钟更新和下
  • 创建和更新 multiprocessing.Manager 对象内的嵌套字典和列表

    我在里面创建了一个嵌套字典multiprocessing Manager dict目的 字典方法如update clear等 当我将它们应用到嵌套字典时不起作用 这是一个例子 from multiprocessing import Mana
  • Gatsby GraphQL 查询多个图像

    我正在努力弄清楚如何在 Gatsby Js 中使用 GraphQL 查询多个特定图像 我最初的想法是做这样的事情 file relativePath eq images front jpg id file relativePath eq i
  • Foundation 6 画布外菜单点击后自动关闭

    我一直在搜索如何在单击某些菜单项后自动关闭画布外菜单 但似乎没有任何效果 因此 我按照 Foundation 6 文档上有关如何制作画布外菜单的指南进行操作 并且它有效 这部分还可以 现在 当我单击某个链接菜单时 它会停留在那里 我希望它关
  • 摄像头下方有一个黑色的底部空间

    我正在介绍一个UIImagePickerController from a UITabBarController let imagePicker UIImagePickerController imagePicker delegate se
  • 预下载所有依赖项

    我需要将 Maven 构建 Java 项目发布给远程 QA 团队 为此 我想下载所有依赖项 然后发送它们 这样他们就不需要下载它们 目前所有依赖项都定义在pom xml文件 我们使用mvn install or mvn package构建项
  • 如何删除Selectbox/Checkbox的默认状态?

    我想知道如何删除选择框的默认箭头和复选框中的渐变 并且我想在其上使用自定义图像 例如 这是一些代码
  • 尝试解析 LocalDateTime 时出现异常

    我正在使用以下时间戳格式 yyyyMMddHHmmssSSS 以下方法效果很好 public static String formatTimestamp final Timestamp timestamp final String form
  • 如何查看 select2 实例的设置选项?

    我想要将选项设置为 select2 实例 特别是如果allowClear 选项设置为 true 或 false 浏览对象我发现了allowClear选项 jQuery gt select2 gt 选项 gt 选项 but I don t k
  • 为什么我无法为对话框视图中的按钮设置 onClickListener?

    我有一个自定义对话框 如下所述 我的自定义对话框布局 my dialog xml 其中只包含一个 关闭 按钮
  • CSS动画闪烁,尝试了我能找到的所有技巧

    我正在 Codepen 中制作一个简单的动画 诗淡入 然后单词 也是按钮 淡入 用户单击单词 它会更改为诗的下一部分 我的问题是 在淡出开始之前 诗歌和单个单词会闪烁 我已经尝试了所有我能找到的技巧 并添加 webkit backface
  • Heroku pg:psql 停止运行

    当我跑步时heroku pg psql i get gt Connecting to postgresql cylindrical 38664 并熄火 一切看起来都很顺利 但它只是卡住了 什么也没做 我似乎在 gitbash 中遇到了同样的
  • 在 perl 中读取和写入文件

    this is just an example 假设上面是out txt 我想读书out txt并写入同一个文件
  • 在 Android 中从纬度/经度获取企业名称或地标

    好吧 我已经为此搜索了相当长的时间 我有一个距我新发现的位置的纬度 经度 geocoder 的 getFromLocation 从纬度 经度返回一定数量的地址 这一切都很好 然后我将它放入一个适配器中 该适配器填充了一个旋转器 也运行得很好
  • UIButton 在单元格被触摸时也会突出显示

    I ve a UIButton在我弹出的表格单元格上 touchUpInside a UIAlertView并询问用户是否要删除与该单元格关联的文件 否则 触摸单元格本身会突出显示该单元格 然后移动到下一个级别以显示内容 问题是当细胞sel
  • 如何在一定时间后重试功能请求

    如果用户数据为空 如何让它重试发送尝试 最多重试 2 次 10 秒后重试 1 次 public class UserHandler private List users new ArrayList public void addUser u
  • 绕过 requiredfieldvalidator

    我有一个网络表单 上面有验证器 当用户按下提交按钮时 验证器可以很好地工作 但是 当用户按下注销按钮时 验证器会停止该按钮的工作 关于如何解决这个问题有什么建议吗 您需要使用CausesValidation按钮上的属性
  • nf_conntrack_helper注册未注册端口返回错误

    我有以下代码从内核 3 18 取消注册和注册 sip conntrack static void nf conntrack sip fini void int i j for i 0 i lt ports c i for j 0 j lt