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>
31 #include <linux/cpumask.h>
33 #include <linux/netfilter_ipv6/ip6_tables.h>
35 MODULE_LICENSE("GPL");
36 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
37 MODULE_DESCRIPTION("IPv6 packet filter");
39 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
40 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
42 /*#define DEBUG_IP_FIREWALL*/
43 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
44 /*#define DEBUG_IP_FIREWALL_USER*/
46 #ifdef DEBUG_IP_FIREWALL
47 #define dprintf(format, args...) printk(format , ## args)
49 #define dprintf(format, args...)
52 #ifdef DEBUG_IP_FIREWALL_USER
53 #define duprintf(format, args...) printk(format , ## args)
55 #define duprintf(format, args...)
58 #ifdef CONFIG_NETFILTER_DEBUG
59 #define IP_NF_ASSERT(x) \
62 printk("IP_NF_ASSERT: %s:%s:%u\n", \
63 __FUNCTION__, __FILE__, __LINE__); \
66 #define IP_NF_ASSERT(x)
68 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
70 static DECLARE_MUTEX(ip6t_mutex);
73 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
74 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
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;
370 indev = in ? in->name : nulldevname;
371 outdev = out ? out->name : nulldevname;
373 /* We handle fragments by dealing with the first fragment as
374 * if it was a normal packet. All other fragments are treated
375 * normally, except that they will NEVER match rules that ask
376 * things we don't know, ie. tcp syn flag or ports). If the
377 * rule is also a fragment-specific rule, non-fragments won't
380 read_lock_bh(&table->lock);
381 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
382 table_base = (void *)table->private->entries
383 + TABLE_OFFSET(table->private, smp_processor_id());
384 e = get_entry(table_base, table->private->hook_entry[hook]);
386 #ifdef CONFIG_NETFILTER_DEBUG
387 /* Check noone else using our table */
388 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
389 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
390 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
393 &((struct ip6t_entry *)table_base)->comefrom,
394 ((struct ip6t_entry *)table_base)->comefrom);
396 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
399 /* For return from builtin chain */
400 back = get_entry(table_base, table->private->underflow[hook]);
405 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
406 &protoff, &offset)) {
407 struct ip6t_entry_target *t;
409 if (IP6T_MATCH_ITERATE(e, do_match,
411 offset, protoff, &hotdrop) != 0)
414 ADD_COUNTER(e->counters,
415 ntohs((*pskb)->nh.ipv6h->payload_len)
419 t = ip6t_get_target(e);
420 IP_NF_ASSERT(t->u.kernel.target);
421 /* Standard target? */
422 if (!t->u.kernel.target->target) {
425 v = ((struct ip6t_standard_target *)t)->verdict;
427 /* Pop from stack? */
428 if (v != IP6T_RETURN) {
429 verdict = (unsigned)(-v) - 1;
433 back = get_entry(table_base,
437 if (table_base + v != (void *)e + e->next_offset
438 && !(e->ipv6.flags & IP6T_F_GOTO)) {
439 /* Save old back ptr in next entry */
440 struct ip6t_entry *next
441 = (void *)e + e->next_offset;
443 = (void *)back - table_base;
444 /* set back pointer to next entry */
448 e = get_entry(table_base, v);
450 /* Targets which reenter must return
452 #ifdef CONFIG_NETFILTER_DEBUG
453 ((struct ip6t_entry *)table_base)->comefrom
456 verdict = t->u.kernel.target->target(pskb,
462 #ifdef CONFIG_NETFILTER_DEBUG
463 if (((struct ip6t_entry *)table_base)->comefrom
465 && verdict == IP6T_CONTINUE) {
466 printk("Target %s reentered!\n",
467 t->u.kernel.target->name);
470 ((struct ip6t_entry *)table_base)->comefrom
473 if (verdict == IP6T_CONTINUE)
474 e = (void *)e + e->next_offset;
482 e = (void *)e + e->next_offset;
486 #ifdef CONFIG_NETFILTER_DEBUG
487 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
489 read_unlock_bh(&table->lock);
491 #ifdef DEBUG_ALLOW_ALL
500 /* If it succeeds, returns element and locks mutex */
502 find_inlist_lock_noload(struct list_head *head,
505 struct semaphore *mutex)
510 duprintf("find_inlist: searching for `%s' in %s.\n",
511 name, head == &ip6t_target ? "ip6t_target"
512 : head == &ip6t_match ? "ip6t_match"
513 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
516 *error = down_interruptible(mutex);
520 ret = list_named_find(head, name);
529 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
532 find_inlist_lock(struct list_head *head,
536 struct semaphore *mutex)
540 ret = find_inlist_lock_noload(head, name, error, mutex);
542 duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
543 request_module("%s%s", prefix, name);
544 ret = find_inlist_lock_noload(head, name, error, mutex);
551 static inline struct ip6t_table *
552 ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
554 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
557 static inline struct ip6t_match *
558 find_match_lock(const char *name, int *error, struct semaphore *mutex)
560 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
563 static struct ip6t_target *
564 ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
566 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
569 /* All zeroes == unconditional rule. */
571 unconditional(const struct ip6t_ip6 *ipv6)
575 for (i = 0; i < sizeof(*ipv6); i++)
576 if (((char *)ipv6)[i])
579 return (i == sizeof(*ipv6));
582 /* Figures out from what hook each rule can be called: returns 0 if
583 there are loops. Puts hook bitmask in comefrom. */
585 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
589 /* No recursion; use packet counter to save back ptrs (reset
590 to 0 as we leave), and comefrom to save source hook bitmask */
591 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
592 unsigned int pos = newinfo->hook_entry[hook];
594 = (struct ip6t_entry *)(newinfo->entries + pos);
596 if (!(valid_hooks & (1 << hook)))
599 /* Set initial back pointer. */
600 e->counters.pcnt = pos;
603 struct ip6t_standard_target *t
604 = (void *)ip6t_get_target(e);
606 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
607 printk("iptables: loop hook %u pos %u %08X.\n",
608 hook, pos, e->comefrom);
612 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
614 /* Unconditional return/END. */
615 if (e->target_offset == sizeof(struct ip6t_entry)
616 && (strcmp(t->target.u.user.name,
617 IP6T_STANDARD_TARGET) == 0)
619 && unconditional(&e->ipv6)) {
620 unsigned int oldpos, size;
622 /* Return: backtrack through the last
625 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
626 #ifdef DEBUG_IP_FIREWALL_USER
628 & (1 << NF_IP6_NUMHOOKS)) {
629 duprintf("Back unset "
636 pos = e->counters.pcnt;
637 e->counters.pcnt = 0;
639 /* We're at the start. */
643 e = (struct ip6t_entry *)
644 (newinfo->entries + pos);
645 } while (oldpos == pos + e->next_offset);
648 size = e->next_offset;
649 e = (struct ip6t_entry *)
650 (newinfo->entries + pos + size);
651 e->counters.pcnt = pos;
654 int newpos = t->verdict;
656 if (strcmp(t->target.u.user.name,
657 IP6T_STANDARD_TARGET) == 0
659 /* This a jump; chase it. */
660 duprintf("Jump rule %u -> %u\n",
663 /* ... this is a fallthru */
664 newpos = pos + e->next_offset;
666 e = (struct ip6t_entry *)
667 (newinfo->entries + newpos);
668 e->counters.pcnt = pos;
673 duprintf("Finished chain %u\n", hook);
679 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
681 if (i && (*i)-- == 0)
684 if (m->u.kernel.match->destroy)
685 m->u.kernel.match->destroy(m->data,
686 m->u.match_size - sizeof(*m));
687 module_put(m->u.kernel.match->me);
692 standard_check(const struct ip6t_entry_target *t,
693 unsigned int max_offset)
695 struct ip6t_standard_target *targ = (void *)t;
697 /* Check standard info. */
699 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
700 duprintf("standard_check: target size %u != %u\n",
702 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
706 if (targ->verdict >= 0
707 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
708 duprintf("ip6t_standard_check: bad verdict (%i)\n",
713 if (targ->verdict < -NF_MAX_VERDICT - 1) {
714 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
722 check_match(struct ip6t_entry_match *m,
724 const struct ip6t_ip6 *ipv6,
725 unsigned int hookmask,
729 struct ip6t_match *match;
731 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
733 // duprintf("check_match: `%s' not found\n", m->u.name);
736 if (!try_module_get(match->me)) {
740 m->u.kernel.match = match;
743 if (m->u.kernel.match->checkentry
744 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
745 m->u.match_size - sizeof(*m),
747 module_put(m->u.kernel.match->me);
748 duprintf("ip_tables: check failed for `%s'.\n",
749 m->u.kernel.match->name);
757 static struct ip6t_target ip6t_standard_target;
760 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
763 struct ip6t_entry_target *t;
764 struct ip6t_target *target;
768 if (!ip6_checkentry(&e->ipv6)) {
769 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
774 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
776 goto cleanup_matches;
778 t = ip6t_get_target(e);
779 target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
781 duprintf("check_entry: `%s' not found\n", t->u.user.name);
782 goto cleanup_matches;
784 if (!try_module_get(target->me)) {
787 goto cleanup_matches;
789 t->u.kernel.target = target;
791 if (!t->u.kernel.target) {
793 goto cleanup_matches;
795 if (t->u.kernel.target == &ip6t_standard_target) {
796 if (!standard_check(t, size)) {
798 goto cleanup_matches;
800 } else if (t->u.kernel.target->checkentry
801 && !t->u.kernel.target->checkentry(name, e, t->data,
805 module_put(t->u.kernel.target->me);
806 duprintf("ip_tables: check failed for `%s'.\n",
807 t->u.kernel.target->name);
809 goto cleanup_matches;
816 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
821 check_entry_size_and_hooks(struct ip6t_entry *e,
822 struct ip6t_table_info *newinfo,
824 unsigned char *limit,
825 const unsigned int *hook_entries,
826 const unsigned int *underflows,
831 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
832 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
833 duprintf("Bad offset %p\n", e);
838 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
839 duprintf("checking: element %p size %u\n",
844 /* Check hooks & underflows */
845 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
846 if ((unsigned char *)e - base == hook_entries[h])
847 newinfo->hook_entry[h] = hook_entries[h];
848 if ((unsigned char *)e - base == underflows[h])
849 newinfo->underflow[h] = underflows[h];
852 /* FIXME: underflows must be unconditional, standard verdicts
853 < 0 (not IP6T_RETURN). --RR */
855 /* Clear counters and comefrom */
856 e->counters = ((struct ip6t_counters) { 0, 0 });
864 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
866 struct ip6t_entry_target *t;
868 if (i && (*i)-- == 0)
871 /* Cleanup all matches */
872 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
873 t = ip6t_get_target(e);
874 if (t->u.kernel.target->destroy)
875 t->u.kernel.target->destroy(t->data,
876 t->u.target_size - sizeof(*t));
877 module_put(t->u.kernel.target->me);
881 /* Checks and translates the user-supplied table segment (held in
884 translate_table(const char *name,
885 unsigned int valid_hooks,
886 struct ip6t_table_info *newinfo,
889 const unsigned int *hook_entries,
890 const unsigned int *underflows)
895 newinfo->size = size;
896 newinfo->number = number;
898 /* Init all hooks to impossible value. */
899 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
900 newinfo->hook_entry[i] = 0xFFFFFFFF;
901 newinfo->underflow[i] = 0xFFFFFFFF;
904 duprintf("translate_table: size %u\n", newinfo->size);
906 /* Walk through entries, checking offsets. */
907 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
908 check_entry_size_and_hooks,
911 newinfo->entries + size,
912 hook_entries, underflows, &i);
917 duprintf("translate_table: %u not %u entries\n",
922 /* Check hooks all assigned */
923 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
924 /* Only hooks which are valid */
925 if (!(valid_hooks & (1 << i)))
927 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
928 duprintf("Invalid hook entry %u %u\n",
932 if (newinfo->underflow[i] == 0xFFFFFFFF) {
933 duprintf("Invalid underflow %u %u\n",
939 if (!mark_source_chains(newinfo, valid_hooks))
942 /* Finally, each sanity check must pass */
944 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
945 check_entry, name, size, &i);
948 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
953 /* And one copy for every other CPU */
957 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size) * i,
959 SMP_ALIGN(newinfo->size));
965 static struct ip6t_table_info *
966 replace_table(struct ip6t_table *table,
967 unsigned int num_counters,
968 struct ip6t_table_info *newinfo,
971 struct ip6t_table_info *oldinfo;
973 #ifdef CONFIG_NETFILTER_DEBUG
975 struct ip6t_entry *table_base;
978 for (i = 0; i < num_possible_cpus(); i++) {
981 (void *)newinfo->entries
982 + TABLE_OFFSET(newinfo, i);
984 table_base->comefrom = 0xdead57ac;
989 /* Do the substitution. */
990 write_lock_bh(&table->lock);
991 /* Check inside lock: is the old number correct? */
992 if (num_counters != table->private->number) {
993 duprintf("num_counters != table->private->number (%u/%u)\n",
994 num_counters, table->private->number);
995 write_unlock_bh(&table->lock);
999 oldinfo = table->private;
1000 table->private = newinfo;
1001 newinfo->initial_entries = oldinfo->initial_entries;
1002 write_unlock_bh(&table->lock);
1007 /* Gets counters. */
1009 add_entry_to_counter(const struct ip6t_entry *e,
1010 struct ip6t_counters total[],
1013 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1020 get_counters(const struct ip6t_table_info *t,
1021 struct ip6t_counters counters[])
1028 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1030 add_entry_to_counter,
1037 copy_entries_to_user(unsigned int total_size,
1038 struct ip6t_table *table,
1039 void __user *userptr)
1041 unsigned int off, num, countersize;
1042 struct ip6t_entry *e;
1043 struct ip6t_counters *counters;
1046 /* We need atomic snapshot of counters: rest doesn't change
1047 (other than comefrom, which userspace doesn't care
1049 countersize = sizeof(struct ip6t_counters) * table->private->number;
1050 counters = vmalloc(countersize);
1052 if (counters == NULL)
1055 /* First, sum counters... */
1056 memset(counters, 0, countersize);
1057 write_lock_bh(&table->lock);
1058 get_counters(table->private, counters);
1059 write_unlock_bh(&table->lock);
1061 /* ... then copy entire thing from CPU 0... */
1062 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1067 /* FIXME: use iterator macros --RR */
1068 /* ... then go back and fix counters and names */
1069 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1071 struct ip6t_entry_match *m;
1072 struct ip6t_entry_target *t;
1074 e = (struct ip6t_entry *)(table->private->entries + off);
1075 if (copy_to_user(userptr + off
1076 + offsetof(struct ip6t_entry, counters),
1078 sizeof(counters[num])) != 0) {
1083 for (i = sizeof(struct ip6t_entry);
1084 i < e->target_offset;
1085 i += m->u.match_size) {
1088 if (copy_to_user(userptr + off + i
1089 + offsetof(struct ip6t_entry_match,
1091 m->u.kernel.match->name,
1092 strlen(m->u.kernel.match->name)+1)
1099 t = ip6t_get_target(e);
1100 if (copy_to_user(userptr + off + e->target_offset
1101 + offsetof(struct ip6t_entry_target,
1103 t->u.kernel.target->name,
1104 strlen(t->u.kernel.target->name)+1) != 0) {
1116 get_entries(const struct ip6t_get_entries *entries,
1117 struct ip6t_get_entries __user *uptr)
1120 struct ip6t_table *t;
1122 t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1124 duprintf("t->private->number = %u\n",
1125 t->private->number);
1126 if (entries->size == t->private->size)
1127 ret = copy_entries_to_user(t->private->size,
1128 t, uptr->entrytable);
1130 duprintf("get_entries: I've got %u not %u!\n",
1137 duprintf("get_entries: Can't find %s!\n",
1144 do_replace(void __user *user, unsigned int len)
1147 struct ip6t_replace tmp;
1148 struct ip6t_table *t;
1149 struct ip6t_table_info *newinfo, *oldinfo;
1150 struct ip6t_counters *counters;
1152 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1155 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1156 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1159 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1160 + SMP_ALIGN(tmp.size) *
1161 (highest_possible_processor_id()+1));
1165 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1171 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1176 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1178 ret = translate_table(tmp.name, tmp.valid_hooks,
1179 newinfo, tmp.size, tmp.num_entries,
1180 tmp.hook_entry, tmp.underflow);
1182 goto free_newinfo_counters;
1184 duprintf("ip_tables: Translated table\n");
1186 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1188 goto free_newinfo_counters_untrans;
1191 if (tmp.valid_hooks != t->valid_hooks) {
1192 duprintf("Valid hook crap: %08X vs %08X\n",
1193 tmp.valid_hooks, t->valid_hooks);
1195 goto free_newinfo_counters_untrans_unlock;
1198 /* Get a reference in advance, we're not allowed fail later */
1199 if (!try_module_get(t->me)) {
1201 goto free_newinfo_counters_untrans_unlock;
1204 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1208 /* Update module usage count based on number of rules */
1209 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1210 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1211 if ((oldinfo->number > oldinfo->initial_entries) ||
1212 (newinfo->number <= oldinfo->initial_entries))
1214 if ((oldinfo->number > oldinfo->initial_entries) &&
1215 (newinfo->number <= oldinfo->initial_entries))
1218 /* Get the old counters. */
1219 get_counters(oldinfo, counters);
1220 /* Decrease module usage counts and free resource */
1221 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1223 /* Silent error: too late now. */
1224 if (copy_to_user(tmp.counters, counters,
1225 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1233 free_newinfo_counters_untrans_unlock:
1235 free_newinfo_counters_untrans:
1236 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1237 free_newinfo_counters:
1244 /* We're lazy, and add to the first CPU; overflow works its fey magic
1245 * and everything is OK. */
1247 add_counter_to_entry(struct ip6t_entry *e,
1248 const struct ip6t_counters addme[],
1252 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1254 (long unsigned int)e->counters.pcnt,
1255 (long unsigned int)e->counters.bcnt,
1256 (long unsigned int)addme[*i].pcnt,
1257 (long unsigned int)addme[*i].bcnt);
1260 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1267 do_add_counters(void __user *user, unsigned int len)
1270 struct ip6t_counters_info tmp, *paddc;
1271 struct ip6t_table *t;
1274 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1277 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1280 paddc = vmalloc(len);
1284 if (copy_from_user(paddc, user, len) != 0) {
1289 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1293 write_lock_bh(&t->lock);
1294 if (t->private->number != paddc->num_counters) {
1296 goto unlock_up_free;
1300 IP6T_ENTRY_ITERATE(t->private->entries,
1302 add_counter_to_entry,
1306 write_unlock_bh(&t->lock);
1315 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1319 if (!capable(CAP_NET_ADMIN))
1323 case IP6T_SO_SET_REPLACE:
1324 ret = do_replace(user, len);
1327 case IP6T_SO_SET_ADD_COUNTERS:
1328 ret = do_add_counters(user, len);
1332 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1340 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1344 if (!capable(CAP_NET_ADMIN))
1348 case IP6T_SO_GET_INFO: {
1349 char name[IP6T_TABLE_MAXNAMELEN];
1350 struct ip6t_table *t;
1352 if (*len != sizeof(struct ip6t_getinfo)) {
1353 duprintf("length %u != %u\n", *len,
1354 sizeof(struct ip6t_getinfo));
1359 if (copy_from_user(name, user, sizeof(name)) != 0) {
1363 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1364 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1366 struct ip6t_getinfo info;
1368 info.valid_hooks = t->valid_hooks;
1369 memcpy(info.hook_entry, t->private->hook_entry,
1370 sizeof(info.hook_entry));
1371 memcpy(info.underflow, t->private->underflow,
1372 sizeof(info.underflow));
1373 info.num_entries = t->private->number;
1374 info.size = t->private->size;
1375 memcpy(info.name, name, sizeof(info.name));
1377 if (copy_to_user(user, &info, *len) != 0)
1387 case IP6T_SO_GET_ENTRIES: {
1388 struct ip6t_get_entries get;
1390 if (*len < sizeof(get)) {
1391 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1393 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1395 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1396 duprintf("get_entries: %u != %u\n", *len,
1397 sizeof(struct ip6t_get_entries) + get.size);
1400 ret = get_entries(&get, user);
1405 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1412 /* Registration hooks for targets. */
1414 ip6t_register_target(struct ip6t_target *target)
1418 ret = down_interruptible(&ip6t_mutex);
1422 if (!list_named_insert(&ip6t_target, target)) {
1423 duprintf("ip6t_register_target: `%s' already in list!\n",
1432 ip6t_unregister_target(struct ip6t_target *target)
1435 LIST_DELETE(&ip6t_target, target);
1440 ip6t_register_match(struct ip6t_match *match)
1444 ret = down_interruptible(&ip6t_mutex);
1448 if (!list_named_insert(&ip6t_match, match)) {
1449 duprintf("ip6t_register_match: `%s' already in list!\n",
1459 ip6t_unregister_match(struct ip6t_match *match)
1462 LIST_DELETE(&ip6t_match, match);
1466 int ip6t_register_table(struct ip6t_table *table,
1467 const struct ip6t_replace *repl)
1470 struct ip6t_table_info *newinfo;
1471 static struct ip6t_table_info bootstrap
1472 = { 0, 0, 0, { 0 }, { 0 }, { } };
1474 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1475 + SMP_ALIGN(repl->size) *
1476 (highest_possible_processor_id()+1));
1480 memcpy(newinfo->entries, repl->entries, repl->size);
1482 ret = translate_table(table->name, table->valid_hooks,
1483 newinfo, repl->size,
1492 ret = down_interruptible(&ip6t_mutex);
1498 /* Don't autoload: we'd eat our tail... */
1499 if (list_named_find(&ip6t_tables, table->name)) {
1504 /* Simplifies replace_table code. */
1505 table->private = &bootstrap;
1506 if (!replace_table(table, 0, newinfo, &ret))
1509 duprintf("table->private->number = %u\n",
1510 table->private->number);
1512 /* save number of initial entries */
1513 table->private->initial_entries = table->private->number;
1515 rwlock_init(&table->lock);
1516 list_prepend(&ip6t_tables, table);
1527 void ip6t_unregister_table(struct ip6t_table *table)
1530 LIST_DELETE(&ip6t_tables, table);
1533 /* Decrease module usage counts and free resources */
1534 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1535 cleanup_entry, NULL);
1536 vfree(table->private);
1539 /* Returns 1 if the port is matched by the range, 0 otherwise */
1541 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1545 ret = (port >= min && port <= max) ^ invert;
1550 tcp_find_option(u_int8_t option,
1551 const struct sk_buff *skb,
1552 unsigned int tcpoff,
1553 unsigned int optlen,
1557 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1558 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1561 duprintf("tcp_match: finding option\n");
1564 /* If we don't have the whole header, drop packet. */
1565 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1572 for (i = 0; i < optlen; ) {
1573 if (op[i] == option) return !invert;
1575 else i += op[i+1]?:1;
1582 tcp_match(const struct sk_buff *skb,
1583 const struct net_device *in,
1584 const struct net_device *out,
1585 const void *matchinfo,
1587 unsigned int protoff,
1590 struct tcphdr _tcph, *th;
1591 const struct ip6t_tcp *tcpinfo = matchinfo;
1596 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1597 causes this. Its a cracker trying to break in by doing a
1598 flag overwrite to pass the direction checks.
1601 duprintf("Dropping evil TCP offset=1 frag.\n");
1604 /* Must not be a fragment. */
1608 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1610 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1612 /* We've been asked to examine this packet, and we
1613 can't. Hence, no choice but to drop. */
1614 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1619 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1621 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1623 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1625 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1627 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1628 == tcpinfo->flg_cmp,
1629 IP6T_TCP_INV_FLAGS))
1631 if (tcpinfo->option) {
1632 if (th->doff * 4 < sizeof(_tcph)) {
1636 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1637 th->doff*4 - sizeof(*th),
1638 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1645 /* Called when user tries to insert an entry of this type. */
1647 tcp_checkentry(const char *tablename,
1648 const struct ip6t_ip6 *ipv6,
1650 unsigned int matchsize,
1651 unsigned int hook_mask)
1653 const struct ip6t_tcp *tcpinfo = matchinfo;
1655 /* Must specify proto == TCP, and no unknown invflags */
1656 return ipv6->proto == IPPROTO_TCP
1657 && !(ipv6->invflags & IP6T_INV_PROTO)
1658 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1659 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1663 udp_match(const struct sk_buff *skb,
1664 const struct net_device *in,
1665 const struct net_device *out,
1666 const void *matchinfo,
1668 unsigned int protoff,
1671 struct udphdr _udph, *uh;
1672 const struct ip6t_udp *udpinfo = matchinfo;
1674 /* Must not be a fragment. */
1678 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1680 /* We've been asked to examine this packet, and we
1681 can't. Hence, no choice but to drop. */
1682 duprintf("Dropping evil UDP tinygram.\n");
1687 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1689 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1690 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1692 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1695 /* Called when user tries to insert an entry of this type. */
1697 udp_checkentry(const char *tablename,
1698 const struct ip6t_ip6 *ipv6,
1700 unsigned int matchinfosize,
1701 unsigned int hook_mask)
1703 const struct ip6t_udp *udpinfo = matchinfo;
1705 /* Must specify proto == UDP, and no unknown invflags */
1706 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1707 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1711 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1712 duprintf("ip6t_udp: matchsize %u != %u\n",
1713 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1716 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1717 duprintf("ip6t_udp: unknown flags %X\n",
1725 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1727 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1728 u_int8_t type, u_int8_t code,
1731 return (type == test_type && code >= min_code && code <= max_code)
1736 icmp6_match(const struct sk_buff *skb,
1737 const struct net_device *in,
1738 const struct net_device *out,
1739 const void *matchinfo,
1741 unsigned int protoff,
1744 struct icmp6hdr _icmp, *ic;
1745 const struct ip6t_icmp *icmpinfo = matchinfo;
1747 /* Must not be a fragment. */
1751 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1753 /* We've been asked to examine this packet, and we
1754 can't. Hence, no choice but to drop. */
1755 duprintf("Dropping evil ICMP tinygram.\n");
1760 return icmp6_type_code_match(icmpinfo->type,
1763 ic->icmp6_type, ic->icmp6_code,
1764 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1767 /* Called when user tries to insert an entry of this type. */
1769 icmp6_checkentry(const char *tablename,
1770 const struct ip6t_ip6 *ipv6,
1772 unsigned int matchsize,
1773 unsigned int hook_mask)
1775 const struct ip6t_icmp *icmpinfo = matchinfo;
1777 /* Must specify proto == ICMP, and no unknown invflags */
1778 return ipv6->proto == IPPROTO_ICMPV6
1779 && !(ipv6->invflags & IP6T_INV_PROTO)
1780 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1781 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1784 /* The built-in targets: standard (NULL) and error. */
1785 static struct ip6t_target ip6t_standard_target = {
1786 .name = IP6T_STANDARD_TARGET,
1789 static struct ip6t_target ip6t_error_target = {
1790 .name = IP6T_ERROR_TARGET,
1791 .target = ip6t_error,
1794 static struct nf_sockopt_ops ip6t_sockopts = {
1796 .set_optmin = IP6T_BASE_CTL,
1797 .set_optmax = IP6T_SO_SET_MAX+1,
1798 .set = do_ip6t_set_ctl,
1799 .get_optmin = IP6T_BASE_CTL,
1800 .get_optmax = IP6T_SO_GET_MAX+1,
1801 .get = do_ip6t_get_ctl,
1804 static struct ip6t_match tcp_matchstruct = {
1806 .match = &tcp_match,
1807 .checkentry = &tcp_checkentry,
1810 static struct ip6t_match udp_matchstruct = {
1812 .match = &udp_match,
1813 .checkentry = &udp_checkentry,
1816 static struct ip6t_match icmp6_matchstruct = {
1818 .match = &icmp6_match,
1819 .checkentry = &icmp6_checkentry,
1822 #ifdef CONFIG_PROC_FS
1823 static inline int print_name(const char *i,
1824 off_t start_offset, char *buffer, int length,
1825 off_t *pos, unsigned int *count)
1827 if ((*count)++ >= start_offset) {
1828 unsigned int namelen;
1830 namelen = sprintf(buffer + *pos, "%s\n",
1831 i + sizeof(struct list_head));
1832 if (*pos + namelen > length) {
1833 /* Stop iterating */
1841 static inline int print_target(const struct ip6t_target *t,
1842 off_t start_offset, char *buffer, int length,
1843 off_t *pos, unsigned int *count)
1845 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1847 return print_name((char *)t, start_offset, buffer, length, pos, count);
1850 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1853 unsigned int count = 0;
1855 if (down_interruptible(&ip6t_mutex) != 0)
1858 LIST_FIND(&ip6t_tables, print_name, char *,
1859 offset, buffer, length, &pos, &count);
1863 /* `start' hack - see fs/proc/generic.c line ~105 */
1864 *start=(char *)((unsigned long)count-offset);
1868 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1871 unsigned int count = 0;
1873 if (down_interruptible(&ip6t_mutex) != 0)
1876 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1877 offset, buffer, length, &pos, &count);
1881 *start = (char *)((unsigned long)count - offset);
1885 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1888 unsigned int count = 0;
1890 if (down_interruptible(&ip6t_mutex) != 0)
1893 LIST_FIND(&ip6t_match, print_name, char *,
1894 offset, buffer, length, &pos, &count);
1898 *start = (char *)((unsigned long)count - offset);
1902 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1903 { { "ip6_tables_names", ip6t_get_tables },
1904 { "ip6_tables_targets", ip6t_get_targets },
1905 { "ip6_tables_matches", ip6t_get_matches },
1907 #endif /*CONFIG_PROC_FS*/
1909 static int __init init(void)
1913 /* Noone else will be downing sem now, so we won't sleep */
1915 list_append(&ip6t_target, &ip6t_standard_target);
1916 list_append(&ip6t_target, &ip6t_error_target);
1917 list_append(&ip6t_match, &tcp_matchstruct);
1918 list_append(&ip6t_match, &udp_matchstruct);
1919 list_append(&ip6t_match, &icmp6_matchstruct);
1922 /* Register setsockopt */
1923 ret = nf_register_sockopt(&ip6t_sockopts);
1925 duprintf("Unable to register sockopts.\n");
1929 #ifdef CONFIG_PROC_FS
1931 struct proc_dir_entry *proc;
1934 for (i = 0; ip6t_proc_entry[i].name; i++) {
1935 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1936 ip6t_proc_entry[i].get_info);
1939 proc_net_remove(ip6t_proc_entry[i].name);
1940 nf_unregister_sockopt(&ip6t_sockopts);
1943 proc->owner = THIS_MODULE;
1948 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1952 static void __exit fini(void)
1954 nf_unregister_sockopt(&ip6t_sockopts);
1955 #ifdef CONFIG_PROC_FS
1958 for (i = 0; ip6t_proc_entry[i].name; i++)
1959 proc_net_remove(ip6t_proc_entry[i].name);
1965 * find specified header up to transport protocol header.
1966 * If found target header, the offset to the header is set to *offset
1967 * and return 0. otherwise, return -1.
1969 * Notes: - non-1st Fragment Header isn't skipped.
1970 * - ESP header isn't skipped.
1971 * - The target header may be trancated.
1973 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
1975 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1976 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1977 unsigned int len = skb->len - start;
1979 while (nexthdr != target) {
1980 struct ipv6_opt_hdr _hdr, *hp;
1981 unsigned int hdrlen;
1983 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE)
1985 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1988 if (nexthdr == NEXTHDR_FRAGMENT) {
1989 unsigned short _frag_off, *fp;
1990 fp = skb_header_pointer(skb,
1991 start+offsetof(struct frag_hdr,
1998 if (ntohs(*fp) & ~0x7)
2001 } else if (nexthdr == NEXTHDR_AUTH)
2002 hdrlen = (hp->hdrlen + 2) << 2;
2004 hdrlen = ipv6_optlen(hp);
2006 nexthdr = hp->nexthdr;
2015 EXPORT_SYMBOL(ip6t_register_table);
2016 EXPORT_SYMBOL(ip6t_unregister_table);
2017 EXPORT_SYMBOL(ip6t_do_table);
2018 EXPORT_SYMBOL(ip6t_register_match);
2019 EXPORT_SYMBOL(ip6t_unregister_match);
2020 EXPORT_SYMBOL(ip6t_register_target);
2021 EXPORT_SYMBOL(ip6t_unregister_target);
2022 EXPORT_SYMBOL(ip6t_ext_hdr);
2023 EXPORT_SYMBOL(ipv6_find_hdr);