免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4525 | 回复: 0
打印 上一主题 下一主题

netfilter之规则执行ipt_do_table [复制链接]

论坛徽章:
1
天蝎座
日期:2014-02-28 16:08:53
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-03 15:01 |只看该作者 |倒序浏览

                                                               
前面说到了netfilter的规则表的保存,是由struct xt_table中的链表来链接的。而具体数据则是在struct xt_table_info结构体中,而struct xt_table_info结构中又有struct ipt_ip结构保存相关的规则的ip地址信息。struct ipt_entry结构体的作用则要在下面的代码中找出作用。
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
    301 unsigned int
    302 ipt_do_table(struct sk_buff *skb,
    303          unsigned int hook,
    304          const struct net_device *in,
    305          const struct net_device *out,
    306          struct xt_table *table)
    307 {
    308     static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
    309     const struct iphdr *ip;
    310     u_int16_t datalen;
    311     bool hotdrop = false;
    312     /* Initializing verdict to NF_DROP keeps gcc happy. */
    313     unsigned int verdict = NF_DROP;
    314     const char *indev, *outdev;
    315     void *table_base;
    316     struct ipt_entry *e, *back;
    317     struct xt_table_info *private;
    318     struct xt_match_param mtpar;
    319     struct xt_target_param tgpar;
    320
    321     /* Initialization */
    322     ip = ip_hdr(skb);
    323     datalen = skb->len - ip->ihl * 4;
    324     indev = in ? in->name : nulldevname;
    325     outdev = out ? out->name : nulldevname;
    326     /* We handle fragments by dealing with the first fragment as
    327      * if it was a normal packet.  All other fragments are treated
    328      * normally, except that they will NEVER match rules that ask
    329      * things we don't know, ie. tcp syn flag or ports).  If the
    330      * rule is also a fragment-specific rule, non-fragments won't
    331      * match it. */
    332     mtpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
    333     mtpar.thoff   = ip_hdrlen(skb);
    334     mtpar.hotdrop = &hotdrop;
    335     mtpar.in      = tgpar.in  = in;
    336     mtpar.out     = tgpar.out = out;
    337     mtpar.family  = tgpar.family = NFPROTO_IPV4;
    338     tgpar.hooknum = hook;
    339
    340     IP_NF_ASSERT(table->valid_hooks & (1  hook));
    341     xt_info_rdlock_bh();
    342     private = table->private;
    343     table_base = private->entries[smp_processor_id()];
    344
    345     e = get_entry(table_base, private->hook_entry[hook]);
    346
    347     /* For return from builtin chain */
    348     back = get_entry(table_base, private->underflow[hook]);
    349
    350     do {
    351         IP_NF_ASSERT(e);
    352         IP_NF_ASSERT(back);
    353         if (ip_packet_match(ip, indev, outdev,
    354             &e->ip, mtpar.fragoff)) {
    355             struct ipt_entry_target *t;
    356
    357             if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0)
    358                 goto no_match;
    359
    360             ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
    361
    362             t = ipt_get_target(e);
    363             IP_NF_ASSERT(t->u.kernel.target);
    364
    365 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
    366     defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
    367             /* The packet is traced: log it */
    368             if (unlikely(skb->nf_trace))
    369                 trace_packet(skb, hook, in, out,
    370                          table->name, private, e);
    371 #endif
    372             /* Standard target? */
    373             if (!t->u.kernel.target->target) {
    374                 int v;
    375
    376                 v = ((struct ipt_standard_target *)t)->verdict;
    377                 if (v  0) {
    378                     /* Pop from stack? */
    379                     if (v != IPT_RETURN) {
    380                         verdict = (unsigned)(-v) - 1;
    381                         break;
    382                     }
    383                     e = back;
    384                     back = get_entry(table_base,
    385                              back->comefrom);
    386                     continue;
    387                 }
    388                 if (table_base + v != (void *)e + e->next_offset
    389                     && !(e->ip.flags & IPT_F_GOTO)) {
    390                     /* Save old back ptr in next entry */
    391                     struct ipt_entry *next
    392                         = (void *)e + e->next_offset;
    393                     next->comefrom
    394                         = (void *)back - table_base;
    395                     /* set back pointer to next entry */
    396                     back = next;
    397                 }
    398
    399                 e = get_entry(table_base, v);
    400             } else {
    401                 /* Targets which reenter must return
    402                    abs. verdicts */
    403                 tgpar.target   = t->u.kernel.target;
    404                 tgpar.targinfo = t->data;
    405 #ifdef CONFIG_NETFILTER_DEBUG
    406                 ((struct ipt_entry *)table_base)->comefrom
    407                     = 0xeeeeeeec;
    408 #endif
    409                 verdict = t->u.kernel.target->target(skb,
    410                                      &tgpar);
    411 #ifdef CONFIG_NETFILTER_DEBUG
    412                 if (((struct ipt_entry *)table_base)->comefrom
    413                     != 0xeeeeeeec
    414                     && verdict == IPT_CONTINUE) {
    415                     printk("Target %s reentered!\n",
    416                            t->u.kernel.target->name);
    417                     verdict = NF_DROP;
    418                 }
    419                 ((struct ipt_entry *)table_base)->comefrom
    420                     = 0x57acc001;
    421 #endif
    422                 /* Target might have changed stuff. */
    423                 ip = ip_hdr(skb);
    424                 datalen = skb->len - ip->ihl * 4;
    425
    426                 if (verdict == IPT_CONTINUE)
    427                     e = (void *)e + e->next_offset;
    428                 else
    429                     /* Verdict */
    430                     break;
    431             }
    432         } else {
    433
    434         no_match:
    435             e = (void *)e + e->next_offset;
    436         }
    437     } while (!hotdrop);
    438     xt_info_rdunlock_bh();
    439
    440 #ifdef DEBUG_ALLOW_ALL
    441     return NF_ACCEPT;
    442 #else
    443     if (hotdrop)
    444         return NF_DROP;
    445     else return verdict;
    446 #endif
    447 }
