初探iptables自動載入模組原理
阿新 • • 發佈:2019-01-03
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/mogo/2.6.17-x86-old/user/iptables/include -fPIC hello.c
[
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是怎麼用的。
庫模組原始碼:
-
#include <stdio.h>
-
#include <match.h>
-
#define _init __attribute__((constructor)) _INIT
-
static int hello()
-
{
-
printf("hello called\n");
-
return 0;
-
}
-
static struct test_match test = {
-
.name = "hello",
-
.match = hello
-
};
-
void _init(void)
-
{
-
printf("init hello\n");
-
register_match(&test);
-
return ;
- }
主程式動態載入so檔案並呼叫模組的函式
-
#include <stdio.h>
-
#include <match.h>
-
#include <dlfcn.h>
-
int main()
-
{
-
struct test_match *ptr;
-
if (dlopen("./libhello.so", RTLD_NOW) == NULL) {
-
printf("load lib error.\n");
-
return 0;
-
}
-
ptr = find_match("hello");
-
if (ptr) {
-
printf("find match:%s\n", ptr->name);
-
ptr->match();
-
}
-
return 0;
- }
-
[[email protected] netcos]# ./main
-
init hello
-
find match:hello
- hello called