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

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: LINUX

2010-01-22 16:52:20

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

1.         命令行参数解析;

2.         kernel取得初始规则集;

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

4.         发送到kernel

 

规则相关说明如下:

1.  规则数据首先从内核读取,存放在handle.entries里面;

2.  将其解析为「チェーン(struct chain_head---ルール(struct rule_head)」的形式

3.  如果要向内核提交规则变更请求,那么需要将其组装为repl。这里将看到

a)         iptcc_compile_table在表尾加ERROR_TARGET

b)        iptcc_compile_chain是如何构筑每条链的,包括对自定义链,加链头的error_target以及链尾的RETURN STANDARD_TARGET等。

4.  提交内核

 

iptables-standalone.c

 

main()

-> do_command()

-> iptc_commit()

 

#ifdef IPTABLES_MULTI

int

iptables_main(int argc, char *argv[])

#else

int

main(int argc, char *argv[])

#endif

{

              int ret;

              char *table = "filter";

              iptc_handle_t handle = NULL;

 

              program_name = "iptables";

              program_version = IPTABLES_VERSION;

 

              lib_dir = getenv("IPTABLES_LIB_DIR");

              if (!lib_dir)

                            lib_dir = IPT_LIB_DIR;

 

#ifdef NO_SHARED_LIBS

              init_extensions();

#endif

 

              ret = do_command(argc, argv, &table, &handle);         // 默认的表是filter,传递一个NULL

              if (ret)                                                                                                                                  // iptc_handle_t handle进去

                            ret = iptc_commit(&handle);                          // 要发生的动作都填充在handle里面了

                                                                                                                                            // 向内核发送动作请求,会首先判断if (!(*handle)->changed)

              if (!ret)

                            fprintf(stderr, "iptables: %s\n",

                                          iptc_strerror(errno));

 

              exit(!ret);

}


 

int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)

table”filter”,后面会通过判断是否有-t选项来修改;

handleNULL

 

如果是显示,则不会改变*handle)->changed

如果是要设置,则会改变*handle)->changed;那么后面iptc_commit()就会向内核发出setsockopt