首先在
               
               
               
    316         struct ipt_entry *e, *back;
      317         struct xt_table_info *private;
      341     xt_info_rdlock_bh();
    342     private = table->private;
    343     table_base = private->entries[smp_processor_id()];
    344
    345     e = get_entry(table_base, private->hook_entry[hook]);
    346
    347     /* For return from builtin chain */
    348     back = get_entry(table_base, private->underflow[hook]);
get_entry():
185 static inline struct ipt_entry *
    186 get_entry(void *base, unsigned int offset)
    187 {
    188     return (struct ipt_entry *)(base + offset);
    189 }
上面的代码基本是就是从取出struct ipt_entry的地址,而struct xt_table_info中的hook_entry[]数组存放的就是struct ipt_entry的偏移量。
然后再往下:进入死循环然后进入函数
if (ip_packet_match(ip, indev, outdev,
    354             &e->ip, mtpar.fragoff)) {
这个函数的功能有详细说明:
  68 /*
     69    We keep a set of rules for each CPU, so we can avoid write-locking
     70    them in the softirq when updating the counters and therefore
     71    only need to read-lock in the softirq; doing a write_lock_bh() in user
     72    context stops packets coming through and allows user context to read
     73    the counters or update the rules.
     74
     75    Hence the start of any table is given by get_table() below.  */
     76
     77 /* Returns whether matches rule or not. */
     78 /* Performance critical - called for every packet */
     79 static inline bool
     80 ip_packet_match(const struct iphdr *ip,
     81         const char *indev,
     82         const char *outdev,
     83         const struct ipt_ip *ipinfo,
     84         int isfrag)
     85 {
     86     unsigned long ret;
     87
     88 #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
     89
     90     if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
     91           IPT_INV_SRCIP)
     92         || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
     93              IPT_INV_DSTIP)) {
     94         dprintf("Source or dest mismatch.\n");
     95
     96         dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n",
     97             &ip->saddr, &ipinfo->smsk.s_addr, &ipinfo->src.s_addr,
     98             ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
     99         dprintf("DST: %pI4 Mask: %pI4 Target: %pI4.%s\n",
    100             &ip->daddr, &ipinfo->dmsk.s_addr, &ipinfo->dst.s_addr,
    101             ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
    102         return false;
    103     }
    104
    105     ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask);
    106
    107     if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
    108         dprintf("VIA in mismatch (%s vs %s).%s\n",
    109             indev, ipinfo->iniface,
    110             ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
    111         return false;
    112     }
    113
    114     ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask);
    115
    116     if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
    117         dprintf("VIA out mismatch (%s vs %s).%s\n",
    118             outdev, ipinfo->outiface,
    119             ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
    120         return false;
    121     }
    122
    123     /* Check specific protocol */
    124     if (ipinfo->proto
    125         && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
    126         dprintf("Packet protocol %hi does not match %hi.%s\n",
    127             ip->protocol, ipinfo->proto,
    128             ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
    129         return false;
    130     }
    131
    132     /* If we have a fragment rule but the packet is not a fragment
    133      * then we return zero */
    134     if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
    135         dprintf("Fragment rule but not fragment.%s\n",
    136             ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
    137         return false;
    138     }
    139
    140     return true;
    141 }
