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 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
8 * - increase module usage count as soon as we have rules inside
10 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
11 * - new extension header parser code
13 #include <linux/config.h>
14 #include <linux/skbuff.h>
15 #include <linux/kmod.h>
16 #include <linux/vmalloc.h>
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 #include <linux/tcp.h>
20 #include <linux/udp.h>
21 #include <linux/icmpv6.h>
23 #include <asm/uaccess.h>
24 #include <asm/semaphore.h>
25 #include <linux/proc_fs.h>
27 #include <linux/netfilter_ipv6/ip6_tables.h>
29 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
30 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
32 /*#define DEBUG_IP_FIREWALL*/
33 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
34 /*#define DEBUG_IP_FIREWALL_USER*/
36 #ifdef DEBUG_IP_FIREWALL
37 #define dprintf(format, args...) printk(format , ## args)
39 #define dprintf(format, args...)
42 #ifdef DEBUG_IP_FIREWALL_USER
43 #define duprintf(format, args...) printk(format , ## args)
45 #define duprintf(format, args...)
48 #ifdef CONFIG_NETFILTER_DEBUG
49 #define IP_NF_ASSERT(x) \
52 printk("IP_NF_ASSERT: %s:%s:%u\n", \
53 __FUNCTION__, __FILE__, __LINE__); \
56 #define IP_NF_ASSERT(x)
58 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
60 /* Mutex protects lists (only traversed in user context). */
61 static DECLARE_MUTEX(ip6t_mutex);
64 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
65 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
66 #include <linux/netfilter_ipv4/lockhelp.h>
67 #include <linux/netfilter_ipv4/listhelp.h>
70 /* All the better to debug you with... */
75 /* Locking is simple: we assume at worst case there will be one packet
76 in user context and one from bottom halves (or soft irq if Alexey's
77 softnet patch was applied).
79 We keep a set of rules for each CPU, so we can avoid write-locking
80 them; doing a readlock_bh() stops packets coming through if we're
83 To be cache friendly on SMP, we arrange them like so:
85 ... cache-align padding ...
88 Hence the start of any table is given by get_table() below. */
90 /* The table itself */
91 struct ip6t_table_info
95 /* Number of entries: FIXME. --RR */
97 /* Initial number of entries. Needed for module usage count */
98 unsigned int initial_entries;
100 /* Entry points and underflows */
101 unsigned int hook_entry[NF_IP6_NUMHOOKS];
102 unsigned int underflow[NF_IP6_NUMHOOKS];
104 char padding[SMP_ALIGN((NF_IP6_NUMHOOKS*2+2)*sizeof(unsigned int))];
106 /* ip6t_entry tables: one per CPU */
110 static LIST_HEAD(ip6t_target);
111 static LIST_HEAD(ip6t_match);
112 static LIST_HEAD(ip6t_tables);
113 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
116 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
118 #define TABLE_OFFSET(t,p) 0
122 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
123 #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; })
124 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
127 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
128 struct in6_addr addr2)
131 for( i = 0; i < 16; i++){
132 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
133 (addr2.s6_addr[i] & mask.s6_addr[i]))
139 /* Check for an extension */
141 ip6t_ext_hdr(u8 nexthdr)
143 return ( (nexthdr == IPPROTO_HOPOPTS) ||
144 (nexthdr == IPPROTO_ROUTING) ||
145 (nexthdr == IPPROTO_FRAGMENT) ||
146 (nexthdr == IPPROTO_ESP) ||
147 (nexthdr == IPPROTO_AH) ||
148 (nexthdr == IPPROTO_NONE) ||
149 (nexthdr == IPPROTO_DSTOPTS) );
152 /* Returns whether matches rule or not. */
154 ip6_packet_match(const struct sk_buff *skb,
155 const struct ipv6hdr *ipv6,
158 const struct ip6t_ip6 *ip6info,
164 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
166 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
168 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
170 dprintf("Source or dest mismatch.\n");
172 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
173 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
174 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
175 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
176 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
177 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
181 /* Look for ifname matches; this should unroll nicely. */
182 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
183 ret |= (((const unsigned long *)indev)[i]
184 ^ ((const unsigned long *)ip6info->iniface)[i])
185 & ((const unsigned long *)ip6info->iniface_mask)[i];
188 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
189 dprintf("VIA in mismatch (%s vs %s).%s\n",
190 indev, ip6info->iniface,
191 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
195 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
196 ret |= (((const unsigned long *)outdev)[i]
197 ^ ((const unsigned long *)ip6info->outiface)[i])
198 & ((const unsigned long *)ip6info->outiface_mask)[i];
201 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
202 dprintf("VIA out mismatch (%s vs %s).%s\n",
203 outdev, ip6info->outiface,
204 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
208 /* ... might want to do something with class and flowlabel here ... */
210 /* look for the desired protocol header */
211 if((ip6info->flags & IP6T_F_PROTO)) {
212 u_int8_t currenthdr = ipv6->nexthdr;
213 struct ipv6_opt_hdr *hdrptr;
214 u_int16_t ptr; /* Header offset in skb */
215 u_int16_t hdrlen; /* Header */
219 while (ip6t_ext_hdr(currenthdr)) {
220 /* Is there enough space for the next ext header? */
221 if (skb->len - ptr < IPV6_OPTHDR_LEN)
224 /* NONE or ESP: there isn't protocol part */
225 /* If we want to count these packets in '-p all',
226 * we will change the return 0 to 1*/
227 if ((currenthdr == IPPROTO_NONE) ||
228 (currenthdr == IPPROTO_ESP))
231 hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
233 /* Size calculation */
234 if (currenthdr == IPPROTO_FRAGMENT) {
236 } else if (currenthdr == IPPROTO_AH)
237 hdrlen = (hdrptr->hdrlen+2)<<2;
239 hdrlen = ipv6_optlen(hdrptr);
241 currenthdr = hdrptr->nexthdr;
243 /* ptr is too large */
244 if ( ptr > skb->len )
248 /* currenthdr contains the protocol header */
250 dprintf("Packet protocol %hi ?= %s%hi.\n",
252 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
255 if (ip6info->proto == currenthdr) {
256 if(ip6info->invflags & IP6T_INV_PROTO) {
262 /* We need match for the '-p all', too! */
263 if ((ip6info->proto != 0) &&
264 !(ip6info->invflags & IP6T_INV_PROTO))
270 /* should be ip6 safe */
272 ip6_checkentry(const struct ip6t_ip6 *ipv6)
274 if (ipv6->flags & ~IP6T_F_MASK) {
275 duprintf("Unknown flag bits set: %08X\n",
276 ipv6->flags & ~IP6T_F_MASK);
279 if (ipv6->invflags & ~IP6T_INV_MASK) {
280 duprintf("Unknown invflag bits set: %08X\n",
281 ipv6->invflags & ~IP6T_INV_MASK);
288 ip6t_error(struct sk_buff **pskb,
289 unsigned int hooknum,
290 const struct net_device *in,
291 const struct net_device *out,
292 const void *targinfo,
296 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
302 int do_match(struct ip6t_entry_match *m,
303 const struct sk_buff *skb,
304 const struct net_device *in,
305 const struct net_device *out,
311 /* Stop iteration if it doesn't match */
312 if (!m->u.kernel.match->match(skb, in, out, m->data,
313 offset, hdr, datalen, hotdrop))
319 static inline struct ip6t_entry *
320 get_entry(void *base, unsigned int offset)
322 return (struct ip6t_entry *)(base + offset);
325 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
327 ip6t_do_table(struct sk_buff **pskb,
329 const struct net_device *in,
330 const struct net_device *out,
331 struct ip6t_table *table,
334 static const char nulldevname[IFNAMSIZ] = { 0 };
335 u_int16_t offset = 0;
336 struct ipv6hdr *ipv6;
340 /* Initializing verdict to NF_DROP keeps gcc happy. */
341 unsigned int verdict = NF_DROP;
342 const char *indev, *outdev;
344 struct ip6t_entry *e, *back;
347 ipv6 = (*pskb)->nh.ipv6h;
348 protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN);
349 datalen = (*pskb)->len - IPV6_HDR_LEN;
350 indev = in ? in->name : nulldevname;
351 outdev = out ? out->name : nulldevname;
353 /* We handle fragments by dealing with the first fragment as
354 * if it was a normal packet. All other fragments are treated
355 * normally, except that they will NEVER match rules that ask
356 * things we don't know, ie. tcp syn flag or ports). If the
357 * rule is also a fragment-specific rule, non-fragments won't
360 read_lock_bh(&table->lock);
361 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
362 table_base = (void *)table->private->entries
363 + TABLE_OFFSET(table->private,
364 cpu_number_map(smp_processor_id()));
365 e = get_entry(table_base, table->private->hook_entry[hook]);
367 #ifdef CONFIG_NETFILTER_DEBUG
368 /* Check noone else using our table */
369 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
370 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
371 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
374 &((struct ip6t_entry *)table_base)->comefrom,
375 ((struct ip6t_entry *)table_base)->comefrom);
377 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
380 /* For return from builtin chain */
381 back = get_entry(table_base, table->private->underflow[hook]);
386 (*pskb)->nfcache |= e->nfcache;
387 if (ip6_packet_match(*pskb, ipv6, indev, outdev,
389 struct ip6t_entry_target *t;
391 if (IP6T_MATCH_ITERATE(e, do_match,
394 datalen, &hotdrop) != 0)
397 ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + IPV6_HDR_LEN, 1);
399 t = ip6t_get_target(e);
400 IP_NF_ASSERT(t->u.kernel.target);
401 /* Standard target? */
402 if (!t->u.kernel.target->target) {
405 v = ((struct ip6t_standard_target *)t)->verdict;
407 /* Pop from stack? */
408 if (v != IP6T_RETURN) {
409 verdict = (unsigned)(-v) - 1;
413 back = get_entry(table_base,
418 != (void *)e + e->next_offset) {
419 /* Save old back ptr in next entry */
420 struct ip6t_entry *next
421 = (void *)e + e->next_offset;
423 = (void *)back - table_base;
424 /* set back pointer to next entry */
428 e = get_entry(table_base, v);
430 /* Targets which reenter must return
432 #ifdef CONFIG_NETFILTER_DEBUG
433 ((struct ip6t_entry *)table_base)->comefrom
436 verdict = t->u.kernel.target->target(pskb,
442 #ifdef CONFIG_NETFILTER_DEBUG
443 if (((struct ip6t_entry *)table_base)->comefrom
445 && verdict == IP6T_CONTINUE) {
446 printk("Target %s reentered!\n",
447 t->u.kernel.target->name);
450 ((struct ip6t_entry *)table_base)->comefrom
453 /* Target might have changed stuff. */
454 ipv6 = (*pskb)->nh.ipv6h;
455 protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN);
456 datalen = (*pskb)->len - IPV6_HDR_LEN;
458 if (verdict == IP6T_CONTINUE)
459 e = (void *)e + e->next_offset;
467 e = (void *)e + e->next_offset;
471 #ifdef CONFIG_NETFILTER_DEBUG
472 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
474 read_unlock_bh(&table->lock);
476 #ifdef DEBUG_ALLOW_ALL
485 /* If it succeeds, returns element and locks mutex */
487 find_inlist_lock_noload(struct list_head *head,
490 struct semaphore *mutex)
495 duprintf("find_inlist: searching for `%s' in %s.\n",
496 name, head == &ip6t_target ? "ip6t_target"
497 : head == &ip6t_match ? "ip6t_match"
498 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
501 *error = down_interruptible(mutex);
505 ret = list_named_find(head, name);
514 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
517 find_inlist_lock(struct list_head *head,
521 struct semaphore *mutex)
525 ret = find_inlist_lock_noload(head, name, error, mutex);
527 char modulename[IP6T_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
528 strcpy(modulename, prefix);
529 strcat(modulename, name);
530 duprintf("find_inlist: loading `%s'.\n", modulename);
531 request_module(modulename);
532 ret = find_inlist_lock_noload(head, name, error, mutex);
539 static inline struct ip6t_table *
540 find_table_lock(const char *name, int *error, struct semaphore *mutex)
542 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
545 static inline struct ip6t_match *
546 find_match_lock(const char *name, int *error, struct semaphore *mutex)
548 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
551 static inline struct ip6t_target *
552 find_target_lock(const char *name, int *error, struct semaphore *mutex)
554 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
557 /* All zeroes == unconditional rule. */
559 unconditional(const struct ip6t_ip6 *ipv6)
563 for (i = 0; i < sizeof(*ipv6); i++)
564 if (((char *)ipv6)[i])
567 return (i == sizeof(*ipv6));
570 /* Figures out from what hook each rule can be called: returns 0 if
571 there are loops. Puts hook bitmask in comefrom. */
573 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
577 /* No recursion; use packet counter to save back ptrs (reset
578 to 0 as we leave), and comefrom to save source hook bitmask */
579 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
580 unsigned int pos = newinfo->hook_entry[hook];
582 = (struct ip6t_entry *)(newinfo->entries + pos);
584 if (!(valid_hooks & (1 << hook)))
587 /* Set initial back pointer. */
588 e->counters.pcnt = pos;
591 struct ip6t_standard_target *t
592 = (void *)ip6t_get_target(e);
594 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
595 printk("iptables: loop hook %u pos %u %08X.\n",
596 hook, pos, e->comefrom);
600 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
602 /* Unconditional return/END. */
603 if (e->target_offset == sizeof(struct ip6t_entry)
604 && (strcmp(t->target.u.user.name,
605 IP6T_STANDARD_TARGET) == 0)
607 && unconditional(&e->ipv6)) {
608 unsigned int oldpos, size;
610 /* Return: backtrack through the last
613 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
614 #ifdef DEBUG_IP_FIREWALL_USER
616 & (1 << NF_IP6_NUMHOOKS)) {
617 duprintf("Back unset "
624 pos = e->counters.pcnt;
625 e->counters.pcnt = 0;
627 /* We're at the start. */
631 e = (struct ip6t_entry *)
632 (newinfo->entries + pos);
633 } while (oldpos == pos + e->next_offset);
636 size = e->next_offset;
637 e = (struct ip6t_entry *)
638 (newinfo->entries + pos + size);
639 e->counters.pcnt = pos;
642 int newpos = t->verdict;
644 if (strcmp(t->target.u.user.name,
645 IP6T_STANDARD_TARGET) == 0
647 /* This a jump; chase it. */
648 duprintf("Jump rule %u -> %u\n",
651 /* ... this is a fallthru */
652 newpos = pos + e->next_offset;
654 e = (struct ip6t_entry *)
655 (newinfo->entries + newpos);
656 e->counters.pcnt = pos;
661 duprintf("Finished chain %u\n", hook);
667 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
669 if (i && (*i)-- == 0)
672 if (m->u.kernel.match->destroy)
673 m->u.kernel.match->destroy(m->data,
674 m->u.match_size - sizeof(*m));
676 if (m->u.kernel.match->me)
677 __MOD_DEC_USE_COUNT(m->u.kernel.match->me);
683 standard_check(const struct ip6t_entry_target *t,
684 unsigned int max_offset)
686 struct ip6t_standard_target *targ = (void *)t;
688 /* Check standard info. */
690 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
691 duprintf("standard_check: target size %u != %u\n",
693 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
697 if (targ->verdict >= 0
698 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
699 duprintf("ip6t_standard_check: bad verdict (%i)\n",
704 if (targ->verdict < -NF_MAX_VERDICT - 1) {
705 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
713 check_match(struct ip6t_entry_match *m,
715 const struct ip6t_ip6 *ipv6,
716 unsigned int hookmask,
720 struct ip6t_match *match;
722 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
724 // duprintf("check_match: `%s' not found\n", m->u.name);
728 __MOD_INC_USE_COUNT(match->me);
729 m->u.kernel.match = match;
732 if (m->u.kernel.match->checkentry
733 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
734 m->u.match_size - sizeof(*m),
736 if (m->u.kernel.match->me)
737 __MOD_DEC_USE_COUNT(m->u.kernel.match->me);
738 duprintf("ip_tables: check failed for `%s'.\n",
739 m->u.kernel.match->name);
747 static struct ip6t_target ip6t_standard_target;
750 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
753 struct ip6t_entry_target *t;
754 struct ip6t_target *target;
758 if (!ip6_checkentry(&e->ipv6)) {
759 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
764 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
766 goto cleanup_matches;
768 t = ip6t_get_target(e);
769 target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
771 duprintf("check_entry: `%s' not found\n", t->u.user.name);
772 goto cleanup_matches;
775 __MOD_INC_USE_COUNT(target->me);
776 t->u.kernel.target = target;
779 if (t->u.kernel.target == &ip6t_standard_target) {
780 if (!standard_check(t, size)) {
782 goto cleanup_matches;
784 } else if (t->u.kernel.target->checkentry
785 && !t->u.kernel.target->checkentry(name, e, t->data,
789 if (t->u.kernel.target->me)
790 __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
791 duprintf("ip_tables: check failed for `%s'.\n",
792 t->u.kernel.target->name);
794 goto cleanup_matches;
801 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
806 check_entry_size_and_hooks(struct ip6t_entry *e,
807 struct ip6t_table_info *newinfo,
809 unsigned char *limit,
810 const unsigned int *hook_entries,
811 const unsigned int *underflows,
816 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
817 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
818 duprintf("Bad offset %p\n", e);
823 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
824 duprintf("checking: element %p size %u\n",
829 /* Check hooks & underflows */
830 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
831 if ((unsigned char *)e - base == hook_entries[h])
832 newinfo->hook_entry[h] = hook_entries[h];
833 if ((unsigned char *)e - base == underflows[h])
834 newinfo->underflow[h] = underflows[h];
837 /* FIXME: underflows must be unconditional, standard verdicts
838 < 0 (not IP6T_RETURN). --RR */
840 /* Clear counters and comefrom */
841 e->counters = ((struct ip6t_counters) { 0, 0 });
849 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
851 struct ip6t_entry_target *t;
853 if (i && (*i)-- == 0)
856 /* Cleanup all matches */
857 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
858 t = ip6t_get_target(e);
859 if (t->u.kernel.target->destroy)
860 t->u.kernel.target->destroy(t->data,
861 t->u.target_size - sizeof(*t));
862 if (t->u.kernel.target->me)
863 __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
868 /* Checks and translates the user-supplied table segment (held in
871 translate_table(const char *name,
872 unsigned int valid_hooks,
873 struct ip6t_table_info *newinfo,
876 const unsigned int *hook_entries,
877 const unsigned int *underflows)
882 newinfo->size = size;
883 newinfo->number = number;
885 /* Init all hooks to impossible value. */
886 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
887 newinfo->hook_entry[i] = 0xFFFFFFFF;
888 newinfo->underflow[i] = 0xFFFFFFFF;
891 duprintf("translate_table: size %u\n", newinfo->size);
893 /* Walk through entries, checking offsets. */
894 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
895 check_entry_size_and_hooks,
898 newinfo->entries + size,
899 hook_entries, underflows, &i);
904 duprintf("translate_table: %u not %u entries\n",
909 /* Check hooks all assigned */
910 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
911 /* Only hooks which are valid */
912 if (!(valid_hooks & (1 << i)))
914 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
915 duprintf("Invalid hook entry %u %u\n",
919 if (newinfo->underflow[i] == 0xFFFFFFFF) {
920 duprintf("Invalid underflow %u %u\n",
926 if (!mark_source_chains(newinfo, valid_hooks))
929 /* Finally, each sanity check must pass */
931 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
932 check_entry, name, size, &i);
935 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
940 /* And one copy for every other CPU */
941 for (i = 1; i < smp_num_cpus; i++) {
942 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
944 SMP_ALIGN(newinfo->size));
950 static struct ip6t_table_info *
951 replace_table(struct ip6t_table *table,
952 unsigned int num_counters,
953 struct ip6t_table_info *newinfo,
956 struct ip6t_table_info *oldinfo;
958 #ifdef CONFIG_NETFILTER_DEBUG
960 struct ip6t_entry *table_base;
963 for (i = 0; i < smp_num_cpus; i++) {
965 (void *)newinfo->entries
966 + TABLE_OFFSET(newinfo, i);
968 table_base->comefrom = 0xdead57ac;
973 /* Do the substitution. */
974 write_lock_bh(&table->lock);
975 /* Check inside lock: is the old number correct? */
976 if (num_counters != table->private->number) {
977 duprintf("num_counters != table->private->number (%u/%u)\n",
978 num_counters, table->private->number);
979 write_unlock_bh(&table->lock);
983 oldinfo = table->private;
984 table->private = newinfo;
985 newinfo->initial_entries = oldinfo->initial_entries;
986 write_unlock_bh(&table->lock);
993 add_entry_to_counter(const struct ip6t_entry *e,
994 struct ip6t_counters total[],
997 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1004 get_counters(const struct ip6t_table_info *t,
1005 struct ip6t_counters counters[])
1010 for (cpu = 0; cpu < smp_num_cpus; cpu++) {
1012 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1014 add_entry_to_counter,
1021 copy_entries_to_user(unsigned int total_size,
1022 struct ip6t_table *table,
1025 unsigned int off, num, countersize;
1026 struct ip6t_entry *e;
1027 struct ip6t_counters *counters;
1030 /* We need atomic snapshot of counters: rest doesn't change
1031 (other than comefrom, which userspace doesn't care
1033 countersize = sizeof(struct ip6t_counters) * table->private->number;
1034 counters = vmalloc(countersize);
1036 if (counters == NULL)
1039 /* First, sum counters... */
1040 memset(counters, 0, countersize);
1041 write_lock_bh(&table->lock);
1042 get_counters(table->private, counters);
1043 write_unlock_bh(&table->lock);
1045 /* ... then copy entire thing from CPU 0... */
1046 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1051 /* FIXME: use iterator macros --RR */
1052 /* ... then go back and fix counters and names */
1053 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1055 struct ip6t_entry_match *m;
1056 struct ip6t_entry_target *t;
1058 e = (struct ip6t_entry *)(table->private->entries + off);
1059 if (copy_to_user(userptr + off
1060 + offsetof(struct ip6t_entry, counters),
1062 sizeof(counters[num])) != 0) {
1067 for (i = sizeof(struct ip6t_entry);
1068 i < e->target_offset;
1069 i += m->u.match_size) {
1072 if (copy_to_user(userptr + off + i
1073 + offsetof(struct ip6t_entry_match,
1075 m->u.kernel.match->name,
1076 strlen(m->u.kernel.match->name)+1)
1083 t = ip6t_get_target(e);
1084 if (copy_to_user(userptr + off + e->target_offset
1085 + offsetof(struct ip6t_entry_target,
1087 t->u.kernel.target->name,
1088 strlen(t->u.kernel.target->name)+1) != 0) {
1100 get_entries(const struct ip6t_get_entries *entries,
1101 struct ip6t_get_entries *uptr)
1104 struct ip6t_table *t;
1106 t = find_table_lock(entries->name, &ret, &ip6t_mutex);
1108 duprintf("t->private->number = %u\n",
1109 t->private->number);
1110 if (entries->size == t->private->size)
1111 ret = copy_entries_to_user(t->private->size,
1112 t, uptr->entrytable);
1114 duprintf("get_entries: I've got %u not %u!\n",
1121 duprintf("get_entries: Can't find %s!\n",
1128 do_replace(void *user, unsigned int len)
1131 struct ip6t_replace tmp;
1132 struct ip6t_table *t;
1133 struct ip6t_table_info *newinfo, *oldinfo;
1134 struct ip6t_counters *counters;
1136 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1139 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1140 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1143 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1144 + SMP_ALIGN(tmp.size) * smp_num_cpus);
1148 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1154 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1159 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1161 ret = translate_table(tmp.name, tmp.valid_hooks,
1162 newinfo, tmp.size, tmp.num_entries,
1163 tmp.hook_entry, tmp.underflow);
1165 goto free_newinfo_counters;
1167 duprintf("ip_tables: Translated table\n");
1169 t = find_table_lock(tmp.name, &ret, &ip6t_mutex);
1171 goto free_newinfo_counters_untrans;
1174 if (tmp.valid_hooks != t->valid_hooks) {
1175 duprintf("Valid hook crap: %08X vs %08X\n",
1176 tmp.valid_hooks, t->valid_hooks);
1178 goto free_newinfo_counters_untrans_unlock;
1181 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1183 goto free_newinfo_counters_untrans_unlock;
1185 /* Update module usage count based on number of rules */
1186 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1187 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1188 if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
1189 (newinfo->number > oldinfo->initial_entries))
1190 __MOD_INC_USE_COUNT(t->me);
1191 else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
1192 (newinfo->number <= oldinfo->initial_entries))
1193 __MOD_DEC_USE_COUNT(t->me);
1195 /* Get the old counters. */
1196 get_counters(oldinfo, counters);
1197 /* Decrease module usage counts and free resource */
1198 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1200 /* Silent error: too late now. */
1201 copy_to_user(tmp.counters, counters,
1202 sizeof(struct ip6t_counters) * tmp.num_counters);
1207 free_newinfo_counters_untrans_unlock:
1209 free_newinfo_counters_untrans:
1210 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1211 free_newinfo_counters:
1218 /* We're lazy, and add to the first CPU; overflow works its fey magic
1219 * and everything is OK. */
1221 add_counter_to_entry(struct ip6t_entry *e,
1222 const struct ip6t_counters addme[],
1226 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1228 (long unsigned int)e->counters.pcnt,
1229 (long unsigned int)e->counters.bcnt,
1230 (long unsigned int)addme[*i].pcnt,
1231 (long unsigned int)addme[*i].bcnt);
1234 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1241 do_add_counters(void *user, unsigned int len)
1244 struct ip6t_counters_info tmp, *paddc;
1245 struct ip6t_table *t;
1248 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1251 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1254 paddc = vmalloc(len);
1258 if (copy_from_user(paddc, user, len) != 0) {
1263 t = find_table_lock(tmp.name, &ret, &ip6t_mutex);
1267 write_lock_bh(&t->lock);
1268 if (t->private->number != paddc->num_counters) {
1270 goto unlock_up_free;
1274 IP6T_ENTRY_ITERATE(t->private->entries,
1276 add_counter_to_entry,
1280 write_unlock_bh(&t->lock);
1289 do_ip6t_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len)
1293 if (!capable(CAP_NET_ADMIN))
1297 case IP6T_SO_SET_REPLACE:
1298 ret = do_replace(user, len);
1301 case IP6T_SO_SET_ADD_COUNTERS:
1302 ret = do_add_counters(user, len);
1306 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1314 do_ip6t_get_ctl(struct sock *sk, int cmd, void *user, int *len)
1318 if (!capable(CAP_NET_ADMIN))
1322 case IP6T_SO_GET_INFO: {
1323 char name[IP6T_TABLE_MAXNAMELEN];
1324 struct ip6t_table *t;
1326 if (*len != sizeof(struct ip6t_getinfo)) {
1327 duprintf("length %u != %u\n", *len,
1328 sizeof(struct ip6t_getinfo));
1333 if (copy_from_user(name, user, sizeof(name)) != 0) {
1337 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1338 t = find_table_lock(name, &ret, &ip6t_mutex);
1340 struct ip6t_getinfo info;
1342 info.valid_hooks = t->valid_hooks;
1343 memcpy(info.hook_entry, t->private->hook_entry,
1344 sizeof(info.hook_entry));
1345 memcpy(info.underflow, t->private->underflow,
1346 sizeof(info.underflow));
1347 info.num_entries = t->private->number;
1348 info.size = t->private->size;
1349 strcpy(info.name, name);
1351 if (copy_to_user(user, &info, *len) != 0)
1361 case IP6T_SO_GET_ENTRIES: {
1362 struct ip6t_get_entries get;
1364 if (*len < sizeof(get)) {
1365 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1367 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1369 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1370 duprintf("get_entries: %u != %u\n", *len,
1371 sizeof(struct ip6t_get_entries) + get.size);
1374 ret = get_entries(&get, user);
1379 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1386 /* Registration hooks for targets. */
1388 ip6t_register_target(struct ip6t_target *target)
1393 ret = down_interruptible(&ip6t_mutex);
1398 if (!list_named_insert(&ip6t_target, target)) {
1399 duprintf("ip6t_register_target: `%s' already in list!\n",
1409 ip6t_unregister_target(struct ip6t_target *target)
1412 LIST_DELETE(&ip6t_target, target);
1418 ip6t_register_match(struct ip6t_match *match)
1423 ret = down_interruptible(&ip6t_mutex);
1428 if (!list_named_insert(&ip6t_match, match)) {
1429 duprintf("ip6t_register_match: `%s' already in list!\n",
1440 ip6t_unregister_match(struct ip6t_match *match)
1443 LIST_DELETE(&ip6t_match, match);
1448 int ip6t_register_table(struct ip6t_table *table)
1451 struct ip6t_table_info *newinfo;
1452 static struct ip6t_table_info bootstrap
1453 = { 0, 0, 0, { 0 }, { 0 }, { }, { } };
1456 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1457 + SMP_ALIGN(table->table->size) * smp_num_cpus);
1463 memcpy(newinfo->entries, table->table->entries, table->table->size);
1465 ret = translate_table(table->name, table->valid_hooks,
1466 newinfo, table->table->size,
1467 table->table->num_entries,
1468 table->table->hook_entry,
1469 table->table->underflow);
1476 ret = down_interruptible(&ip6t_mutex);
1483 /* Don't autoload: we'd eat our tail... */
1484 if (list_named_find(&ip6t_tables, table->name)) {
1489 /* Simplifies replace_table code. */
1490 table->private = &bootstrap;
1491 if (!replace_table(table, 0, newinfo, &ret))
1494 duprintf("table->private->number = %u\n",
1495 table->private->number);
1497 /* save number of initial entries */
1498 table->private->initial_entries = table->private->number;
1500 table->lock = RW_LOCK_UNLOCKED;
1501 list_prepend(&ip6t_tables, table);
1513 void ip6t_unregister_table(struct ip6t_table *table)
1516 LIST_DELETE(&ip6t_tables, table);
1519 /* Decrease module usage counts and free resources */
1520 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1521 cleanup_entry, NULL);
1522 vfree(table->private);
1526 /* Returns 1 if the port is matched by the range, 0 otherwise */
1528 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1532 ret = (port >= min && port <= max) ^ invert;
1537 tcp_find_option(u_int8_t option,
1538 const struct tcphdr *tcp,
1543 unsigned int i = sizeof(struct tcphdr);
1544 const u_int8_t *opt = (u_int8_t *)tcp;
1546 duprintf("tcp_match: finding option\n");
1547 /* If we don't have the whole header, drop packet. */
1548 if (tcp->doff * 4 > datalen) {
1553 while (i < tcp->doff * 4) {
1554 if (opt[i] == option) return !invert;
1555 if (opt[i] < 2) i++;
1556 else i += opt[i+1]?:1;
1563 tcp_match(const struct sk_buff *skb,
1564 const struct net_device *in,
1565 const struct net_device *out,
1566 const void *matchinfo,
1572 const struct tcphdr *tcp = hdr;
1573 const struct ip6t_tcp *tcpinfo = matchinfo;
1577 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1578 causes this. Its a cracker trying to break in by doing a
1579 flag overwrite to pass the direction checks.
1583 duprintf("Dropping evil TCP offset=1 frag.\n");
1586 } else if (offset == 0 && datalen < sizeof(struct tcphdr)) {
1587 /* We've been asked to examine this packet, and we
1588 can't. Hence, no choice but to drop. */
1589 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1594 /* FIXME: Try tcp doff >> packet len against various stacks --RR */
1596 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1598 /* Must not be a fragment. */
1600 && port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1602 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT))
1603 && port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1605 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT))
1606 && FWINVTCP((((unsigned char *)tcp)[13]
1607 & tcpinfo->flg_mask)
1608 == tcpinfo->flg_cmp,
1610 && (!tcpinfo->option
1611 || tcp_find_option(tcpinfo->option, tcp, datalen,
1613 & IP6T_TCP_INV_OPTION,
1617 /* Called when user tries to insert an entry of this type. */
1619 tcp_checkentry(const char *tablename,
1620 const struct ip6t_ip6 *ipv6,
1622 unsigned int matchsize,
1623 unsigned int hook_mask)
1625 const struct ip6t_tcp *tcpinfo = matchinfo;
1627 /* Must specify proto == TCP, and no unknown invflags */
1628 return ipv6->proto == IPPROTO_TCP
1629 && !(ipv6->invflags & IP6T_INV_PROTO)
1630 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1631 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1635 udp_match(const struct sk_buff *skb,
1636 const struct net_device *in,
1637 const struct net_device *out,
1638 const void *matchinfo,
1644 const struct udphdr *udp = hdr;
1645 const struct ip6t_udp *udpinfo = matchinfo;
1647 if (offset == 0 && datalen < sizeof(struct udphdr)) {
1648 /* We've been asked to examine this packet, and we
1649 can't. Hence, no choice but to drop. */
1650 duprintf("Dropping evil UDP tinygram.\n");
1655 /* Must not be a fragment. */
1657 && port_match(udpinfo->spts[0], udpinfo->spts[1],
1659 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1660 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1662 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1665 /* Called when user tries to insert an entry of this type. */
1667 udp_checkentry(const char *tablename,
1668 const struct ip6t_ip6 *ipv6,
1670 unsigned int matchinfosize,
1671 unsigned int hook_mask)
1673 const struct ip6t_udp *udpinfo = matchinfo;
1675 /* Must specify proto == UDP, and no unknown invflags */
1676 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1677 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1681 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1682 duprintf("ip6t_udp: matchsize %u != %u\n",
1683 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1686 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1687 duprintf("ip6t_udp: unknown flags %X\n",
1695 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1697 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1698 u_int8_t type, u_int8_t code,
1701 return (type == test_type && code >= min_code && code <= max_code)
1706 icmp6_match(const struct sk_buff *skb,
1707 const struct net_device *in,
1708 const struct net_device *out,
1709 const void *matchinfo,
1715 const struct icmp6hdr *icmp = hdr;
1716 const struct ip6t_icmp *icmpinfo = matchinfo;
1718 if (offset == 0 && datalen < 2) {
1719 /* We've been asked to examine this packet, and we
1720 can't. Hence, no choice but to drop. */
1721 duprintf("Dropping evil ICMP tinygram.\n");
1726 /* Must not be a fragment. */
1728 && icmp6_type_code_match(icmpinfo->type,
1731 icmp->icmp6_type, icmp->icmp6_code,
1732 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1735 /* Called when user tries to insert an entry of this type. */
1737 icmp6_checkentry(const char *tablename,
1738 const struct ip6t_ip6 *ipv6,
1740 unsigned int matchsize,
1741 unsigned int hook_mask)
1743 const struct ip6t_icmp *icmpinfo = matchinfo;
1745 /* Must specify proto == ICMP, and no unknown invflags */
1746 return ipv6->proto == IPPROTO_ICMPV6
1747 && !(ipv6->invflags & IP6T_INV_PROTO)
1748 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1749 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1752 /* The built-in targets: standard (NULL) and error. */
1753 static struct ip6t_target ip6t_standard_target
1754 = { { NULL, NULL }, IP6T_STANDARD_TARGET, NULL, NULL, NULL };
1755 static struct ip6t_target ip6t_error_target
1756 = { { NULL, NULL }, IP6T_ERROR_TARGET, ip6t_error, NULL, NULL };
1758 static struct nf_sockopt_ops ip6t_sockopts
1759 = { { NULL, NULL }, PF_INET6, IP6T_BASE_CTL, IP6T_SO_SET_MAX+1, do_ip6t_set_ctl,
1760 IP6T_BASE_CTL, IP6T_SO_GET_MAX+1, do_ip6t_get_ctl, 0, NULL };
1762 static struct ip6t_match tcp_matchstruct
1763 = { { NULL, NULL }, "tcp", &tcp_match, &tcp_checkentry, NULL };
1764 static struct ip6t_match udp_matchstruct
1765 = { { NULL, NULL }, "udp", &udp_match, &udp_checkentry, NULL };
1766 static struct ip6t_match icmp6_matchstruct
1767 = { { NULL, NULL }, "icmp6", &icmp6_match, &icmp6_checkentry, NULL };
1769 #ifdef CONFIG_PROC_FS
1770 static inline int print_name(const struct ip6t_table *t,
1771 off_t start_offset, char *buffer, int length,
1772 off_t *pos, unsigned int *count)
1774 if ((*count)++ >= start_offset) {
1775 unsigned int namelen;
1777 namelen = sprintf(buffer + *pos, "%s\n", t->name);
1778 if (*pos + namelen > length) {
1779 /* Stop iterating */
1787 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1790 unsigned int count = 0;
1792 if (down_interruptible(&ip6t_mutex) != 0)
1795 LIST_FIND(&ip6t_tables, print_name, struct ip6t_table *,
1796 offset, buffer, length, &pos, &count);
1800 /* `start' hack - see fs/proc/generic.c line ~105 */
1801 *start=(char *)((unsigned long)count-offset);
1804 #endif /*CONFIG_PROC_FS*/
1806 static int __init init(void)
1810 /* Noone else will be downing sem now, so we won't sleep */
1812 list_append(&ip6t_target, &ip6t_standard_target);
1813 list_append(&ip6t_target, &ip6t_error_target);
1814 list_append(&ip6t_match, &tcp_matchstruct);
1815 list_append(&ip6t_match, &udp_matchstruct);
1816 list_append(&ip6t_match, &icmp6_matchstruct);
1819 /* Register setsockopt */
1820 ret = nf_register_sockopt(&ip6t_sockopts);
1822 duprintf("Unable to register sockopts.\n");
1826 #ifdef CONFIG_PROC_FS
1828 struct proc_dir_entry *proc;
1829 proc = proc_net_create("ip6_tables_names", 0,
1832 nf_unregister_sockopt(&ip6t_sockopts);
1835 proc->owner = THIS_MODULE;
1839 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1843 static void __exit fini(void)
1845 nf_unregister_sockopt(&ip6t_sockopts);
1846 #ifdef CONFIG_PROC_FS
1847 proc_net_remove("ip6_tables_names");
1851 EXPORT_SYMBOL(ip6t_register_table);
1852 EXPORT_SYMBOL(ip6t_unregister_table);
1853 EXPORT_SYMBOL(ip6t_do_table);
1854 EXPORT_SYMBOL(ip6t_register_match);
1855 EXPORT_SYMBOL(ip6t_unregister_match);
1856 EXPORT_SYMBOL(ip6t_register_target);
1857 EXPORT_SYMBOL(ip6t_unregister_target);
1858 EXPORT_SYMBOL(ip6t_ext_hdr);
1862 MODULE_LICENSE("GPL");