[PATCH] Fix pSeries identification in prom_init.c
[linux-2.6.22.y-op.git] / net / ipv6 / netfilter / ip6_tables.c
blob0a673038344fe30142e0d095f3f6bb5c6a8854a8
1 /*
2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
13 * a table
14 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
15 * - new extension header parser code
16 * 15 Oct 2005 Harald Welte <laforge@netfilter.org>
17 * - Unification of {ip,ip6}_tables into x_tables
18 * - Removed tcp and udp code, since it's not ipv6 specific
21 #include <linux/capability.h>
22 #include <linux/config.h>
23 #include <linux/in.h>
24 #include <linux/skbuff.h>
25 #include <linux/kmod.h>
26 #include <linux/vmalloc.h>
27 #include <linux/netdevice.h>
28 #include <linux/module.h>
29 #include <linux/icmpv6.h>
30 #include <net/ipv6.h>
31 #include <asm/uaccess.h>
32 #include <linux/mutex.h>
33 #include <linux/proc_fs.h>
34 #include <linux/cpumask.h>
36 #include <linux/netfilter_ipv6/ip6_tables.h>
37 #include <linux/netfilter/x_tables.h>
39 MODULE_LICENSE("GPL");
40 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
41 MODULE_DESCRIPTION("IPv6 packet filter");
43 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
44 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
46 /*#define DEBUG_IP_FIREWALL*/
47 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
48 /*#define DEBUG_IP_FIREWALL_USER*/
50 #ifdef DEBUG_IP_FIREWALL
51 #define dprintf(format, args...) printk(format , ## args)
52 #else
53 #define dprintf(format, args...)
54 #endif
56 #ifdef DEBUG_IP_FIREWALL_USER
57 #define duprintf(format, args...) printk(format , ## args)
58 #else
59 #define duprintf(format, args...)
60 #endif
62 #ifdef CONFIG_NETFILTER_DEBUG
63 #define IP_NF_ASSERT(x) \
64 do { \
65 if (!(x)) \
66 printk("IP_NF_ASSERT: %s:%s:%u\n", \
67 __FUNCTION__, __FILE__, __LINE__); \
68 } while(0)
69 #else
70 #define IP_NF_ASSERT(x)
71 #endif
74 #include <linux/netfilter_ipv4/listhelp.h>
76 #if 0
77 /* All the better to debug you with... */
78 #define static
79 #define inline
80 #endif
83 We keep a set of rules for each CPU, so we can avoid write-locking
84 them in the softirq when updating the counters and therefore
85 only need to read-lock in the softirq; doing a write_lock_bh() in user
86 context stops packets coming through and allows user context to read
87 the counters or update the rules.
89 Hence the start of any table is given by get_table() below. */
91 #if 0
92 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
93 #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
94 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
95 #endif
97 /* Check for an extension */
98 int
99 ip6t_ext_hdr(u8 nexthdr)
101 return ( (nexthdr == IPPROTO_HOPOPTS) ||
102 (nexthdr == IPPROTO_ROUTING) ||
103 (nexthdr == IPPROTO_FRAGMENT) ||
104 (nexthdr == IPPROTO_ESP) ||
105 (nexthdr == IPPROTO_AH) ||
106 (nexthdr == IPPROTO_NONE) ||
107 (nexthdr == IPPROTO_DSTOPTS) );
110 /* Returns whether matches rule or not. */
111 static inline int
112 ip6_packet_match(const struct sk_buff *skb,
113 const char *indev,
114 const char *outdev,
115 const struct ip6t_ip6 *ip6info,
116 unsigned int *protoff,
117 int *fragoff)
119 size_t i;
120 unsigned long ret;
121 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
123 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
125 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
126 &ip6info->src), IP6T_INV_SRCIP)
127 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
128 &ip6info->dst), IP6T_INV_DSTIP)) {
129 dprintf("Source or dest mismatch.\n");
131 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
132 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
133 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
134 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
135 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
136 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
137 return 0;
140 /* Look for ifname matches; this should unroll nicely. */
141 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
142 ret |= (((const unsigned long *)indev)[i]
143 ^ ((const unsigned long *)ip6info->iniface)[i])
144 & ((const unsigned long *)ip6info->iniface_mask)[i];
147 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
148 dprintf("VIA in mismatch (%s vs %s).%s\n",
149 indev, ip6info->iniface,
150 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
151 return 0;
154 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
155 ret |= (((const unsigned long *)outdev)[i]
156 ^ ((const unsigned long *)ip6info->outiface)[i])
157 & ((const unsigned long *)ip6info->outiface_mask)[i];
160 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
161 dprintf("VIA out mismatch (%s vs %s).%s\n",
162 outdev, ip6info->outiface,
163 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
164 return 0;
167 /* ... might want to do something with class and flowlabel here ... */
169 /* look for the desired protocol header */
170 if((ip6info->flags & IP6T_F_PROTO)) {
171 int protohdr;
172 unsigned short _frag_off;
174 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
175 if (protohdr < 0)
176 return 0;
178 *fragoff = _frag_off;
180 dprintf("Packet protocol %hi ?= %s%hi.\n",
181 protohdr,
182 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
183 ip6info->proto);
185 if (ip6info->proto == protohdr) {
186 if(ip6info->invflags & IP6T_INV_PROTO) {
187 return 0;
189 return 1;
192 /* We need match for the '-p all', too! */
193 if ((ip6info->proto != 0) &&
194 !(ip6info->invflags & IP6T_INV_PROTO))
195 return 0;
197 return 1;
200 /* should be ip6 safe */
201 static inline int
202 ip6_checkentry(const struct ip6t_ip6 *ipv6)
204 if (ipv6->flags & ~IP6T_F_MASK) {
205 duprintf("Unknown flag bits set: %08X\n",
206 ipv6->flags & ~IP6T_F_MASK);
207 return 0;
209 if (ipv6->invflags & ~IP6T_INV_MASK) {
210 duprintf("Unknown invflag bits set: %08X\n",
211 ipv6->invflags & ~IP6T_INV_MASK);
212 return 0;
214 return 1;
217 static unsigned int
218 ip6t_error(struct sk_buff **pskb,
219 const struct net_device *in,
220 const struct net_device *out,
221 unsigned int hooknum,
222 const struct xt_target *target,
223 const void *targinfo,
224 void *userinfo)
226 if (net_ratelimit())
227 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
229 return NF_DROP;
232 static inline
233 int do_match(struct ip6t_entry_match *m,
234 const struct sk_buff *skb,
235 const struct net_device *in,
236 const struct net_device *out,
237 int offset,
238 unsigned int protoff,
239 int *hotdrop)
241 /* Stop iteration if it doesn't match */
242 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
243 offset, protoff, hotdrop))
244 return 1;
245 else
246 return 0;
249 static inline struct ip6t_entry *
250 get_entry(void *base, unsigned int offset)
252 return (struct ip6t_entry *)(base + offset);
255 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
256 unsigned int
257 ip6t_do_table(struct sk_buff **pskb,
258 unsigned int hook,
259 const struct net_device *in,
260 const struct net_device *out,
261 struct xt_table *table,
262 void *userdata)
264 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
265 int offset = 0;
266 unsigned int protoff = 0;
267 int hotdrop = 0;
268 /* Initializing verdict to NF_DROP keeps gcc happy. */
269 unsigned int verdict = NF_DROP;
270 const char *indev, *outdev;
271 void *table_base;
272 struct ip6t_entry *e, *back;
273 struct xt_table_info *private;
275 /* Initialization */
276 indev = in ? in->name : nulldevname;
277 outdev = out ? out->name : nulldevname;
278 /* We handle fragments by dealing with the first fragment as
279 * if it was a normal packet. All other fragments are treated
280 * normally, except that they will NEVER match rules that ask
281 * things we don't know, ie. tcp syn flag or ports). If the
282 * rule is also a fragment-specific rule, non-fragments won't
283 * match it. */
285 read_lock_bh(&table->lock);
286 private = table->private;
287 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
288 table_base = (void *)private->entries[smp_processor_id()];
289 e = get_entry(table_base, private->hook_entry[hook]);
291 /* For return from builtin chain */
292 back = get_entry(table_base, private->underflow[hook]);
294 do {
295 IP_NF_ASSERT(e);
296 IP_NF_ASSERT(back);
297 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
298 &protoff, &offset)) {
299 struct ip6t_entry_target *t;
301 if (IP6T_MATCH_ITERATE(e, do_match,
302 *pskb, in, out,
303 offset, protoff, &hotdrop) != 0)
304 goto no_match;
306 ADD_COUNTER(e->counters,
307 ntohs((*pskb)->nh.ipv6h->payload_len)
308 + IPV6_HDR_LEN,
311 t = ip6t_get_target(e);
312 IP_NF_ASSERT(t->u.kernel.target);
313 /* Standard target? */
314 if (!t->u.kernel.target->target) {
315 int v;
317 v = ((struct ip6t_standard_target *)t)->verdict;
318 if (v < 0) {
319 /* Pop from stack? */
320 if (v != IP6T_RETURN) {
321 verdict = (unsigned)(-v) - 1;
322 break;
324 e = back;
325 back = get_entry(table_base,
326 back->comefrom);
327 continue;
329 if (table_base + v != (void *)e + e->next_offset
330 && !(e->ipv6.flags & IP6T_F_GOTO)) {
331 /* Save old back ptr in next entry */
332 struct ip6t_entry *next
333 = (void *)e + e->next_offset;
334 next->comefrom
335 = (void *)back - table_base;
336 /* set back pointer to next entry */
337 back = next;
340 e = get_entry(table_base, v);
341 } else {
342 /* Targets which reenter must return
343 abs. verdicts */
344 #ifdef CONFIG_NETFILTER_DEBUG
345 ((struct ip6t_entry *)table_base)->comefrom
346 = 0xeeeeeeec;
347 #endif
348 verdict = t->u.kernel.target->target(pskb,
349 in, out,
350 hook,
351 t->u.kernel.target,
352 t->data,
353 userdata);
355 #ifdef CONFIG_NETFILTER_DEBUG
356 if (((struct ip6t_entry *)table_base)->comefrom
357 != 0xeeeeeeec
358 && verdict == IP6T_CONTINUE) {
359 printk("Target %s reentered!\n",
360 t->u.kernel.target->name);
361 verdict = NF_DROP;
363 ((struct ip6t_entry *)table_base)->comefrom
364 = 0x57acc001;
365 #endif
366 if (verdict == IP6T_CONTINUE)
367 e = (void *)e + e->next_offset;
368 else
369 /* Verdict */
370 break;
372 } else {
374 no_match:
375 e = (void *)e + e->next_offset;
377 } while (!hotdrop);
379 #ifdef CONFIG_NETFILTER_DEBUG
380 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
381 #endif
382 read_unlock_bh(&table->lock);
384 #ifdef DEBUG_ALLOW_ALL
385 return NF_ACCEPT;
386 #else
387 if (hotdrop)
388 return NF_DROP;
389 else return verdict;
390 #endif
393 /* All zeroes == unconditional rule. */
394 static inline int
395 unconditional(const struct ip6t_ip6 *ipv6)
397 unsigned int i;
399 for (i = 0; i < sizeof(*ipv6); i++)
400 if (((char *)ipv6)[i])
401 break;
403 return (i == sizeof(*ipv6));
406 /* Figures out from what hook each rule can be called: returns 0 if
407 there are loops. Puts hook bitmask in comefrom. */
408 static int
409 mark_source_chains(struct xt_table_info *newinfo,
410 unsigned int valid_hooks, void *entry0)
412 unsigned int hook;
414 /* No recursion; use packet counter to save back ptrs (reset
415 to 0 as we leave), and comefrom to save source hook bitmask */
416 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
417 unsigned int pos = newinfo->hook_entry[hook];
418 struct ip6t_entry *e
419 = (struct ip6t_entry *)(entry0 + pos);
421 if (!(valid_hooks & (1 << hook)))
422 continue;
424 /* Set initial back pointer. */
425 e->counters.pcnt = pos;
427 for (;;) {
428 struct ip6t_standard_target *t
429 = (void *)ip6t_get_target(e);
431 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
432 printk("iptables: loop hook %u pos %u %08X.\n",
433 hook, pos, e->comefrom);
434 return 0;
436 e->comefrom
437 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
439 /* Unconditional return/END. */
440 if (e->target_offset == sizeof(struct ip6t_entry)
441 && (strcmp(t->target.u.user.name,
442 IP6T_STANDARD_TARGET) == 0)
443 && t->verdict < 0
444 && unconditional(&e->ipv6)) {
445 unsigned int oldpos, size;
447 /* Return: backtrack through the last
448 big jump. */
449 do {
450 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
451 #ifdef DEBUG_IP_FIREWALL_USER
452 if (e->comefrom
453 & (1 << NF_IP6_NUMHOOKS)) {
454 duprintf("Back unset "
455 "on hook %u "
456 "rule %u\n",
457 hook, pos);
459 #endif
460 oldpos = pos;
461 pos = e->counters.pcnt;
462 e->counters.pcnt = 0;
464 /* We're at the start. */
465 if (pos == oldpos)
466 goto next;
468 e = (struct ip6t_entry *)
469 (entry0 + pos);
470 } while (oldpos == pos + e->next_offset);
472 /* Move along one */
473 size = e->next_offset;
474 e = (struct ip6t_entry *)
475 (entry0 + pos + size);
476 e->counters.pcnt = pos;
477 pos += size;
478 } else {
479 int newpos = t->verdict;
481 if (strcmp(t->target.u.user.name,
482 IP6T_STANDARD_TARGET) == 0
483 && newpos >= 0) {
484 /* This a jump; chase it. */
485 duprintf("Jump rule %u -> %u\n",
486 pos, newpos);
487 } else {
488 /* ... this is a fallthru */
489 newpos = pos + e->next_offset;
491 e = (struct ip6t_entry *)
492 (entry0 + newpos);
493 e->counters.pcnt = pos;
494 pos = newpos;
497 next:
498 duprintf("Finished chain %u\n", hook);
500 return 1;
503 static inline int
504 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
506 if (i && (*i)-- == 0)
507 return 1;
509 if (m->u.kernel.match->destroy)
510 m->u.kernel.match->destroy(m->u.kernel.match, m->data,
511 m->u.match_size - sizeof(*m));
512 module_put(m->u.kernel.match->me);
513 return 0;
516 static inline int
517 standard_check(const struct ip6t_entry_target *t,
518 unsigned int max_offset)
520 struct ip6t_standard_target *targ = (void *)t;
522 /* Check standard info. */
523 if (targ->verdict >= 0
524 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
525 duprintf("ip6t_standard_check: bad verdict (%i)\n",
526 targ->verdict);
527 return 0;
529 if (targ->verdict < -NF_MAX_VERDICT - 1) {
530 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
531 targ->verdict);
532 return 0;
534 return 1;
537 static inline int
538 check_match(struct ip6t_entry_match *m,
539 const char *name,
540 const struct ip6t_ip6 *ipv6,
541 unsigned int hookmask,
542 unsigned int *i)
544 struct ip6t_match *match;
545 int ret;
547 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
548 m->u.user.revision),
549 "ip6t_%s", m->u.user.name);
550 if (IS_ERR(match) || !match) {
551 duprintf("check_match: `%s' not found\n", m->u.user.name);
552 return match ? PTR_ERR(match) : -ENOENT;
554 m->u.kernel.match = match;
556 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
557 name, hookmask, ipv6->proto,
558 ipv6->invflags & IP6T_INV_PROTO);
559 if (ret)
560 goto err;
562 if (m->u.kernel.match->checkentry
563 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
564 m->u.match_size - sizeof(*m),
565 hookmask)) {
566 duprintf("ip_tables: check failed for `%s'.\n",
567 m->u.kernel.match->name);
568 ret = -EINVAL;
569 goto err;
572 (*i)++;
573 return 0;
574 err:
575 module_put(m->u.kernel.match->me);
576 return ret;
579 static struct ip6t_target ip6t_standard_target;
581 static inline int
582 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
583 unsigned int *i)
585 struct ip6t_entry_target *t;
586 struct ip6t_target *target;
587 int ret;
588 unsigned int j;
590 if (!ip6_checkentry(&e->ipv6)) {
591 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
592 return -EINVAL;
595 j = 0;
596 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
597 if (ret != 0)
598 goto cleanup_matches;
600 t = ip6t_get_target(e);
601 target = try_then_request_module(xt_find_target(AF_INET6,
602 t->u.user.name,
603 t->u.user.revision),
604 "ip6t_%s", t->u.user.name);
605 if (IS_ERR(target) || !target) {
606 duprintf("check_entry: `%s' not found\n", t->u.user.name);
607 ret = target ? PTR_ERR(target) : -ENOENT;
608 goto cleanup_matches;
610 t->u.kernel.target = target;
612 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
613 name, e->comefrom, e->ipv6.proto,
614 e->ipv6.invflags & IP6T_INV_PROTO);
615 if (ret)
616 goto err;
618 if (t->u.kernel.target == &ip6t_standard_target) {
619 if (!standard_check(t, size)) {
620 ret = -EINVAL;
621 goto cleanup_matches;
623 } else if (t->u.kernel.target->checkentry
624 && !t->u.kernel.target->checkentry(name, e, target, t->data,
625 t->u.target_size
626 - sizeof(*t),
627 e->comefrom)) {
628 duprintf("ip_tables: check failed for `%s'.\n",
629 t->u.kernel.target->name);
630 ret = -EINVAL;
631 goto err;
634 (*i)++;
635 return 0;
636 err:
637 module_put(t->u.kernel.target->me);
638 cleanup_matches:
639 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
640 return ret;
643 static inline int
644 check_entry_size_and_hooks(struct ip6t_entry *e,
645 struct xt_table_info *newinfo,
646 unsigned char *base,
647 unsigned char *limit,
648 const unsigned int *hook_entries,
649 const unsigned int *underflows,
650 unsigned int *i)
652 unsigned int h;
654 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
655 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
656 duprintf("Bad offset %p\n", e);
657 return -EINVAL;
660 if (e->next_offset
661 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
662 duprintf("checking: element %p size %u\n",
663 e, e->next_offset);
664 return -EINVAL;
667 /* Check hooks & underflows */
668 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
669 if ((unsigned char *)e - base == hook_entries[h])
670 newinfo->hook_entry[h] = hook_entries[h];
671 if ((unsigned char *)e - base == underflows[h])
672 newinfo->underflow[h] = underflows[h];
675 /* FIXME: underflows must be unconditional, standard verdicts
676 < 0 (not IP6T_RETURN). --RR */
678 /* Clear counters and comefrom */
679 e->counters = ((struct xt_counters) { 0, 0 });
680 e->comefrom = 0;
682 (*i)++;
683 return 0;
686 static inline int
687 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
689 struct ip6t_entry_target *t;
691 if (i && (*i)-- == 0)
692 return 1;
694 /* Cleanup all matches */
695 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
696 t = ip6t_get_target(e);
697 if (t->u.kernel.target->destroy)
698 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
699 t->u.target_size - sizeof(*t));
700 module_put(t->u.kernel.target->me);
701 return 0;
704 /* Checks and translates the user-supplied table segment (held in
705 newinfo) */
706 static int
707 translate_table(const char *name,
708 unsigned int valid_hooks,
709 struct xt_table_info *newinfo,
710 void *entry0,
711 unsigned int size,
712 unsigned int number,
713 const unsigned int *hook_entries,
714 const unsigned int *underflows)
716 unsigned int i;
717 int ret;
719 newinfo->size = size;
720 newinfo->number = number;
722 /* Init all hooks to impossible value. */
723 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
724 newinfo->hook_entry[i] = 0xFFFFFFFF;
725 newinfo->underflow[i] = 0xFFFFFFFF;
728 duprintf("translate_table: size %u\n", newinfo->size);
729 i = 0;
730 /* Walk through entries, checking offsets. */
731 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
732 check_entry_size_and_hooks,
733 newinfo,
734 entry0,
735 entry0 + size,
736 hook_entries, underflows, &i);
737 if (ret != 0)
738 return ret;
740 if (i != number) {
741 duprintf("translate_table: %u not %u entries\n",
742 i, number);
743 return -EINVAL;
746 /* Check hooks all assigned */
747 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
748 /* Only hooks which are valid */
749 if (!(valid_hooks & (1 << i)))
750 continue;
751 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
752 duprintf("Invalid hook entry %u %u\n",
753 i, hook_entries[i]);
754 return -EINVAL;
756 if (newinfo->underflow[i] == 0xFFFFFFFF) {
757 duprintf("Invalid underflow %u %u\n",
758 i, underflows[i]);
759 return -EINVAL;
763 if (!mark_source_chains(newinfo, valid_hooks, entry0))
764 return -ELOOP;
766 /* Finally, each sanity check must pass */
767 i = 0;
768 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
769 check_entry, name, size, &i);
771 if (ret != 0) {
772 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
773 cleanup_entry, &i);
774 return ret;
777 /* And one copy for every other CPU */
778 for_each_possible_cpu(i) {
779 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
780 memcpy(newinfo->entries[i], entry0, newinfo->size);
783 return ret;
786 /* Gets counters. */
787 static inline int
788 add_entry_to_counter(const struct ip6t_entry *e,
789 struct xt_counters total[],
790 unsigned int *i)
792 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
794 (*i)++;
795 return 0;
798 static inline int
799 set_entry_to_counter(const struct ip6t_entry *e,
800 struct ip6t_counters total[],
801 unsigned int *i)
803 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
805 (*i)++;
806 return 0;
809 static void
810 get_counters(const struct xt_table_info *t,
811 struct xt_counters counters[])
813 unsigned int cpu;
814 unsigned int i;
815 unsigned int curcpu;
817 /* Instead of clearing (by a previous call to memset())
818 * the counters and using adds, we set the counters
819 * with data used by 'current' CPU
820 * We dont care about preemption here.
822 curcpu = raw_smp_processor_id();
824 i = 0;
825 IP6T_ENTRY_ITERATE(t->entries[curcpu],
826 t->size,
827 set_entry_to_counter,
828 counters,
829 &i);
831 for_each_possible_cpu(cpu) {
832 if (cpu == curcpu)
833 continue;
834 i = 0;
835 IP6T_ENTRY_ITERATE(t->entries[cpu],
836 t->size,
837 add_entry_to_counter,
838 counters,
839 &i);
843 static int
844 copy_entries_to_user(unsigned int total_size,
845 struct xt_table *table,
846 void __user *userptr)
848 unsigned int off, num, countersize;
849 struct ip6t_entry *e;
850 struct xt_counters *counters;
851 struct xt_table_info *private = table->private;
852 int ret = 0;
853 void *loc_cpu_entry;
855 /* We need atomic snapshot of counters: rest doesn't change
856 (other than comefrom, which userspace doesn't care
857 about). */
858 countersize = sizeof(struct xt_counters) * private->number;
859 counters = vmalloc(countersize);
861 if (counters == NULL)
862 return -ENOMEM;
864 /* First, sum counters... */
865 write_lock_bh(&table->lock);
866 get_counters(private, counters);
867 write_unlock_bh(&table->lock);
869 /* choose the copy that is on ourc node/cpu */
870 loc_cpu_entry = private->entries[raw_smp_processor_id()];
871 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
872 ret = -EFAULT;
873 goto free_counters;
876 /* FIXME: use iterator macros --RR */
877 /* ... then go back and fix counters and names */
878 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
879 unsigned int i;
880 struct ip6t_entry_match *m;
881 struct ip6t_entry_target *t;
883 e = (struct ip6t_entry *)(loc_cpu_entry + off);
884 if (copy_to_user(userptr + off
885 + offsetof(struct ip6t_entry, counters),
886 &counters[num],
887 sizeof(counters[num])) != 0) {
888 ret = -EFAULT;
889 goto free_counters;
892 for (i = sizeof(struct ip6t_entry);
893 i < e->target_offset;
894 i += m->u.match_size) {
895 m = (void *)e + i;
897 if (copy_to_user(userptr + off + i
898 + offsetof(struct ip6t_entry_match,
899 u.user.name),
900 m->u.kernel.match->name,
901 strlen(m->u.kernel.match->name)+1)
902 != 0) {
903 ret = -EFAULT;
904 goto free_counters;
908 t = ip6t_get_target(e);
909 if (copy_to_user(userptr + off + e->target_offset
910 + offsetof(struct ip6t_entry_target,
911 u.user.name),
912 t->u.kernel.target->name,
913 strlen(t->u.kernel.target->name)+1) != 0) {
914 ret = -EFAULT;
915 goto free_counters;
919 free_counters:
920 vfree(counters);
921 return ret;
924 static int
925 get_entries(const struct ip6t_get_entries *entries,
926 struct ip6t_get_entries __user *uptr)
928 int ret;
929 struct xt_table *t;
931 t = xt_find_table_lock(AF_INET6, entries->name);
932 if (t && !IS_ERR(t)) {
933 struct xt_table_info *private = t->private;
934 duprintf("t->private->number = %u\n", private->number);
935 if (entries->size == private->size)
936 ret = copy_entries_to_user(private->size,
937 t, uptr->entrytable);
938 else {
939 duprintf("get_entries: I've got %u not %u!\n",
940 private->size, entries->size);
941 ret = -EINVAL;
943 module_put(t->me);
944 xt_table_unlock(t);
945 } else
946 ret = t ? PTR_ERR(t) : -ENOENT;
948 return ret;
951 static int
952 do_replace(void __user *user, unsigned int len)
954 int ret;
955 struct ip6t_replace tmp;
956 struct xt_table *t;
957 struct xt_table_info *newinfo, *oldinfo;
958 struct xt_counters *counters;
959 void *loc_cpu_entry, *loc_cpu_old_entry;
961 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
962 return -EFAULT;
964 /* overflow check */
965 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
966 SMP_CACHE_BYTES)
967 return -ENOMEM;
968 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
969 return -ENOMEM;
971 newinfo = xt_alloc_table_info(tmp.size);
972 if (!newinfo)
973 return -ENOMEM;
975 /* choose the copy that is on our node/cpu */
976 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
977 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
978 tmp.size) != 0) {
979 ret = -EFAULT;
980 goto free_newinfo;
983 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
984 if (!counters) {
985 ret = -ENOMEM;
986 goto free_newinfo;
989 ret = translate_table(tmp.name, tmp.valid_hooks,
990 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
991 tmp.hook_entry, tmp.underflow);
992 if (ret != 0)
993 goto free_newinfo_counters;
995 duprintf("ip_tables: Translated table\n");
997 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
998 "ip6table_%s", tmp.name);
999 if (!t || IS_ERR(t)) {
1000 ret = t ? PTR_ERR(t) : -ENOENT;
1001 goto free_newinfo_counters_untrans;
1004 /* You lied! */
1005 if (tmp.valid_hooks != t->valid_hooks) {
1006 duprintf("Valid hook crap: %08X vs %08X\n",
1007 tmp.valid_hooks, t->valid_hooks);
1008 ret = -EINVAL;
1009 goto put_module;
1012 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1013 if (!oldinfo)
1014 goto put_module;
1016 /* Update module usage count based on number of rules */
1017 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1018 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1019 if ((oldinfo->number > oldinfo->initial_entries) ||
1020 (newinfo->number <= oldinfo->initial_entries))
1021 module_put(t->me);
1022 if ((oldinfo->number > oldinfo->initial_entries) &&
1023 (newinfo->number <= oldinfo->initial_entries))
1024 module_put(t->me);
1026 /* Get the old counters. */
1027 get_counters(oldinfo, counters);
1028 /* Decrease module usage counts and free resource */
1029 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1030 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1031 xt_free_table_info(oldinfo);
1032 if (copy_to_user(tmp.counters, counters,
1033 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1034 ret = -EFAULT;
1035 vfree(counters);
1036 xt_table_unlock(t);
1037 return ret;
1039 put_module:
1040 module_put(t->me);
1041 xt_table_unlock(t);
1042 free_newinfo_counters_untrans:
1043 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1044 free_newinfo_counters:
1045 vfree(counters);
1046 free_newinfo:
1047 xt_free_table_info(newinfo);
1048 return ret;
1051 /* We're lazy, and add to the first CPU; overflow works its fey magic
1052 * and everything is OK. */
1053 static inline int
1054 add_counter_to_entry(struct ip6t_entry *e,
1055 const struct xt_counters addme[],
1056 unsigned int *i)
1058 #if 0
1059 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1061 (long unsigned int)e->counters.pcnt,
1062 (long unsigned int)e->counters.bcnt,
1063 (long unsigned int)addme[*i].pcnt,
1064 (long unsigned int)addme[*i].bcnt);
1065 #endif
1067 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1069 (*i)++;
1070 return 0;
1073 static int
1074 do_add_counters(void __user *user, unsigned int len)
1076 unsigned int i;
1077 struct xt_counters_info tmp, *paddc;
1078 struct xt_table_info *private;
1079 struct xt_table *t;
1080 int ret = 0;
1081 void *loc_cpu_entry;
1083 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1084 return -EFAULT;
1086 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1087 return -EINVAL;
1089 paddc = vmalloc(len);
1090 if (!paddc)
1091 return -ENOMEM;
1093 if (copy_from_user(paddc, user, len) != 0) {
1094 ret = -EFAULT;
1095 goto free;
1098 t = xt_find_table_lock(AF_INET6, tmp.name);
1099 if (!t || IS_ERR(t)) {
1100 ret = t ? PTR_ERR(t) : -ENOENT;
1101 goto free;
1104 write_lock_bh(&t->lock);
1105 private = t->private;
1106 if (private->number != paddc->num_counters) {
1107 ret = -EINVAL;
1108 goto unlock_up_free;
1111 i = 0;
1112 /* Choose the copy that is on our node */
1113 loc_cpu_entry = private->entries[smp_processor_id()];
1114 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1115 private->size,
1116 add_counter_to_entry,
1117 paddc->counters,
1118 &i);
1119 unlock_up_free:
1120 write_unlock_bh(&t->lock);
1121 xt_table_unlock(t);
1122 module_put(t->me);
1123 free:
1124 vfree(paddc);
1126 return ret;
1129 static int
1130 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1132 int ret;
1134 if (!capable(CAP_NET_ADMIN))
1135 return -EPERM;
1137 switch (cmd) {
1138 case IP6T_SO_SET_REPLACE:
1139 ret = do_replace(user, len);
1140 break;
1142 case IP6T_SO_SET_ADD_COUNTERS:
1143 ret = do_add_counters(user, len);
1144 break;
1146 default:
1147 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1148 ret = -EINVAL;
1151 return ret;
1154 static int
1155 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1157 int ret;
1159 if (!capable(CAP_NET_ADMIN))
1160 return -EPERM;
1162 switch (cmd) {
1163 case IP6T_SO_GET_INFO: {
1164 char name[IP6T_TABLE_MAXNAMELEN];
1165 struct xt_table *t;
1167 if (*len != sizeof(struct ip6t_getinfo)) {
1168 duprintf("length %u != %u\n", *len,
1169 sizeof(struct ip6t_getinfo));
1170 ret = -EINVAL;
1171 break;
1174 if (copy_from_user(name, user, sizeof(name)) != 0) {
1175 ret = -EFAULT;
1176 break;
1178 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1180 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1181 "ip6table_%s", name);
1182 if (t && !IS_ERR(t)) {
1183 struct ip6t_getinfo info;
1184 struct xt_table_info *private = t->private;
1186 info.valid_hooks = t->valid_hooks;
1187 memcpy(info.hook_entry, private->hook_entry,
1188 sizeof(info.hook_entry));
1189 memcpy(info.underflow, private->underflow,
1190 sizeof(info.underflow));
1191 info.num_entries = private->number;
1192 info.size = private->size;
1193 memcpy(info.name, name, sizeof(info.name));
1195 if (copy_to_user(user, &info, *len) != 0)
1196 ret = -EFAULT;
1197 else
1198 ret = 0;
1199 xt_table_unlock(t);
1200 module_put(t->me);
1201 } else
1202 ret = t ? PTR_ERR(t) : -ENOENT;
1204 break;
1206 case IP6T_SO_GET_ENTRIES: {
1207 struct ip6t_get_entries get;
1209 if (*len < sizeof(get)) {
1210 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1211 ret = -EINVAL;
1212 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1213 ret = -EFAULT;
1214 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1215 duprintf("get_entries: %u != %u\n", *len,
1216 sizeof(struct ip6t_get_entries) + get.size);
1217 ret = -EINVAL;
1218 } else
1219 ret = get_entries(&get, user);
1220 break;
1223 case IP6T_SO_GET_REVISION_MATCH:
1224 case IP6T_SO_GET_REVISION_TARGET: {
1225 struct ip6t_get_revision rev;
1226 int target;
1228 if (*len != sizeof(rev)) {
1229 ret = -EINVAL;
1230 break;
1232 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1233 ret = -EFAULT;
1234 break;
1237 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1238 target = 1;
1239 else
1240 target = 0;
1242 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1243 rev.revision,
1244 target, &ret),
1245 "ip6t_%s", rev.name);
1246 break;
1249 default:
1250 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1251 ret = -EINVAL;
1254 return ret;
1257 int ip6t_register_table(struct xt_table *table,
1258 const struct ip6t_replace *repl)
1260 int ret;
1261 struct xt_table_info *newinfo;
1262 static struct xt_table_info bootstrap
1263 = { 0, 0, 0, { 0 }, { 0 }, { } };
1264 void *loc_cpu_entry;
1266 newinfo = xt_alloc_table_info(repl->size);
1267 if (!newinfo)
1268 return -ENOMEM;
1270 /* choose the copy on our node/cpu */
1271 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1272 memcpy(loc_cpu_entry, repl->entries, repl->size);
1274 ret = translate_table(table->name, table->valid_hooks,
1275 newinfo, loc_cpu_entry, repl->size,
1276 repl->num_entries,
1277 repl->hook_entry,
1278 repl->underflow);
1279 if (ret != 0) {
1280 xt_free_table_info(newinfo);
1281 return ret;
1284 if (xt_register_table(table, &bootstrap, newinfo) != 0) {
1285 xt_free_table_info(newinfo);
1286 return ret;
1289 return 0;
1292 void ip6t_unregister_table(struct xt_table *table)
1294 struct xt_table_info *private;
1295 void *loc_cpu_entry;
1297 private = xt_unregister_table(table);
1299 /* Decrease module usage counts and free resources */
1300 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1301 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1302 xt_free_table_info(private);
1305 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1306 static inline int
1307 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1308 u_int8_t type, u_int8_t code,
1309 int invert)
1311 return (type == test_type && code >= min_code && code <= max_code)
1312 ^ invert;
1315 static int
1316 icmp6_match(const struct sk_buff *skb,
1317 const struct net_device *in,
1318 const struct net_device *out,
1319 const struct xt_match *match,
1320 const void *matchinfo,
1321 int offset,
1322 unsigned int protoff,
1323 int *hotdrop)
1325 struct icmp6hdr _icmp, *ic;
1326 const struct ip6t_icmp *icmpinfo = matchinfo;
1328 /* Must not be a fragment. */
1329 if (offset)
1330 return 0;
1332 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1333 if (ic == NULL) {
1334 /* We've been asked to examine this packet, and we
1335 can't. Hence, no choice but to drop. */
1336 duprintf("Dropping evil ICMP tinygram.\n");
1337 *hotdrop = 1;
1338 return 0;
1341 return icmp6_type_code_match(icmpinfo->type,
1342 icmpinfo->code[0],
1343 icmpinfo->code[1],
1344 ic->icmp6_type, ic->icmp6_code,
1345 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1348 /* Called when user tries to insert an entry of this type. */
1349 static int
1350 icmp6_checkentry(const char *tablename,
1351 const void *entry,
1352 const struct xt_match *match,
1353 void *matchinfo,
1354 unsigned int matchsize,
1355 unsigned int hook_mask)
1357 const struct ip6t_icmp *icmpinfo = matchinfo;
1359 /* Must specify no unknown invflags */
1360 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1363 /* The built-in targets: standard (NULL) and error. */
1364 static struct ip6t_target ip6t_standard_target = {
1365 .name = IP6T_STANDARD_TARGET,
1366 .targetsize = sizeof(int),
1367 .family = AF_INET6,
1370 static struct ip6t_target ip6t_error_target = {
1371 .name = IP6T_ERROR_TARGET,
1372 .target = ip6t_error,
1373 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1374 .family = AF_INET6,
1377 static struct nf_sockopt_ops ip6t_sockopts = {
1378 .pf = PF_INET6,
1379 .set_optmin = IP6T_BASE_CTL,
1380 .set_optmax = IP6T_SO_SET_MAX+1,
1381 .set = do_ip6t_set_ctl,
1382 .get_optmin = IP6T_BASE_CTL,
1383 .get_optmax = IP6T_SO_GET_MAX+1,
1384 .get = do_ip6t_get_ctl,
1387 static struct ip6t_match icmp6_matchstruct = {
1388 .name = "icmp6",
1389 .match = &icmp6_match,
1390 .matchsize = sizeof(struct ip6t_icmp),
1391 .checkentry = icmp6_checkentry,
1392 .proto = IPPROTO_ICMPV6,
1393 .family = AF_INET6,
1396 static int __init ip6_tables_init(void)
1398 int ret;
1400 xt_proto_init(AF_INET6);
1402 /* Noone else will be downing sem now, so we won't sleep */
1403 xt_register_target(&ip6t_standard_target);
1404 xt_register_target(&ip6t_error_target);
1405 xt_register_match(&icmp6_matchstruct);
1407 /* Register setsockopt */
1408 ret = nf_register_sockopt(&ip6t_sockopts);
1409 if (ret < 0) {
1410 duprintf("Unable to register sockopts.\n");
1411 xt_proto_fini(AF_INET6);
1412 return ret;
1415 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1416 return 0;
1419 static void __exit ip6_tables_fini(void)
1421 nf_unregister_sockopt(&ip6t_sockopts);
1422 xt_unregister_match(&icmp6_matchstruct);
1423 xt_unregister_target(&ip6t_error_target);
1424 xt_unregister_target(&ip6t_standard_target);
1425 xt_proto_fini(AF_INET6);
1429 * find the offset to specified header or the protocol number of last header
1430 * if target < 0. "last header" is transport protocol header, ESP, or
1431 * "No next header".
1433 * If target header is found, its offset is set in *offset and return protocol
1434 * number. Otherwise, return -1.
1436 * Note that non-1st fragment is special case that "the protocol number
1437 * of last header" is "next header" field in Fragment header. In this case,
1438 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1439 * isn't NULL.
1442 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1443 int target, unsigned short *fragoff)
1445 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1446 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1447 unsigned int len = skb->len - start;
1449 if (fragoff)
1450 *fragoff = 0;
1452 while (nexthdr != target) {
1453 struct ipv6_opt_hdr _hdr, *hp;
1454 unsigned int hdrlen;
1456 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1457 if (target < 0)
1458 break;
1459 return -1;
1462 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1463 if (hp == NULL)
1464 return -1;
1465 if (nexthdr == NEXTHDR_FRAGMENT) {
1466 unsigned short _frag_off, *fp;
1467 fp = skb_header_pointer(skb,
1468 start+offsetof(struct frag_hdr,
1469 frag_off),
1470 sizeof(_frag_off),
1471 &_frag_off);
1472 if (fp == NULL)
1473 return -1;
1475 _frag_off = ntohs(*fp) & ~0x7;
1476 if (_frag_off) {
1477 if (target < 0 &&
1478 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1479 nexthdr == NEXTHDR_NONE)) {
1480 if (fragoff)
1481 *fragoff = _frag_off;
1482 return hp->nexthdr;
1484 return -1;
1486 hdrlen = 8;
1487 } else if (nexthdr == NEXTHDR_AUTH)
1488 hdrlen = (hp->hdrlen + 2) << 2;
1489 else
1490 hdrlen = ipv6_optlen(hp);
1492 nexthdr = hp->nexthdr;
1493 len -= hdrlen;
1494 start += hdrlen;
1497 *offset = start;
1498 return nexthdr;
1501 EXPORT_SYMBOL(ip6t_register_table);
1502 EXPORT_SYMBOL(ip6t_unregister_table);
1503 EXPORT_SYMBOL(ip6t_do_table);
1504 EXPORT_SYMBOL(ip6t_ext_hdr);
1505 EXPORT_SYMBOL(ipv6_find_hdr);
1507 module_init(ip6_tables_init);
1508 module_exit(ip6_tables_fini);