说说这个宏:#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
看看这个些宏先:

     61 /* Values for "flag" field in struct ipt_ip (general ip structure). */
     62 #define IPT_F_FRAG        0x01    /* Set if rule is a fragment rule */
     63 #define IPT_F_GOTO        0x02    /* Set if jump is a goto */
     64 #define IPT_F_MASK        0x03    /* All possible flag bits mask. */
     65
     66 /* Values for "inv" field in struct ipt_ip. */
     67 #define IPT_INV_VIA_IN        0x01    /* Invert the sense of IN IFACE. */
     68 #define IPT_INV_VIA_OUT        0x02    /* Invert the sense of OUT IFACE */
     69 #define IPT_INV_TOS        0x04    /* Invert the sense of TOS. */
     70 #define IPT_INV_SRCIP        0x08    /* Invert the sense of SRC IP. */
     71 #define IPT_INV_DSTIP        0x10    /* Invert the sense of DST OP. */
     72 #define IPT_INV_FRAG        0x20    /* Invert the sense of FRAG. */
     73 #define IPT_INV_PROTO        XT_INV_PROTO
     74 #define IPT_INV_MASK        0x7F    /* All possible flag bits mask. */
      75
               
将ipinfo->invflags与上面的宏中的一个相与。相与判断了值是否相等,相=则为1,不=则为0,取反两次,值不变,然后再与一个bool值想异或。当bool和invflg的是一真一假的情况时,返回真。同时为真时,返回0,然后if语句不成立。
然后处理源和目标ip地址,if语句的意义是:到达分组的源ip地址经过掩码处理后与规则中的ip不匹配并且规则中没有包含某个宏定义,或者规则中包含了某个宏定义,但到达分组的源ip与规则中的ip地址匹配,if的第一部分返回真,同样道理处理到达分组的目的ip地址。这两部分任意部分为真时,源或者目标地址不匹配。
然后下面
    ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask);
    106
    107     if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
    108         dprintf("VIA in mismatch (%s vs %s).%s\n",
    109             indev, ipinfo->iniface,
    110             ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
    111         return false;
    112     }
    113
    114     ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask);
    115
比较出口和入口。再下面就是协议的比较。
好,现在回到ipt_do_table,若ip_packet_match返回为假,即规则不匹配,则跳到
no_match:
      e = (void *)e + e->next_offset;
即下一条规则处。若匹配,则
    356        struct ipt_entry_target *t; 
    357        if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0)
    358                 goto no_match;
                t = ipt_get_target(e);
IPT_MATCH_ITERATE 实际执行了do_match,进行match的匹配;
看看do_match():
    169 /* Performance critical - called for every packet */
    170 static inline bool
    171 do_match(struct ipt_entry_match *m, const struct sk_buff *skb,
    172      struct xt_match_param *par)
    173 {
    174     par->match     = m->u.kernel.match;
    175     par->matchinfo = m->data;
    176
    177     /* Stop iteration if it doesn't match */
    178     if (!m->u.kernel.match->match(skb, par))
    179         return true;
    180     else
    181         return false;
    182 }
