- 論壇徽章:
- 1
|
前面說到了netfilter的規(guī)則表的保存,是由struct xt_table中的鏈表來鏈接的。而具體數(shù)據(jù)則是在struct xt_table_info結(jié)構(gòu)體中,而struct xt_table_info結(jié)構(gòu)中又有struct ipt_ip結(jié)構(gòu)保存相關(guān)的規(guī)則的ip地址信息。struct ipt_entry結(jié)構(gòu)體的作用則要在下面的代碼中找出作用。
/* 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[]數(shù)組存放的就是struct ipt_entry的偏移量。
然后再往下:進(jìn)入死循環(huán)然后進(jìn)入函數(shù)
if (ip_packet_match(ip, indev, outdev,
354 &e->ip, mtpar.fragoff)) {
這個函數(shù)的功能有詳細(xì)說明:
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值想異或。當(dāng)bool和invflg的是一真一假的情況時,返回真。同時為真時,返回0,然后if語句不成立。
然后處理源和目標(biāo)ip地址,if語句的意義是:到達(dá)分組的源ip地址經(jīng)過掩碼處理后與規(guī)則中的ip不匹配并且規(guī)則中沒有包含某個宏定義,或者規(guī)則中包含了某個宏定義,但到達(dá)分組的源ip與規(guī)則中的ip地址匹配,if的第一部分返回真,同樣道理處理到達(dá)分組的目的ip地址。這兩部分任意部分為真時,源或者目標(biāo)地址不匹配。
然后下面
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
比較出口和入口。再下面就是協(xié)議的比較。
好,現(xiàn)在回到ipt_do_table,若ip_packet_match返回為假,即規(guī)則不匹配,則跳到
no_match:
e = (void *)e + e->next_offset;
即下一條規(guī)則處。若匹配,則
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 實際執(zhí)行了do_match,進(jìn)行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 }
繼續(xù):
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 }
現(xiàn)在target_offset的作用于是明顯了,保存了struct ipt_entry_target 結(jié)構(gòu)。再回想下struct ipt_entry結(jié)構(gòu)中的定義:
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結(jié)構(gòu)如下:
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 };
又是一個結(jié)構(gòu)體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
暈菜,現(xiàn)在為止,了解了struct ipt_entry中的struct ipt_ip用于了規(guī)則的保存,target_offset用于保存了一個指向struct xt_entry_match的偏移量,它里面的成員結(jié)構(gòu)體struct xt_match;然后next_offset 指向了下一個ipt_entry,
如果對ipt_ip匹配ok,則執(zhí)行ipt_entry_match匹配,若ok,則執(zhí)行xt_entry_target
不過到這里,問題來了,什么是match,什么又是target ,暈菜了。。。
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u3/102292/showart_2085413.html |
|