Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103449
  • 博文数量: 41
  • 博客积分: 2520
  • 博客等级: 少校
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 16:25
文章分类

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: LINUX

2010-01-22 16:59:34

本章主要是讲用户空间match以及match的注册,包括:

1.         match结构体形态;

2.         icmp match来说明match里面的parse函数;

3.         match的注册过程;

 

/* Include file for additions: new matches and targets. */

struct iptables_match

{

              struct iptables_match *next;

 

              ipt_chainlabel name;

 

              /* Revision of match (0 by default). */

              u_int8_t revision;

 

              const char *version;

 

              /* Size of match data. */

              size_t size;

 

              /* Size of match data relevent for userspace comparison purposes */

              size_t userspacesize;

 

              /* Function which prints out usage message. */

              void (*help)(void);

 

              /* Initialize the match. */

              void (*init)(struct ipt_entry_match *m, unsigned int *nfcache);

 

              /* Function which parses command options; returns true if it

           ate an option */

              int (*parse)(int c, char **argv, int invert, unsigned int *flags,

                                 const struct ipt_entry *entry,

                                 unsigned int *nfcache,

                                 struct ipt_entry_match **match);

 

              /* Final check; exit if not ok. */

              void (*final_check)(unsigned int flags);

 

              /* Prints out the match iff non-NULL: put space at end */

              void (*print)(const struct ipt_ip *ip,

                                  const struct ipt_entry_match *match, int numeric);

 

              /* Saves the match info in parsable form to stdout. */

              void (*save)(const struct ipt_ip *ip,

                                 const struct ipt_entry_match *match);

 

              /* Pointer to list of extra command-line options */

              const struct option *extra_opts;                                    // 用于parse函数内部

 

              /* Ignore these men behind the curtain: */

              unsigned int option_offset;

              struct ipt_entry_match *m;

              unsigned int mflags;                                                                      // 用于final_check,作为函数的参数

#ifdef NO_SHARED_LIBS

              unsigned int loaded; /* simulate loading so options are merged properly */

#endif

};

 

例子:

static struct iptables_match icmp = {

              .next                     = NULL,

              .name                    = "icmp",                                           // 库的文件名(也就是libipt_icmp

              .version   = IPTABLES_VERSION,      // iptables 的版本

              .size                      = IPT_ALIGN(sizeof(struct ipt_icmp)),                                          // 保持用户态程序和核心态

              .userspacesize        = IPT_ALIGN(sizeof(struct ipt_icmp)),                            // 共享结构的大小一致性

              .help                     = &help,                              // 'iptables -m module -h' 时使用

              .init                       = &init,                               // 初始化一些特定的东西

              .parse                   = &parse,                           // 输入新规则时,写入我们将共享给kernel的信息

              .final_check           = &final_check,     // 用于验证参数的合法性

              .print                     = &print,                             // 'iptables -L'显示规则时使用

              .save                     = &save,                             // 'iptables-save'保存规则中本match时使用的

              .extra_opts            = opts                                 // 将每个参数映射到一个值,用于struct iptables_matchparse函数

};

 

 

注册:

register_match(&icmp);                                    // 注册方法参考下面

 

 

函数parse()

/* Function which parses command options; returns true if it

   ate an option */

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)

此函数主要是根据argv来填充(*match)->data;

{

              struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data;

 

              switch (c) {

              case '1':

                            check_inverse(optarg, &invert, &optind, 0);

                            parse_icmp(argv[optind-1], &icmpinfo->type,

                                             icmpinfo->code);

                            if (invert)

                                          icmpinfo->invflags |= IPT_ICMP_INV;                            // 填充match

                            break;

 

              default:

                            return 0;

              }

 

              return 1;

}

 

关于上面的case语句,实际根据是iptables_match 结构体里的extra_opts来处理的。例如:

static struct option opts[] = {

              { "icmp-type", 1, 0, '1' },                                  // 后面那个是被映射的值,参考libipt_dscp.c

              {0}

};

 

static struct iptables_match icmp = {

              .next                     = NULL,

              .name                    = "icmp",

              .version   = IPTABLES_VERSION,

              .size                      = IPT_ALIGN(sizeof(struct ipt_icmp)),

              .userspacesize        = IPT_ALIGN(sizeof(struct ipt_icmp)),

              .help                     = &help,

              .init                       = &init,

              .parse                    = &parse,

              .final_check           = &final_check,

              .print                     = &print,

              .save                     = &save,

              .extra_opts            = opts

};

在加载struct iptables_match icmp的时候,做过某些处理。
void

register_match(struct iptables_match *me)

{

              struct iptables_match **i, *old;

 

              if (strcmp(me->version, program_version) != 0) {                                         // 如果版本和iptables版本不一致,退出

                            fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n",

                                          program_name, me->name, me->version, program_version);

                            exit(1);

              }

 

              /* Revision field stole a char from name. */

              if (strlen(me->name) >= IPT_FUNCTION_MAXNAMELEN-1) {     // match名字过长,退出

                            fprintf(stderr, "%s: target `%s' has invalid name\n",

                                          program_name, me->name);

                            exit(1);

              }

 

              old = find_match(me->name, DURING_LOAD, NULL);                  // 寻找此match是否已经存在

              if (old) {                                                                                                                                                            // 参考下面

                            if (old->revision == me->revision) {

                                          fprintf(stderr,

                                                        "%s: match `%s' already registered.\n",

                                                        program_name, me->name);

                                          exit(1);

                            }

 

                            /* Now we have two (or more) options, check compatibility. */

                            if (compatible_match_revision(old->name, old->revision)                 // 如果已经存在的是适合的

                                && old->revision > me->revision)                                                                                    // 并且版本比现在要加载的还新

                                          return;

 

                            /* Replace if compatible. */

                            if (!compatible_match_revision(me->name, me->revision))               // 如果新的不适合

                                          return;

 

                            /* Delete old one. */

                            for (i = &iptables_matches; *i!=old; i = &(*i)->next);

                            *i = old->next;

              }

 

              if (me->size != IPT_ALIGN(me->size)) {

                            fprintf(stderr, "%s: match `%s' has invalid size %u.\n",

                                          program_name, me->name, (unsigned int)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;

}


struct iptables_match *

find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_match **matches)

{

              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 && tryload != DURING_LOAD) {         // 如果已加载列表中不存在,

                            char path[strlen(lib_dir) + sizeof("/libipt_.so")                                                              // 并且标志不为DONT_LOAD

                                           + strlen(name)];                                                                                                                                 // DURING_LOAD

                            sprintf(path, "%s/libipt_%s.so", lib_dir, 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, NULL);                                            // 不再次打开动态库的方式寻找

 

                                          if (!ptr)                 // 如果还是没找到,那么报告不能加载此match

                                                        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 && matches) {

                            struct iptables_rule_match **i;

                            struct iptables_rule_match *newentry;

 

                            newentry = fw_malloc(sizeof(struct iptables_rule_match));

 

                            for (i = matches; *i; i = &(*i)->next);

                            newentry->match = ptr;

                            newentry->next = NULL;

                            *i = newentry;

              }

 

              return ptr;

}

 

阅读(731) | 评论(0) | 转发(0) |
0

上一篇:iptables (5)

下一篇:iptables target

给主人留下些什么吧!~~