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>
19 #include <linux/skbuff.h>
20 #include <linux/kmod.h>
21 #include <linux/vmalloc.h>
22 #include <linux/netdevice.h>
23 #include <linux/module.h>
24 #include <linux/tcp.h>
25 #include <linux/udp.h>
26 #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... */
84 We keep a set of rules for each CPU, so we can avoid write-locking
85 them in the softirq when updating the counters and therefore
86 only need to read-lock in the softirq; doing a write_lock_bh() in user
87 context stops packets coming through and allows user context to read
88 the counters or update the rules.
90 Hence the start of any table is given by get_table() below. */
92 /* The table itself */
93 struct ip6t_table_info
97 /* Number of entries: FIXME. --RR */
99 /* Initial number of entries. Needed for module usage count */
100 unsigned int initial_entries;
102 /* Entry points and underflows */
103 unsigned int hook_entry[NF_IP6_NUMHOOKS];
104 unsigned int underflow[NF_IP6_NUMHOOKS];
106 /* ip6t_entry tables: one per CPU */
107 void *entries[NR_CPUS];
110 static LIST_HEAD(ip6t_target);
111 static LIST_HEAD(ip6t_match);
112 static LIST_HEAD(ip6t_tables);
113 #define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
114 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
117 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
118 #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; })
119 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
123 ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask,
124 const struct in6_addr *addr2)
127 for( i = 0; i < 16; i++){
128 if((addr1->s6_addr[i] & mask->s6_addr[i]) !=
129 (addr2->s6_addr[i] & mask->s6_addr[i]))
135 /* Check for an extension */
137 ip6t_ext_hdr(u8 nexthdr)
139 return ( (nexthdr == IPPROTO_HOPOPTS) ||
140 (nexthdr == IPPROTO_ROUTING) ||
141 (nexthdr == IPPROTO_FRAGMENT) ||
142 (nexthdr == IPPROTO_ESP) ||
143 (nexthdr == IPPROTO_AH) ||
144 (nexthdr == IPPROTO_NONE) ||
145 (nexthdr == IPPROTO_DSTOPTS) );
148 /* Returns whether matches rule or not. */
150 ip6_packet_match(const struct sk_buff *skb,
153 const struct ip6t_ip6 *ip6info,
154 unsigned int *protoff,
159 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
161 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
163 if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk,
164 &ip6info->src), IP6T_INV_SRCIP)
165 || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk,
166 &ip6info->dst), IP6T_INV_DSTIP)) {
167 dprintf("Source or dest mismatch.\n");
169 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
170 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
171 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
172 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
173 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
174 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
178 /* Look for ifname matches; this should unroll nicely. */
179 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
180 ret |= (((const unsigned long *)indev)[i]
181 ^ ((const unsigned long *)ip6info->iniface)[i])
182 & ((const unsigned long *)ip6info->iniface_mask)[i];
185 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
186 dprintf("VIA in mismatch (%s vs %s).%s\n",
187 indev, ip6info->iniface,
188 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
192 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
193 ret |= (((const unsigned long *)outdev)[i]
194 ^ ((const unsigned long *)ip6info->outiface)[i])
195 & ((const unsigned long *)ip6info->outiface_mask)[i];
198 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
199 dprintf("VIA out mismatch (%s vs %s).%s\n",
200 outdev, ip6info->outiface,
201 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
205 /* ... might want to do something with class and flowlabel here ... */
207 /* look for the desired protocol header */
208 if((ip6info->flags & IP6T_F_PROTO)) {
210 unsigned short _frag_off;
212 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
216 *fragoff = _frag_off;
218 dprintf("Packet protocol %hi ?= %s%hi.\n",
220 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
223 if (ip6info->proto == protohdr) {
224 if(ip6info->invflags & IP6T_INV_PROTO) {
230 /* We need match for the '-p all', too! */
231 if ((ip6info->proto != 0) &&
232 !(ip6info->invflags & IP6T_INV_PROTO))
238 /* should be ip6 safe */
240 ip6_checkentry(const struct ip6t_ip6 *ipv6)
242 if (ipv6->flags & ~IP6T_F_MASK) {
243 duprintf("Unknown flag bits set: %08X\n",
244 ipv6->flags & ~IP6T_F_MASK);
247 if (ipv6->invflags & ~IP6T_INV_MASK) {
248 duprintf("Unknown invflag bits set: %08X\n",
249 ipv6->invflags & ~IP6T_INV_MASK);
256 ip6t_error(struct sk_buff **pskb,
257 const struct net_device *in,
258 const struct net_device *out,
259 unsigned int hooknum,
260 const void *targinfo,
264 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
270 int do_match(struct ip6t_entry_match *m,
271 const struct sk_buff *skb,
272 const struct net_device *in,
273 const struct net_device *out,
275 unsigned int protoff,
278 /* Stop iteration if it doesn't match */
279 if (!m->u.kernel.match->match(skb, in, out, m->data,
280 offset, protoff, hotdrop))
286 static inline struct ip6t_entry *
287 get_entry(void *base, unsigned int offset)
289 return (struct ip6t_entry *)(base + offset);
292 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
294 ip6t_do_table(struct sk_buff **pskb,
296 const struct net_device *in,
297 const struct net_device *out,
298 struct ip6t_table *table,
301 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
303 unsigned int protoff = 0;
305 /* Initializing verdict to NF_DROP keeps gcc happy. */
306 unsigned int verdict = NF_DROP;
307 const char *indev, *outdev;
309 struct ip6t_entry *e, *back;
312 indev = in ? in->name : nulldevname;
313 outdev = out ? out->name : nulldevname;
314 /* We handle fragments by dealing with the first fragment as
315 * if it was a normal packet. All other fragments are treated
316 * normally, except that they will NEVER match rules that ask
317 * things we don't know, ie. tcp syn flag or ports). If the
318 * rule is also a fragment-specific rule, non-fragments won't
321 read_lock_bh(&table->lock);
322 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
323 table_base = (void *)table->private->entries[smp_processor_id()];
324 e = get_entry(table_base, table->private->hook_entry[hook]);
326 #ifdef CONFIG_NETFILTER_DEBUG
327 /* Check noone else using our table */
328 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
329 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
330 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
333 &((struct ip6t_entry *)table_base)->comefrom,
334 ((struct ip6t_entry *)table_base)->comefrom);
336 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
339 /* For return from builtin chain */
340 back = get_entry(table_base, table->private->underflow[hook]);
345 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
346 &protoff, &offset)) {
347 struct ip6t_entry_target *t;
349 if (IP6T_MATCH_ITERATE(e, do_match,
351 offset, protoff, &hotdrop) != 0)
354 ADD_COUNTER(e->counters,
355 ntohs((*pskb)->nh.ipv6h->payload_len)
359 t = ip6t_get_target(e);
360 IP_NF_ASSERT(t->u.kernel.target);
361 /* Standard target? */
362 if (!t->u.kernel.target->target) {
365 v = ((struct ip6t_standard_target *)t)->verdict;
367 /* Pop from stack? */
368 if (v != IP6T_RETURN) {
369 verdict = (unsigned)(-v) - 1;
373 back = get_entry(table_base,
377 if (table_base + v != (void *)e + e->next_offset
378 && !(e->ipv6.flags & IP6T_F_GOTO)) {
379 /* Save old back ptr in next entry */
380 struct ip6t_entry *next
381 = (void *)e + e->next_offset;
383 = (void *)back - table_base;
384 /* set back pointer to next entry */
388 e = get_entry(table_base, v);
390 /* Targets which reenter must return
392 #ifdef CONFIG_NETFILTER_DEBUG
393 ((struct ip6t_entry *)table_base)->comefrom
396 verdict = t->u.kernel.target->target(pskb,
402 #ifdef CONFIG_NETFILTER_DEBUG
403 if (((struct ip6t_entry *)table_base)->comefrom
405 && verdict == IP6T_CONTINUE) {
406 printk("Target %s reentered!\n",
407 t->u.kernel.target->name);
410 ((struct ip6t_entry *)table_base)->comefrom
413 if (verdict == IP6T_CONTINUE)
414 e = (void *)e + e->next_offset;
422 e = (void *)e + e->next_offset;
426 #ifdef CONFIG_NETFILTER_DEBUG
427 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
429 read_unlock_bh(&table->lock);
431 #ifdef DEBUG_ALLOW_ALL
441 * These are weird, but module loading must not be done with mutex
442 * held (since they will register), and we have to have a single
443 * function to use try_then_request_module().
446 /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
447 static inline struct ip6t_table *find_table_lock(const char *name)
449 struct ip6t_table *t;
451 if (down_interruptible(&ip6t_mutex) != 0)
452 return ERR_PTR(-EINTR);
454 list_for_each_entry(t, &ip6t_tables, list)
455 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
461 /* Find match, grabs ref. Returns ERR_PTR() on error. */
462 static inline struct ip6t_match *find_match(const char *name, u8 revision)
464 struct ip6t_match *m;
467 if (down_interruptible(&ip6t_mutex) != 0)
468 return ERR_PTR(-EINTR);
470 list_for_each_entry(m, &ip6t_match, list) {
471 if (strcmp(m->name, name) == 0) {
472 if (m->revision == revision) {
473 if (try_module_get(m->me)) {
478 err = -EPROTOTYPE; /* Found something. */
485 /* Find target, grabs ref. Returns ERR_PTR() on error. */
486 static inline struct ip6t_target *find_target(const char *name, u8 revision)
488 struct ip6t_target *t;
491 if (down_interruptible(&ip6t_mutex) != 0)
492 return ERR_PTR(-EINTR);
494 list_for_each_entry(t, &ip6t_target, list) {
495 if (strcmp(t->name, name) == 0) {
496 if (t->revision == revision) {
497 if (try_module_get(t->me)) {
502 err = -EPROTOTYPE; /* Found something. */
509 struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
511 struct ip6t_target *target;
513 target = try_then_request_module(find_target(name, revision),
515 if (IS_ERR(target) || !target)
520 static int match_revfn(const char *name, u8 revision, int *bestp)
522 struct ip6t_match *m;
525 list_for_each_entry(m, &ip6t_match, list) {
526 if (strcmp(m->name, name) == 0) {
527 if (m->revision > *bestp)
528 *bestp = m->revision;
529 if (m->revision == revision)
536 static int target_revfn(const char *name, u8 revision, int *bestp)
538 struct ip6t_target *t;
541 list_for_each_entry(t, &ip6t_target, list) {
542 if (strcmp(t->name, name) == 0) {
543 if (t->revision > *bestp)
544 *bestp = t->revision;
545 if (t->revision == revision)
552 /* Returns true or fals (if no such extension at all) */
553 static inline int find_revision(const char *name, u8 revision,
554 int (*revfn)(const char *, u8, int *),
557 int have_rev, best = -1;
559 if (down_interruptible(&ip6t_mutex) != 0) {
563 have_rev = revfn(name, revision, &best);
566 /* Nothing at all? Return 0 to try loading module. */
574 *err = -EPROTONOSUPPORT;
579 /* All zeroes == unconditional rule. */
581 unconditional(const struct ip6t_ip6 *ipv6)
585 for (i = 0; i < sizeof(*ipv6); i++)
586 if (((char *)ipv6)[i])
589 return (i == sizeof(*ipv6));
592 /* Figures out from what hook each rule can be called: returns 0 if
593 there are loops. Puts hook bitmask in comefrom. */
595 mark_source_chains(struct ip6t_table_info *newinfo,
596 unsigned int valid_hooks, void *entry0)
600 /* No recursion; use packet counter to save back ptrs (reset
601 to 0 as we leave), and comefrom to save source hook bitmask */
602 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
603 unsigned int pos = newinfo->hook_entry[hook];
605 = (struct ip6t_entry *)(entry0 + pos);
607 if (!(valid_hooks & (1 << hook)))
610 /* Set initial back pointer. */
611 e->counters.pcnt = pos;
614 struct ip6t_standard_target *t
615 = (void *)ip6t_get_target(e);
617 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
618 printk("iptables: loop hook %u pos %u %08X.\n",
619 hook, pos, e->comefrom);
623 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
625 /* Unconditional return/END. */
626 if (e->target_offset == sizeof(struct ip6t_entry)
627 && (strcmp(t->target.u.user.name,
628 IP6T_STANDARD_TARGET) == 0)
630 && unconditional(&e->ipv6)) {
631 unsigned int oldpos, size;
633 /* Return: backtrack through the last
636 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
637 #ifdef DEBUG_IP_FIREWALL_USER
639 & (1 << NF_IP6_NUMHOOKS)) {
640 duprintf("Back unset "
647 pos = e->counters.pcnt;
648 e->counters.pcnt = 0;
650 /* We're at the start. */
654 e = (struct ip6t_entry *)
656 } while (oldpos == pos + e->next_offset);
659 size = e->next_offset;
660 e = (struct ip6t_entry *)
661 (entry0 + pos + size);
662 e->counters.pcnt = pos;
665 int newpos = t->verdict;
667 if (strcmp(t->target.u.user.name,
668 IP6T_STANDARD_TARGET) == 0
670 /* This a jump; chase it. */
671 duprintf("Jump rule %u -> %u\n",
674 /* ... this is a fallthru */
675 newpos = pos + e->next_offset;
677 e = (struct ip6t_entry *)
679 e->counters.pcnt = pos;
684 duprintf("Finished chain %u\n", hook);
690 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
692 if (i && (*i)-- == 0)
695 if (m->u.kernel.match->destroy)
696 m->u.kernel.match->destroy(m->data,
697 m->u.match_size - sizeof(*m));
698 module_put(m->u.kernel.match->me);
703 standard_check(const struct ip6t_entry_target *t,
704 unsigned int max_offset)
706 struct ip6t_standard_target *targ = (void *)t;
708 /* Check standard info. */
710 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
711 duprintf("standard_check: target size %u != %u\n",
713 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
717 if (targ->verdict >= 0
718 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
719 duprintf("ip6t_standard_check: bad verdict (%i)\n",
724 if (targ->verdict < -NF_MAX_VERDICT - 1) {
725 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
733 check_match(struct ip6t_entry_match *m,
735 const struct ip6t_ip6 *ipv6,
736 unsigned int hookmask,
739 struct ip6t_match *match;
741 match = try_then_request_module(find_match(m->u.user.name,
743 "ip6t_%s", m->u.user.name);
744 if (IS_ERR(match) || !match) {
745 duprintf("check_match: `%s' not found\n", m->u.user.name);
746 return match ? PTR_ERR(match) : -ENOENT;
748 m->u.kernel.match = match;
750 if (m->u.kernel.match->checkentry
751 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
752 m->u.match_size - sizeof(*m),
754 module_put(m->u.kernel.match->me);
755 duprintf("ip_tables: check failed for `%s'.\n",
756 m->u.kernel.match->name);
764 static struct ip6t_target ip6t_standard_target;
767 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
770 struct ip6t_entry_target *t;
771 struct ip6t_target *target;
775 if (!ip6_checkentry(&e->ipv6)) {
776 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
781 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
783 goto cleanup_matches;
785 t = ip6t_get_target(e);
786 target = try_then_request_module(find_target(t->u.user.name,
788 "ip6t_%s", t->u.user.name);
789 if (IS_ERR(target) || !target) {
790 duprintf("check_entry: `%s' not found\n", t->u.user.name);
791 ret = target ? PTR_ERR(target) : -ENOENT;
792 goto cleanup_matches;
794 t->u.kernel.target = target;
796 if (t->u.kernel.target == &ip6t_standard_target) {
797 if (!standard_check(t, size)) {
799 goto cleanup_matches;
801 } else if (t->u.kernel.target->checkentry
802 && !t->u.kernel.target->checkentry(name, e, t->data,
806 module_put(t->u.kernel.target->me);
807 duprintf("ip_tables: check failed for `%s'.\n",
808 t->u.kernel.target->name);
810 goto cleanup_matches;
817 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
822 check_entry_size_and_hooks(struct ip6t_entry *e,
823 struct ip6t_table_info *newinfo,
825 unsigned char *limit,
826 const unsigned int *hook_entries,
827 const unsigned int *underflows,
832 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
833 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
834 duprintf("Bad offset %p\n", e);
839 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
840 duprintf("checking: element %p size %u\n",
845 /* Check hooks & underflows */
846 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
847 if ((unsigned char *)e - base == hook_entries[h])
848 newinfo->hook_entry[h] = hook_entries[h];
849 if ((unsigned char *)e - base == underflows[h])
850 newinfo->underflow[h] = underflows[h];
853 /* FIXME: underflows must be unconditional, standard verdicts
854 < 0 (not IP6T_RETURN). --RR */
856 /* Clear counters and comefrom */
857 e->counters = ((struct ip6t_counters) { 0, 0 });
865 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
867 struct ip6t_entry_target *t;
869 if (i && (*i)-- == 0)
872 /* Cleanup all matches */
873 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
874 t = ip6t_get_target(e);
875 if (t->u.kernel.target->destroy)
876 t->u.kernel.target->destroy(t->data,
877 t->u.target_size - sizeof(*t));
878 module_put(t->u.kernel.target->me);
882 /* Checks and translates the user-supplied table segment (held in
885 translate_table(const char *name,
886 unsigned int valid_hooks,
887 struct ip6t_table_info *newinfo,
891 const unsigned int *hook_entries,
892 const unsigned int *underflows)
897 newinfo->size = size;
898 newinfo->number = number;
900 /* Init all hooks to impossible value. */
901 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
902 newinfo->hook_entry[i] = 0xFFFFFFFF;
903 newinfo->underflow[i] = 0xFFFFFFFF;
906 duprintf("translate_table: size %u\n", newinfo->size);
908 /* Walk through entries, checking offsets. */
909 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
910 check_entry_size_and_hooks,
914 hook_entries, underflows, &i);
919 duprintf("translate_table: %u not %u entries\n",
924 /* Check hooks all assigned */
925 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
926 /* Only hooks which are valid */
927 if (!(valid_hooks & (1 << i)))
929 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
930 duprintf("Invalid hook entry %u %u\n",
934 if (newinfo->underflow[i] == 0xFFFFFFFF) {
935 duprintf("Invalid underflow %u %u\n",
941 if (!mark_source_chains(newinfo, valid_hooks, entry0))
944 /* Finally, each sanity check must pass */
946 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
947 check_entry, name, size, &i);
950 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
955 /* And one copy for every other CPU */
957 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
958 memcpy(newinfo->entries[i], entry0, newinfo->size);
964 static struct ip6t_table_info *
965 replace_table(struct ip6t_table *table,
966 unsigned int num_counters,
967 struct ip6t_table_info *newinfo,
970 struct ip6t_table_info *oldinfo;
972 #ifdef CONFIG_NETFILTER_DEBUG
977 struct ip6t_entry *table_base = newinfo->entries[cpu];
979 table_base->comefrom = 0xdead57ac;
984 /* Do the substitution. */
985 write_lock_bh(&table->lock);
986 /* Check inside lock: is the old number correct? */
987 if (num_counters != table->private->number) {
988 duprintf("num_counters != table->private->number (%u/%u)\n",
989 num_counters, table->private->number);
990 write_unlock_bh(&table->lock);
994 oldinfo = table->private;
995 table->private = newinfo;
996 newinfo->initial_entries = oldinfo->initial_entries;
997 write_unlock_bh(&table->lock);
1002 /* Gets counters. */
1004 add_entry_to_counter(const struct ip6t_entry *e,
1005 struct ip6t_counters total[],
1008 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1015 set_entry_to_counter(const struct ip6t_entry *e,
1016 struct ip6t_counters total[],
1019 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1026 get_counters(const struct ip6t_table_info *t,
1027 struct ip6t_counters counters[])
1031 unsigned int curcpu;
1033 /* Instead of clearing (by a previous call to memset())
1034 * the counters and using adds, we set the counters
1035 * with data used by 'current' CPU
1036 * We dont care about preemption here.
1038 curcpu = raw_smp_processor_id();
1041 IP6T_ENTRY_ITERATE(t->entries[curcpu],
1043 set_entry_to_counter,
1051 IP6T_ENTRY_ITERATE(t->entries[cpu],
1053 add_entry_to_counter,
1060 copy_entries_to_user(unsigned int total_size,
1061 struct ip6t_table *table,
1062 void __user *userptr)
1064 unsigned int off, num, countersize;
1065 struct ip6t_entry *e;
1066 struct ip6t_counters *counters;
1068 void *loc_cpu_entry;
1070 /* We need atomic snapshot of counters: rest doesn't change
1071 (other than comefrom, which userspace doesn't care
1073 countersize = sizeof(struct ip6t_counters) * table->private->number;
1074 counters = vmalloc(countersize);
1076 if (counters == NULL)
1079 /* First, sum counters... */
1080 write_lock_bh(&table->lock);
1081 get_counters(table->private, counters);
1082 write_unlock_bh(&table->lock);
1084 /* choose the copy that is on ourc node/cpu */
1085 loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
1086 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
1091 /* FIXME: use iterator macros --RR */
1092 /* ... then go back and fix counters and names */
1093 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1095 struct ip6t_entry_match *m;
1096 struct ip6t_entry_target *t;
1098 e = (struct ip6t_entry *)(loc_cpu_entry + off);
1099 if (copy_to_user(userptr + off
1100 + offsetof(struct ip6t_entry, counters),
1102 sizeof(counters[num])) != 0) {
1107 for (i = sizeof(struct ip6t_entry);
1108 i < e->target_offset;
1109 i += m->u.match_size) {
1112 if (copy_to_user(userptr + off + i
1113 + offsetof(struct ip6t_entry_match,
1115 m->u.kernel.match->name,
1116 strlen(m->u.kernel.match->name)+1)
1123 t = ip6t_get_target(e);
1124 if (copy_to_user(userptr + off + e->target_offset
1125 + offsetof(struct ip6t_entry_target,
1127 t->u.kernel.target->name,
1128 strlen(t->u.kernel.target->name)+1) != 0) {
1140 get_entries(const struct ip6t_get_entries *entries,
1141 struct ip6t_get_entries __user *uptr)
1144 struct ip6t_table *t;
1146 t = find_table_lock(entries->name);
1147 if (t && !IS_ERR(t)) {
1148 duprintf("t->private->number = %u\n",
1149 t->private->number);
1150 if (entries->size == t->private->size)
1151 ret = copy_entries_to_user(t->private->size,
1152 t, uptr->entrytable);
1154 duprintf("get_entries: I've got %u not %u!\n",
1162 ret = t ? PTR_ERR(t) : -ENOENT;
1167 static void free_table_info(struct ip6t_table_info *info)
1171 if (info->size <= PAGE_SIZE)
1172 kfree(info->entries[cpu]);
1174 vfree(info->entries[cpu]);
1179 static struct ip6t_table_info *alloc_table_info(unsigned int size)
1181 struct ip6t_table_info *newinfo;
1184 newinfo = kzalloc(sizeof(struct ip6t_table_info), GFP_KERNEL);
1188 newinfo->size = size;
1191 if (size <= PAGE_SIZE)
1192 newinfo->entries[cpu] = kmalloc_node(size,
1196 newinfo->entries[cpu] = vmalloc_node(size,
1198 if (newinfo->entries[cpu] == NULL) {
1199 free_table_info(newinfo);
1208 do_replace(void __user *user, unsigned int len)
1211 struct ip6t_replace tmp;
1212 struct ip6t_table *t;
1213 struct ip6t_table_info *newinfo, *oldinfo;
1214 struct ip6t_counters *counters;
1215 void *loc_cpu_entry, *loc_cpu_old_entry;
1217 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1220 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1221 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1224 newinfo = alloc_table_info(tmp.size);
1228 /* choose the copy that is on our node/cpu */
1229 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1230 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1236 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1242 ret = translate_table(tmp.name, tmp.valid_hooks,
1243 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1244 tmp.hook_entry, tmp.underflow);
1246 goto free_newinfo_counters;
1248 duprintf("ip_tables: Translated table\n");
1250 t = try_then_request_module(find_table_lock(tmp.name),
1251 "ip6table_%s", tmp.name);
1252 if (!t || IS_ERR(t)) {
1253 ret = t ? PTR_ERR(t) : -ENOENT;
1254 goto free_newinfo_counters_untrans;
1258 if (tmp.valid_hooks != t->valid_hooks) {
1259 duprintf("Valid hook crap: %08X vs %08X\n",
1260 tmp.valid_hooks, t->valid_hooks);
1265 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1269 /* Update module usage count based on number of rules */
1270 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1271 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1272 if ((oldinfo->number > oldinfo->initial_entries) ||
1273 (newinfo->number <= oldinfo->initial_entries))
1275 if ((oldinfo->number > oldinfo->initial_entries) &&
1276 (newinfo->number <= oldinfo->initial_entries))
1279 /* Get the old counters. */
1280 get_counters(oldinfo, counters);
1281 /* Decrease module usage counts and free resource */
1282 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1283 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1284 free_table_info(oldinfo);
1285 if (copy_to_user(tmp.counters, counters,
1286 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1295 free_newinfo_counters_untrans:
1296 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1297 free_newinfo_counters:
1300 free_table_info(newinfo);
1304 /* We're lazy, and add to the first CPU; overflow works its fey magic
1305 * and everything is OK. */
1307 add_counter_to_entry(struct ip6t_entry *e,
1308 const struct ip6t_counters addme[],
1312 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1314 (long unsigned int)e->counters.pcnt,
1315 (long unsigned int)e->counters.bcnt,
1316 (long unsigned int)addme[*i].pcnt,
1317 (long unsigned int)addme[*i].bcnt);
1320 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1327 do_add_counters(void __user *user, unsigned int len)
1330 struct ip6t_counters_info tmp, *paddc;
1331 struct ip6t_table *t;
1333 void *loc_cpu_entry;
1335 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1338 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1341 paddc = vmalloc(len);
1345 if (copy_from_user(paddc, user, len) != 0) {
1350 t = find_table_lock(tmp.name);
1351 if (!t || IS_ERR(t)) {
1352 ret = t ? PTR_ERR(t) : -ENOENT;
1356 write_lock_bh(&t->lock);
1357 if (t->private->number != paddc->num_counters) {
1359 goto unlock_up_free;
1363 /* Choose the copy that is on our node */
1364 loc_cpu_entry = t->private->entries[smp_processor_id()];
1365 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1367 add_counter_to_entry,
1371 write_unlock_bh(&t->lock);
1381 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1385 if (!capable(CAP_NET_ADMIN))
1389 case IP6T_SO_SET_REPLACE:
1390 ret = do_replace(user, len);
1393 case IP6T_SO_SET_ADD_COUNTERS:
1394 ret = do_add_counters(user, len);
1398 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1406 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1410 if (!capable(CAP_NET_ADMIN))
1414 case IP6T_SO_GET_INFO: {
1415 char name[IP6T_TABLE_MAXNAMELEN];
1416 struct ip6t_table *t;
1418 if (*len != sizeof(struct ip6t_getinfo)) {
1419 duprintf("length %u != %u\n", *len,
1420 sizeof(struct ip6t_getinfo));
1425 if (copy_from_user(name, user, sizeof(name)) != 0) {
1429 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1431 t = try_then_request_module(find_table_lock(name),
1432 "ip6table_%s", name);
1433 if (t && !IS_ERR(t)) {
1434 struct ip6t_getinfo info;
1436 info.valid_hooks = t->valid_hooks;
1437 memcpy(info.hook_entry, t->private->hook_entry,
1438 sizeof(info.hook_entry));
1439 memcpy(info.underflow, t->private->underflow,
1440 sizeof(info.underflow));
1441 info.num_entries = t->private->number;
1442 info.size = t->private->size;
1443 memcpy(info.name, name, sizeof(info.name));
1445 if (copy_to_user(user, &info, *len) != 0)
1452 ret = t ? PTR_ERR(t) : -ENOENT;
1456 case IP6T_SO_GET_ENTRIES: {
1457 struct ip6t_get_entries get;
1459 if (*len < sizeof(get)) {
1460 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1462 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1464 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1465 duprintf("get_entries: %u != %u\n", *len,
1466 sizeof(struct ip6t_get_entries) + get.size);
1469 ret = get_entries(&get, user);
1473 case IP6T_SO_GET_REVISION_MATCH:
1474 case IP6T_SO_GET_REVISION_TARGET: {
1475 struct ip6t_get_revision rev;
1476 int (*revfn)(const char *, u8, int *);
1478 if (*len != sizeof(rev)) {
1482 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1487 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1488 revfn = target_revfn;
1490 revfn = match_revfn;
1492 try_then_request_module(find_revision(rev.name, rev.revision,
1494 "ip6t_%s", rev.name);
1499 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1506 /* Registration hooks for targets. */
1508 ip6t_register_target(struct ip6t_target *target)
1512 ret = down_interruptible(&ip6t_mutex);
1515 list_add(&target->list, &ip6t_target);
1521 ip6t_unregister_target(struct ip6t_target *target)
1524 LIST_DELETE(&ip6t_target, target);
1529 ip6t_register_match(struct ip6t_match *match)
1533 ret = down_interruptible(&ip6t_mutex);
1537 list_add(&match->list, &ip6t_match);
1544 ip6t_unregister_match(struct ip6t_match *match)
1547 LIST_DELETE(&ip6t_match, match);
1551 int ip6t_register_table(struct ip6t_table *table,
1552 const struct ip6t_replace *repl)
1555 struct ip6t_table_info *newinfo;
1556 static struct ip6t_table_info bootstrap
1557 = { 0, 0, 0, { 0 }, { 0 }, { } };
1558 void *loc_cpu_entry;
1560 newinfo = alloc_table_info(repl->size);
1564 /* choose the copy on our node/cpu */
1565 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1566 memcpy(loc_cpu_entry, repl->entries, repl->size);
1568 ret = translate_table(table->name, table->valid_hooks,
1569 newinfo, loc_cpu_entry, repl->size,
1574 free_table_info(newinfo);
1578 ret = down_interruptible(&ip6t_mutex);
1580 free_table_info(newinfo);
1584 /* Don't autoload: we'd eat our tail... */
1585 if (list_named_find(&ip6t_tables, table->name)) {
1590 /* Simplifies replace_table code. */
1591 table->private = &bootstrap;
1592 if (!replace_table(table, 0, newinfo, &ret))
1595 duprintf("table->private->number = %u\n",
1596 table->private->number);
1598 /* save number of initial entries */
1599 table->private->initial_entries = table->private->number;
1601 rwlock_init(&table->lock);
1602 list_prepend(&ip6t_tables, table);
1609 free_table_info(newinfo);
1613 void ip6t_unregister_table(struct ip6t_table *table)
1615 void *loc_cpu_entry;
1618 LIST_DELETE(&ip6t_tables, table);
1621 /* Decrease module usage counts and free resources */
1622 loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
1623 IP6T_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
1624 cleanup_entry, NULL);
1625 free_table_info(table->private);
1628 /* Returns 1 if the port is matched by the range, 0 otherwise */
1630 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1634 ret = (port >= min && port <= max) ^ invert;
1639 tcp_find_option(u_int8_t option,
1640 const struct sk_buff *skb,
1641 unsigned int tcpoff,
1642 unsigned int optlen,
1646 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1647 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1650 duprintf("tcp_match: finding option\n");
1653 /* If we don't have the whole header, drop packet. */
1654 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1661 for (i = 0; i < optlen; ) {
1662 if (op[i] == option) return !invert;
1664 else i += op[i+1]?:1;
1671 tcp_match(const struct sk_buff *skb,
1672 const struct net_device *in,
1673 const struct net_device *out,
1674 const void *matchinfo,
1676 unsigned int protoff,
1679 struct tcphdr _tcph, *th;
1680 const struct ip6t_tcp *tcpinfo = matchinfo;
1685 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1686 causes this. Its a cracker trying to break in by doing a
1687 flag overwrite to pass the direction checks.
1690 duprintf("Dropping evil TCP offset=1 frag.\n");
1693 /* Must not be a fragment. */
1697 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1699 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1701 /* We've been asked to examine this packet, and we
1702 can't. Hence, no choice but to drop. */
1703 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1708 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1710 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1712 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1714 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1716 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1717 == tcpinfo->flg_cmp,
1718 IP6T_TCP_INV_FLAGS))
1720 if (tcpinfo->option) {
1721 if (th->doff * 4 < sizeof(_tcph)) {
1725 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1726 th->doff*4 - sizeof(*th),
1727 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1734 /* Called when user tries to insert an entry of this type. */
1736 tcp_checkentry(const char *tablename,
1737 const struct ip6t_ip6 *ipv6,
1739 unsigned int matchsize,
1740 unsigned int hook_mask)
1742 const struct ip6t_tcp *tcpinfo = matchinfo;
1744 /* Must specify proto == TCP, and no unknown invflags */
1745 return ipv6->proto == IPPROTO_TCP
1746 && !(ipv6->invflags & IP6T_INV_PROTO)
1747 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1748 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1752 udp_match(const struct sk_buff *skb,
1753 const struct net_device *in,
1754 const struct net_device *out,
1755 const void *matchinfo,
1757 unsigned int protoff,
1760 struct udphdr _udph, *uh;
1761 const struct ip6t_udp *udpinfo = matchinfo;
1763 /* Must not be a fragment. */
1767 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1769 /* We've been asked to examine this packet, and we
1770 can't. Hence, no choice but to drop. */
1771 duprintf("Dropping evil UDP tinygram.\n");
1776 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1778 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1779 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1781 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1784 /* Called when user tries to insert an entry of this type. */
1786 udp_checkentry(const char *tablename,
1787 const struct ip6t_ip6 *ipv6,
1789 unsigned int matchinfosize,
1790 unsigned int hook_mask)
1792 const struct ip6t_udp *udpinfo = matchinfo;
1794 /* Must specify proto == UDP, and no unknown invflags */
1795 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1796 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1800 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1801 duprintf("ip6t_udp: matchsize %u != %u\n",
1802 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1805 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1806 duprintf("ip6t_udp: unknown flags %X\n",
1814 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1816 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1817 u_int8_t type, u_int8_t code,
1820 return (type == test_type && code >= min_code && code <= max_code)
1825 icmp6_match(const struct sk_buff *skb,
1826 const struct net_device *in,
1827 const struct net_device *out,
1828 const void *matchinfo,
1830 unsigned int protoff,
1833 struct icmp6hdr _icmp, *ic;
1834 const struct ip6t_icmp *icmpinfo = matchinfo;
1836 /* Must not be a fragment. */
1840 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1842 /* We've been asked to examine this packet, and we
1843 can't. Hence, no choice but to drop. */
1844 duprintf("Dropping evil ICMP tinygram.\n");
1849 return icmp6_type_code_match(icmpinfo->type,
1852 ic->icmp6_type, ic->icmp6_code,
1853 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1856 /* Called when user tries to insert an entry of this type. */
1858 icmp6_checkentry(const char *tablename,
1859 const struct ip6t_ip6 *ipv6,
1861 unsigned int matchsize,
1862 unsigned int hook_mask)
1864 const struct ip6t_icmp *icmpinfo = matchinfo;
1866 /* Must specify proto == ICMP, and no unknown invflags */
1867 return ipv6->proto == IPPROTO_ICMPV6
1868 && !(ipv6->invflags & IP6T_INV_PROTO)
1869 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1870 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1873 /* The built-in targets: standard (NULL) and error. */
1874 static struct ip6t_target ip6t_standard_target = {
1875 .name = IP6T_STANDARD_TARGET,
1878 static struct ip6t_target ip6t_error_target = {
1879 .name = IP6T_ERROR_TARGET,
1880 .target = ip6t_error,
1883 static struct nf_sockopt_ops ip6t_sockopts = {
1885 .set_optmin = IP6T_BASE_CTL,
1886 .set_optmax = IP6T_SO_SET_MAX+1,
1887 .set = do_ip6t_set_ctl,
1888 .get_optmin = IP6T_BASE_CTL,
1889 .get_optmax = IP6T_SO_GET_MAX+1,
1890 .get = do_ip6t_get_ctl,
1893 static struct ip6t_match tcp_matchstruct = {
1895 .match = &tcp_match,
1896 .checkentry = &tcp_checkentry,
1899 static struct ip6t_match udp_matchstruct = {
1901 .match = &udp_match,
1902 .checkentry = &udp_checkentry,
1905 static struct ip6t_match icmp6_matchstruct = {
1907 .match = &icmp6_match,
1908 .checkentry = &icmp6_checkentry,
1911 #ifdef CONFIG_PROC_FS
1912 static inline int print_name(const char *i,
1913 off_t start_offset, char *buffer, int length,
1914 off_t *pos, unsigned int *count)
1916 if ((*count)++ >= start_offset) {
1917 unsigned int namelen;
1919 namelen = sprintf(buffer + *pos, "%s\n",
1920 i + sizeof(struct list_head));
1921 if (*pos + namelen > length) {
1922 /* Stop iterating */
1930 static inline int print_target(const struct ip6t_target *t,
1931 off_t start_offset, char *buffer, int length,
1932 off_t *pos, unsigned int *count)
1934 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1936 return print_name((char *)t, start_offset, buffer, length, pos, count);
1939 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1942 unsigned int count = 0;
1944 if (down_interruptible(&ip6t_mutex) != 0)
1947 LIST_FIND(&ip6t_tables, print_name, char *,
1948 offset, buffer, length, &pos, &count);
1952 /* `start' hack - see fs/proc/generic.c line ~105 */
1953 *start=(char *)((unsigned long)count-offset);
1957 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1960 unsigned int count = 0;
1962 if (down_interruptible(&ip6t_mutex) != 0)
1965 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1966 offset, buffer, length, &pos, &count);
1970 *start = (char *)((unsigned long)count - offset);
1974 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1977 unsigned int count = 0;
1979 if (down_interruptible(&ip6t_mutex) != 0)
1982 LIST_FIND(&ip6t_match, print_name, char *,
1983 offset, buffer, length, &pos, &count);
1987 *start = (char *)((unsigned long)count - offset);
1991 static const struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1992 { { "ip6_tables_names", ip6t_get_tables },
1993 { "ip6_tables_targets", ip6t_get_targets },
1994 { "ip6_tables_matches", ip6t_get_matches },
1996 #endif /*CONFIG_PROC_FS*/
1998 static int __init init(void)
2002 /* Noone else will be downing sem now, so we won't sleep */
2004 list_append(&ip6t_target, &ip6t_standard_target);
2005 list_append(&ip6t_target, &ip6t_error_target);
2006 list_append(&ip6t_match, &tcp_matchstruct);
2007 list_append(&ip6t_match, &udp_matchstruct);
2008 list_append(&ip6t_match, &icmp6_matchstruct);
2011 /* Register setsockopt */
2012 ret = nf_register_sockopt(&ip6t_sockopts);
2014 duprintf("Unable to register sockopts.\n");
2018 #ifdef CONFIG_PROC_FS
2020 struct proc_dir_entry *proc;
2023 for (i = 0; ip6t_proc_entry[i].name; i++) {
2024 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
2025 ip6t_proc_entry[i].get_info);
2028 proc_net_remove(ip6t_proc_entry[i].name);
2029 nf_unregister_sockopt(&ip6t_sockopts);
2032 proc->owner = THIS_MODULE;
2037 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
2041 static void __exit fini(void)
2043 nf_unregister_sockopt(&ip6t_sockopts);
2044 #ifdef CONFIG_PROC_FS
2047 for (i = 0; ip6t_proc_entry[i].name; i++)
2048 proc_net_remove(ip6t_proc_entry[i].name);
2054 * find the offset to specified header or the protocol number of last header
2055 * if target < 0. "last header" is transport protocol header, ESP, or
2058 * If target header is found, its offset is set in *offset and return protocol
2059 * number. Otherwise, return -1.
2061 * Note that non-1st fragment is special case that "the protocol number
2062 * of last header" is "next header" field in Fragment header. In this case,
2063 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2067 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2068 int target, unsigned short *fragoff)
2070 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
2071 u8 nexthdr = skb->nh.ipv6h->nexthdr;
2072 unsigned int len = skb->len - start;
2077 while (nexthdr != target) {
2078 struct ipv6_opt_hdr _hdr, *hp;
2079 unsigned int hdrlen;
2081 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2087 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2090 if (nexthdr == NEXTHDR_FRAGMENT) {
2091 unsigned short _frag_off, *fp;
2092 fp = skb_header_pointer(skb,
2093 start+offsetof(struct frag_hdr,
2100 _frag_off = ntohs(*fp) & ~0x7;
2103 ((!ipv6_ext_hdr(hp->nexthdr)) ||
2104 nexthdr == NEXTHDR_NONE)) {
2106 *fragoff = _frag_off;
2112 } else if (nexthdr == NEXTHDR_AUTH)
2113 hdrlen = (hp->hdrlen + 2) << 2;
2115 hdrlen = ipv6_optlen(hp);
2117 nexthdr = hp->nexthdr;
2126 EXPORT_SYMBOL(ip6t_register_table);
2127 EXPORT_SYMBOL(ip6t_unregister_table);
2128 EXPORT_SYMBOL(ip6t_do_table);
2129 EXPORT_SYMBOL(ip6t_register_match);
2130 EXPORT_SYMBOL(ip6t_unregister_match);
2131 EXPORT_SYMBOL(ip6t_register_target);
2132 EXPORT_SYMBOL(ip6t_unregister_target);
2133 EXPORT_SYMBOL(ip6t_ext_hdr);
2134 EXPORT_SYMBOL(ipv6_find_hdr);
2135 EXPORT_SYMBOL(ip6_masked_addrcmp);