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

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: LINUX

2010-01-22 16:53:24

本章主要是讲iptables命令的整个处理过程,包括:

1.         命令行参数解析;

2.         kernel取得初始规则集;

3.         显示规则;或如果要设置,那么组装要发送到kernel的数据结构;

4.         发送到kernel

 

 

 

                            default:

                                          /* FIXME: This scheme doesn't allow two of the same

                                             matches --RR */

                                          if (!target

                                              || !(target->parse(c - target->option_offset,                          // target数据的取得

                                                                             argv, invert,

                                                                             &target->tflags,

                                                                             &fw, &target->t))) {

                                                        for (matchp = matches; matchp; matchp = matchp->next) {

                                                                      if (matchp->match->parse(c - matchp->match->option_offset,    // match数据的取得

                                                                                         argv, invert,

                                                                                         &matchp->match->mflags,

                                                                                         &fw,

                                                                                         &fw.nfcache,

                                                                                         &matchp->match->m))

                                                                                    break;

                                                        }

                                                        m = matchp ? matchp->match : NULL;

 

                                                        /* If you listen carefully, you can

                                                           actually hear this code suck. */

 

                                                        /* some explanations (after four different bugs

                                                         * in 3 different releases): If we encountere a

                                                         * parameter, that has not been parsed yet,

                                                         * it's not an option of an explicitly loaded

                                                         * match or a target.  However, we support

                                                         * implicit loading of the protocol match

                                                         * extension.  '-p tcp' means 'l4 proto 6' and

                                                         * at the same time 'load tcp protocol match on

                                                         * demand if we specify --dport'.

                                                         *

                                                         * To make this work, we need to make sure:

                                                         * - the parameter has not been parsed by

                                                         *   a match (m above)

                                                         * - a protocol has been specified

                                                         * - the protocol extension has not been

                                                         *   loaded yet, or is loaded and unused

                                                         *   [think of iptables-restore!]

                                                         * - the protocol extension can be successively

                                                         *   loaded

                                                         */

                                                        if (m == NULL

                                                            && protocol

                                                            && (!find_proto(protocol, DONT_LOAD,

                                                                                       options&OPT_NUMERIC, NULL)

                                                                      || (find_proto(protocol, DONT_LOAD,

                                                                                                  options&OPT_NUMERIC, NULL)

                                                                          && (proto_used == 0))

                                                               )

                                                            && (m = find_proto(protocol, TRY_LOAD,

                                                                                           options&OPT_NUMERIC, &matches))) {

                                                                      /* Try loading protocol */

                                                                      size_t size;

                                                                     

                                                                      proto_used = 1;

 

                                                                      size = IPT_ALIGN(sizeof(struct ipt_entry_match))

                                                                                                   + m->size;

 

                                                                      m->m = fw_calloc(1, size);

                                                                      m->m->u.match_size = size;

                                                                      strcpy(m->m->u.user.name, m->name);

                                                                      set_revision(m->m->u.user.name,

                                                                                         m->revision);

                                                                      if (m->init != NULL)

                                                                                    m->init(m->m, &fw.nfcache);

 

                                                                      opts = merge_options(opts,

                                                                          m->extra_opts, &m->option_offset);

 

                                                                      optind--;

                                                                      continue;

                                                        }

                                                        if (!m)

                                                                      exit_error(PARAMETER_PROBLEM,

                                                                                       "Unknown arg `%s'",

                                                                                       argv[optind-1]);

                                          }

                            }

                            invert = FALSE;

              }

 

              for (matchp = matches; matchp; matchp = matchp->next)          // 应该是通过动态库,读取了很多match

                            matchp->match->final_check(matchp->match->mflags);            // 检查

 

              if (target)                                                                                                                                                         // 有一个target

                            target->final_check(target->tflags);                                                         // 检查

 

              /* Fix me: must put inverse options checking here --MN */

 

              if (optind < argc)

                            exit_error(PARAMETER_PROBLEM,

                                             "unknown arguments found on commandline");

              if (!command)

                            exit_error(PARAMETER_PROBLEM, "no command specified");

              if (invert)

                            exit_error(PARAMETER_PROBLEM,

                                             "nothing appropriate following !");

 

              if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {

                            if (!(options & OPT_DESTINATION))

                                          dhostnetworkmask = "0.0.0.0/0";

                            if (!(options & OPT_SOURCE))

                                          shostnetworkmask = "0.0.0.0/0";

              }

 

              if (shostnetworkmask)

                            parse_hostnetworkmask(shostnetworkmask, &saddrs,

                                                              &(fw.ip.smsk), &nsaddrs);

 

              if (dhostnetworkmask)

                            parse_hostnetworkmask(dhostnetworkmask, &daddrs,

                                                              &(fw.ip.dmsk), &ndaddrs);

 

              if ((nsaddrs > 1 || ndaddrs > 1) &&

                  (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))

                            exit_error(PARAMETER_PROBLEM, "! not allowed with multiple"

                                             " source or destination IP addresses");

 

              if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))

                            exit_error(PARAMETER_PROBLEM, "Replacement rule does not "

                                             "specify a unique address");

 

              generic_opt_check(command, options);

 

              if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN)

                            exit_error(PARAMETER_PROBLEM,

                                             "chain name `%s' too long (must be under %i chars)",

                                             chain, IPT_FUNCTION_MAXNAMELEN);

 

              /* only allocate handle if we weren't called with a handle */

              if (!*handle)

                            *handle = iptc_init(*table);

根据table的名称,让handle指针指向相应的表的地址空间,也就是把对应表的所有信息从内核中取出来

#define TC_INIT                               iptc_init

至于函数的实体TC_INIT(),下面有详细解释

 

              /* try to insmod the module if iptc_init failed */

              if (!*handle && iptables_insmod("ip_tables", modprobe) != -1)

                            *handle = iptc_init(*table);

如果获取换败,将试着插入模块,再次获取

 

              if (!*handle)

                            exit_error(errno == EPERM ? OTHER_PROBLEM : VERSION_PROBLEM,

                                             "can't initialize iptables table `%s': %s",

                                             *table, iptc_strerror(errno));

 

              if (command == CMD_APPEND

                  || command == CMD_DELETE

                  || command == CMD_INSERT

                  || command == CMD_REPLACE) {

                            if (strcmp(chain, "PREROUTING") == 0

                                || strcmp(chain, "INPUT") == 0) {

                                          /* -o not valid with incoming packets. */

                                          if (options & OPT_VIANAMEOUT)

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "Can't use -%c with %s\n",

                                                                         opt2char(OPT_VIANAMEOUT),

                                                                         chain);

                            }

 

                            if (strcmp(chain, "POSTROUTING") == 0

                                || strcmp(chain, "OUTPUT") == 0) {

                                          /* -i not valid with outgoing packets */

                                          if (options & OPT_VIANAMEIN)

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "Can't use -%c with %s\n",

                                                                         opt2char(OPT_VIANAMEIN),

                                                                         chain);

                            }

 

                            if (target && iptc_is_chain(jumpto, *handle)) {

                                          printf("Warning: using chain %s, not extension\n",

                                                 jumpto);

 

                                          if (target->t)

                                                        free(target->t);

 

                                          target = NULL;

                            }

 

                            /* If they didn't specify a target, or it's a chain

                               name, use standard. */

                            if (!target

                                && (strlen(jumpto) == 0

                                          || iptc_is_chain(jumpto, *handle))) {

                                          size_t size;

 

                                          target = find_target(IPT_STANDARD_TARGET,

                                                                           LOAD_MUST_SUCCEED);

 

                                          size = sizeof(struct ipt_entry_target)

                                                        + target->size;

                                          target->t = fw_calloc(1, size);

                                          target->t->u.target_size = size;

                                          strcpy(target->t->u.user.name, jumpto);

                                          if (!iptc_is_chain(jumpto, *handle))

                                                        set_revision(target->t->u.user.name,

                                                                           target->revision);

                                          if (target->init != NULL)

                                                        target->init(target->t, &fw.nfcache);

                            }

 

                            if (!target) {

                                          /* it is no chain, and we can't load a plugin.

                                           * We cannot know if the plugin is corrupt, non

                                           * existant OR if the user just misspelled a

                                           * chain. */

#ifdef IPT_F_GOTO

                                          if (fw.ip.flags & IPT_F_GOTO)

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "goto '%s' is not a chain\n", jumpto);

#endif

                                          find_target(jumpto, LOAD_MUST_SUCCEED);

                            } else {

                                          e = generate_entry(&fw, matches, target->t);                                  // 生成规则

                                          free(target->t);

                            }

              }

 

              switch (command) {

              case CMD_APPEND:

                            ret = append_entry(chain, e,                                                                                      // 添加规则,问题是向哪里添加?

                                                           nsaddrs, saddrs, ndaddrs, daddrs,                               // 解释在下面。感觉只是加在了chain

                                                           options&OPT_VERBOSE,

                                                           handle);

                            break;

              case CMD_DELETE:

                            ret = delete_entry(chain, e,

                                                           nsaddrs, saddrs, ndaddrs, daddrs,

                                                           options&OPT_VERBOSE,

                                                           handle, matches);

                            break;

              case CMD_DELETE_NUM:

                            ret = iptc_delete_num_entry(chain, rulenum - 1, handle);

                            break;

              case CMD_REPLACE:

                            ret = replace_entry(chain, e, rulenum - 1,

                                                            saddrs, daddrs, options&OPT_VERBOSE,

                                                            handle);

                            break;

              case CMD_INSERT:

                            ret = insert_entry(chain, e, rulenum - 1,

                                                           nsaddrs, saddrs, ndaddrs, daddrs,

                                                           options&OPT_VERBOSE,

                                                           handle);

                            break;

              case CMD_LIST:

                            ret = list_entries(chain,                                                                             // 显示某个表的所有规则,下面解释

                                                           options&OPT_VERBOSE,

                                                           options&OPT_NUMERIC,

                                                           options&OPT_EXPANDED,

                                                           options&OPT_LINENUMBERS,

                                                           handle);                                                                                // 不需要在指定表了,因为handle就属于一个表

                            break;

              case CMD_FLUSH:

                            ret = flush_entries(chain, options&OPT_VERBOSE, handle);

                            break;

              case CMD_ZERO:

                            ret = zero_entries(chain, options&OPT_VERBOSE, handle);

                            break;

              case CMD_LIST|CMD_ZERO:

                            ret = list_entries(chain,                                                                                           // 下面解释

                                                           options&OPT_VERBOSE,

                                                           options&OPT_NUMERIC,

                                                           options&OPT_EXPANDED,

                                                           options&OPT_LINENUMBERS,

                                                           handle);

                            if (ret)

                                          ret = zero_entries(chain,

                                                                         options&OPT_VERBOSE, handle);

                            break;

              case CMD_NEW_CHAIN:

                            ret = iptc_create_chain(chain, handle);                                       // 通过自定义链,对command进行举例说明

                            break;

              case CMD_DELETE_CHAIN:

                            ret = delete_chain(chain, options&OPT_VERBOSE, handle);

                            break;

              case CMD_RENAME_CHAIN:

                            ret = iptc_rename_chain(chain, newname,           handle);

                            break;

              case CMD_SET_POLICY:

                            ret = iptc_set_policy(chain, policy, NULL, handle);

                            break;

              default:

                            /* We should never reach this... */

                            exit_tryhelp(2);

              }

 

              if (verbose > 1)

                            dump_entries(*handle);

 

              clear_rule_matches(&matches);

 

              if (e != NULL) {

                            free(e);

                            e = NULL;

              }

 

              free(saddrs);

              free(daddrs);

              free_opts(1);

 

              return ret;

}


 

static void

add_command(unsigned int *cmd, const int newcmd, const int othercmds,

                  int invert)

{

              if (invert)                                           // 禁止取反

                            exit_error(PARAMETER_PROBLEM, "unexpected ! flag");

              if (*cmd & (~othercmds))

                            exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",

                                             cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));

              *cmd |= newcmd;                              // 设置标志位

}

 

static void

set_option(unsigned int *options, unsigned int option, u_int8_t *invflg,

                 int invert)

{

              if (*options & option)

                            exit_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",

                                             opt2char(option));

              *options |= option;                           // 设置标志位

 

              if (invert) {                                                                                  // 如果取反

                            unsigned int i;

                            for (i = 0; 1 << i != option; i++);

 

                            if (!inverse_for_options[i])                  // 检查是否允许取反

                                          exit_error(PARAMETER_PROBLEM,

                                                           "cannot have ! before -%c",

                                                           opt2char(option));

                            *invflg |= inverse_for_options[i];         // 允许的话,取反

              }

}


 

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")

                                           + strlen(name)];

                            sprintf(path, "%s/libipt_%s.so", lib_dir, name);

                            if (dlopen(path, RTLD_NOW)) {                                                                               // 打开管理match的动态链接库

                                          /* Found library.  If it didn't register itself,                                     // 打开库时会调用构造函数

                                             maybe they specified target as match. */

例子:libipt_addrtype.c:

void __attribute((constructor)) my_init(void)

{

              register_match(&addrtype);

}

 

                                          ptr = find_match(name, DONT_LOAD, NULL);                // 再次查找,应该能找到了。

 

                                          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 && 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;

}

 

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

上一篇:iptables (1)

下一篇:iptables (3)

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