然match是以可扩展的形式表现出来,那么,当然就需要find_match这样的函数将它们一一找出来了。
前面说过,在输出规则的函数中:
IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
用来遍历每一个match,找到了后,就调用print_match来输出。print_match是调用find_match来查找的:
struct iptables_match *
find_match(const char *name, enum ipt_tryload tryload)
{
struct iptables_match *ptr;
for (ptr = iptables_matches; ptr; ptr = ptr->next) {
if (strcmp(name, ptr->name) == 0)
break;
}
#ifndef NO_SHARED_LIBS
if (!ptr && tryload != DONT_LOAD) {
char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
+ strlen(name)];
sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
if (dlopen(path, RTLD_NOW)) {
/* Found library. If it didn't register itself,
maybe they specified target as match. */
ptr = find_match(name, DONT_LOAD);
if (!ptr)
exit_error(PARAMETER_PROBLEM,
"Couldn't load match `%s'/n",
name);
} else if (tryload == LOAD_MUST_SUCCEED)
exit_error(PARAMETER_PROBLEM,
"Couldn't load match `%s':%s/n",
name, dlerror());
}
#else
if (ptr && !ptr->loaded) {
if (tryload != DONT_LOAD)
ptr->loaded = 1;
else
ptr = NULL;
}
if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
exit_error(PARAMETER_PROBLEM,
"Couldn't find match `%s'/n", name);
}
#endif
if (ptr)
ptr->used = 1;
return ptr;
}
分析这个函数,不从开头来看,先看这一段:
if (!ptr && tryload != DONT_LOAD) {
char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
+ strlen(name)];
sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
if (dlopen(path, RTLD_NOW)) {
/* Found library. If it didn't register itself,
maybe they specified target as match. */
ptr = find_match(name, DONT_LOAD);
if (!ptr)
exit_error(PARAMETER_PROBLEM,
"Couldn't load match `%s'/n",
name);
} else if (tryload == LOAD_MUST_SUCCEED)
exit_error(PARAMETER_PROBLEM,
"Couldn't load match `%s':%s/n",
name, dlerror());
}
函数根据传递过来的match名称,从指定位置,加载对应的共享库,呵呵,这些共享库的源码,全部在Extensions目录下边:
如果加载它们,那么其_init函数就会被调用。这个初始化函数用来向iptables_match全局结构注册当前match的相关处理函数。(这样,我们可以写我们自己的用户空间的扩展match处理工具了)。注册好后,函数再来调用自己:
ptr = find_match(name, DONT_LOAD);
递归回来后,呵呵,就是开头那一段了,我们需要从已经注册好的全局结构中查找与当前match名称相同的iptables_match成员,因为该成员中封装了print函数,这样就可以顺利地输出来了:
比如,加载了libptc_tcp.so,它用来处理tcp的扩展,我们来看Extensions/libiptc_tcp.c:
static
struct iptables_match tcp
= { NULL,
"tcp",
IPTABLES_VERSION,
IPT_ALIGN(sizeof(struct ipt_tcp)),
IPT_ALIGN(sizeof(struct ipt_tcp)),
&help,
&init,
&parse,
&final_check,
&print,
&save,
opts };
void
_init(void)
{
register_match(&tcp);
}
构建了一个
iptables_match结构,其间有其对应的所有用户空间工具函数,如分析命令行、输出、保存……
然后,就调用register_match函数将其插入至全局结构iptables_match当中:
void
register_match(struct iptables_match *me)
{
struct iptables_match **i;
if (strcmp(me->version, program_version) != 0) {
fprintf(stderr, "%s: match `%s' v%s (I'm v%s)./n",
program_name, me->name, me->version, program_version);
exit(1);
}
if (find_match(me->name, DONT_LOAD)) {
fprintf(stderr, "%s: match `%s' already registered./n",
program_name, me->name);
exit(1);
}
if (me->size != IPT_ALIGN(me->size)) {
fprintf(stderr, "%s: match `%s' has invalid size %u./n",
program_name, me->name, me->size);
exit(1);
}
/* Append to list. */
for (i = &iptables_matches; *i; i = &(*i)->next);
me->next = NULL;
*i = me;
me->m = NULL;
me->mflags = 0;
}
函数就是一个建立链表的过程。不进一步分析了。