继续:
    9 struct xt_entry_match
     10 {
     11     union {
     12         struct {
     13             __u16 match_size;
     14
     15             /* Used by userspace */
     16             char name[XT_FUNCTION_MAXNAMELEN-1];
     17
     18             __u8 revision;
     19         } user;
     20         struct {
     21             __u16 match_size;
     22
     23             /* Used inside the kernel */
     24             struct xt_match *match;
     25         } kernel;
     26
     27         /* Total length */
     28         __u16 match_size;
     29     } u;
     30
     31     unsigned char data[0];
     32 };
     33
  269
    270 struct xt_match
    271 {
    272     struct list_head list;
    273
    274     const char name[XT_FUNCTION_MAXNAMELEN-1];
    275     u_int8_t revision;
    276
    277     /* Return true or false: return FALSE and set *hotdrop = 1 to
    278            force immediate packet drop. */
    279     /* Arguments changed since 2.6.9, as this must now handle
    280        non-linear skb, using skb_header_pointer and
    281        skb_ip_make_writable. */
    282     bool (*match)(const struct sk_buff *skb,
    283               const struct xt_match_param *);
    284
    285     /* Called when user tries to insert an entry of this type. */
    286     bool (*checkentry)(const struct xt_mtchk_param *);
    287
    288     /* Called when entry of this type deleted. */
    289     void (*destroy)(const struct xt_mtdtor_param *);
    290
    291     /* Called when userspace align differs from kernel space one */
    292     void (*compat_from_user)(void *dst, void *src);
    293     int (*compat_to_user)(void __user *dst, void *src);
    294
    295     /* Set this to THIS_MODULE if you are a module, otherwise NULL */
    296     struct module *me;
    297
    298     /* Free to use by each match */
    299     unsigned long data;
    300
    301     const char *table;
    302     unsigned int matchsize;
    303     unsigned int compatsize;
    304     unsigned int hooks;
    305     unsigned short proto;
    306
    307     unsigned short family;
    308 };
    309
若不匹配,则no_match,匹配的话,然后,获取target的地址。   
    226 ipt_get_target(struct ipt_entry *e)
    227 {
    228     return (void *)e + e->target_offset;
    229 }
现在target_offset的作用于是明显了,保存了struct ipt_entry_target 结构。再回想下struct ipt_entry结构中的定义:
   86         /* Size of ipt_entry + matches */
     87         u_int16_t target_offset;
     88         /* Size of ipt_entry + matches + target */
     89         u_int16_t next_offset;
struct xt_entry_target结构如下:
  34 struct xt_entry_target
     35 {
     36     union {
     37         struct {
     38             __u16 target_size;
     39
     40             /* Used by userspace */
     41             char name[XT_FUNCTION_MAXNAMELEN-1];
     42
     43             __u8 revision;
     44         } user;
     45         struct {
     46             __u16 target_size;
     47
     48             /* Used inside the kernel */
     49             struct xt_target *target;
     50         } kernel;
     51
     52         /* Total length */
     53         __u16 target_size;
     54     } u;
     55
     56     unsigned char data[0];
     57 };   
又是一个结构体strcut_target
   311 struct xt_target
    312 {
    313     struct list_head list;
    314
    315     const char name[XT_FUNCTION_MAXNAMELEN-1];
    316
    317     /* Returns verdict. Argument order changed since 2.6.9, as this
    318        must now handle non-linear skbs, using skb_copy_bits and
    319        skb_ip_make_writable. */
    320     unsigned int (*target)(struct sk_buff *skb,
    321                    const struct xt_target_param *);
    322
    323     /* Called when user tries to insert an entry of this type:
    324            hook_mask is a bitmask of hooks from which it can be
    325            called. */
    326     /* Should return true or false. */
    327     bool (*checkentry)(const struct xt_tgchk_param *);
    328
    329     /* Called when entry of this type deleted. */
    330     void (*destroy)(const struct xt_tgdtor_param *);
    331
    332     /* Called when userspace align differs from kernel space one */
    333     void (*compat_from_user)(void *dst, void *src);
    334     int (*compat_to_user)(void __user *dst, void *src);
    335
    336     /* Set this to THIS_MODULE if you are a module, otherwise NULL */
    337     struct module *me;
    338
    339     const char *table;
    340     unsigned int targetsize;
    341     unsigned int compatsize;
    342     unsigned int hooks;
    343     unsigned short proto;
    344
    345     unsigned short family;
    346     u_int8_t revision;
    347 };
    348
晕菜,现在为止,了解了struct ipt_entry中的struct ipt_ip用于了规则的保存,target_offset用于保存了一个指向struct xt_entry_match的偏移量,它里面的成员结构体struct xt_match;然后next_offset 指向了下一个ipt_entry,
如果对ipt_ip匹配ok,则执行ipt_entry_match匹配,若ok,则执行xt_entry_target
不过到这里,问题来了,什么是match,什么又是target ,晕菜了。。。
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/102292/showart_2085413.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP