2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2002 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
14 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
15 * - new extension header parser code
17 #include <linux/config.h>
18 #include <linux/skbuff.h>
19 #include <linux/kmod.h>
20 #include <linux/vmalloc.h>
21 #include <linux/netdevice.h>
22 #include <linux/module.h>
23 #include <linux/tcp.h>
24 #include <linux/udp.h>
25 #include <linux/icmpv6.h>
28 #include <asm/uaccess.h>
29 #include <asm/semaphore.h>
30 #include <linux/proc_fs.h>
32 #include <linux/netfilter_ipv6/ip6_tables.h>
34 MODULE_LICENSE("GPL");
35 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36 MODULE_DESCRIPTION("IPv6 packet filter");
38 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
39 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
41 /*#define DEBUG_IP_FIREWALL*/
42 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
43 /*#define DEBUG_IP_FIREWALL_USER*/
45 #ifdef DEBUG_IP_FIREWALL
46 #define dprintf(format, args...) printk(format , ## args)
48 #define dprintf(format, args...)
51 #ifdef DEBUG_IP_FIREWALL_USER
52 #define duprintf(format, args...) printk(format , ## args)
54 #define duprintf(format, args...)
57 #ifdef CONFIG_NETFILTER_DEBUG
58 #define IP_NF_ASSERT(x) \
61 printk("IP_NF_ASSERT: %s:%s:%u\n", \
62 __FUNCTION__, __FILE__, __LINE__); \
65 #define IP_NF_ASSERT(x)
67 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
69 static DECLARE_MUTEX(ip6t_mutex);
72 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
73 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
74 #include <linux/netfilter_ipv4/lockhelp.h>
75 #include <linux/netfilter_ipv4/listhelp.h>
78 /* All the better to debug you with... */
83 /* Locking is simple: we assume at worst case there will be one packet
84 in user context and one from bottom halves (or soft irq if Alexey's
85 softnet patch was applied).
87 We keep a set of rules for each CPU, so we can avoid write-locking
88 them; doing a readlock_bh() stops packets coming through if we're
91 To be cache friendly on SMP, we arrange them like so:
93 ... cache-align padding ...
96 Hence the start of any table is given by get_table() below. */
98 /* The table itself */
99 struct ip6t_table_info
103 /* Number of entries: FIXME. --RR */
105 /* Initial number of entries. Needed for module usage count */
106 unsigned int initial_entries;
108 /* Entry points and underflows */
109 unsigned int hook_entry[NF_IP6_NUMHOOKS];
110 unsigned int underflow[NF_IP6_NUMHOOKS];
112 /* ip6t_entry tables: one per CPU */
113 char entries[0] ____cacheline_aligned;
116 static LIST_HEAD(ip6t_target);
117 static LIST_HEAD(ip6t_match);
118 static LIST_HEAD(ip6t_tables);
119 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
122 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
124 #define TABLE_OFFSET(t,p) 0
128 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
129 #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; })
130 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
133 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
134 struct in6_addr addr2)
137 for( i = 0; i < 16; i++){
138 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
139 (addr2.s6_addr[i] & mask.s6_addr[i]))
145 /* Check for an extension */
147 ip6t_ext_hdr(u8 nexthdr)
149 return ( (nexthdr == IPPROTO_HOPOPTS) ||
150 (nexthdr == IPPROTO_ROUTING) ||
151 (nexthdr == IPPROTO_FRAGMENT) ||
152 (nexthdr == IPPROTO_ESP) ||
153 (nexthdr == IPPROTO_AH) ||
154 (nexthdr == IPPROTO_NONE) ||
155 (nexthdr == IPPROTO_DSTOPTS) );
158 /* Returns whether matches rule or not. */
160 ip6_packet_match(const struct sk_buff *skb,
163 const struct ip6t_ip6 *ip6info,
164 unsigned int *protoff,
169 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
171 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
173 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
175 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
177 dprintf("Source or dest mismatch.\n");
179 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
180 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
181 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
182 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
183 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
184 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
188 /* Look for ifname matches; this should unroll nicely. */
189 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
190 ret |= (((const unsigned long *)indev)[i]
191 ^ ((const unsigned long *)ip6info->iniface)[i])
192 & ((const unsigned long *)ip6info->iniface_mask)[i];
195 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
196 dprintf("VIA in mismatch (%s vs %s).%s\n",
197 indev, ip6info->iniface,
198 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
202 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
203 ret |= (((const unsigned long *)outdev)[i]
204 ^ ((const unsigned long *)ip6info->outiface)[i])
205 & ((const unsigned long *)ip6info->outiface_mask)[i];
208 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
209 dprintf("VIA out mismatch (%s vs %s).%s\n",
210 outdev, ip6info->outiface,
211 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
215 /* ... might want to do something with class and flowlabel here ... */
217 /* look for the desired protocol header */
218 if((ip6info->flags & IP6T_F_PROTO)) {
219 u_int8_t currenthdr = ipv6->nexthdr;
220 struct ipv6_opt_hdr _hdr, *hp;
221 u_int16_t ptr; /* Header offset in skb */
222 u_int16_t hdrlen; /* Header */
223 u_int16_t _fragoff = 0, *fp = NULL;
227 while (ip6t_ext_hdr(currenthdr)) {
228 /* Is there enough space for the next ext header? */
229 if (skb->len - ptr < IPV6_OPTHDR_LEN)
232 /* NONE or ESP: there isn't protocol part */
233 /* If we want to count these packets in '-p all',
234 * we will change the return 0 to 1*/
235 if ((currenthdr == IPPROTO_NONE) ||
236 (currenthdr == IPPROTO_ESP))
239 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
242 /* Size calculation */
243 if (currenthdr == IPPROTO_FRAGMENT) {
244 fp = skb_header_pointer(skb,
245 ptr+offsetof(struct frag_hdr,
252 _fragoff = ntohs(*fp) & ~0x7;
254 } else if (currenthdr == IPPROTO_AH)
255 hdrlen = (hp->hdrlen+2)<<2;
257 hdrlen = ipv6_optlen(hp);
259 currenthdr = hp->nexthdr;
261 /* ptr is too large */
262 if ( ptr > skb->len )
265 if (ip6t_ext_hdr(currenthdr))
274 /* currenthdr contains the protocol header */
276 dprintf("Packet protocol %hi ?= %s%hi.\n",
278 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
281 if (ip6info->proto == currenthdr) {
282 if(ip6info->invflags & IP6T_INV_PROTO) {
288 /* We need match for the '-p all', too! */
289 if ((ip6info->proto != 0) &&
290 !(ip6info->invflags & IP6T_INV_PROTO))
296 /* should be ip6 safe */
298 ip6_checkentry(const struct ip6t_ip6 *ipv6)
300 if (ipv6->flags & ~IP6T_F_MASK) {
301 duprintf("Unknown flag bits set: %08X\n",
302 ipv6->flags & ~IP6T_F_MASK);
305 if (ipv6->invflags & ~IP6T_INV_MASK) {
306 duprintf("Unknown invflag bits set: %08X\n",
307 ipv6->invflags & ~IP6T_INV_MASK);
314 ip6t_error(struct sk_buff **pskb,
315 const struct net_device *in,
316 const struct net_device *out,
317 unsigned int hooknum,
318 const void *targinfo,
322 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
328 int do_match(struct ip6t_entry_match *m,
329 const struct sk_buff *skb,
330 const struct net_device *in,
331 const struct net_device *out,
333 unsigned int protoff,
336 /* Stop iteration if it doesn't match */
337 if (!m->u.kernel.match->match(skb, in, out, m->data,
338 offset, protoff, hotdrop))
344 static inline struct ip6t_entry *
345 get_entry(void *base, unsigned int offset)
347 return (struct ip6t_entry *)(base + offset);
350 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
352 ip6t_do_table(struct sk_buff **pskb,
354 const struct net_device *in,
355 const struct net_device *out,
356 struct ip6t_table *table,
359 static const char nulldevname[IFNAMSIZ];
361 unsigned int protoff = 0;
363 /* Initializing verdict to NF_DROP keeps gcc happy. */
364 unsigned int verdict = NF_DROP;
365 const char *indev, *outdev;
367 struct ip6t_entry *e, *back;
369 /* FIXME: Push down to extensions --RR */
370 if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
374 indev = in ? in->name : nulldevname;
375 outdev = out ? out->name : nulldevname;
377 /* We handle fragments by dealing with the first fragment as
378 * if it was a normal packet. All other fragments are treated
379 * normally, except that they will NEVER match rules that ask
380 * things we don't know, ie. tcp syn flag or ports). If the
381 * rule is also a fragment-specific rule, non-fragments won't
384 read_lock_bh(&table->lock);
385 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
386 table_base = (void *)table->private->entries
387 + TABLE_OFFSET(table->private, smp_processor_id());
388 e = get_entry(table_base, table->private->hook_entry[hook]);
390 #ifdef CONFIG_NETFILTER_DEBUG
391 /* Check noone else using our table */
392 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
393 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
394 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
397 &((struct ip6t_entry *)table_base)->comefrom,
398 ((struct ip6t_entry *)table_base)->comefrom);
400 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
403 /* For return from builtin chain */
404 back = get_entry(table_base, table->private->underflow[hook]);
409 (*pskb)->nfcache |= e->nfcache;
410 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
411 &protoff, &offset)) {
412 struct ip6t_entry_target *t;
414 if (IP6T_MATCH_ITERATE(e, do_match,
416 offset, protoff, &hotdrop) != 0)
419 ADD_COUNTER(e->counters,
420 ntohs((*pskb)->nh.ipv6h->payload_len)
424 t = ip6t_get_target(e);
425 IP_NF_ASSERT(t->u.kernel.target);
426 /* Standard target? */
427 if (!t->u.kernel.target->target) {
430 v = ((struct ip6t_standard_target *)t)->verdict;
432 /* Pop from stack? */
433 if (v != IP6T_RETURN) {
434 verdict = (unsigned)(-v) - 1;
438 back = get_entry(table_base,
443 != (void *)e + e->next_offset) {
444 /* Save old back ptr in next entry */
445 struct ip6t_entry *next
446 = (void *)e + e->next_offset;
448 = (void *)back - table_base;
449 /* set back pointer to next entry */
453 e = get_entry(table_base, v);
455 /* Targets which reenter must return
457 #ifdef CONFIG_NETFILTER_DEBUG
458 ((struct ip6t_entry *)table_base)->comefrom
461 verdict = t->u.kernel.target->target(pskb,
467 #ifdef CONFIG_NETFILTER_DEBUG
468 if (((struct ip6t_entry *)table_base)->comefrom
470 && verdict == IP6T_CONTINUE) {
471 printk("Target %s reentered!\n",
472 t->u.kernel.target->name);
475 ((struct ip6t_entry *)table_base)->comefrom
478 if (verdict == IP6T_CONTINUE)
479 e = (void *)e + e->next_offset;
487 e = (void *)e + e->next_offset;
491 #ifdef CONFIG_NETFILTER_DEBUG
492 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
494 read_unlock_bh(&table->lock);
496 #ifdef DEBUG_ALLOW_ALL
505 /* If it succeeds, returns element and locks mutex */
507 find_inlist_lock_noload(struct list_head *head,
510 struct semaphore *mutex)
515 duprintf("find_inlist: searching for `%s' in %s.\n",
516 name, head == &ip6t_target ? "ip6t_target"
517 : head == &ip6t_match ? "ip6t_match"
518 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
521 *error = down_interruptible(mutex);
525 ret = list_named_find(head, name);
534 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
537 find_inlist_lock(struct list_head *head,
541 struct semaphore *mutex)
545 ret = find_inlist_lock_noload(head, name, error, mutex);
547 duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
548 request_module("%s%s", prefix, name);
549 ret = find_inlist_lock_noload(head, name, error, mutex);
556 static inline struct ip6t_table *
557 ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
559 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
562 static inline struct ip6t_match *
563 find_match_lock(const char *name, int *error, struct semaphore *mutex)
565 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
568 static struct ip6t_target *
569 ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
571 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
574 /* All zeroes == unconditional rule. */
576 unconditional(const struct ip6t_ip6 *ipv6)
580 for (i = 0; i < sizeof(*ipv6); i++)
581 if (((char *)ipv6)[i])
584 return (i == sizeof(*ipv6));
587 /* Figures out from what hook each rule can be called: returns 0 if
588 there are loops. Puts hook bitmask in comefrom. */
590 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
594 /* No recursion; use packet counter to save back ptrs (reset
595 to 0 as we leave), and comefrom to save source hook bitmask */
596 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
597 unsigned int pos = newinfo->hook_entry[hook];
599 = (struct ip6t_entry *)(newinfo->entries + pos);
601 if (!(valid_hooks & (1 << hook)))
604 /* Set initial back pointer. */
605 e->counters.pcnt = pos;
608 struct ip6t_standard_target *t
609 = (void *)ip6t_get_target(e);
611 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
612 printk("iptables: loop hook %u pos %u %08X.\n",
613 hook, pos, e->comefrom);
617 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
619 /* Unconditional return/END. */
620 if (e->target_offset == sizeof(struct ip6t_entry)
621 && (strcmp(t->target.u.user.name,
622 IP6T_STANDARD_TARGET) == 0)
624 && unconditional(&e->ipv6)) {
625 unsigned int oldpos, size;
627 /* Return: backtrack through the last
630 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
631 #ifdef DEBUG_IP_FIREWALL_USER
633 & (1 << NF_IP6_NUMHOOKS)) {
634 duprintf("Back unset "
641 pos = e->counters.pcnt;
642 e->counters.pcnt = 0;
644 /* We're at the start. */
648 e = (struct ip6t_entry *)
649 (newinfo->entries + pos);
650 } while (oldpos == pos + e->next_offset);
653 size = e->next_offset;
654 e = (struct ip6t_entry *)
655 (newinfo->entries + pos + size);
656 e->counters.pcnt = pos;
659 int newpos = t->verdict;
661 if (strcmp(t->target.u.user.name,
662 IP6T_STANDARD_TARGET) == 0
664 /* This a jump; chase it. */
665 duprintf("Jump rule %u -> %u\n",
668 /* ... this is a fallthru */
669 newpos = pos + e->next_offset;
671 e = (struct ip6t_entry *)
672 (newinfo->entries + newpos);
673 e->counters.pcnt = pos;
678 duprintf("Finished chain %u\n", hook);
684 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
686 if (i && (*i)-- == 0)
689 if (m->u.kernel.match->destroy)
690 m->u.kernel.match->destroy(m->data,
691 m->u.match_size - sizeof(*m));
692 module_put(m->u.kernel.match->me);
697 standard_check(const struct ip6t_entry_target *t,
698 unsigned int max_offset)
700 struct ip6t_standard_target *targ = (void *)t;
702 /* Check standard info. */
704 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
705 duprintf("standard_check: target size %u != %u\n",
707 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
711 if (targ->verdict >= 0
712 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
713 duprintf("ip6t_standard_check: bad verdict (%i)\n",
718 if (targ->verdict < -NF_MAX_VERDICT - 1) {
719 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
727 check_match(struct ip6t_entry_match *m,
729 const struct ip6t_ip6 *ipv6,
730 unsigned int hookmask,
734 struct ip6t_match *match;
736 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
738 // duprintf("check_match: `%s' not found\n", m->u.name);
741 if (!try_module_get(match->me)) {
745 m->u.kernel.match = match;
748 if (m->u.kernel.match->checkentry
749 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
750 m->u.match_size - sizeof(*m),
752 module_put(m->u.kernel.match->me);
753 duprintf("ip_tables: check failed for `%s'.\n",
754 m->u.kernel.match->name);
762 static struct ip6t_target ip6t_standard_target;
765 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
768 struct ip6t_entry_target *t;
769 struct ip6t_target *target;
773 if (!ip6_checkentry(&e->ipv6)) {
774 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
779 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
781 goto cleanup_matches;
783 t = ip6t_get_target(e);
784 target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
786 duprintf("check_entry: `%s' not found\n", t->u.user.name);
787 goto cleanup_matches;
789 if (!try_module_get(target->me)) {
792 goto cleanup_matches;
794 t->u.kernel.target = target;
796 if (!t->u.kernel.target) {
798 goto cleanup_matches;
800 if (t->u.kernel.target == &ip6t_standard_target) {
801 if (!standard_check(t, size)) {
803 goto cleanup_matches;
805 } else if (t->u.kernel.target->checkentry
806 && !t->u.kernel.target->checkentry(name, e, t->data,
810 module_put(t->u.kernel.target->me);
811 duprintf("ip_tables: check failed for `%s'.\n",
812 t->u.kernel.target->name);
814 goto cleanup_matches;
821 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
826 check_entry_size_and_hooks(struct ip6t_entry *e,
827 struct ip6t_table_info *newinfo,
829 unsigned char *limit,
830 const unsigned int *hook_entries,
831 const unsigned int *underflows,
836 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
837 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
838 duprintf("Bad offset %p\n", e);
843 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
844 duprintf("checking: element %p size %u\n",
849 /* Check hooks & underflows */
850 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
851 if ((unsigned char *)e - base == hook_entries[h])
852 newinfo->hook_entry[h] = hook_entries[h];
853 if ((unsigned char *)e - base == underflows[h])
854 newinfo->underflow[h] = underflows[h];
857 /* FIXME: underflows must be unconditional, standard verdicts
858 < 0 (not IP6T_RETURN). --RR */
860 /* Clear counters and comefrom */
861 e->counters = ((struct ip6t_counters) { 0, 0 });
869 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
871 struct ip6t_entry_target *t;
873 if (i && (*i)-- == 0)
876 /* Cleanup all matches */
877 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
878 t = ip6t_get_target(e);
879 if (t->u.kernel.target->destroy)
880 t->u.kernel.target->destroy(t->data,
881 t->u.target_size - sizeof(*t));
882 module_put(t->u.kernel.target->me);
886 /* Checks and translates the user-supplied table segment (held in
889 translate_table(const char *name,
890 unsigned int valid_hooks,
891 struct ip6t_table_info *newinfo,
894 const unsigned int *hook_entries,
895 const unsigned int *underflows)
900 newinfo->size = size;
901 newinfo->number = number;
903 /* Init all hooks to impossible value. */
904 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
905 newinfo->hook_entry[i] = 0xFFFFFFFF;
906 newinfo->underflow[i] = 0xFFFFFFFF;
909 duprintf("translate_table: size %u\n", newinfo->size);
911 /* Walk through entries, checking offsets. */
912 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
913 check_entry_size_and_hooks,
916 newinfo->entries + size,
917 hook_entries, underflows, &i);
922 duprintf("translate_table: %u not %u entries\n",
927 /* Check hooks all assigned */
928 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
929 /* Only hooks which are valid */
930 if (!(valid_hooks & (1 << i)))
932 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
933 duprintf("Invalid hook entry %u %u\n",
937 if (newinfo->underflow[i] == 0xFFFFFFFF) {
938 duprintf("Invalid underflow %u %u\n",
944 if (!mark_source_chains(newinfo, valid_hooks))
947 /* Finally, each sanity check must pass */
949 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
950 check_entry, name, size, &i);
953 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
958 /* And one copy for every other CPU */
959 for (i = 1; i < NR_CPUS; i++) {
960 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
962 SMP_ALIGN(newinfo->size));
968 static struct ip6t_table_info *
969 replace_table(struct ip6t_table *table,
970 unsigned int num_counters,
971 struct ip6t_table_info *newinfo,
974 struct ip6t_table_info *oldinfo;
976 #ifdef CONFIG_NETFILTER_DEBUG
978 struct ip6t_entry *table_base;
981 for (i = 0; i < NR_CPUS; i++) {
983 (void *)newinfo->entries
984 + TABLE_OFFSET(newinfo, i);
986 table_base->comefrom = 0xdead57ac;
991 /* Do the substitution. */
992 write_lock_bh(&table->lock);
993 /* Check inside lock: is the old number correct? */
994 if (num_counters != table->private->number) {
995 duprintf("num_counters != table->private->number (%u/%u)\n",
996 num_counters, table->private->number);
997 write_unlock_bh(&table->lock);
1001 oldinfo = table->private;
1002 table->private = newinfo;
1003 newinfo->initial_entries = oldinfo->initial_entries;
1004 write_unlock_bh(&table->lock);
1009 /* Gets counters. */
1011 add_entry_to_counter(const struct ip6t_entry *e,
1012 struct ip6t_counters total[],
1015 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1022 get_counters(const struct ip6t_table_info *t,
1023 struct ip6t_counters counters[])
1028 for (cpu = 0; cpu < NR_CPUS; cpu++) {
1030 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1032 add_entry_to_counter,
1039 copy_entries_to_user(unsigned int total_size,
1040 struct ip6t_table *table,
1041 void __user *userptr)
1043 unsigned int off, num, countersize;
1044 struct ip6t_entry *e;
1045 struct ip6t_counters *counters;
1048 /* We need atomic snapshot of counters: rest doesn't change
1049 (other than comefrom, which userspace doesn't care
1051 countersize = sizeof(struct ip6t_counters) * table->private->number;
1052 counters = vmalloc(countersize);
1054 if (counters == NULL)
1057 /* First, sum counters... */
1058 memset(counters, 0, countersize);
1059 write_lock_bh(&table->lock);
1060 get_counters(table->private, counters);
1061 write_unlock_bh(&table->lock);
1063 /* ... then copy entire thing from CPU 0... */
1064 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1069 /* FIXME: use iterator macros --RR */
1070 /* ... then go back and fix counters and names */
1071 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1073 struct ip6t_entry_match *m;
1074 struct ip6t_entry_target *t;
1076 e = (struct ip6t_entry *)(table->private->entries + off);
1077 if (copy_to_user(userptr + off
1078 + offsetof(struct ip6t_entry, counters),
1080 sizeof(counters[num])) != 0) {
1085 for (i = sizeof(struct ip6t_entry);
1086 i < e->target_offset;
1087 i += m->u.match_size) {
1090 if (copy_to_user(userptr + off + i
1091 + offsetof(struct ip6t_entry_match,
1093 m->u.kernel.match->name,
1094 strlen(m->u.kernel.match->name)+1)
1101 t = ip6t_get_target(e);
1102 if (copy_to_user(userptr + off + e->target_offset
1103 + offsetof(struct ip6t_entry_target,
1105 t->u.kernel.target->name,
1106 strlen(t->u.kernel.target->name)+1) != 0) {
1118 get_entries(const struct ip6t_get_entries *entries,
1119 struct ip6t_get_entries __user *uptr)
1122 struct ip6t_table *t;
1124 t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1126 duprintf("t->private->number = %u\n",
1127 t->private->number);
1128 if (entries->size == t->private->size)
1129 ret = copy_entries_to_user(t->private->size,
1130 t, uptr->entrytable);
1132 duprintf("get_entries: I've got %u not %u!\n",
1139 duprintf("get_entries: Can't find %s!\n",
1146 do_replace(void __user *user, unsigned int len)
1149 struct ip6t_replace tmp;
1150 struct ip6t_table *t;
1151 struct ip6t_table_info *newinfo, *oldinfo;
1152 struct ip6t_counters *counters;
1154 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1157 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1158 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1161 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1162 + SMP_ALIGN(tmp.size) * NR_CPUS);
1166 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1172 if(tmp.num_counters >= (4 << 20)/sizeof(struct ip6t_counters)) {
1177 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1182 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1184 ret = translate_table(tmp.name, tmp.valid_hooks,
1185 newinfo, tmp.size, tmp.num_entries,
1186 tmp.hook_entry, tmp.underflow);
1188 goto free_newinfo_counters;
1190 duprintf("ip_tables: Translated table\n");
1192 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1194 goto free_newinfo_counters_untrans;
1197 if (tmp.valid_hooks != t->valid_hooks) {
1198 duprintf("Valid hook crap: %08X vs %08X\n",
1199 tmp.valid_hooks, t->valid_hooks);
1201 goto free_newinfo_counters_untrans_unlock;
1204 /* Get a reference in advance, we're not allowed fail later */
1205 if (!try_module_get(t->me)) {
1207 goto free_newinfo_counters_untrans_unlock;
1210 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1214 /* Update module usage count based on number of rules */
1215 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1216 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1217 if ((oldinfo->number > oldinfo->initial_entries) ||
1218 (newinfo->number <= oldinfo->initial_entries))
1220 if ((oldinfo->number > oldinfo->initial_entries) &&
1221 (newinfo->number <= oldinfo->initial_entries))
1224 /* Get the old counters. */
1225 get_counters(oldinfo, counters);
1226 /* Decrease module usage counts and free resource */
1227 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1229 /* Silent error: too late now. */
1230 copy_to_user(tmp.counters, counters,
1231 sizeof(struct ip6t_counters) * tmp.num_counters);
1238 free_newinfo_counters_untrans_unlock:
1240 free_newinfo_counters_untrans:
1241 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1242 free_newinfo_counters:
1249 /* We're lazy, and add to the first CPU; overflow works its fey magic
1250 * and everything is OK. */
1252 add_counter_to_entry(struct ip6t_entry *e,
1253 const struct ip6t_counters addme[],
1257 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1259 (long unsigned int)e->counters.pcnt,
1260 (long unsigned int)e->counters.bcnt,
1261 (long unsigned int)addme[*i].pcnt,
1262 (long unsigned int)addme[*i].bcnt);
1265 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1272 do_add_counters(void __user *user, unsigned int len)
1275 struct ip6t_counters_info tmp, *paddc;
1276 struct ip6t_table *t;
1279 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1282 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1285 paddc = vmalloc(len);
1289 if (copy_from_user(paddc, user, len) != 0) {
1294 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1298 write_lock_bh(&t->lock);
1299 if (t->private->number != paddc->num_counters) {
1301 goto unlock_up_free;
1305 IP6T_ENTRY_ITERATE(t->private->entries,
1307 add_counter_to_entry,
1311 write_unlock_bh(&t->lock);
1320 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1324 if (!capable(CAP_NET_ADMIN))
1328 case IP6T_SO_SET_REPLACE:
1329 ret = do_replace(user, len);
1332 case IP6T_SO_SET_ADD_COUNTERS:
1333 ret = do_add_counters(user, len);
1337 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1345 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1349 if (!capable(CAP_NET_ADMIN))
1353 case IP6T_SO_GET_INFO: {
1354 char name[IP6T_TABLE_MAXNAMELEN];
1355 struct ip6t_table *t;
1357 if (*len != sizeof(struct ip6t_getinfo)) {
1358 duprintf("length %u != %u\n", *len,
1359 sizeof(struct ip6t_getinfo));
1364 if (copy_from_user(name, user, sizeof(name)) != 0) {
1368 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1369 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1371 struct ip6t_getinfo info;
1373 info.valid_hooks = t->valid_hooks;
1374 memcpy(info.hook_entry, t->private->hook_entry,
1375 sizeof(info.hook_entry));
1376 memcpy(info.underflow, t->private->underflow,
1377 sizeof(info.underflow));
1378 info.num_entries = t->private->number;
1379 info.size = t->private->size;
1380 memcpy(info.name, name, sizeof(info.name));
1382 if (copy_to_user(user, &info, *len) != 0)
1392 case IP6T_SO_GET_ENTRIES: {
1393 struct ip6t_get_entries get;
1395 if (*len < sizeof(get)) {
1396 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1398 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1400 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1401 duprintf("get_entries: %u != %u\n", *len,
1402 sizeof(struct ip6t_get_entries) + get.size);
1405 ret = get_entries(&get, user);
1410 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1417 /* Registration hooks for targets. */
1419 ip6t_register_target(struct ip6t_target *target)
1423 ret = down_interruptible(&ip6t_mutex);
1427 if (!list_named_insert(&ip6t_target, target)) {
1428 duprintf("ip6t_register_target: `%s' already in list!\n",
1437 ip6t_unregister_target(struct ip6t_target *target)
1440 LIST_DELETE(&ip6t_target, target);
1445 ip6t_register_match(struct ip6t_match *match)
1449 ret = down_interruptible(&ip6t_mutex);
1453 if (!list_named_insert(&ip6t_match, match)) {
1454 duprintf("ip6t_register_match: `%s' already in list!\n",
1464 ip6t_unregister_match(struct ip6t_match *match)
1467 LIST_DELETE(&ip6t_match, match);
1471 int ip6t_register_table(struct ip6t_table *table)
1474 struct ip6t_table_info *newinfo;
1475 static struct ip6t_table_info bootstrap
1476 = { 0, 0, 0, { 0 }, { 0 }, { } };
1478 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1479 + SMP_ALIGN(table->table->size) * NR_CPUS);
1483 memcpy(newinfo->entries, table->table->entries, table->table->size);
1485 ret = translate_table(table->name, table->valid_hooks,
1486 newinfo, table->table->size,
1487 table->table->num_entries,
1488 table->table->hook_entry,
1489 table->table->underflow);
1495 ret = down_interruptible(&ip6t_mutex);
1501 /* Don't autoload: we'd eat our tail... */
1502 if (list_named_find(&ip6t_tables, table->name)) {
1507 /* Simplifies replace_table code. */
1508 table->private = &bootstrap;
1509 if (!replace_table(table, 0, newinfo, &ret))
1512 duprintf("table->private->number = %u\n",
1513 table->private->number);
1515 /* save number of initial entries */
1516 table->private->initial_entries = table->private->number;
1518 rwlock_init(&table->lock);
1519 list_prepend(&ip6t_tables, table);
1530 void ip6t_unregister_table(struct ip6t_table *table)
1533 LIST_DELETE(&ip6t_tables, table);
1536 /* Decrease module usage counts and free resources */
1537 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1538 cleanup_entry, NULL);
1539 vfree(table->private);
1542 /* Returns 1 if the port is matched by the range, 0 otherwise */
1544 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1548 ret = (port >= min && port <= max) ^ invert;
1553 tcp_find_option(u_int8_t option,
1554 const struct sk_buff *skb,
1555 unsigned int tcpoff,
1556 unsigned int optlen,
1560 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1561 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1564 duprintf("tcp_match: finding option\n");
1567 /* If we don't have the whole header, drop packet. */
1568 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1575 for (i = 0; i < optlen; ) {
1576 if (op[i] == option) return !invert;
1578 else i += op[i+1]?:1;
1585 tcp_match(const struct sk_buff *skb,
1586 const struct net_device *in,
1587 const struct net_device *out,
1588 const void *matchinfo,
1590 unsigned int protoff,
1593 struct tcphdr _tcph, *th;
1594 const struct ip6t_tcp *tcpinfo = matchinfo;
1599 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1600 causes this. Its a cracker trying to break in by doing a
1601 flag overwrite to pass the direction checks.
1604 duprintf("Dropping evil TCP offset=1 frag.\n");
1607 /* Must not be a fragment. */
1611 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1613 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1615 /* We've been asked to examine this packet, and we
1616 can't. Hence, no choice but to drop. */
1617 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1622 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1624 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1626 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1628 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1630 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1631 == tcpinfo->flg_cmp,
1632 IP6T_TCP_INV_FLAGS))
1634 if (tcpinfo->option) {
1635 if (th->doff * 4 < sizeof(_tcph)) {
1639 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1640 th->doff*4 - sizeof(*th),
1641 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1648 /* Called when user tries to insert an entry of this type. */
1650 tcp_checkentry(const char *tablename,
1651 const struct ip6t_ip6 *ipv6,
1653 unsigned int matchsize,
1654 unsigned int hook_mask)
1656 const struct ip6t_tcp *tcpinfo = matchinfo;
1658 /* Must specify proto == TCP, and no unknown invflags */
1659 return ipv6->proto == IPPROTO_TCP
1660 && !(ipv6->invflags & IP6T_INV_PROTO)
1661 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1662 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1666 udp_match(const struct sk_buff *skb,
1667 const struct net_device *in,
1668 const struct net_device *out,
1669 const void *matchinfo,
1671 unsigned int protoff,
1674 struct udphdr _udph, *uh;
1675 const struct ip6t_udp *udpinfo = matchinfo;
1677 /* Must not be a fragment. */
1681 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1683 /* We've been asked to examine this packet, and we
1684 can't. Hence, no choice but to drop. */
1685 duprintf("Dropping evil UDP tinygram.\n");
1690 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1692 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1693 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1695 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1698 /* Called when user tries to insert an entry of this type. */
1700 udp_checkentry(const char *tablename,
1701 const struct ip6t_ip6 *ipv6,
1703 unsigned int matchinfosize,
1704 unsigned int hook_mask)
1706 const struct ip6t_udp *udpinfo = matchinfo;
1708 /* Must specify proto == UDP, and no unknown invflags */
1709 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1710 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1714 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1715 duprintf("ip6t_udp: matchsize %u != %u\n",
1716 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1719 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1720 duprintf("ip6t_udp: unknown flags %X\n",
1728 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1730 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1731 u_int8_t type, u_int8_t code,
1734 return (type == test_type && code >= min_code && code <= max_code)
1739 icmp6_match(const struct sk_buff *skb,
1740 const struct net_device *in,
1741 const struct net_device *out,
1742 const void *matchinfo,
1744 unsigned int protoff,
1747 struct icmp6hdr _icmp, *ic;
1748 const struct ip6t_icmp *icmpinfo = matchinfo;
1750 /* Must not be a fragment. */
1754 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1756 /* We've been asked to examine this packet, and we
1757 can't. Hence, no choice but to drop. */
1758 duprintf("Dropping evil ICMP tinygram.\n");
1763 return icmp6_type_code_match(icmpinfo->type,
1766 ic->icmp6_type, ic->icmp6_code,
1767 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1770 /* Called when user tries to insert an entry of this type. */
1772 icmp6_checkentry(const char *tablename,
1773 const struct ip6t_ip6 *ipv6,
1775 unsigned int matchsize,
1776 unsigned int hook_mask)
1778 const struct ip6t_icmp *icmpinfo = matchinfo;
1780 /* Must specify proto == ICMP, and no unknown invflags */
1781 return ipv6->proto == IPPROTO_ICMPV6
1782 && !(ipv6->invflags & IP6T_INV_PROTO)
1783 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1784 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1787 /* The built-in targets: standard (NULL) and error. */
1788 static struct ip6t_target ip6t_standard_target = {
1789 .name = IP6T_STANDARD_TARGET,
1792 static struct ip6t_target ip6t_error_target = {
1793 .name = IP6T_ERROR_TARGET,
1794 .target = ip6t_error,
1797 static struct nf_sockopt_ops ip6t_sockopts = {
1799 .set_optmin = IP6T_BASE_CTL,
1800 .set_optmax = IP6T_SO_SET_MAX+1,
1801 .set = do_ip6t_set_ctl,
1802 .get_optmin = IP6T_BASE_CTL,
1803 .get_optmax = IP6T_SO_GET_MAX+1,
1804 .get = do_ip6t_get_ctl,
1807 static struct ip6t_match tcp_matchstruct = {
1809 .match = &tcp_match,
1810 .checkentry = &tcp_checkentry,
1813 static struct ip6t_match udp_matchstruct = {
1815 .match = &udp_match,
1816 .checkentry = &udp_checkentry,
1819 static struct ip6t_match icmp6_matchstruct = {
1821 .match = &icmp6_match,
1822 .checkentry = &icmp6_checkentry,
1825 #ifdef CONFIG_PROC_FS
1826 static inline int print_name(const char *i,
1827 off_t start_offset, char *buffer, int length,
1828 off_t *pos, unsigned int *count)
1830 if ((*count)++ >= start_offset) {
1831 unsigned int namelen;
1833 namelen = sprintf(buffer + *pos, "%s\n",
1834 i + sizeof(struct list_head));
1835 if (*pos + namelen > length) {
1836 /* Stop iterating */
1844 static inline int print_target(const struct ip6t_target *t,
1845 off_t start_offset, char *buffer, int length,
1846 off_t *pos, unsigned int *count)
1848 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1850 return print_name((char *)t, start_offset, buffer, length, pos, count);
1853 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1856 unsigned int count = 0;
1858 if (down_interruptible(&ip6t_mutex) != 0)
1861 LIST_FIND(&ip6t_tables, print_name, char *,
1862 offset, buffer, length, &pos, &count);
1866 /* `start' hack - see fs/proc/generic.c line ~105 */
1867 *start=(char *)((unsigned long)count-offset);
1871 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1874 unsigned int count = 0;
1876 if (down_interruptible(&ip6t_mutex) != 0)
1879 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1880 offset, buffer, length, &pos, &count);
1884 *start = (char *)((unsigned long)count - offset);
1888 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1891 unsigned int count = 0;
1893 if (down_interruptible(&ip6t_mutex) != 0)
1896 LIST_FIND(&ip6t_match, print_name, char *,
1897 offset, buffer, length, &pos, &count);
1901 *start = (char *)((unsigned long)count - offset);
1905 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1906 { { "ip6_tables_names", ip6t_get_tables },
1907 { "ip6_tables_targets", ip6t_get_targets },
1908 { "ip6_tables_matches", ip6t_get_matches },
1910 #endif /*CONFIG_PROC_FS*/
1912 static int __init init(void)
1916 /* Noone else will be downing sem now, so we won't sleep */
1918 list_append(&ip6t_target, &ip6t_standard_target);
1919 list_append(&ip6t_target, &ip6t_error_target);
1920 list_append(&ip6t_match, &tcp_matchstruct);
1921 list_append(&ip6t_match, &udp_matchstruct);
1922 list_append(&ip6t_match, &icmp6_matchstruct);
1925 /* Register setsockopt */
1926 ret = nf_register_sockopt(&ip6t_sockopts);
1928 duprintf("Unable to register sockopts.\n");
1932 #ifdef CONFIG_PROC_FS
1934 struct proc_dir_entry *proc;
1937 for (i = 0; ip6t_proc_entry[i].name; i++) {
1938 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1939 ip6t_proc_entry[i].get_info);
1942 proc_net_remove(ip6t_proc_entry[i].name);
1943 nf_unregister_sockopt(&ip6t_sockopts);
1946 proc->owner = THIS_MODULE;
1951 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1955 static void __exit fini(void)
1957 nf_unregister_sockopt(&ip6t_sockopts);
1958 #ifdef CONFIG_PROC_FS
1961 for (i = 0; ip6t_proc_entry[i].name; i++)
1962 proc_net_remove(ip6t_proc_entry[i].name);
1967 EXPORT_SYMBOL(ip6t_register_table);
1968 EXPORT_SYMBOL(ip6t_unregister_table);
1969 EXPORT_SYMBOL(ip6t_do_table);
1970 EXPORT_SYMBOL(ip6t_register_match);
1971 EXPORT_SYMBOL(ip6t_unregister_match);
1972 EXPORT_SYMBOL(ip6t_register_target);
1973 EXPORT_SYMBOL(ip6t_unregister_target);
1974 EXPORT_SYMBOL(ip6t_ext_hdr);