{

              struct ipt_entry fw, *e = NULL;

              int invert = 0;

              unsigned int nsaddrs = 0, ndaddrs = 0;

              struct in_addr *saddrs = NULL, *daddrs = NULL;

 

              int c, verbose = 0;

              const char *chain = NULL;

              const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;

              const char *policy = NULL, *newname = NULL;

              unsigned int rulenum = 0, options = 0, command = 0;                      // 参数位变量;命令位变量

              const char *pcnt = NULL, *bcnt = NULL;

              int ret = 1;

              struct iptables_match *m;

              struct iptables_rule_match *matches = NULL;     // 下面会在-m选项那边改

              struct iptables_rule_match *matchp;

              struct iptables_target *target = NULL;  // 下面会在-j选项那边改。指定目标(动作)或同一个表内的链

              struct iptables_target *t;

              const char *jumpto = "";

              char *protocol = NULL;

              const char *modprobe = NULL;

              int proto_used = 0;

 

              memset(&fw, 0, sizeof(fw));

 

              /* re-set optind to 0 in case do_command gets called

               * a second time */

              optind = 0;

 

              /* clear mflags in case do_command gets called a second time

               * (we clear the global list of all matches for security)*/

              for (m = iptables_matches; m; m = m->next)                                // 全局变量初始化

                            m->mflags = 0;

 

              for (t = iptables_targets; t; t = t->next) {                                                    // 全局变量初始化

                            t->tflags = 0;

                            t->used = 0;

              }

/* Keeping track of external matches and targets: linked lists.  */

struct iptables_match *iptables_matches = NULL;

struct iptables_target *iptables_targets = NULL;

              /* Suppress error messages: we may add new options if we

           demand-load a protocol. */

              opterr = 0;

 

              while ((c = getopt_long(argc, argv,

                 "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",

                                                                         opts, NULL)) != -1) {

                            switch (c) {

                                          /*

                                           * Command selection

                                           */

                            case 'A':

                                          add_command(&command, CMD_APPEND, CMD_NONE,

                                                            invert);

                                          chain = optarg;

                                          break;

 

                            case 'D':

                                          add_command(&command, CMD_DELETE, CMD_NONE,

                                                            invert);

                                          chain = optarg;

                                          if (optind < argc && argv[optind][0] != '-'

                                              && argv[optind][0] != '!') {

                                                        rulenum = parse_rulenumber(argv[optind++]);

                                                        command = CMD_DELETE_NUM;

                                          }

                                          break;

 

                            case 'R':

                                          add_command(&command, CMD_REPLACE, CMD_NONE,

                                                            invert);

                                          chain = optarg;

                                          if (optind < argc && argv[optind][0] != '-'

                                              && argv[optind][0] != '!')

                                                        rulenum = parse_rulenumber(argv[optind++]);

                                          else

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "-%c requires a rule number",

                                                                         cmd2char(CMD_REPLACE));

                                          break;

 

                            case 'I':

                                          add_command(&command, CMD_INSERT, CMD_NONE,

                                                            invert);

                                          chain = optarg;

                                          if (optind < argc && argv[optind][0] != '-'

                                              && argv[optind][0] != '!')

                                                        rulenum = parse_rulenumber(argv[optind++]);

                                          else rulenum = 1;

                                          break;

 

                            case 'L':                                                                                                                                 // 列出当前存在的规则

                                          add_command(&command, CMD_LIST, CMD_ZERO,     // 后面详细讲此函数

                                                            invert);           // 其实就是在command里面设置CMD_LIST标志位,并检查冲突

                                          if (optarg) chain = optarg;                                                          // 取得需要列出的链的名称

                                          else if (optind < argc && argv[optind][0] != '-'   // 什么情况下optarg会为NULL

                                                         && argv[optind][0] != '!')

                                                        chain = argv[optind++];

                                          break;

 

                            case 'F':

                                          add_command(&command, CMD_FLUSH, CMD_NONE,

                                                            invert);

                                          if (optarg) chain = optarg;

                                          else if (optind < argc && argv[optind][0] != '-'

                                                         && argv[optind][0] != '!')

                                                        chain = argv[optind++];

                                          break;

 

                            case 'Z':

                                          add_command(&command, CMD_ZERO, CMD_LIST,

                                                            invert);

                                          if (optarg) chain = optarg;

                                          else if (optind < argc && argv[optind][0] != '-'

                                                        && argv[optind][0] != '!')

                                                        chain = argv[optind++];

                                          break;

 

                            case 'N':

                                          if (optarg && (*optarg == '-' || *optarg == '!'))                 // 操作数,也就是链名不能为’-’’!’

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "chain name not allowed to start "

                                                                         "with `%c'\n", *optarg);

                                          if (find_target(optarg, TRY_LOAD))                                              // 也不能和target名字一样。

                                                        exit_error(PARAMETER_PROBLEM,                               // 实际也不能和match的名字一样

                                                                         "chain name may not clash "                                       // 否则find_target这里通不过

                                                                         "with target name\n");

                                          add_command(&command, CMD_NEW_CHAIN, CMD_NONE,

                                                            invert);                                       // #define CMD_NEW_CHAIN                          0x0100U

                                          chain = optarg;                                   // 取得链名

                                          break;

 

                            case 'X':

                                          add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,

                                                            invert);

                                          if (optarg) chain = optarg;

                                          else if (optind < argc && argv[optind][0] != '-'

                                                         && argv[optind][0] != '!')

                                                        chain = argv[optind++];

                                          break;

 

                            case 'E':

                                          add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,

                                                            invert);

                                          chain = optarg;

                                          if (optind < argc && argv[optind][0] != '-'

                                              && argv[optind][0] != '!')

                                                        newname = argv[optind++];

                                          else

                                                        exit_error(PARAMETER_PROBLEM,

                                                                   "-%c requires old-chain-name and "

                                                                         "new-chain-name",

                                                                          cmd2char(CMD_RENAME_CHAIN));

                                          break;

 

                            case 'P':

                                          add_command(&command, CMD_SET_POLICY, CMD_NONE,

                                                            invert);

                                          chain = optarg;

                                          if (optind < argc && argv[optind][0] != '-'

                                              && argv[optind][0] != '!')

                                                        policy = argv[optind++];

                                          else

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "-%c requires a chain and a policy",

                                                                         cmd2char(CMD_SET_POLICY));

                                          break;

 

                            case 'h':

                                          if (!optarg)

                                                        optarg = argv[optind];

 

                                          /* iptables -p icmp -h */

                                          if (!matches && protocol)

                                                        find_match(protocol, TRY_LOAD, &matches);

 

                                          exit_printhelp(matches);

 

                                          /*

                                           * Option selection

                                           */

                            case 'p':

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

                                          set_option(&options, OPT_PROTOCOL, &fw.ip.invflags,

                                                           invert);

 

                                          /* Canonicalize into lower case */

                                          for (protocol = argv[optind-1]; *protocol; protocol++)

                                                        *protocol = tolower(*protocol);

 

                                          protocol = argv[optind-1];

                                          fw.ip.proto = parse_protocol(protocol);

 

                                          if (fw.ip.proto == 0

                                              && (fw.ip.invflags & IPT_INV_PROTO))

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "rule would never match protocol");

                                          break;

 

                            case 's':

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

                                          set_option(&options, OPT_SOURCE, &fw.ip.invflags,                 // 设置option位变量

                                                           invert);                                                                                                                                         // 下面详细讲

                                          shostnetworkmask = argv[optind-1];

                                          break;

 

                            case 'd':

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

                                          set_option(&options, OPT_DESTINATION, &fw.ip.invflags,

                                                           invert);

                                          dhostnetworkmask = argv[optind-1];

                                          break;

 

