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
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>
27 #include <asm/uaccess.h>
28 #include <asm/semaphore.h>
29 #include <linux/proc_fs.h>
30 #include <linux/cpumask.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/listhelp.h>
77 /* All the better to debug you with... */
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 To be cache friendly on SMP, we arrange them like so:
91 ... cache-align padding ...
94 Hence the start of any table is given by get_table() below. */
96 /* The table itself */
97 struct ip6t_table_info
101 /* Number of entries: FIXME. --RR */
103 /* Initial number of entries. Needed for module usage count */
104 unsigned int initial_entries;
106 /* Entry points and underflows */
107 unsigned int hook_entry[NF_IP6_NUMHOOKS];
108 unsigned int underflow[NF_IP6_NUMHOOKS];
110 /* ip6t_entry tables: one per CPU */
111 char entries[0] ____cacheline_aligned;
114 static LIST_HEAD(ip6t_target);
115 static LIST_HEAD(ip6t_match);
116 static LIST_HEAD(ip6t_tables);
117 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
120 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
122 #define TABLE_OFFSET(t,p) 0
126 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
127 #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; })
128 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
131 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
132 struct in6_addr addr2)
135 for( i = 0; i < 16; i++){
136 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
137 (addr2.s6_addr[i] & mask.s6_addr[i]))
143 /* Check for an extension */
145 ip6t_ext_hdr(u8 nexthdr)
147 return ( (nexthdr == IPPROTO_HOPOPTS) ||
148 (nexthdr == IPPROTO_ROUTING) ||
149 (nexthdr == IPPROTO_FRAGMENT) ||
150 (nexthdr == IPPROTO_ESP) ||
151 (nexthdr == IPPROTO_AH) ||
152 (nexthdr == IPPROTO_NONE) ||
153 (nexthdr == IPPROTO_DSTOPTS) );
156 /* Returns whether matches rule or not. */
158 ip6_packet_match(const struct sk_buff *skb,
161 const struct ip6t_ip6 *ip6info,
162 unsigned int *protoff,
167 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
169 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
171 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
173 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
175 dprintf("Source or dest mismatch.\n");
177 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
178 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
179 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
180 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
181 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
182 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
186 /* Look for ifname matches; this should unroll nicely. */
187 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
188 ret |= (((const unsigned long *)indev)[i]
189 ^ ((const unsigned long *)ip6info->iniface)[i])
190 & ((const unsigned long *)ip6info->iniface_mask)[i];
193 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
194 dprintf("VIA in mismatch (%s vs %s).%s\n",
195 indev, ip6info->iniface,
196 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
200 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
201 ret |= (((const unsigned long *)outdev)[i]
202 ^ ((const unsigned long *)ip6info->outiface)[i])
203 & ((const unsigned long *)ip6info->outiface_mask)[i];
206 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
207 dprintf("VIA out mismatch (%s vs %s).%s\n",
208 outdev, ip6info->outiface,
209 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
213 /* ... might want to do something with class and flowlabel here ... */
215 /* look for the desired protocol header */
216 if((ip6info->flags & IP6T_F_PROTO)) {
217 u_int8_t currenthdr = ipv6->nexthdr;
218 struct ipv6_opt_hdr _hdr, *hp;
219 u_int16_t ptr; /* Header offset in skb */
220 u_int16_t hdrlen; /* Header */
221 u_int16_t _fragoff = 0, *fp = NULL;
225 while (ip6t_ext_hdr(currenthdr)) {
226 /* Is there enough space for the next ext header? */
227 if (skb->len - ptr < IPV6_OPTHDR_LEN)
230 /* NONE or ESP: there isn't protocol part */
231 /* If we want to count these packets in '-p all',
232 * we will change the return 0 to 1*/
233 if ((currenthdr == IPPROTO_NONE) ||
234 (currenthdr == IPPROTO_ESP))
237 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
240 /* Size calculation */
241 if (currenthdr == IPPROTO_FRAGMENT) {
242 fp = skb_header_pointer(skb,
243 ptr+offsetof(struct frag_hdr,
250 _fragoff = ntohs(*fp) & ~0x7;
252 } else if (currenthdr == IPPROTO_AH)
253 hdrlen = (hp->hdrlen+2)<<2;
255 hdrlen = ipv6_optlen(hp);
257 currenthdr = hp->nexthdr;
259 /* ptr is too large */
260 if ( ptr > skb->len )
263 if (ip6t_ext_hdr(currenthdr))
272 /* currenthdr contains the protocol header */
274 dprintf("Packet protocol %hi ?= %s%hi.\n",
276 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
279 if (ip6info->proto == currenthdr) {
280 if(ip6info->invflags & IP6T_INV_PROTO) {
286 /* We need match for the '-p all', too! */
287 if ((ip6info->proto != 0) &&
288 !(ip6info->invflags & IP6T_INV_PROTO))
294 /* should be ip6 safe */
296 ip6_checkentry(const struct ip6t_ip6 *ipv6)
298 if (ipv6->flags & ~IP6T_F_MASK) {
299 duprintf("Unknown flag bits set: %08X\n",
300 ipv6->flags & ~IP6T_F_MASK);
303 if (ipv6->invflags & ~IP6T_INV_MASK) {
304 duprintf("Unknown invflag bits set: %08X\n",
305 ipv6->invflags & ~IP6T_INV_MASK);
312 ip6t_error(struct sk_buff **pskb,
313 const struct net_device *in,
314 const struct net_device *out,
315 unsigned int hooknum,
316 const void *targinfo,
320 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
326 int do_match(struct ip6t_entry_match *m,
327 const struct sk_buff *skb,
328 const struct net_device *in,
329 const struct net_device *out,
331 unsigned int protoff,
334 /* Stop iteration if it doesn't match */
335 if (!m->u.kernel.match->match(skb, in, out, m->data,
336 offset, protoff, hotdrop))
342 static inline struct ip6t_entry *
343 get_entry(void *base, unsigned int offset)
345 return (struct ip6t_entry *)(base + offset);
348 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
350 ip6t_do_table(struct sk_buff **pskb,
352 const struct net_device *in,
353 const struct net_device *out,
354 struct ip6t_table *table,
357 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
359 unsigned int protoff = 0;
361 /* Initializing verdict to NF_DROP keeps gcc happy. */
362 unsigned int verdict = NF_DROP;
363 const char *indev, *outdev;
365 struct ip6t_entry *e, *back;
368 indev = in ? in->name : nulldevname;
369 outdev = out ? out->name : nulldevname;
370 /* We handle fragments by dealing with the first fragment as
371 * if it was a normal packet. All other fragments are treated
372 * normally, except that they will NEVER match rules that ask
373 * things we don't know, ie. tcp syn flag or ports). If the
374 * rule is also a fragment-specific rule, non-fragments won't
377 read_lock_bh(&table->lock);
378 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
379 table_base = (void *)table->private->entries
380 + TABLE_OFFSET(table->private, smp_processor_id());
381 e = get_entry(table_base, table->private->hook_entry[hook]);
383 #ifdef CONFIG_NETFILTER_DEBUG
384 /* Check noone else using our table */
385 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
386 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
387 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
390 &((struct ip6t_entry *)table_base)->comefrom,
391 ((struct ip6t_entry *)table_base)->comefrom);
393 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
396 /* For return from builtin chain */
397 back = get_entry(table_base, table->private->underflow[hook]);
402 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
403 &protoff, &offset)) {
404 struct ip6t_entry_target *t;
406 if (IP6T_MATCH_ITERATE(e, do_match,
408 offset, protoff, &hotdrop) != 0)
411 ADD_COUNTER(e->counters,
412 ntohs((*pskb)->nh.ipv6h->payload_len)
416 t = ip6t_get_target(e);
417 IP_NF_ASSERT(t->u.kernel.target);
418 /* Standard target? */
419 if (!t->u.kernel.target->target) {
422 v = ((struct ip6t_standard_target *)t)->verdict;
424 /* Pop from stack? */
425 if (v != IP6T_RETURN) {
426 verdict = (unsigned)(-v) - 1;
430 back = get_entry(table_base,
434 if (table_base + v != (void *)e + e->next_offset
435 && !(e->ipv6.flags & IP6T_F_GOTO)) {
436 /* Save old back ptr in next entry */
437 struct ip6t_entry *next
438 = (void *)e + e->next_offset;
440 = (void *)back - table_base;
441 /* set back pointer to next entry */
445 e = get_entry(table_base, v);
447 /* Targets which reenter must return
449 #ifdef CONFIG_NETFILTER_DEBUG
450 ((struct ip6t_entry *)table_base)->comefrom
453 verdict = t->u.kernel.target->target(pskb,
459 #ifdef CONFIG_NETFILTER_DEBUG
460 if (((struct ip6t_entry *)table_base)->comefrom
462 && verdict == IP6T_CONTINUE) {
463 printk("Target %s reentered!\n",
464 t->u.kernel.target->name);
467 ((struct ip6t_entry *)table_base)->comefrom
470 if (verdict == IP6T_CONTINUE)
471 e = (void *)e + e->next_offset;
479 e = (void *)e + e->next_offset;
483 #ifdef CONFIG_NETFILTER_DEBUG
484 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
486 read_unlock_bh(&table->lock);
488 #ifdef DEBUG_ALLOW_ALL
498 * These are weird, but module loading must not be done with mutex
499 * held (since they will register), and we have to have a single
500 * function to use try_then_request_module().
503 /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
504 static inline struct ip6t_table *find_table_lock(const char *name)
506 struct ip6t_table *t;
508 if (down_interruptible(&ip6t_mutex) != 0)
509 return ERR_PTR(-EINTR);
511 list_for_each_entry(t, &ip6t_tables, list)
512 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
518 /* Find match, grabs ref. Returns ERR_PTR() on error. */
519 static inline struct ip6t_match *find_match(const char *name, u8 revision)
521 struct ip6t_match *m;
524 if (down_interruptible(&ip6t_mutex) != 0)
525 return ERR_PTR(-EINTR);
527 list_for_each_entry(m, &ip6t_match, list) {
528 if (strcmp(m->name, name) == 0) {
529 if (m->revision == revision) {
530 if (try_module_get(m->me)) {
535 err = -EPROTOTYPE; /* Found something. */
542 /* Find target, grabs ref. Returns ERR_PTR() on error. */
543 static inline struct ip6t_target *find_target(const char *name, u8 revision)
545 struct ip6t_target *t;
548 if (down_interruptible(&ip6t_mutex) != 0)
549 return ERR_PTR(-EINTR);
551 list_for_each_entry(t, &ip6t_target, list) {
552 if (strcmp(t->name, name) == 0) {
553 if (t->revision == revision) {
554 if (try_module_get(t->me)) {
559 err = -EPROTOTYPE; /* Found something. */
566 struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
568 struct ip6t_target *target;
570 target = try_then_request_module(find_target(name, revision),
572 if (IS_ERR(target) || !target)
577 static int match_revfn(const char *name, u8 revision, int *bestp)
579 struct ip6t_match *m;
582 list_for_each_entry(m, &ip6t_match, list) {
583 if (strcmp(m->name, name) == 0) {
584 if (m->revision > *bestp)
585 *bestp = m->revision;
586 if (m->revision == revision)
593 static int target_revfn(const char *name, u8 revision, int *bestp)
595 struct ip6t_target *t;
598 list_for_each_entry(t, &ip6t_target, list) {
599 if (strcmp(t->name, name) == 0) {
600 if (t->revision > *bestp)
601 *bestp = t->revision;
602 if (t->revision == revision)
609 /* Returns true or fals (if no such extension at all) */
610 static inline int find_revision(const char *name, u8 revision,
611 int (*revfn)(const char *, u8, int *),
614 int have_rev, best = -1;
616 if (down_interruptible(&ip6t_mutex) != 0) {
620 have_rev = revfn(name, revision, &best);
623 /* Nothing at all? Return 0 to try loading module. */
631 *err = -EPROTONOSUPPORT;
636 /* All zeroes == unconditional rule. */
638 unconditional(const struct ip6t_ip6 *ipv6)
642 for (i = 0; i < sizeof(*ipv6); i++)
643 if (((char *)ipv6)[i])
646 return (i == sizeof(*ipv6));
649 /* Figures out from what hook each rule can be called: returns 0 if
650 there are loops. Puts hook bitmask in comefrom. */
652 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
656 /* No recursion; use packet counter to save back ptrs (reset
657 to 0 as we leave), and comefrom to save source hook bitmask */
658 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
659 unsigned int pos = newinfo->hook_entry[hook];
661 = (struct ip6t_entry *)(newinfo->entries + pos);
663 if (!(valid_hooks & (1 << hook)))
666 /* Set initial back pointer. */
667 e->counters.pcnt = pos;
670 struct ip6t_standard_target *t
671 = (void *)ip6t_get_target(e);
673 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
674 printk("iptables: loop hook %u pos %u %08X.\n",
675 hook, pos, e->comefrom);
679 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
681 /* Unconditional return/END. */
682 if (e->target_offset == sizeof(struct ip6t_entry)
683 && (strcmp(t->target.u.user.name,
684 IP6T_STANDARD_TARGET) == 0)
686 && unconditional(&e->ipv6)) {
687 unsigned int oldpos, size;
689 /* Return: backtrack through the last
692 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
693 #ifdef DEBUG_IP_FIREWALL_USER
695 & (1 << NF_IP6_NUMHOOKS)) {
696 duprintf("Back unset "
703 pos = e->counters.pcnt;
704 e->counters.pcnt = 0;
706 /* We're at the start. */
710 e = (struct ip6t_entry *)
711 (newinfo->entries + pos);
712 } while (oldpos == pos + e->next_offset);
715 size = e->next_offset;
716 e = (struct ip6t_entry *)
717 (newinfo->entries + pos + size);
718 e->counters.pcnt = pos;
721 int newpos = t->verdict;
723 if (strcmp(t->target.u.user.name,
724 IP6T_STANDARD_TARGET) == 0
726 /* This a jump; chase it. */
727 duprintf("Jump rule %u -> %u\n",
730 /* ... this is a fallthru */
731 newpos = pos + e->next_offset;
733 e = (struct ip6t_entry *)
734 (newinfo->entries + newpos);
735 e->counters.pcnt = pos;
740 duprintf("Finished chain %u\n", hook);
746 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
748 if (i && (*i)-- == 0)
751 if (m->u.kernel.match->destroy)
752 m->u.kernel.match->destroy(m->data,
753 m->u.match_size - sizeof(*m));
754 module_put(m->u.kernel.match->me);
759 standard_check(const struct ip6t_entry_target *t,
760 unsigned int max_offset)
762 struct ip6t_standard_target *targ = (void *)t;
764 /* Check standard info. */
766 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
767 duprintf("standard_check: target size %u != %u\n",
769 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
773 if (targ->verdict >= 0
774 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
775 duprintf("ip6t_standard_check: bad verdict (%i)\n",
780 if (targ->verdict < -NF_MAX_VERDICT - 1) {
781 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
789 check_match(struct ip6t_entry_match *m,
791 const struct ip6t_ip6 *ipv6,
792 unsigned int hookmask,
795 struct ip6t_match *match;
797 match = try_then_request_module(find_match(m->u.user.name,
799 "ip6t_%s", m->u.user.name);
800 if (IS_ERR(match) || !match) {
801 duprintf("check_match: `%s' not found\n", m->u.user.name);
802 return match ? PTR_ERR(match) : -ENOENT;
804 m->u.kernel.match = match;
806 if (m->u.kernel.match->checkentry
807 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
808 m->u.match_size - sizeof(*m),
810 module_put(m->u.kernel.match->me);
811 duprintf("ip_tables: check failed for `%s'.\n",
812 m->u.kernel.match->name);
820 static struct ip6t_target ip6t_standard_target;
823 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
826 struct ip6t_entry_target *t;
827 struct ip6t_target *target;
831 if (!ip6_checkentry(&e->ipv6)) {
832 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
837 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
839 goto cleanup_matches;
841 t = ip6t_get_target(e);
842 target = try_then_request_module(find_target(t->u.user.name,
844 "ip6t_%s", t->u.user.name);
845 if (IS_ERR(target) || !target) {
846 duprintf("check_entry: `%s' not found\n", t->u.user.name);
847 ret = target ? PTR_ERR(target) : -ENOENT;
848 goto cleanup_matches;
850 t->u.kernel.target = target;
852 if (t->u.kernel.target == &ip6t_standard_target) {
853 if (!standard_check(t, size)) {
855 goto cleanup_matches;
857 } else if (t->u.kernel.target->checkentry
858 && !t->u.kernel.target->checkentry(name, e, t->data,
862 module_put(t->u.kernel.target->me);
863 duprintf("ip_tables: check failed for `%s'.\n",
864 t->u.kernel.target->name);
866 goto cleanup_matches;
873 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
878 check_entry_size_and_hooks(struct ip6t_entry *e,
879 struct ip6t_table_info *newinfo,
881 unsigned char *limit,
882 const unsigned int *hook_entries,
883 const unsigned int *underflows,
888 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
889 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
890 duprintf("Bad offset %p\n", e);
895 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
896 duprintf("checking: element %p size %u\n",
901 /* Check hooks & underflows */
902 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
903 if ((unsigned char *)e - base == hook_entries[h])
904 newinfo->hook_entry[h] = hook_entries[h];
905 if ((unsigned char *)e - base == underflows[h])
906 newinfo->underflow[h] = underflows[h];
909 /* FIXME: underflows must be unconditional, standard verdicts
910 < 0 (not IP6T_RETURN). --RR */
912 /* Clear counters and comefrom */
913 e->counters = ((struct ip6t_counters) { 0, 0 });
921 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
923 struct ip6t_entry_target *t;
925 if (i && (*i)-- == 0)
928 /* Cleanup all matches */
929 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
930 t = ip6t_get_target(e);
931 if (t->u.kernel.target->destroy)
932 t->u.kernel.target->destroy(t->data,
933 t->u.target_size - sizeof(*t));
934 module_put(t->u.kernel.target->me);
938 /* Checks and translates the user-supplied table segment (held in
941 translate_table(const char *name,
942 unsigned int valid_hooks,
943 struct ip6t_table_info *newinfo,
946 const unsigned int *hook_entries,
947 const unsigned int *underflows)
952 newinfo->size = size;
953 newinfo->number = number;
955 /* Init all hooks to impossible value. */
956 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
957 newinfo->hook_entry[i] = 0xFFFFFFFF;
958 newinfo->underflow[i] = 0xFFFFFFFF;
961 duprintf("translate_table: size %u\n", newinfo->size);
963 /* Walk through entries, checking offsets. */
964 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
965 check_entry_size_and_hooks,
968 newinfo->entries + size,
969 hook_entries, underflows, &i);
974 duprintf("translate_table: %u not %u entries\n",
979 /* Check hooks all assigned */
980 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
981 /* Only hooks which are valid */
982 if (!(valid_hooks & (1 << i)))
984 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
985 duprintf("Invalid hook entry %u %u\n",
989 if (newinfo->underflow[i] == 0xFFFFFFFF) {
990 duprintf("Invalid underflow %u %u\n",
996 if (!mark_source_chains(newinfo, valid_hooks))
999 /* Finally, each sanity check must pass */
1001 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
1002 check_entry, name, size, &i);
1005 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
1010 /* And one copy for every other CPU */
1014 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size) * i,
1016 SMP_ALIGN(newinfo->size));
1022 static struct ip6t_table_info *
1023 replace_table(struct ip6t_table *table,
1024 unsigned int num_counters,
1025 struct ip6t_table_info *newinfo,
1028 struct ip6t_table_info *oldinfo;
1030 #ifdef CONFIG_NETFILTER_DEBUG
1032 struct ip6t_entry *table_base;
1037 (void *)newinfo->entries
1038 + TABLE_OFFSET(newinfo, i);
1040 table_base->comefrom = 0xdead57ac;
1045 /* Do the substitution. */
1046 write_lock_bh(&table->lock);
1047 /* Check inside lock: is the old number correct? */
1048 if (num_counters != table->private->number) {
1049 duprintf("num_counters != table->private->number (%u/%u)\n",
1050 num_counters, table->private->number);
1051 write_unlock_bh(&table->lock);
1055 oldinfo = table->private;
1056 table->private = newinfo;
1057 newinfo->initial_entries = oldinfo->initial_entries;
1058 write_unlock_bh(&table->lock);
1063 /* Gets counters. */
1065 add_entry_to_counter(const struct ip6t_entry *e,
1066 struct ip6t_counters total[],
1069 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1076 get_counters(const struct ip6t_table_info *t,
1077 struct ip6t_counters counters[])
1084 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1086 add_entry_to_counter,
1093 copy_entries_to_user(unsigned int total_size,
1094 struct ip6t_table *table,
1095 void __user *userptr)
1097 unsigned int off, num, countersize;
1098 struct ip6t_entry *e;
1099 struct ip6t_counters *counters;
1102 /* We need atomic snapshot of counters: rest doesn't change
1103 (other than comefrom, which userspace doesn't care
1105 countersize = sizeof(struct ip6t_counters) * table->private->number;
1106 counters = vmalloc(countersize);
1108 if (counters == NULL)
1111 /* First, sum counters... */
1112 memset(counters, 0, countersize);
1113 write_lock_bh(&table->lock);
1114 get_counters(table->private, counters);
1115 write_unlock_bh(&table->lock);
1117 /* ... then copy entire thing from CPU 0... */
1118 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1123 /* FIXME: use iterator macros --RR */
1124 /* ... then go back and fix counters and names */
1125 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1127 struct ip6t_entry_match *m;
1128 struct ip6t_entry_target *t;
1130 e = (struct ip6t_entry *)(table->private->entries + off);
1131 if (copy_to_user(userptr + off
1132 + offsetof(struct ip6t_entry, counters),
1134 sizeof(counters[num])) != 0) {
1139 for (i = sizeof(struct ip6t_entry);
1140 i < e->target_offset;
1141 i += m->u.match_size) {
1144 if (copy_to_user(userptr + off + i
1145 + offsetof(struct ip6t_entry_match,
1147 m->u.kernel.match->name,
1148 strlen(m->u.kernel.match->name)+1)
1155 t = ip6t_get_target(e);
1156 if (copy_to_user(userptr + off + e->target_offset
1157 + offsetof(struct ip6t_entry_target,
1159 t->u.kernel.target->name,
1160 strlen(t->u.kernel.target->name)+1) != 0) {
1172 get_entries(const struct ip6t_get_entries *entries,
1173 struct ip6t_get_entries __user *uptr)
1176 struct ip6t_table *t;
1178 t = find_table_lock(entries->name);
1179 if (t && !IS_ERR(t)) {
1180 duprintf("t->private->number = %u\n",
1181 t->private->number);
1182 if (entries->size == t->private->size)
1183 ret = copy_entries_to_user(t->private->size,
1184 t, uptr->entrytable);
1186 duprintf("get_entries: I've got %u not %u!\n",
1194 ret = t ? PTR_ERR(t) : -ENOENT;
1200 do_replace(void __user *user, unsigned int len)
1203 struct ip6t_replace tmp;
1204 struct ip6t_table *t;
1205 struct ip6t_table_info *newinfo, *oldinfo;
1206 struct ip6t_counters *counters;
1208 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1211 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1212 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1215 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1216 + SMP_ALIGN(tmp.size) *
1217 (highest_possible_processor_id()+1));
1221 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1227 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1232 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1234 ret = translate_table(tmp.name, tmp.valid_hooks,
1235 newinfo, tmp.size, tmp.num_entries,
1236 tmp.hook_entry, tmp.underflow);
1238 goto free_newinfo_counters;
1240 duprintf("ip_tables: Translated table\n");
1242 t = try_then_request_module(find_table_lock(tmp.name),
1243 "ip6table_%s", tmp.name);
1244 if (!t || IS_ERR(t)) {
1245 ret = t ? PTR_ERR(t) : -ENOENT;
1246 goto free_newinfo_counters_untrans;
1250 if (tmp.valid_hooks != t->valid_hooks) {
1251 duprintf("Valid hook crap: %08X vs %08X\n",
1252 tmp.valid_hooks, t->valid_hooks);
1257 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1261 /* Update module usage count based on number of rules */
1262 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1263 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1264 if ((oldinfo->number > oldinfo->initial_entries) ||
1265 (newinfo->number <= oldinfo->initial_entries))
1267 if ((oldinfo->number > oldinfo->initial_entries) &&
1268 (newinfo->number <= oldinfo->initial_entries))
1271 /* Get the old counters. */
1272 get_counters(oldinfo, counters);
1273 /* Decrease module usage counts and free resource */
1274 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1276 if (copy_to_user(tmp.counters, counters,
1277 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1286 free_newinfo_counters_untrans:
1287 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1288 free_newinfo_counters:
1295 /* We're lazy, and add to the first CPU; overflow works its fey magic
1296 * and everything is OK. */
1298 add_counter_to_entry(struct ip6t_entry *e,
1299 const struct ip6t_counters addme[],
1303 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1305 (long unsigned int)e->counters.pcnt,
1306 (long unsigned int)e->counters.bcnt,
1307 (long unsigned int)addme[*i].pcnt,
1308 (long unsigned int)addme[*i].bcnt);
1311 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1318 do_add_counters(void __user *user, unsigned int len)
1321 struct ip6t_counters_info tmp, *paddc;
1322 struct ip6t_table *t;
1325 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1328 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1331 paddc = vmalloc(len);
1335 if (copy_from_user(paddc, user, len) != 0) {
1340 t = find_table_lock(tmp.name);
1341 if (!t || IS_ERR(t)) {
1342 ret = t ? PTR_ERR(t) : -ENOENT;
1346 write_lock_bh(&t->lock);
1347 if (t->private->number != paddc->num_counters) {
1349 goto unlock_up_free;
1353 IP6T_ENTRY_ITERATE(t->private->entries,
1355 add_counter_to_entry,
1359 write_unlock_bh(&t->lock);
1369 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1373 if (!capable(CAP_NET_ADMIN))
1377 case IP6T_SO_SET_REPLACE:
1378 ret = do_replace(user, len);
1381 case IP6T_SO_SET_ADD_COUNTERS:
1382 ret = do_add_counters(user, len);
1386 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1394 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1398 if (!capable(CAP_NET_ADMIN))
1402 case IP6T_SO_GET_INFO: {
1403 char name[IP6T_TABLE_MAXNAMELEN];
1404 struct ip6t_table *t;
1406 if (*len != sizeof(struct ip6t_getinfo)) {
1407 duprintf("length %u != %u\n", *len,
1408 sizeof(struct ip6t_getinfo));
1413 if (copy_from_user(name, user, sizeof(name)) != 0) {
1417 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1419 t = try_then_request_module(find_table_lock(name),
1420 "ip6table_%s", name);
1421 if (t && !IS_ERR(t)) {
1422 struct ip6t_getinfo info;
1424 info.valid_hooks = t->valid_hooks;
1425 memcpy(info.hook_entry, t->private->hook_entry,
1426 sizeof(info.hook_entry));
1427 memcpy(info.underflow, t->private->underflow,
1428 sizeof(info.underflow));
1429 info.num_entries = t->private->number;
1430 info.size = t->private->size;
1431 memcpy(info.name, name, sizeof(info.name));
1433 if (copy_to_user(user, &info, *len) != 0)
1440 ret = t ? PTR_ERR(t) : -ENOENT;
1444 case IP6T_SO_GET_ENTRIES: {
1445 struct ip6t_get_entries get;
1447 if (*len < sizeof(get)) {
1448 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1450 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1452 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1453 duprintf("get_entries: %u != %u\n", *len,
1454 sizeof(struct ip6t_get_entries) + get.size);
1457 ret = get_entries(&get, user);
1461 case IP6T_SO_GET_REVISION_MATCH:
1462 case IP6T_SO_GET_REVISION_TARGET: {
1463 struct ip6t_get_revision rev;
1464 int (*revfn)(const char *, u8, int *);
1466 if (*len != sizeof(rev)) {
1470 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1475 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1476 revfn = target_revfn;
1478 revfn = match_revfn;
1480 try_then_request_module(find_revision(rev.name, rev.revision,
1482 "ip6t_%s", rev.name);
1487 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1494 /* Registration hooks for targets. */
1496 ip6t_register_target(struct ip6t_target *target)
1500 ret = down_interruptible(&ip6t_mutex);
1503 list_add(&target->list, &ip6t_target);
1509 ip6t_unregister_target(struct ip6t_target *target)
1512 LIST_DELETE(&ip6t_target, target);
1517 ip6t_register_match(struct ip6t_match *match)
1521 ret = down_interruptible(&ip6t_mutex);
1525 list_add(&match->list, &ip6t_match);
1532 ip6t_unregister_match(struct ip6t_match *match)
1535 LIST_DELETE(&ip6t_match, match);
1539 int ip6t_register_table(struct ip6t_table *table,
1540 const struct ip6t_replace *repl)
1543 struct ip6t_table_info *newinfo;
1544 static struct ip6t_table_info bootstrap
1545 = { 0, 0, 0, { 0 }, { 0 }, { } };
1547 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1548 + SMP_ALIGN(repl->size) *
1549 (highest_possible_processor_id()+1));
1553 memcpy(newinfo->entries, repl->entries, repl->size);
1555 ret = translate_table(table->name, table->valid_hooks,
1556 newinfo, repl->size,
1565 ret = down_interruptible(&ip6t_mutex);
1571 /* Don't autoload: we'd eat our tail... */
1572 if (list_named_find(&ip6t_tables, table->name)) {
1577 /* Simplifies replace_table code. */
1578 table->private = &bootstrap;
1579 if (!replace_table(table, 0, newinfo, &ret))
1582 duprintf("table->private->number = %u\n",
1583 table->private->number);
1585 /* save number of initial entries */
1586 table->private->initial_entries = table->private->number;
1588 rwlock_init(&table->lock);
1589 list_prepend(&ip6t_tables, table);
1600 void ip6t_unregister_table(struct ip6t_table *table)
1603 LIST_DELETE(&ip6t_tables, table);
1606 /* Decrease module usage counts and free resources */
1607 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1608 cleanup_entry, NULL);
1609 vfree(table->private);
1612 /* Returns 1 if the port is matched by the range, 0 otherwise */
1614 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1618 ret = (port >= min && port <= max) ^ invert;
1623 tcp_find_option(u_int8_t option,
1624 const struct sk_buff *skb,
1625 unsigned int tcpoff,
1626 unsigned int optlen,
1630 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1631 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1634 duprintf("tcp_match: finding option\n");
1637 /* If we don't have the whole header, drop packet. */
1638 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1645 for (i = 0; i < optlen; ) {
1646 if (op[i] == option) return !invert;
1648 else i += op[i+1]?:1;
1655 tcp_match(const struct sk_buff *skb,
1656 const struct net_device *in,
1657 const struct net_device *out,
1658 const void *matchinfo,
1660 unsigned int protoff,
1663 struct tcphdr _tcph, *th;
1664 const struct ip6t_tcp *tcpinfo = matchinfo;
1669 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1670 causes this. Its a cracker trying to break in by doing a
1671 flag overwrite to pass the direction checks.
1674 duprintf("Dropping evil TCP offset=1 frag.\n");
1677 /* Must not be a fragment. */
1681 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1683 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1685 /* We've been asked to examine this packet, and we
1686 can't. Hence, no choice but to drop. */
1687 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1692 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1694 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1696 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1698 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1700 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1701 == tcpinfo->flg_cmp,
1702 IP6T_TCP_INV_FLAGS))
1704 if (tcpinfo->option) {
1705 if (th->doff * 4 < sizeof(_tcph)) {
1709 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1710 th->doff*4 - sizeof(*th),
1711 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1718 /* Called when user tries to insert an entry of this type. */
1720 tcp_checkentry(const char *tablename,
1721 const struct ip6t_ip6 *ipv6,
1723 unsigned int matchsize,
1724 unsigned int hook_mask)
1726 const struct ip6t_tcp *tcpinfo = matchinfo;
1728 /* Must specify proto == TCP, and no unknown invflags */
1729 return ipv6->proto == IPPROTO_TCP
1730 && !(ipv6->invflags & IP6T_INV_PROTO)
1731 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1732 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1736 udp_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 udphdr _udph, *uh;
1745 const struct ip6t_udp *udpinfo = matchinfo;
1747 /* Must not be a fragment. */
1751 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1753 /* We've been asked to examine this packet, and we
1754 can't. Hence, no choice but to drop. */
1755 duprintf("Dropping evil UDP tinygram.\n");
1760 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1762 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1763 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1765 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1768 /* Called when user tries to insert an entry of this type. */
1770 udp_checkentry(const char *tablename,
1771 const struct ip6t_ip6 *ipv6,
1773 unsigned int matchinfosize,
1774 unsigned int hook_mask)
1776 const struct ip6t_udp *udpinfo = matchinfo;
1778 /* Must specify proto == UDP, and no unknown invflags */
1779 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1780 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1784 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1785 duprintf("ip6t_udp: matchsize %u != %u\n",
1786 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1789 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1790 duprintf("ip6t_udp: unknown flags %X\n",
1798 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1800 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1801 u_int8_t type, u_int8_t code,
1804 return (type == test_type && code >= min_code && code <= max_code)
1809 icmp6_match(const struct sk_buff *skb,
1810 const struct net_device *in,
1811 const struct net_device *out,
1812 const void *matchinfo,
1814 unsigned int protoff,
1817 struct icmp6hdr _icmp, *ic;
1818 const struct ip6t_icmp *icmpinfo = matchinfo;
1820 /* Must not be a fragment. */
1824 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1826 /* We've been asked to examine this packet, and we
1827 can't. Hence, no choice but to drop. */
1828 duprintf("Dropping evil ICMP tinygram.\n");
1833 return icmp6_type_code_match(icmpinfo->type,
1836 ic->icmp6_type, ic->icmp6_code,
1837 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1840 /* Called when user tries to insert an entry of this type. */
1842 icmp6_checkentry(const char *tablename,
1843 const struct ip6t_ip6 *ipv6,
1845 unsigned int matchsize,
1846 unsigned int hook_mask)
1848 const struct ip6t_icmp *icmpinfo = matchinfo;
1850 /* Must specify proto == ICMP, and no unknown invflags */
1851 return ipv6->proto == IPPROTO_ICMPV6
1852 && !(ipv6->invflags & IP6T_INV_PROTO)
1853 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1854 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1857 /* The built-in targets: standard (NULL) and error. */
1858 static struct ip6t_target ip6t_standard_target = {
1859 .name = IP6T_STANDARD_TARGET,
1862 static struct ip6t_target ip6t_error_target = {
1863 .name = IP6T_ERROR_TARGET,
1864 .target = ip6t_error,
1867 static struct nf_sockopt_ops ip6t_sockopts = {
1869 .set_optmin = IP6T_BASE_CTL,
1870 .set_optmax = IP6T_SO_SET_MAX+1,
1871 .set = do_ip6t_set_ctl,
1872 .get_optmin = IP6T_BASE_CTL,
1873 .get_optmax = IP6T_SO_GET_MAX+1,
1874 .get = do_ip6t_get_ctl,
1877 static struct ip6t_match tcp_matchstruct = {
1879 .match = &tcp_match,
1880 .checkentry = &tcp_checkentry,
1883 static struct ip6t_match udp_matchstruct = {
1885 .match = &udp_match,
1886 .checkentry = &udp_checkentry,
1889 static struct ip6t_match icmp6_matchstruct = {
1891 .match = &icmp6_match,
1892 .checkentry = &icmp6_checkentry,
1895 #ifdef CONFIG_PROC_FS
1896 static inline int print_name(const char *i,
1897 off_t start_offset, char *buffer, int length,
1898 off_t *pos, unsigned int *count)
1900 if ((*count)++ >= start_offset) {
1901 unsigned int namelen;
1903 namelen = sprintf(buffer + *pos, "%s\n",
1904 i + sizeof(struct list_head));
1905 if (*pos + namelen > length) {
1906 /* Stop iterating */
1914 static inline int print_target(const struct ip6t_target *t,
1915 off_t start_offset, char *buffer, int length,
1916 off_t *pos, unsigned int *count)
1918 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1920 return print_name((char *)t, start_offset, buffer, length, pos, count);
1923 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1926 unsigned int count = 0;
1928 if (down_interruptible(&ip6t_mutex) != 0)
1931 LIST_FIND(&ip6t_tables, print_name, char *,
1932 offset, buffer, length, &pos, &count);
1936 /* `start' hack - see fs/proc/generic.c line ~105 */
1937 *start=(char *)((unsigned long)count-offset);
1941 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1944 unsigned int count = 0;
1946 if (down_interruptible(&ip6t_mutex) != 0)
1949 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1950 offset, buffer, length, &pos, &count);
1954 *start = (char *)((unsigned long)count - offset);
1958 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1961 unsigned int count = 0;
1963 if (down_interruptible(&ip6t_mutex) != 0)
1966 LIST_FIND(&ip6t_match, print_name, char *,
1967 offset, buffer, length, &pos, &count);
1971 *start = (char *)((unsigned long)count - offset);
1975 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1976 { { "ip6_tables_names", ip6t_get_tables },
1977 { "ip6_tables_targets", ip6t_get_targets },
1978 { "ip6_tables_matches", ip6t_get_matches },
1980 #endif /*CONFIG_PROC_FS*/
1982 static int __init init(void)
1986 /* Noone else will be downing sem now, so we won't sleep */
1988 list_append(&ip6t_target, &ip6t_standard_target);
1989 list_append(&ip6t_target, &ip6t_error_target);
1990 list_append(&ip6t_match, &tcp_matchstruct);
1991 list_append(&ip6t_match, &udp_matchstruct);
1992 list_append(&ip6t_match, &icmp6_matchstruct);
1995 /* Register setsockopt */
1996 ret = nf_register_sockopt(&ip6t_sockopts);
1998 duprintf("Unable to register sockopts.\n");
2002 #ifdef CONFIG_PROC_FS
2004 struct proc_dir_entry *proc;
2007 for (i = 0; ip6t_proc_entry[i].name; i++) {
2008 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
2009 ip6t_proc_entry[i].get_info);
2012 proc_net_remove(ip6t_proc_entry[i].name);
2013 nf_unregister_sockopt(&ip6t_sockopts);
2016 proc->owner = THIS_MODULE;
2021 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
2025 static void __exit fini(void)
2027 nf_unregister_sockopt(&ip6t_sockopts);
2028 #ifdef CONFIG_PROC_FS
2031 for (i = 0; ip6t_proc_entry[i].name; i++)
2032 proc_net_remove(ip6t_proc_entry[i].name);
2038 * find specified header up to transport protocol header.
2039 * If found target header, the offset to the header is set to *offset
2040 * and return 0. otherwise, return -1.
2042 * Notes: - non-1st Fragment Header isn't skipped.
2043 * - ESP header isn't skipped.
2044 * - The target header may be trancated.
2046 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
2048 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
2049 u8 nexthdr = skb->nh.ipv6h->nexthdr;
2050 unsigned int len = skb->len - start;
2052 while (nexthdr != target) {
2053 struct ipv6_opt_hdr _hdr, *hp;
2054 unsigned int hdrlen;
2056 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE)
2058 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2061 if (nexthdr == NEXTHDR_FRAGMENT) {
2062 unsigned short _frag_off, *fp;
2063 fp = skb_header_pointer(skb,
2064 start+offsetof(struct frag_hdr,
2071 if (ntohs(*fp) & ~0x7)
2074 } else if (nexthdr == NEXTHDR_AUTH)
2075 hdrlen = (hp->hdrlen + 2) << 2;
2077 hdrlen = ipv6_optlen(hp);
2079 nexthdr = hp->nexthdr;
2088 EXPORT_SYMBOL(ip6t_register_table);
2089 EXPORT_SYMBOL(ip6t_unregister_table);
2090 EXPORT_SYMBOL(ip6t_do_table);
2091 EXPORT_SYMBOL(ip6t_register_match);
2092 EXPORT_SYMBOL(ip6t_unregister_match);
2093 EXPORT_SYMBOL(ip6t_register_target);
2094 EXPORT_SYMBOL(ip6t_unregister_target);
2095 EXPORT_SYMBOL(ip6t_ext_hdr);
2096 EXPORT_SYMBOL(ipv6_find_hdr);