自己写 Netfilter 匹配器[2]

[入库:2006年2月23日] [更新:2007年3月24日]

本文简介:

 

1.2 深入骨架程序

 

1.2.1 初始化

我们首先初始化 'iptables_match' 结构中的常用字段:
static struct iptables_match ipaddr
= {
'Name' 是你的函数库的文件名(也就是 libipt_ipaddr)。
你不能在这个位置放其它的东西,这是用来自动加载你的库的。
    .name            = "ipaddr",
下一个字段 'version' 是 iptables 的版本。后面的两个字段都是用于保持用户态程序和核心态共享结构的大小一致性的。
    .version         = IPTABLES_VERSION,
.size = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)),
.userspacesize = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)),
'Help' 是用户输入 'iptables -m module -h' 的时候要调用的函数。'Parse' 是用户输入一条新规则的时候调用的,用于验证参数的合法性。'print' 就是使用 'iptables -L' 的时候显示前面添加的规则的。
    .help            = &help,
.init = &init,
.parse = &parse,
.final_check = &final_check,
.print = &print,
.save = &save,
.extra_opts = opts
};
iptables 架构能够支持多个共享库。每个共享库必须使用 <iptables/iptables.c> 中定义的 'register_match()' 向 iptables 注册。这个函数将在模块被 iptables 加载的时候调用。 更多信息请参考:'man dlopen'。
void _init(void)
{
register_match(&ipaddr);
}
 

1.2.2 save 函数

如果我们有一个需要保存的规则集,可以利用 iptables 提供的工具 'iptables-save',它可以保存下所有的规则。显然你需要扩展这个工具来保存下来这些规则。这个扩展通过 save 函数完成。
static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;
如果源地址是规则的一部分的话,打印它。
   if (info->flags & IPADDR_SRC) {
if (info->flags & IPADDR_SRC_INV)
printf("! ");
printf("--ipsrc ");
print_ipaddr((u_int32_t *)&info->ipaddr.src);
}
如果目的地址是规则的一部分的话就打印目的地址。
   if (info->flags & IPADDR_DST) {
if (info->flags & IPADDR_DST_INV)
printf("! ");
printf("--ipdst ");
print_ipaddr((u_int32_t *)&info->ipaddr.dst);
}
}
 

1.2.3 print 函数

和上面的 save 所蕴含的哲学一样,也有一个 print 函数用于打印规则。它在 'iptables -L' 的时候被调用。我们将在下文里看到参数 'ipt_entry_match *match' 的用途,不过我们已经对它有了一点概念了,是吧?
static void print(const struct ipt_ip *ip,
const struct ipt_entry_match *match,
int numeric)
{
const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;

if (info->flags & IPADDR_SRC) {
printf("src IP ");
if (info->flags & IPADDR_SRC_INV)
printf("! ");
print_ipaddr((u_int32_t *)&info->ipaddr.src);
}

if (info->flags & IPADDR_DST) {
printf("dst IP ");
if (info->flags & IPADDR_DST_INV)
printf("! ");
print_ipaddr((u_int32_t *)&info->ipaddr.dst);
}
}
 

1.2.4 final check 函数

这个函数是最后一次正确性检查的机会。它在用户输入完规则之后、参数解析刚刚完成的时候被调用。
static void final_check(unsigned int flags)
{
if (!flags)
exit_error(PARAMETER_PROBLEM, "ipt_ipaddr: Invalid parameters.");
}
 

1.2.5 parse 函数

parse 是最重要的一个函数,因为这里要检查参数的正确性,并写入我们将共享给核心态程序的信息。它在每次参数被发现的时候被调用,也就是说,如果用户输入了两个参数,这个函数就将被以不同的参数代码 c 调用两次。
static int parse(int c, char **argv, int invert, unsigned int *flags,
const struct ipt_entry *entry,
unsigned int *nfcache,
struct ipt_entry_match **match)
{
我们使用特殊结构来保存我们要传递给核心态程序的信息。'match' 指针被传递给多个函数,我们可以每次使用同样的数据结构。一旦规则被加载了,这个指针就被复制到了核心态程序里。通过这个方式,内核模块可以知道用户想要分析什么(这正是问题的关键,不是么?)。
   struct ipt_ipaddr_info *info = (struct ipt_ipaddr_info *)(*match)->data;
每个参数对应着一个单独的值,于是我们能根据进入的参数决定采取何种行动。下文中我们将看到我们如何把参数变成数值。
   switch(c) {
首先,我们检查参数是否被使用了多次。如果使用了多次的话,调用 <iptables/iptables.c> 中定义的 'exit_error()' 函数,这样程序会立刻带着 <iptables/include/iptables_common.h> 中定义的 'PARAMETER_PROBLEM' 的错误状态推出。否则,我们在我们的头文件中定义的 'IPADDR_SRC' 中设置 'flags' 和 'info->flags'。稍后我们将介绍这个头文件。

虽然这两个标志看起来差不多,但是是完全不同的。'flag' 的作用域就是这个函数,而 'info->flags' 是我们用于和核心态程序共享信息的结构的一部分。
      case '1':
if (*flags & IPADDR_SRC)
exit_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipsrc once!");
*flags |= IPADDR_SRC;
info->flags |= IPADDR_SRC;
检查如

本文关键:自己写 Netfilter 匹配器
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top