#ifdef IPT_F_GOTO

                            case 'g':

                                          set_option(&options, OPT_JUMP, &fw.ip.invflags,

                                                           invert);

                                          fw.ip.flags |= IPT_F_GOTO;

                                          jumpto = parse_target(optarg);

                                          break;

#endif

 

                            case 'j':                                                                                                                                              // 设置target

                                          set_option(&options, OPT_JUMP, &fw.ip.invflags,

                                                           invert);

                                          jumpto = parse_target(optarg);

                                          /* TRY_LOAD (may be chain name) */

                                          target = find_target(jumpto, TRY_LOAD);                                     // 得到targetfind_target函数也要讲

 

                                          if (target) {

                                                        size_t size;

 

                                                        size = IPT_ALIGN(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);

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

                                                                           target->revision);

                                                        if (target->init != NULL)

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

                                                        opts = merge_options(opts, target->extra_opts, &target->option_offset);

                                          }

                                          break;

 

 

                            case 'i':

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

                                          set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags,

                                                           invert);

                                          parse_interface(argv[optind-1],

                                                                      fw.ip.iniface,

                                                                      fw.ip.iniface_mask);

                                          break;

 

                            case 'o':

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

                                          set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags,

                                                           invert);

                                          parse_interface(argv[optind-1],

                                                                      fw.ip.outiface,

                                                                      fw.ip.outiface_mask);

                                          break;

 

                            case 'f':

                                          set_option(&options, OPT_FRAGMENT, &fw.ip.invflags,

                                                           invert);

                                          fw.ip.flags |= IPT_F_FRAG;

                                          break;

 

                            case 'v':

                                          if (!verbose)

                                                        set_option(&options, OPT_VERBOSE,

                                                                         &fw.ip.invflags, invert);

                                          verbose++;

                                          break;

 

                            case 'm': {                                                                                                // 设置match

                                          size_t size;

 

                                          if (invert)                                                                                     // 禁止取反

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "unexpected ! flag before --match");

 

                                          m = find_match(optarg, LOAD_MUST_SUCCEED, &matches);  // 重要的函数,下面讲

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

                            }

                            break;

 

                            case 'n':

                                          set_option(&options, OPT_NUMERIC, &fw.ip.invflags,

                                                           invert);

                                          break;

 

                            case 't':

                                          if (invert)                                                                                     // table不能指定!

                                                        exit_error(PARAMETER_PROBLEM,

                                                                         "unexpected ! flag before --table");

                                          *table = argv[optind-1];                                                  // 修改table

                                          break;

 

                            case 'x':

                                          set_option(&options, OPT_EXPANDED, &fw.ip.invflags,

                                                           invert);

                                          break;

 

                            case 'V':

                                          if (invert)

                                                        printf("Not %s ;-)\n", program_version);

                                          else

                                                        printf("%s v%s\n",

                                                               program_name, program_version);

                                          exit(0);

 

                            case '0':

                                          set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags,

                                                           invert);

                                          break;

 

                            case 'M':

                                          modprobe = optarg;

                                          break;

 

                            case 'c':

 

                                          set_option(&options, OPT_COUNTERS, &fw.ip.invflags,

                                                           invert);

                                          pcnt = optarg;

                                          if (optind < argc && argv[optind][0] != '-'

                                              && argv[optind][0] != '!')

                                                        bcnt = argv[optind++];

                                          else

                                                        exit_error(PARAMETER_PROBLEM,

                                                                      "-%c requires packet and byte counter",

                                                                      opt2char(OPT_COUNTERS));

 

                                          if (sscanf(pcnt, "%llu", (unsigned long long *)&fw.counters.pcnt) != 1)

                                                        exit_error(PARAMETER_PROBLEM,

                                                                      "-%c packet counter not numeric",

                                                                      opt2char(OPT_COUNTERS));

 

                                          if (sscanf(bcnt, "%llu", (unsigned long long *)&fw.counters.bcnt) != 1)

                                                        exit_error(PARAMETER_PROBLEM,

                                                                      "-%c byte counter not numeric",

                                                                      opt2char(OPT_COUNTERS));

                                         

                                          break;

 

 

                            case 1: /* non option */

                                          if (optarg[0] == '!' && optarg[1] == '\0') {

                                                        if (invert)

                                                                      exit_error(PARAMETER_PROBLEM,

                                                                                       "multiple consecutive ! not"

                                                                                       " allowed");

                                                        invert = TRUE;

                                                        optarg[0] = '\0';

                                                        continue;

                                          }

                                          printf("Bad argument `%s'\n", optarg);

                                          exit_tryhelp(2);

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

上一篇:Check of match/target (2)

下一篇:iptables (2)

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