免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2647 | 回复: 0
打印 上一主题 下一主题

[内核模块] iptables自动加载模块原理 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-04-16 16:47 |只看该作者 |倒序浏览
本帖最后由 netcos 于 2014-01-26 14:38 编辑

iptables使用dlopen加载动态库,每个库中都定义了void _init(void)函数,在使用dlopen加载库的时候系统会调用_init函数,
在_init函数中调用xtables_register_match对模块进行注册。iptables这种动态加载模块的方式很适合做定制开发,所以我就自己摸索了下。

我自己写了一个测试的例子:
gcc -O2 -Wall  -fPIC -c hello.c
gcc -shared -o hello.so hello.o
hello.o: In function `_init':
hello.c:(.text+0x0): multiple definition of `_init'
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../crti.o:(.init+0x0): first defined here

编译的时候出现了重复定义的错误。这是为什么?

_init是共享库用来初始化全局变量和对象的,在库文件中已经定义过了。有什么办法可以使用_init来初始化我们自己的函数呢?
通过查看iptables的模块代码,发现所有的文件都包含#include <xtables.h>头文件,会不会是xtables.h中动了什么手脚?
在hello.c中包含xtables.h头文件,果然编译通过。

#include <stdio.h>
#include <xtables.h>

int main()
{
        return 0;
}

void _init(void)
{
        printf("init hello\n");

        return ;
}

gcc -O2 -Wall -o hello -I/home/iptables/include -fPIC hello.c

[root@rhce netcos]# ./hello
init hello

xtables.h头文件中到底做了什么呢?
我在代码中看到一个宏定义:#   define _init __attribute__((constructor)) _INIT,会不会是这个?
于是在hello.c中去掉头文件xtables.h,将该宏定义换进去,果然没问题。

那这个宏定义是什么意思呢?
用__attribute__((constructor))来定义的函数,表示函数是构造函数,在main执行之前被调用;相应的用__attribute__ ((destructor))析构函数,在main退出时执行。
void _init(void)就相当于是__attribute__((constructor)) _INIT(void),其实不管函数名定义成什么都会被执行到。

自动初始化的问题解决了,现在就来看看dlopen是怎么用的。
库模块源码:

  1. #include <stdio.h>
  2. #include <match.h>

  3. #define _init __attribute__((constructor)) _INIT

  4. static int hello()
  5. {
  6.         printf("hello called\n");

  7.         return 0;
  8. }

  9. static struct test_match test = {
  10.         .name  = "hello",
  11.         .match = hello
  12. };

  13. void _init(void)
  14. {
  15.         printf("init hello\n");

  16.         register_match(&test);

  17.         return ;
  18. }
复制代码
运行后生成libhello.so文件

主程式动态加载so文件并调用模块的函数
  1. #include <stdio.h>
  2. #include <match.h>
  3. #include <dlfcn.h>

  4. int main()
  5. {
  6.         struct test_match *ptr;

  7.         if (dlopen("./libhello.so", RTLD_NOW) == NULL) {
  8.                 printf("load lib error.\n");

  9.                 return 0;
  10.         }

  11.         ptr = find_match("hello");
  12.         if (ptr) {
  13.                 printf("find match:%s\n", ptr->name);
  14.                 ptr->match();
  15.         }

  16.         return 0;
  17. }
复制代码
编译成可执行文件运行:
  1. [root@rhce netcos]# ./main
  2. init hello
  3. find match:hello
  4. hello called
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP