当前位置: 首页>编程语言>正文

iptables mangle 源码 iptables源代码

iptables : version 1.2 版本分析

主要是基于ipv4的, ipv6的没有分析。

一. extentions

   iptable的所有的extenion源文件在 extention 目录中,

每个extention 都有一个.c文件。

extention 可以是一个match 或 一个target,

每个match/target 必须提供init 函数, register函数和一个结构体。

结构体中包含有多个函数指针和一些数据。

struct iptables_match, struct iptables_target 见附录 【1】,【2】

运行iptables 命令时, 第一个操作就是加载所有的extention。

也就是将所有的match/target结构体加入到一个链表中。

加载步骤是:

1. init_extensions 函数

   此调用所有extension的初始化函数。

   函数的名字很类似都是ipt_extensionname_init();

   例如:

ipt_ah_init(); 
    ipt_conntrack_init(); 
    ipt_dscp_init();

2. 各个模块的_init函数被调用。

   对于match的extension:

   _init函数主要动作就是调用register_match 将当前模块的

   iptables_match 注册到系统中全局变量iptables_matches

   所指定的链表中。

   对于target的extension:

   _init函数主要动作就是调用register_target 将当前模块的

   iptables_target 注册到系统中全局变量iptables_targets

   所指定的链表中。

   

在后续版本中register_match, register_target 改为了

 xtables_register_match, _target. 同时有增加了xtables 模块。

其实只是代码结构上的变化, 功能和实现方式上并没用本质的变化。

这里就不分析了。

二 iptables主流程介绍:

1. 加载extensions

2. 初始化match list 和taget list, 表示没有match和taget 被选中。

3. 循环调用getopt_long 函数 解析出所有option 并加以处理。

   option的处理分三类:

   1). 大写字母: 视为命令 调用add_command函数将其加入command 变量中。

      (后面会对command变量解析(command变量是一个命令集), 处理所有命令)

   2). 小写字母: 视为OPtion, 调用set_option函数将其加入options变量中,

                 并更新 &fw.ip.invflags 变量, 表明是否是一个反转option

                (反转option即取反, /bin/iptables -A INPUT ! -i br0 -d 255.255.255.254 -j DROP

                 !表示取反操作, 表示INPUT链 如果不是br0发出的包且, 目的地址是       

                 255.255.255.254

 则丢掉)

   3). 特殊字母: 对于各个特殊字母有特殊处理。

      a. 'h' 表示帮助, 显示帮助后直接退出

      b.  'p' 表示protocol, 找到protocol , 赋值到 fw.ip.proto ,fw.nfcache |= NFC_IP_PROTO;

        (fw 是一个ipt_entry 变量, 表示一条iptable rule)

      c. 'm' 表示启用extension 模块中的类型为match的模块, 找到指定的match 记录下来, 留待将来使用。

      d. '1' no option , 显示错误信息 并退出

      e. 'M' 表示需要加载内核模块, 记录下模块名, 后面会主动加载

         (iptables_insmod("ip_tables", modprobe);)

          这一点对在内核中加入新的netfilter 模块应该非常有用。

   4). default:

        会遍历所有match, 找到指定的match(以前标记过的, 可以是一个也可以是多个)。

        调用match的parse 函数来分析相关信息  

        如果这条命令没有使用match 并且这条命令使用了protocol, 则加载相应的protocol 模块。

4. 循环调用getopt_long 函数 结束。

5. 对所有match 遍历做final_check. (大多数的match 对这个函数只是“空实现”。所谓的"空实现"是自定义的名词, 即函数中do nothing, 直接返回)

6. 出错处理

7. 对解析出来的部分数据进行分析和校验

   a. 如果 参数(options)中含有 -s, 即  [!] --source    -s address[/mask][...]

        调用函数parse_hostnetworkmask 解析到的networkmask 输出到 fw.ip.smsk ,saddrs, nsaddrs

   b. 如果 参数(options)中含有 -d, 即  [!] --destination -d address[/mask][...]

        调用函数parse_hostnetworkmask 解析到的networkmask 输出到 fw.ip.dmsk, daddrs, ndaddrs

   c. 对解析出来的地址进行错误校验。

   d. 对所有的command option 组合进行校验。 command 和option 的解释见附录【3】

8. 从内核中得到当前所有的iptable表项

    (如果还没有得到, 一般情况下是没有得到,需要在这初始化, 如果在main函数中得到的,可以通过

     do_command的参数handle传到这)

    执行iptc_init(即函数TC_INIT)

struct ipt_get_entries 
     { 
         /* Which table: user fills this in. */ 
         char name[IPT_TABLE_MAXNAMELEN]; 
         /* User fills this in: total entry size. */ 
         unsigned int size; 
         /* The entries. */ 所有的entries都存到这。 
         struct ipt_entry entrytable[0]; 
     };

9. 处理chain 和target信息

   找到相应的target 和chain,如果没有target 则使用standard target。

   在这个过程中有一个小的问题,

   ibt_is_chain->find_label->populate_cache(handle))->addchain()

   为什么之前不直接populate_cache呢, 反正ibt_is_chain总是要被执行的,可能需要仔细分析代码。

10. 生成iptentry

    根据fw 信息, match 信息, target 信息 生成一个entry

    e = generate_entry(&fw, iptables_matches, target->t);

10. 处理command,

     根据command 类型调用相应的iptc函数做相应的操作。

     参数主要有 option 信息, 生成的entry, handle(所有现有的kernel 中的iptable entries)

     在每个iptc 函数最后, 都会调用TC_COMMIT将数据同步到内核中。

11

附录 【1】

/* Include file for additions: new matches and targets. */ 
 struct iptables_match 
 { 
     struct iptables_match *next; 
     ipt_chainlabel name; 
     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; 
     /* Ignore these men behind the curtain: */ 
     unsigned int option_offset; 
     struct ipt_entry_match *m; 
     unsigned int mflags; 
     unsigned int used; 
 #ifdef NO_SHARED_LIBS 
     unsigned int loaded; /* simulate loading so options are merged properly */ 
 #endif 
 };

附录【2】

struct iptables_target 
 { 
     struct iptables_target *next; 
     ipt_chainlabel name; 
     const char *version; 
     /* Size of target data. */ 
     size_t size; 
     /* Size of target data relevent for userspace comparison purposes */ 
     size_t userspacesize; 
     /* Function which prints out usage message. */ 
     void (*help)(void); 
     /* Initialize the target. */ 
     void (*init)(struct ipt_entry_target *t, 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, 
              struct ipt_entry_target **target); 
     /* Final check; exit if not ok. */ 
     void (*final_check)(unsigned int flags); 
     /* Prints out the target iff non-NULL: put space at end */ 
     void (*print)(const struct ipt_ip *ip, 
               const struct ipt_entry_target *target, int numeric); 
     /* Saves the targinfo in parsable form to stdout. */ 
     void (*save)(const struct ipt_ip *ip, 
              const struct ipt_entry_target *target); 
     /* Pointer to list of extra command-line options */ 
     struct option *extra_opts; 
     /* Ignore these men behind the curtain: */ 
     unsigned int option_offset; 
     struct ipt_entry_target *t; 
     unsigned int tflags; 
     unsigned int used; 
 #ifdef NO_SHARED_LIBS 
     unsigned int loaded; /* simulate loading so options are merged properly */ 
 #endif 
 };

附录【3】

在iptables 命令中, 参数分为两部分Command Option

command : 是一个action , 包含append, check, delete insert 等动作(后面加chain )

option : 是依附于 command的 选项, 表示这个操作具体要做些什么, 或完成这个action后要做些什么。

哪个action 可以有那些option, 近下面的数组定义。

/* Table of legal combinations of commands and options.  If any of the 
  * given commands make an option legal, that option is legal (applies to 
  * CMD_LIST and CMD_ZERO only). 
  * Key: 
  *  +  compulsory  必须的, 相当于MUST or MANDATE 
  *  x  illegal     非法的, 相当于 MUST NOT or ERROR 
  *     optional    可选的。 
  */ 
 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = 
 /* Well, it's better than "Re: Linux vs FreeBSD" */ 
 { 
     /*     -n  -s  -d  -p  -j  -v  -x  -i  -o  -f  --line */ 
 /*INSERT*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 
 /*DELETE*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 
 /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'}, 
 /*REPLACE*/   {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 
 /*APPEND*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 
 /*LIST*/      {' ','x','x','x','x',' ',' ','x','x','x',' '}, 
 /*FLUSH*/     {'x','x','x','x','x',' ','x','x','x','x','x'}, 
 /*ZERO*/      {'x','x','x','x','x',' ','x','x','x','x','x'}, 
 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 
 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 
 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x'}, 
 /*CHECK*/     {'x','+','+','+','x',' ','x',' ',' ',' ','x'}, 
 /*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x'} 
 }; 
 iptables --help 
 iptables v1.4.21 
 Usage: iptables -[ACD] chain rule-specification [options] 
        iptables -I chain [rulenum] rule-specification [options] 
        iptables -R chain rulenum rule-specification [options] 
        iptables -D chain rulenum [options] 
        iptables -[LS] [chain [rulenum]] [options] 
        iptables -[FZ] [chain] [options] 
        iptables -[NX] chain 
        iptables -E old-chain-name new-chain-name 
        iptables -P chain target [options] 
        iptables -h (print this help information) 
 Commands: 
 Either long or short options are allowed. 
   --append  -A chain        Append to chain 
   --check   -C chain        Check for the existence of a rule 
   --delete  -D chain        Delete matching rule from chain 
   --delete  -D chain rulenum 
                 Delete rule rulenum (1 = first) from chain 
   --insert  -I chain [rulenum] 
                 Insert in chain as rulenum (default 1=first) 
   --replace -R chain rulenum 
                 Replace rule rulenum (1 = first) in chain 
   --list    -L [chain [rulenum]] 
                 List the rules in a chain or all chains 
   --list-rules -S [chain [rulenum]] 
                 Print the rules in a chain or all chains 
   --flush   -F [chain]        Delete all rules in  chain or all chains 
   --zero    -Z [chain [rulenum]] 
                 Zero counters in chain or all chains 
   --new     -N chain        Create a new user-defined chain 
   --delete-chain 
             -X [chain]        Delete a user-defined chain 
   --policy  -P chain target 
                 Change policy on chain to target 
   --rename-chain 
             -E old-chain new-chain 
                 Change chain name, (moving any references) 
 Options: 
     --ipv4    -4        Nothing (line is ignored by ip6tables-restore) 
     --ipv6    -6        Error (line is ignored by iptables-restore) 
 [!] --protocol    -p proto    protocol: by number or name, eg. `tcp' 
 [!] --source    -s address[/mask][...] 
                 source specification 
 [!] --destination -d address[/mask][...] 
                 destination specification 
 [!] --in-interface -i input name[+] 
                 network interface name ([+] for wildcard) 
  --jump    -j target 
                 target for rule (may load target extension) 
   --goto      -g chain 
                               jump to chain with no return 
   --match    -m match 
                 extended match (may load extension) 
   --numeric    -n        numeric output of addresses and ports 
 [!] --out-interface -o output name[+] 
                 network interface name ([+] for wildcard) 
   --table    -t table    table to manipulate (default: `filter') 
   --verbose    -v        verbose mode 
   --wait    -w        wait for the xtables lock 
   --line-numbers        print line numbers when listing 
   --exact    -x        expand numbers (display exact values) 
 [!] --fragment    -f        match second or further fragments only 
   --modprobe=<command>        try to insert modules using this command 
   --set-counters PKTS BYTES    set the counter during insert/append 
 [!] --version    -V        print package version.


https://www.xamrdz.com/lan/5mt1951210.html

相关文章: