1 /*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
6 *
7 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
8 * - increase module usage count as soon as we have rules inside
9 * a table
10 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
11 * - new extension header parser code
12 */
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>
22 #include <net/ip.h>
23 #include <net/ipv6.h>
24 #include <asm/uaccess.h>
25 #include <asm/semaphore.h>
26 #include <linux/proc_fs.h>
27
28 #include <linux/netfilter_ipv6/ip6_tables.h>
29
30 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
31 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
32
33 /*#define DEBUG_IP_FIREWALL*/
34 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
35 /*#define DEBUG_IP_FIREWALL_USER*/
36
37 #ifdef DEBUG_IP_FIREWALL
38 #define dprintf(format, args...) printk(format , ## args)
39 #else
40 #define dprintf(format, args...)
41 #endif
42
43 #ifdef DEBUG_IP_FIREWALL_USER
44 #define duprintf(format, args...) printk(format , ## args)
45 #else
46 #define duprintf(format, args...)
47 #endif
48
49 #ifdef CONFIG_NETFILTER_DEBUG
50 #define IP_NF_ASSERT(x) \
51 do { \
52 if (!(x)) \
53 printk("IP_NF_ASSERT: %s:%s:%u\n", \
54 __FUNCTION__, __FILE__, __LINE__); \
55 } while(0)
56 #else
57 #define IP_NF_ASSERT(x)
58 #endif
59 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
60
61 static DECLARE_MUTEX(ip6t_mutex);
62
63 /* Must have 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>
68
69 #if 0
70 /* All the better to debug you with... */
71 #define static
72 #define inline
73 #endif
74
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).
78
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
81 in user context.
82
83 To be cache friendly on SMP, we arrange them like so:
84 [ n-entries ]
85 ... cache-align padding ...
86 [ n-entries ]
87
88 Hence the start of any table is given by get_table() below. */
89
90 /* The table itself */
91 struct ip6t_table_info
92 {
93 /* Size per table */
94 unsigned int size;
95 /* Number of entries: FIXME. --RR */
96 unsigned int number;
97 /* Initial number of entries. Needed for module usage count */
98 unsigned int initial_entries;
99
100 /* Entry points and underflows */
101 unsigned int hook_entry[NF_IP6_NUMHOOKS];
102 unsigned int underflow[NF_IP6_NUMHOOKS];
103
104 /* ip6t_entry tables: one per CPU */
105 char entries[0] ____cacheline_aligned;
106 };
107
108 static LIST_HEAD(ip6t_target);
109 static LIST_HEAD(ip6t_match);
110 static LIST_HEAD(ip6t_tables);
111 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
112
113 #ifdef CONFIG_SMP
114 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
115 #else
116 #define TABLE_OFFSET(t,p) 0
117 #endif
118
119 #if 0
120 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
121 #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; })
122 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
123 #endif
124
ip6_masked_addrcmp(struct in6_addr addr1,struct in6_addr mask,struct in6_addr addr2)125 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
126 struct in6_addr addr2)
127 {
128 int i;
129 for( i = 0; i < 16; i++){
130 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
131 (addr2.s6_addr[i] & mask.s6_addr[i]))
132 return 1;
133 }
134 return 0;
135 }
136
137 /* Check for an extension */
138 int
ip6t_ext_hdr(u8 nexthdr)139 ip6t_ext_hdr(u8 nexthdr)
140 {
141 return ( (nexthdr == IPPROTO_HOPOPTS) ||
142 (nexthdr == IPPROTO_ROUTING) ||
143 (nexthdr == IPPROTO_FRAGMENT) ||
144 (nexthdr == IPPROTO_ESP) ||
145 (nexthdr == IPPROTO_AH) ||
146 (nexthdr == IPPROTO_NONE) ||
147 (nexthdr == IPPROTO_DSTOPTS) );
148 }
149
150 /* Returns whether matches rule or not. */
151 static inline int
ip6_packet_match(const struct sk_buff * skb,const char * indev,const char * outdev,const struct ip6t_ip6 * ip6info,unsigned int * protoff,int * fragoff)152 ip6_packet_match(const struct sk_buff *skb,
153 const char *indev,
154 const char *outdev,
155 const struct ip6t_ip6 *ip6info,
156 unsigned int *protoff,
157 int *fragoff)
158 {
159 size_t i;
160 unsigned long ret;
161 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
162
163 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
164
165 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
166 IP6T_INV_SRCIP)
167 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
168 IP6T_INV_DSTIP)) {
169 dprintf("Source or dest mismatch.\n");
170 /*
171 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
172 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
173 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
174 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
175 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
176 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
177 return 0;
178 }
179
180 /* Look for ifname matches; this should unroll nicely. */
181 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
182 ret |= (((const unsigned long *)indev)[i]
183 ^ ((const unsigned long *)ip6info->iniface)[i])
184 & ((const unsigned long *)ip6info->iniface_mask)[i];
185 }
186
187 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
188 dprintf("VIA in mismatch (%s vs %s).%s\n",
189 indev, ip6info->iniface,
190 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
191 return 0;
192 }
193
194 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
195 ret |= (((const unsigned long *)outdev)[i]
196 ^ ((const unsigned long *)ip6info->outiface)[i])
197 & ((const unsigned long *)ip6info->outiface_mask)[i];
198 }
199
200 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
201 dprintf("VIA out mismatch (%s vs %s).%s\n",
202 outdev, ip6info->outiface,
203 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
204 return 0;
205 }
206
207 /* ... might want to do something with class and flowlabel here ... */
208
209 /* look for the desired protocol header */
210 if((ip6info->flags & IP6T_F_PROTO)) {
211 u_int8_t currenthdr = ipv6->nexthdr;
212 struct ipv6_opt_hdr *hdrptr;
213 u_int16_t ptr; /* Header offset in skb */
214 u_int16_t hdrlen; /* Header */
215 u_int16_t foff = 0;
216
217 ptr = IPV6_HDR_LEN;
218
219 while (ip6t_ext_hdr(currenthdr)) {
220 /* Is there enough space for the next ext header? */
221 if (skb->len - ptr < IPV6_OPTHDR_LEN)
222 return 0;
223
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))
229 break;
230
231 hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
232
233 /* Size calculation */
234 if (currenthdr == IPPROTO_FRAGMENT) {
235 unsigned int foff_off;
236
237 foff_off = ptr + offsetof(struct frag_hdr,
238 frag_off);
239 if (skb->len - foff_off < sizeof(foff))
240 return 0;
241
242 foff = ntohs(*(u_int16_t *)(skb->data
243 + foff_off))
244 & ~0x7;
245 hdrlen = 8;
246 } else if (currenthdr == IPPROTO_AH)
247 hdrlen = (hdrptr->hdrlen+2)<<2;
248 else
249 hdrlen = ipv6_optlen(hdrptr);
250
251 currenthdr = hdrptr->nexthdr;
252 ptr += hdrlen;
253 /* ptr is too large */
254 if ( ptr > skb->len )
255 return 0;
256 if (foff) {
257 if (ip6t_ext_hdr(currenthdr))
258 return 0;
259 break;
260 }
261 }
262
263 *protoff = ptr;
264 *fragoff = foff;
265
266 /* currenthdr contains the protocol header */
267
268 dprintf("Packet protocol %hi ?= %s%hi.\n",
269 currenthdr,
270 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
271 ip6info->proto);
272
273 if (ip6info->proto == currenthdr) {
274 if(ip6info->invflags & IP6T_INV_PROTO) {
275 return 0;
276 }
277 return 1;
278 }
279
280 /* We need match for the '-p all', too! */
281 if ((ip6info->proto != 0) &&
282 !(ip6info->invflags & IP6T_INV_PROTO))
283 return 0;
284 }
285 return 1;
286 }
287
288 /* should be ip6 safe */
289 static inline int
ip6_checkentry(const struct ip6t_ip6 * ipv6)290 ip6_checkentry(const struct ip6t_ip6 *ipv6)
291 {
292 if (ipv6->flags & ~IP6T_F_MASK) {
293 duprintf("Unknown flag bits set: %08X\n",
294 ipv6->flags & ~IP6T_F_MASK);
295 return 0;
296 }
297 if (ipv6->invflags & ~IP6T_INV_MASK) {
298 duprintf("Unknown invflag bits set: %08X\n",
299 ipv6->invflags & ~IP6T_INV_MASK);
300 return 0;
301 }
302 return 1;
303 }
304
305 static unsigned int
ip6t_error(struct sk_buff ** pskb,unsigned int hooknum,const struct net_device * in,const struct net_device * out,const void * targinfo,void * userinfo)306 ip6t_error(struct sk_buff **pskb,
307 unsigned int hooknum,
308 const struct net_device *in,
309 const struct net_device *out,
310 const void *targinfo,
311 void *userinfo)
312 {
313 if (net_ratelimit())
314 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
315
316 return NF_DROP;
317 }
318
319 static inline
do_match(struct ip6t_entry_match * m,const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,int offset,const void * hdr,u_int16_t datalen,int * hotdrop)320 int do_match(struct ip6t_entry_match *m,
321 const struct sk_buff *skb,
322 const struct net_device *in,
323 const struct net_device *out,
324 int offset,
325 const void *hdr,
326 u_int16_t datalen,
327 int *hotdrop)
328 {
329 /* Stop iteration if it doesn't match */
330 if (!m->u.kernel.match->match(skb, in, out, m->data,
331 offset, hdr, datalen, hotdrop))
332 return 1;
333 else
334 return 0;
335 }
336
337 static inline struct ip6t_entry *
get_entry(void * base,unsigned int offset)338 get_entry(void *base, unsigned int offset)
339 {
340 return (struct ip6t_entry *)(base + offset);
341 }
342
343 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
344 unsigned int
ip6t_do_table(struct sk_buff ** pskb,unsigned int hook,const struct net_device * in,const struct net_device * out,struct ip6t_table * table,void * userdata)345 ip6t_do_table(struct sk_buff **pskb,
346 unsigned int hook,
347 const struct net_device *in,
348 const struct net_device *out,
349 struct ip6t_table *table,
350 void *userdata)
351 {
352 static const char nulldevname[IFNAMSIZ] = { 0 };
353 int offset = 0;
354 unsigned int protoff = 0;
355 int hotdrop = 0;
356 /* Initializing verdict to NF_DROP keeps gcc happy. */
357 unsigned int verdict = NF_DROP;
358 const char *indev, *outdev;
359 void *table_base;
360 struct ip6t_entry *e, *back;
361
362 /* Initialization */
363 indev = in ? in->name : nulldevname;
364 outdev = out ? out->name : nulldevname;
365
366 /* We handle fragments by dealing with the first fragment as
367 * if it was a normal packet. All other fragments are treated
368 * normally, except that they will NEVER match rules that ask
369 * things we don't know, ie. tcp syn flag or ports). If the
370 * rule is also a fragment-specific rule, non-fragments won't
371 * match it. */
372
373 read_lock_bh(&table->lock);
374 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
375 table_base = (void *)table->private->entries
376 + TABLE_OFFSET(table->private,
377 cpu_number_map(smp_processor_id()));
378 e = get_entry(table_base, table->private->hook_entry[hook]);
379
380 #ifdef CONFIG_NETFILTER_DEBUG
381 /* Check noone else using our table */
382 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
383 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
384 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
385 smp_processor_id(),
386 table->name,
387 &((struct ip6t_entry *)table_base)->comefrom,
388 ((struct ip6t_entry *)table_base)->comefrom);
389 }
390 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
391 #endif
392
393 /* For return from builtin chain */
394 back = get_entry(table_base, table->private->underflow[hook]);
395
396 do {
397 IP_NF_ASSERT(e);
398 IP_NF_ASSERT(back);
399 (*pskb)->nfcache |= e->nfcache;
400 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
401 &protoff, &offset)) {
402 struct ip6t_entry_target *t;
403
404 if (IP6T_MATCH_ITERATE(e, do_match,
405 *pskb, in, out,
406 offset,
407 (void *)((*pskb)->data
408 + protoff),
409 (*pskb)->len - protoff,
410 &hotdrop) != 0)
411 goto no_match;
412
413 ADD_COUNTER(e->counters, ntohs((*pskb)->nh.ipv6h->payload_len) + IPV6_HDR_LEN, 1);
414
415 t = ip6t_get_target(e);
416 IP_NF_ASSERT(t->u.kernel.target);
417 /* Standard target? */
418 if (!t->u.kernel.target->target) {
419 int v;
420
421 v = ((struct ip6t_standard_target *)t)->verdict;
422 if (v < 0) {
423 /* Pop from stack? */
424 if (v != IP6T_RETURN) {
425 verdict = (unsigned)(-v) - 1;
426 break;
427 }
428 e = back;
429 back = get_entry(table_base,
430 back->comefrom);
431 continue;
432 }
433 if (table_base + v
434 != (void *)e + e->next_offset) {
435 /* Save old back ptr in next entry */
436 struct ip6t_entry *next
437 = (void *)e + e->next_offset;
438 next->comefrom
439 = (void *)back - table_base;
440 /* set back pointer to next entry */
441 back = next;
442 }
443
444 e = get_entry(table_base, v);
445 } else {
446 /* Targets which reenter must return
447 abs. verdicts */
448 #ifdef CONFIG_NETFILTER_DEBUG
449 ((struct ip6t_entry *)table_base)->comefrom
450 = 0xeeeeeeec;
451 #endif
452 verdict = t->u.kernel.target->target(pskb,
453 hook,
454 in, out,
455 t->data,
456 userdata);
457
458 #ifdef CONFIG_NETFILTER_DEBUG
459 if (((struct ip6t_entry *)table_base)->comefrom
460 != 0xeeeeeeec
461 && verdict == IP6T_CONTINUE) {
462 printk("Target %s reentered!\n",
463 t->u.kernel.target->name);
464 verdict = NF_DROP;
465 }
466 ((struct ip6t_entry *)table_base)->comefrom
467 = 0x57acc001;
468 #endif
469 if (verdict == IP6T_CONTINUE)
470 e = (void *)e + e->next_offset;
471 else
472 /* Verdict */
473 break;
474 }
475 } else {
476
477 no_match:
478 e = (void *)e + e->next_offset;
479 }
480 } while (!hotdrop);
481
482 #ifdef CONFIG_NETFILTER_DEBUG
483 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
484 #endif
485 read_unlock_bh(&table->lock);
486
487 #ifdef DEBUG_ALLOW_ALL
488 return NF_ACCEPT;
489 #else
490 if (hotdrop)
491 return NF_DROP;
492 else return verdict;
493 #endif
494 }
495
496 /* If it succeeds, returns element and locks mutex */
497 static inline void *
find_inlist_lock_noload(struct list_head * head,const char * name,int * error,struct semaphore * mutex)498 find_inlist_lock_noload(struct list_head *head,
499 const char *name,
500 int *error,
501 struct semaphore *mutex)
502 {
503 void *ret;
504
505 #if 1
506 duprintf("find_inlist: searching for `%s' in %s.\n",
507 name, head == &ip6t_target ? "ip6t_target"
508 : head == &ip6t_match ? "ip6t_match"
509 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
510 #endif
511
512 *error = down_interruptible(mutex);
513 if (*error != 0)
514 return NULL;
515
516 ret = list_named_find(head, name);
517 if (!ret) {
518 *error = -ENOENT;
519 up(mutex);
520 }
521 return ret;
522 }
523
524 #ifndef CONFIG_KMOD
525 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
526 #else
527 static void *
find_inlist_lock(struct list_head * head,const char * name,const char * prefix,int * error,struct semaphore * mutex)528 find_inlist_lock(struct list_head *head,
529 const char *name,
530 const char *prefix,
531 int *error,
532 struct semaphore *mutex)
533 {
534 void *ret;
535
536 ret = find_inlist_lock_noload(head, name, error, mutex);
537 if (!ret) {
538 char modulename[IP6T_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
539 strcpy(modulename, prefix);
540 strcat(modulename, name);
541 duprintf("find_inlist: loading `%s'.\n", modulename);
542 request_module(modulename);
543 ret = find_inlist_lock_noload(head, name, error, mutex);
544 }
545
546 return ret;
547 }
548 #endif
549
550 static inline struct ip6t_table *
ip6t_find_table_lock(const char * name,int * error,struct semaphore * mutex)551 ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
552 {
553 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
554 }
555
556 static inline struct ip6t_match *
find_match_lock(const char * name,int * error,struct semaphore * mutex)557 find_match_lock(const char *name, int *error, struct semaphore *mutex)
558 {
559 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
560 }
561
562 struct ip6t_target *
ip6t_find_target_lock(const char * name,int * error,struct semaphore * mutex)563 ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
564 {
565 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
566 }
567
568 /* All zeroes == unconditional rule. */
569 static inline int
unconditional(const struct ip6t_ip6 * ipv6)570 unconditional(const struct ip6t_ip6 *ipv6)
571 {
572 unsigned int i;
573
574 for (i = 0; i < sizeof(*ipv6); i++)
575 if (((char *)ipv6)[i])
576 break;
577
578 return (i == sizeof(*ipv6));
579 }
580
581 /* Figures out from what hook each rule can be called: returns 0 if
582 there are loops. Puts hook bitmask in comefrom. */
583 static int
mark_source_chains(struct ip6t_table_info * newinfo,unsigned int valid_hooks)584 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
585 {
586 unsigned int hook;
587
588 /* No recursion; use packet counter to save back ptrs (reset
589 to 0 as we leave), and comefrom to save source hook bitmask */
590 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
591 unsigned int pos = newinfo->hook_entry[hook];
592 struct ip6t_entry *e
593 = (struct ip6t_entry *)(newinfo->entries + pos);
594
595 if (!(valid_hooks & (1 << hook)))
596 continue;
597
598 /* Set initial back pointer. */
599 e->counters.pcnt = pos;
600
601 for (;;) {
602 struct ip6t_standard_target *t
603 = (void *)ip6t_get_target(e);
604
605 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
606 printk("iptables: loop hook %u pos %u %08X.\n",
607 hook, pos, e->comefrom);
608 return 0;
609 }
610 e->comefrom
611 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
612
613 /* Unconditional return/END. */
614 if (e->target_offset == sizeof(struct ip6t_entry)
615 && (strcmp(t->target.u.user.name,
616 IP6T_STANDARD_TARGET) == 0)
617 && t->verdict < 0
618 && unconditional(&e->ipv6)) {
619 unsigned int oldpos, size;
620
621 /* Return: backtrack through the last
622 big jump. */
623 do {
624 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
625 #ifdef DEBUG_IP_FIREWALL_USER
626 if (e->comefrom
627 & (1 << NF_IP6_NUMHOOKS)) {
628 duprintf("Back unset "
629 "on hook %u "
630 "rule %u\n",
631 hook, pos);
632 }
633 #endif
634 oldpos = pos;
635 pos = e->counters.pcnt;
636 e->counters.pcnt = 0;
637
638 /* We're at the start. */
639 if (pos == oldpos)
640 goto next;
641
642 e = (struct ip6t_entry *)
643 (newinfo->entries + pos);
644 } while (oldpos == pos + e->next_offset);
645
646 /* Move along one */
647 size = e->next_offset;
648 e = (struct ip6t_entry *)
649 (newinfo->entries + pos + size);
650 e->counters.pcnt = pos;
651 pos += size;
652 } else {
653 int newpos = t->verdict;
654
655 if (strcmp(t->target.u.user.name,
656 IP6T_STANDARD_TARGET) == 0
657 && newpos >= 0) {
658 /* This a jump; chase it. */
659 duprintf("Jump rule %u -> %u\n",
660 pos, newpos);
661 } else {
662 /* ... this is a fallthru */
663 newpos = pos + e->next_offset;
664 }
665 e = (struct ip6t_entry *)
666 (newinfo->entries + newpos);
667 e->counters.pcnt = pos;
668 pos = newpos;
669 }
670 }
671 next:
672 duprintf("Finished chain %u\n", hook);
673 }
674 return 1;
675 }
676
677 static inline int
cleanup_match(struct ip6t_entry_match * m,unsigned int * i)678 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
679 {
680 if (i && (*i)-- == 0)
681 return 1;
682
683 if (m->u.kernel.match->destroy)
684 m->u.kernel.match->destroy(m->data,
685 m->u.match_size - sizeof(*m));
686
687 if (m->u.kernel.match->me)
688 __MOD_DEC_USE_COUNT(m->u.kernel.match->me);
689
690 return 0;
691 }
692
693 static inline int
standard_check(const struct ip6t_entry_target * t,unsigned int max_offset)694 standard_check(const struct ip6t_entry_target *t,
695 unsigned int max_offset)
696 {
697 struct ip6t_standard_target *targ = (void *)t;
698
699 /* Check standard info. */
700 if (t->u.target_size
701 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
702 duprintf("standard_check: target size %u != %u\n",
703 t->u.target_size,
704 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
705 return 0;
706 }
707
708 if (targ->verdict >= 0
709 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
710 duprintf("ip6t_standard_check: bad verdict (%i)\n",
711 targ->verdict);
712 return 0;
713 }
714
715 if (targ->verdict < -NF_MAX_VERDICT - 1) {
716 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
717 targ->verdict);
718 return 0;
719 }
720 return 1;
721 }
722
723 static inline int
check_match(struct ip6t_entry_match * m,const char * name,const struct ip6t_ip6 * ipv6,unsigned int hookmask,unsigned int * i)724 check_match(struct ip6t_entry_match *m,
725 const char *name,
726 const struct ip6t_ip6 *ipv6,
727 unsigned int hookmask,
728 unsigned int *i)
729 {
730 int ret;
731 struct ip6t_match *match;
732
733 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
734 if (!match) {
735 // duprintf("check_match: `%s' not found\n", m->u.name);
736 return ret;
737 }
738 if (match->me)
739 __MOD_INC_USE_COUNT(match->me);
740 m->u.kernel.match = match;
741 up(&ip6t_mutex);
742
743 if (m->u.kernel.match->checkentry
744 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
745 m->u.match_size - sizeof(*m),
746 hookmask)) {
747 if (m->u.kernel.match->me)
748 __MOD_DEC_USE_COUNT(m->u.kernel.match->me);
749 duprintf("ip_tables: check failed for `%s'.\n",
750 m->u.kernel.match->name);
751 return -EINVAL;
752 }
753
754 (*i)++;
755 return 0;
756 }
757
758 static struct ip6t_target ip6t_standard_target;
759
760 static inline int
check_entry(struct ip6t_entry * e,const char * name,unsigned int size,unsigned int * i)761 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
762 unsigned int *i)
763 {
764 struct ip6t_entry_target *t;
765 struct ip6t_target *target;
766 int ret;
767 unsigned int j;
768
769 if (!ip6_checkentry(&e->ipv6)) {
770 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
771 return -EINVAL;
772 }
773
774 j = 0;
775 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
776 if (ret != 0)
777 goto cleanup_matches;
778
779 t = ip6t_get_target(e);
780 target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
781 if (!target) {
782 duprintf("check_entry: `%s' not found\n", t->u.user.name);
783 goto cleanup_matches;
784 }
785 if (target->me)
786 __MOD_INC_USE_COUNT(target->me);
787 t->u.kernel.target = target;
788 up(&ip6t_mutex);
789
790 if (t->u.kernel.target == &ip6t_standard_target) {
791 if (!standard_check(t, size)) {
792 ret = -EINVAL;
793 goto cleanup_matches;
794 }
795 } else if (t->u.kernel.target->checkentry
796 && !t->u.kernel.target->checkentry(name, e, t->data,
797 t->u.target_size
798 - sizeof(*t),
799 e->comefrom)) {
800 if (t->u.kernel.target->me)
801 __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
802 duprintf("ip_tables: check failed for `%s'.\n",
803 t->u.kernel.target->name);
804 ret = -EINVAL;
805 goto cleanup_matches;
806 }
807
808 (*i)++;
809 return 0;
810
811 cleanup_matches:
812 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
813 return ret;
814 }
815
816 static inline int
check_entry_size_and_hooks(struct ip6t_entry * e,struct ip6t_table_info * newinfo,unsigned char * base,unsigned char * limit,const unsigned int * hook_entries,const unsigned int * underflows,unsigned int * i)817 check_entry_size_and_hooks(struct ip6t_entry *e,
818 struct ip6t_table_info *newinfo,
819 unsigned char *base,
820 unsigned char *limit,
821 const unsigned int *hook_entries,
822 const unsigned int *underflows,
823 unsigned int *i)
824 {
825 unsigned int h;
826
827 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
828 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
829 duprintf("Bad offset %p\n", e);
830 return -EINVAL;
831 }
832
833 if (e->next_offset
834 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
835 duprintf("checking: element %p size %u\n",
836 e, e->next_offset);
837 return -EINVAL;
838 }
839
840 /* Check hooks & underflows */
841 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
842 if ((unsigned char *)e - base == hook_entries[h])
843 newinfo->hook_entry[h] = hook_entries[h];
844 if ((unsigned char *)e - base == underflows[h])
845 newinfo->underflow[h] = underflows[h];
846 }
847
848 /* FIXME: underflows must be unconditional, standard verdicts
849 < 0 (not IP6T_RETURN). --RR */
850
851 /* Clear counters and comefrom */
852 e->counters = ((struct ip6t_counters) { 0, 0 });
853 e->comefrom = 0;
854
855 (*i)++;
856 return 0;
857 }
858
859 static inline int
cleanup_entry(struct ip6t_entry * e,unsigned int * i)860 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
861 {
862 struct ip6t_entry_target *t;
863
864 if (i && (*i)-- == 0)
865 return 1;
866
867 /* Cleanup all matches */
868 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
869 t = ip6t_get_target(e);
870 if (t->u.kernel.target->destroy)
871 t->u.kernel.target->destroy(t->data,
872 t->u.target_size - sizeof(*t));
873 if (t->u.kernel.target->me)
874 __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
875
876 return 0;
877 }
878
879 /* Checks and translates the user-supplied table segment (held in
880 newinfo) */
881 static int
translate_table(const char * name,unsigned int valid_hooks,struct ip6t_table_info * newinfo,unsigned int size,unsigned int number,const unsigned int * hook_entries,const unsigned int * underflows)882 translate_table(const char *name,
883 unsigned int valid_hooks,
884 struct ip6t_table_info *newinfo,
885 unsigned int size,
886 unsigned int number,
887 const unsigned int *hook_entries,
888 const unsigned int *underflows)
889 {
890 unsigned int i;
891 int ret;
892
893 newinfo->size = size;
894 newinfo->number = number;
895
896 /* Init all hooks to impossible value. */
897 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
898 newinfo->hook_entry[i] = 0xFFFFFFFF;
899 newinfo->underflow[i] = 0xFFFFFFFF;
900 }
901
902 duprintf("translate_table: size %u\n", newinfo->size);
903 i = 0;
904 /* Walk through entries, checking offsets. */
905 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
906 check_entry_size_and_hooks,
907 newinfo,
908 newinfo->entries,
909 newinfo->entries + size,
910 hook_entries, underflows, &i);
911 if (ret != 0)
912 return ret;
913
914 if (i != number) {
915 duprintf("translate_table: %u not %u entries\n",
916 i, number);
917 return -EINVAL;
918 }
919
920 /* Check hooks all assigned */
921 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
922 /* Only hooks which are valid */
923 if (!(valid_hooks & (1 << i)))
924 continue;
925 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
926 duprintf("Invalid hook entry %u %u\n",
927 i, hook_entries[i]);
928 return -EINVAL;
929 }
930 if (newinfo->underflow[i] == 0xFFFFFFFF) {
931 duprintf("Invalid underflow %u %u\n",
932 i, underflows[i]);
933 return -EINVAL;
934 }
935 }
936
937 if (!mark_source_chains(newinfo, valid_hooks))
938 return -ELOOP;
939
940 /* Finally, each sanity check must pass */
941 i = 0;
942 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
943 check_entry, name, size, &i);
944
945 if (ret != 0) {
946 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
947 cleanup_entry, &i);
948 return ret;
949 }
950
951 /* And one copy for every other CPU */
952 for (i = 1; i < smp_num_cpus; i++) {
953 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
954 newinfo->entries,
955 SMP_ALIGN(newinfo->size));
956 }
957
958 return ret;
959 }
960
961 static struct ip6t_table_info *
replace_table(struct ip6t_table * table,unsigned int num_counters,struct ip6t_table_info * newinfo,int * error)962 replace_table(struct ip6t_table *table,
963 unsigned int num_counters,
964 struct ip6t_table_info *newinfo,
965 int *error)
966 {
967 struct ip6t_table_info *oldinfo;
968
969 #ifdef CONFIG_NETFILTER_DEBUG
970 {
971 struct ip6t_entry *table_base;
972 unsigned int i;
973
974 for (i = 0; i < smp_num_cpus; i++) {
975 table_base =
976 (void *)newinfo->entries
977 + TABLE_OFFSET(newinfo, i);
978
979 table_base->comefrom = 0xdead57ac;
980 }
981 }
982 #endif
983
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);
991 *error = -EAGAIN;
992 return NULL;
993 }
994 oldinfo = table->private;
995 table->private = newinfo;
996 newinfo->initial_entries = oldinfo->initial_entries;
997 write_unlock_bh(&table->lock);
998
999 return oldinfo;
1000 }
1001
1002 /* Gets counters. */
1003 static inline int
add_entry_to_counter(const struct ip6t_entry * e,struct ip6t_counters total[],unsigned int * i)1004 add_entry_to_counter(const struct ip6t_entry *e,
1005 struct ip6t_counters total[],
1006 unsigned int *i)
1007 {
1008 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1009
1010 (*i)++;
1011 return 0;
1012 }
1013
1014 static void
get_counters(const struct ip6t_table_info * t,struct ip6t_counters counters[])1015 get_counters(const struct ip6t_table_info *t,
1016 struct ip6t_counters counters[])
1017 {
1018 unsigned int cpu;
1019 unsigned int i;
1020
1021 for (cpu = 0; cpu < smp_num_cpus; cpu++) {
1022 i = 0;
1023 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1024 t->size,
1025 add_entry_to_counter,
1026 counters,
1027 &i);
1028 }
1029 }
1030
1031 static int
copy_entries_to_user(unsigned int total_size,struct ip6t_table * table,void * userptr)1032 copy_entries_to_user(unsigned int total_size,
1033 struct ip6t_table *table,
1034 void *userptr)
1035 {
1036 unsigned int off, num, countersize;
1037 struct ip6t_entry *e;
1038 struct ip6t_counters *counters;
1039 int ret = 0;
1040
1041 /* We need atomic snapshot of counters: rest doesn't change
1042 (other than comefrom, which userspace doesn't care
1043 about). */
1044 countersize = sizeof(struct ip6t_counters) * table->private->number;
1045 counters = vmalloc(countersize);
1046
1047 if (counters == NULL)
1048 return -ENOMEM;
1049
1050 /* First, sum counters... */
1051 memset(counters, 0, countersize);
1052 write_lock_bh(&table->lock);
1053 get_counters(table->private, counters);
1054 write_unlock_bh(&table->lock);
1055
1056 /* ... then copy entire thing from CPU 0... */
1057 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1058 ret = -EFAULT;
1059 goto free_counters;
1060 }
1061
1062 /* FIXME: use iterator macros --RR */
1063 /* ... then go back and fix counters and names */
1064 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1065 unsigned int i;
1066 struct ip6t_entry_match *m;
1067 struct ip6t_entry_target *t;
1068
1069 e = (struct ip6t_entry *)(table->private->entries + off);
1070 if (copy_to_user(userptr + off
1071 + offsetof(struct ip6t_entry, counters),
1072 &counters[num],
1073 sizeof(counters[num])) != 0) {
1074 ret = -EFAULT;
1075 goto free_counters;
1076 }
1077
1078 for (i = sizeof(struct ip6t_entry);
1079 i < e->target_offset;
1080 i += m->u.match_size) {
1081 m = (void *)e + i;
1082
1083 if (copy_to_user(userptr + off + i
1084 + offsetof(struct ip6t_entry_match,
1085 u.user.name),
1086 m->u.kernel.match->name,
1087 strlen(m->u.kernel.match->name)+1)
1088 != 0) {
1089 ret = -EFAULT;
1090 goto free_counters;
1091 }
1092 }
1093
1094 t = ip6t_get_target(e);
1095 if (copy_to_user(userptr + off + e->target_offset
1096 + offsetof(struct ip6t_entry_target,
1097 u.user.name),
1098 t->u.kernel.target->name,
1099 strlen(t->u.kernel.target->name)+1) != 0) {
1100 ret = -EFAULT;
1101 goto free_counters;
1102 }
1103 }
1104
1105 free_counters:
1106 vfree(counters);
1107 return ret;
1108 }
1109
1110 static int
get_entries(const struct ip6t_get_entries * entries,struct ip6t_get_entries * uptr)1111 get_entries(const struct ip6t_get_entries *entries,
1112 struct ip6t_get_entries *uptr)
1113 {
1114 int ret;
1115 struct ip6t_table *t;
1116
1117 t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1118 if (t) {
1119 duprintf("t->private->number = %u\n",
1120 t->private->number);
1121 if (entries->size == t->private->size)
1122 ret = copy_entries_to_user(t->private->size,
1123 t, uptr->entrytable);
1124 else {
1125 duprintf("get_entries: I've got %u not %u!\n",
1126 t->private->size,
1127 entries->size);
1128 ret = -EINVAL;
1129 }
1130 up(&ip6t_mutex);
1131 } else
1132 duprintf("get_entries: Can't find %s!\n",
1133 entries->name);
1134
1135 return ret;
1136 }
1137
1138 static int
do_replace(void * user,unsigned int len)1139 do_replace(void *user, unsigned int len)
1140 {
1141 int ret;
1142 struct ip6t_replace tmp;
1143 struct ip6t_table *t;
1144 struct ip6t_table_info *newinfo, *oldinfo;
1145 struct ip6t_counters *counters;
1146
1147 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1148 return -EFAULT;
1149
1150 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1151 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1152 return -ENOMEM;
1153
1154 /* overflow check */
1155 if (tmp.size >= (INT_MAX - sizeof(struct ip6t_table_info)) / NR_CPUS -
1156 SMP_CACHE_BYTES)
1157 return -ENOMEM;
1158 if (tmp.num_counters >= INT_MAX / sizeof(struct ip6t_counters))
1159 return -ENOMEM;
1160
1161 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1162 + SMP_ALIGN(tmp.size) * smp_num_cpus);
1163 if (!newinfo)
1164 return -ENOMEM;
1165
1166 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1167 tmp.size) != 0) {
1168 ret = -EFAULT;
1169 goto free_newinfo;
1170 }
1171
1172 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1173 if (!counters) {
1174 ret = -ENOMEM;
1175 goto free_newinfo;
1176 }
1177 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1178
1179 ret = translate_table(tmp.name, tmp.valid_hooks,
1180 newinfo, tmp.size, tmp.num_entries,
1181 tmp.hook_entry, tmp.underflow);
1182 if (ret != 0)
1183 goto free_newinfo_counters;
1184
1185 duprintf("ip_tables: Translated table\n");
1186
1187 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1188 if (!t)
1189 goto free_newinfo_counters_untrans;
1190
1191 /* You lied! */
1192 if (tmp.valid_hooks != t->valid_hooks) {
1193 duprintf("Valid hook crap: %08X vs %08X\n",
1194 tmp.valid_hooks, t->valid_hooks);
1195 ret = -EINVAL;
1196 goto free_newinfo_counters_untrans_unlock;
1197 }
1198
1199 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1200 if (!oldinfo)
1201 goto free_newinfo_counters_untrans_unlock;
1202
1203 /* Update module usage count based on number of rules */
1204 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1205 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1206 if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
1207 (newinfo->number > oldinfo->initial_entries))
1208 __MOD_INC_USE_COUNT(t->me);
1209 else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
1210 (newinfo->number <= oldinfo->initial_entries))
1211 __MOD_DEC_USE_COUNT(t->me);
1212
1213 /* Get the old counters. */
1214 get_counters(oldinfo, counters);
1215 /* Decrease module usage counts and free resource */
1216 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1217 vfree(oldinfo);
1218 /* Silent error: too late now. */
1219 copy_to_user(tmp.counters, counters,
1220 sizeof(struct ip6t_counters) * tmp.num_counters);
1221 vfree(counters);
1222 up(&ip6t_mutex);
1223 return 0;
1224
1225 free_newinfo_counters_untrans_unlock:
1226 up(&ip6t_mutex);
1227 free_newinfo_counters_untrans:
1228 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1229 free_newinfo_counters:
1230 vfree(counters);
1231 free_newinfo:
1232 vfree(newinfo);
1233 return ret;
1234 }
1235
1236 /* We're lazy, and add to the first CPU; overflow works its fey magic
1237 * and everything is OK. */
1238 static inline int
add_counter_to_entry(struct ip6t_entry * e,const struct ip6t_counters addme[],unsigned int * i)1239 add_counter_to_entry(struct ip6t_entry *e,
1240 const struct ip6t_counters addme[],
1241 unsigned int *i)
1242 {
1243 #if 0
1244 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1245 *i,
1246 (long unsigned int)e->counters.pcnt,
1247 (long unsigned int)e->counters.bcnt,
1248 (long unsigned int)addme[*i].pcnt,
1249 (long unsigned int)addme[*i].bcnt);
1250 #endif
1251
1252 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1253
1254 (*i)++;
1255 return 0;
1256 }
1257
1258 static int
do_add_counters(void * user,unsigned int len)1259 do_add_counters(void *user, unsigned int len)
1260 {
1261 unsigned int i;
1262 struct ip6t_counters_info tmp, *paddc;
1263 struct ip6t_table *t;
1264 int ret;
1265
1266 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1267 return -EFAULT;
1268
1269 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1270 return -EINVAL;
1271
1272 paddc = vmalloc(len);
1273 if (!paddc)
1274 return -ENOMEM;
1275
1276 if (copy_from_user(paddc, user, len) != 0) {
1277 ret = -EFAULT;
1278 goto free;
1279 }
1280
1281 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1282 if (!t)
1283 goto free;
1284
1285 write_lock_bh(&t->lock);
1286 if (t->private->number != tmp.num_counters) {
1287 ret = -EINVAL;
1288 goto unlock_up_free;
1289 }
1290
1291 i = 0;
1292 IP6T_ENTRY_ITERATE(t->private->entries,
1293 t->private->size,
1294 add_counter_to_entry,
1295 paddc->counters,
1296 &i);
1297 unlock_up_free:
1298 write_unlock_bh(&t->lock);
1299 up(&ip6t_mutex);
1300 free:
1301 vfree(paddc);
1302
1303 return ret;
1304 }
1305
1306 static int
do_ip6t_set_ctl(struct sock * sk,int cmd,void * user,unsigned int len)1307 do_ip6t_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len)
1308 {
1309 int ret;
1310
1311 if (!capable(CAP_NET_ADMIN))
1312 return -EPERM;
1313
1314 switch (cmd) {
1315 case IP6T_SO_SET_REPLACE:
1316 ret = do_replace(user, len);
1317 break;
1318
1319 case IP6T_SO_SET_ADD_COUNTERS:
1320 ret = do_add_counters(user, len);
1321 break;
1322
1323 default:
1324 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1325 ret = -EINVAL;
1326 }
1327
1328 return ret;
1329 }
1330
1331 static int
do_ip6t_get_ctl(struct sock * sk,int cmd,void * user,int * len)1332 do_ip6t_get_ctl(struct sock *sk, int cmd, void *user, int *len)
1333 {
1334 int ret;
1335
1336 if (!capable(CAP_NET_ADMIN))
1337 return -EPERM;
1338
1339 switch (cmd) {
1340 case IP6T_SO_GET_INFO: {
1341 char name[IP6T_TABLE_MAXNAMELEN];
1342 struct ip6t_table *t;
1343
1344 if (*len != sizeof(struct ip6t_getinfo)) {
1345 duprintf("length %u != %u\n", *len,
1346 sizeof(struct ip6t_getinfo));
1347 ret = -EINVAL;
1348 break;
1349 }
1350
1351 if (copy_from_user(name, user, sizeof(name)) != 0) {
1352 ret = -EFAULT;
1353 break;
1354 }
1355 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1356 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1357 if (t) {
1358 struct ip6t_getinfo info;
1359
1360 info.valid_hooks = t->valid_hooks;
1361 memcpy(info.hook_entry, t->private->hook_entry,
1362 sizeof(info.hook_entry));
1363 memcpy(info.underflow, t->private->underflow,
1364 sizeof(info.underflow));
1365 info.num_entries = t->private->number;
1366 info.size = t->private->size;
1367 memcpy(info.name, name, sizeof(info.name));
1368
1369 if (copy_to_user(user, &info, *len) != 0)
1370 ret = -EFAULT;
1371 else
1372 ret = 0;
1373
1374 up(&ip6t_mutex);
1375 }
1376 }
1377 break;
1378
1379 case IP6T_SO_GET_ENTRIES: {
1380 struct ip6t_get_entries get;
1381
1382 if (*len < sizeof(get)) {
1383 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1384 ret = -EINVAL;
1385 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1386 ret = -EFAULT;
1387 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1388 duprintf("get_entries: %u != %u\n", *len,
1389 sizeof(struct ip6t_get_entries) + get.size);
1390 ret = -EINVAL;
1391 } else
1392 ret = get_entries(&get, user);
1393 break;
1394 }
1395
1396 default:
1397 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1398 ret = -EINVAL;
1399 }
1400
1401 return ret;
1402 }
1403
1404 /* Registration hooks for targets. */
1405 int
ip6t_register_target(struct ip6t_target * target)1406 ip6t_register_target(struct ip6t_target *target)
1407 {
1408 int ret;
1409
1410 MOD_INC_USE_COUNT;
1411 ret = down_interruptible(&ip6t_mutex);
1412 if (ret != 0) {
1413 MOD_DEC_USE_COUNT;
1414 return ret;
1415 }
1416 if (!list_named_insert(&ip6t_target, target)) {
1417 duprintf("ip6t_register_target: `%s' already in list!\n",
1418 target->name);
1419 ret = -EINVAL;
1420 MOD_DEC_USE_COUNT;
1421 }
1422 up(&ip6t_mutex);
1423 return ret;
1424 }
1425
1426 void
ip6t_unregister_target(struct ip6t_target * target)1427 ip6t_unregister_target(struct ip6t_target *target)
1428 {
1429 down(&ip6t_mutex);
1430 LIST_DELETE(&ip6t_target, target);
1431 up(&ip6t_mutex);
1432 MOD_DEC_USE_COUNT;
1433 }
1434
1435 int
ip6t_register_match(struct ip6t_match * match)1436 ip6t_register_match(struct ip6t_match *match)
1437 {
1438 int ret;
1439
1440 MOD_INC_USE_COUNT;
1441 ret = down_interruptible(&ip6t_mutex);
1442 if (ret != 0) {
1443 MOD_DEC_USE_COUNT;
1444 return ret;
1445 }
1446 if (!list_named_insert(&ip6t_match, match)) {
1447 duprintf("ip6t_register_match: `%s' already in list!\n",
1448 match->name);
1449 MOD_DEC_USE_COUNT;
1450 ret = -EINVAL;
1451 }
1452 up(&ip6t_mutex);
1453
1454 return ret;
1455 }
1456
1457 void
ip6t_unregister_match(struct ip6t_match * match)1458 ip6t_unregister_match(struct ip6t_match *match)
1459 {
1460 down(&ip6t_mutex);
1461 LIST_DELETE(&ip6t_match, match);
1462 up(&ip6t_mutex);
1463 MOD_DEC_USE_COUNT;
1464 }
1465
ip6t_register_table(struct ip6t_table * table)1466 int ip6t_register_table(struct ip6t_table *table)
1467 {
1468 int ret;
1469 struct ip6t_table_info *newinfo;
1470 static struct ip6t_table_info bootstrap
1471 = { 0, 0, 0, { 0 }, { 0 }, { } };
1472
1473 MOD_INC_USE_COUNT;
1474 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1475 + SMP_ALIGN(table->table->size) * smp_num_cpus);
1476 if (!newinfo) {
1477 ret = -ENOMEM;
1478 MOD_DEC_USE_COUNT;
1479 return ret;
1480 }
1481 memcpy(newinfo->entries, table->table->entries, table->table->size);
1482
1483 ret = translate_table(table->name, table->valid_hooks,
1484 newinfo, table->table->size,
1485 table->table->num_entries,
1486 table->table->hook_entry,
1487 table->table->underflow);
1488 if (ret != 0) {
1489 vfree(newinfo);
1490 MOD_DEC_USE_COUNT;
1491 return ret;
1492 }
1493
1494 ret = down_interruptible(&ip6t_mutex);
1495 if (ret != 0) {
1496 vfree(newinfo);
1497 MOD_DEC_USE_COUNT;
1498 return ret;
1499 }
1500
1501 /* Don't autoload: we'd eat our tail... */
1502 if (list_named_find(&ip6t_tables, table->name)) {
1503 ret = -EEXIST;
1504 goto free_unlock;
1505 }
1506
1507 /* Simplifies replace_table code. */
1508 table->private = &bootstrap;
1509 if (!replace_table(table, 0, newinfo, &ret))
1510 goto free_unlock;
1511
1512 duprintf("table->private->number = %u\n",
1513 table->private->number);
1514
1515 /* save number of initial entries */
1516 table->private->initial_entries = table->private->number;
1517
1518 table->lock = RW_LOCK_UNLOCKED;
1519 list_prepend(&ip6t_tables, table);
1520
1521 unlock:
1522 up(&ip6t_mutex);
1523 return ret;
1524
1525 free_unlock:
1526 vfree(newinfo);
1527 MOD_DEC_USE_COUNT;
1528 goto unlock;
1529 }
1530
ip6t_unregister_table(struct ip6t_table * table)1531 void ip6t_unregister_table(struct ip6t_table *table)
1532 {
1533 down(&ip6t_mutex);
1534 LIST_DELETE(&ip6t_tables, table);
1535 up(&ip6t_mutex);
1536
1537 /* Decrease module usage counts and free resources */
1538 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1539 cleanup_entry, NULL);
1540 vfree(table->private);
1541 MOD_DEC_USE_COUNT;
1542 }
1543
1544 /* Returns 1 if the port is matched by the range, 0 otherwise */
1545 static inline int
port_match(u_int16_t min,u_int16_t max,u_int16_t port,int invert)1546 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1547 {
1548 int ret;
1549
1550 ret = (port >= min && port <= max) ^ invert;
1551 return ret;
1552 }
1553
1554 static int
tcp_find_option(u_int8_t option,const struct tcphdr * tcp,u_int16_t datalen,int invert,int * hotdrop)1555 tcp_find_option(u_int8_t option,
1556 const struct tcphdr *tcp,
1557 u_int16_t datalen,
1558 int invert,
1559 int *hotdrop)
1560 {
1561 unsigned int i = sizeof(struct tcphdr);
1562 const u_int8_t *opt = (u_int8_t *)tcp;
1563
1564 duprintf("tcp_match: finding option\n");
1565 /* If we don't have the whole header, drop packet. */
1566 if (tcp->doff * 4 < sizeof(struct tcphdr) ||
1567 tcp->doff * 4 > datalen) {
1568 *hotdrop = 1;
1569 return 0;
1570 }
1571
1572 while (i < tcp->doff * 4) {
1573 if (opt[i] == option) return !invert;
1574 if (opt[i] < 2) i++;
1575 else i += opt[i+1]?:1;
1576 }
1577
1578 return invert;
1579 }
1580
1581 static int
tcp_match(const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,const void * matchinfo,int offset,const void * hdr,u_int16_t datalen,int * hotdrop)1582 tcp_match(const struct sk_buff *skb,
1583 const struct net_device *in,
1584 const struct net_device *out,
1585 const void *matchinfo,
1586 int offset,
1587 const void *hdr,
1588 u_int16_t datalen,
1589 int *hotdrop)
1590 {
1591 const struct tcphdr *tcp = hdr;
1592 const struct ip6t_tcp *tcpinfo = matchinfo;
1593
1594 /* To quote Alan:
1595
1596 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1597 causes this. Its a cracker trying to break in by doing a
1598 flag overwrite to pass the direction checks.
1599 */
1600
1601 if (offset == 1) {
1602 duprintf("Dropping evil TCP offset=1 frag.\n");
1603 *hotdrop = 1;
1604 return 0;
1605 } else if (offset == 0 && datalen < sizeof(struct tcphdr)) {
1606 /* We've been asked to examine this packet, and we
1607 can't. Hence, no choice but to drop. */
1608 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1609 *hotdrop = 1;
1610 return 0;
1611 }
1612
1613 /* FIXME: Try tcp doff >> packet len against various stacks --RR */
1614
1615 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1616
1617 /* Must not be a fragment. */
1618 return !offset
1619 && port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1620 ntohs(tcp->source),
1621 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT))
1622 && port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1623 ntohs(tcp->dest),
1624 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT))
1625 && FWINVTCP((((unsigned char *)tcp)[13]
1626 & tcpinfo->flg_mask)
1627 == tcpinfo->flg_cmp,
1628 IP6T_TCP_INV_FLAGS)
1629 && (!tcpinfo->option
1630 || tcp_find_option(tcpinfo->option, tcp, datalen,
1631 tcpinfo->invflags
1632 & IP6T_TCP_INV_OPTION,
1633 hotdrop));
1634 }
1635
1636 /* Called when user tries to insert an entry of this type. */
1637 static int
tcp_checkentry(const char * tablename,const struct ip6t_ip6 * ipv6,void * matchinfo,unsigned int matchsize,unsigned int hook_mask)1638 tcp_checkentry(const char *tablename,
1639 const struct ip6t_ip6 *ipv6,
1640 void *matchinfo,
1641 unsigned int matchsize,
1642 unsigned int hook_mask)
1643 {
1644 const struct ip6t_tcp *tcpinfo = matchinfo;
1645
1646 /* Must specify proto == TCP, and no unknown invflags */
1647 return ipv6->proto == IPPROTO_TCP
1648 && !(ipv6->invflags & IP6T_INV_PROTO)
1649 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1650 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1651 }
1652
1653 static int
udp_match(const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,const void * matchinfo,int offset,const void * hdr,u_int16_t datalen,int * hotdrop)1654 udp_match(const struct sk_buff *skb,
1655 const struct net_device *in,
1656 const struct net_device *out,
1657 const void *matchinfo,
1658 int offset,
1659 const void *hdr,
1660 u_int16_t datalen,
1661 int *hotdrop)
1662 {
1663 const struct udphdr *udp = hdr;
1664 const struct ip6t_udp *udpinfo = matchinfo;
1665
1666 if (offset == 0 && datalen < sizeof(struct udphdr)) {
1667 /* We've been asked to examine this packet, and we
1668 can't. Hence, no choice but to drop. */
1669 duprintf("Dropping evil UDP tinygram.\n");
1670 *hotdrop = 1;
1671 return 0;
1672 }
1673
1674 /* Must not be a fragment. */
1675 return !offset
1676 && port_match(udpinfo->spts[0], udpinfo->spts[1],
1677 ntohs(udp->source),
1678 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1679 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1680 ntohs(udp->dest),
1681 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1682 }
1683
1684 /* Called when user tries to insert an entry of this type. */
1685 static int
udp_checkentry(const char * tablename,const struct ip6t_ip6 * ipv6,void * matchinfo,unsigned int matchinfosize,unsigned int hook_mask)1686 udp_checkentry(const char *tablename,
1687 const struct ip6t_ip6 *ipv6,
1688 void *matchinfo,
1689 unsigned int matchinfosize,
1690 unsigned int hook_mask)
1691 {
1692 const struct ip6t_udp *udpinfo = matchinfo;
1693
1694 /* Must specify proto == UDP, and no unknown invflags */
1695 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1696 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1697 IPPROTO_UDP);
1698 return 0;
1699 }
1700 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1701 duprintf("ip6t_udp: matchsize %u != %u\n",
1702 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1703 return 0;
1704 }
1705 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1706 duprintf("ip6t_udp: unknown flags %X\n",
1707 udpinfo->invflags);
1708 return 0;
1709 }
1710
1711 return 1;
1712 }
1713
1714 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1715 static inline int
icmp6_type_code_match(u_int8_t test_type,u_int8_t min_code,u_int8_t max_code,u_int8_t type,u_int8_t code,int invert)1716 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1717 u_int8_t type, u_int8_t code,
1718 int invert)
1719 {
1720 return (type == test_type && code >= min_code && code <= max_code)
1721 ^ invert;
1722 }
1723
1724 static int
icmp6_match(const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,const void * matchinfo,int offset,const void * hdr,u_int16_t datalen,int * hotdrop)1725 icmp6_match(const struct sk_buff *skb,
1726 const struct net_device *in,
1727 const struct net_device *out,
1728 const void *matchinfo,
1729 int offset,
1730 const void *hdr,
1731 u_int16_t datalen,
1732 int *hotdrop)
1733 {
1734 const struct icmp6hdr *icmp = hdr;
1735 const struct ip6t_icmp *icmpinfo = matchinfo;
1736
1737 if (offset == 0 && datalen < 2) {
1738 /* We've been asked to examine this packet, and we
1739 can't. Hence, no choice but to drop. */
1740 duprintf("Dropping evil ICMP tinygram.\n");
1741 *hotdrop = 1;
1742 return 0;
1743 }
1744
1745 /* Must not be a fragment. */
1746 return !offset
1747 && icmp6_type_code_match(icmpinfo->type,
1748 icmpinfo->code[0],
1749 icmpinfo->code[1],
1750 icmp->icmp6_type, icmp->icmp6_code,
1751 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1752 }
1753
1754 /* Called when user tries to insert an entry of this type. */
1755 static int
icmp6_checkentry(const char * tablename,const struct ip6t_ip6 * ipv6,void * matchinfo,unsigned int matchsize,unsigned int hook_mask)1756 icmp6_checkentry(const char *tablename,
1757 const struct ip6t_ip6 *ipv6,
1758 void *matchinfo,
1759 unsigned int matchsize,
1760 unsigned int hook_mask)
1761 {
1762 const struct ip6t_icmp *icmpinfo = matchinfo;
1763
1764 /* Must specify proto == ICMP, and no unknown invflags */
1765 return ipv6->proto == IPPROTO_ICMPV6
1766 && !(ipv6->invflags & IP6T_INV_PROTO)
1767 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1768 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1769 }
1770
1771 /* The built-in targets: standard (NULL) and error. */
1772 static struct ip6t_target ip6t_standard_target
1773 = { { NULL, NULL }, IP6T_STANDARD_TARGET, NULL, NULL, NULL };
1774 static struct ip6t_target ip6t_error_target
1775 = { { NULL, NULL }, IP6T_ERROR_TARGET, ip6t_error, NULL, NULL };
1776
1777 static struct nf_sockopt_ops ip6t_sockopts
1778 = { { NULL, NULL }, PF_INET6, IP6T_BASE_CTL, IP6T_SO_SET_MAX+1, do_ip6t_set_ctl,
1779 IP6T_BASE_CTL, IP6T_SO_GET_MAX+1, do_ip6t_get_ctl, 0, NULL };
1780
1781 static struct ip6t_match tcp_matchstruct
1782 = { { NULL, NULL }, "tcp", &tcp_match, &tcp_checkentry, NULL };
1783 static struct ip6t_match udp_matchstruct
1784 = { { NULL, NULL }, "udp", &udp_match, &udp_checkentry, NULL };
1785 static struct ip6t_match icmp6_matchstruct
1786 = { { NULL, NULL }, "icmp6", &icmp6_match, &icmp6_checkentry, NULL };
1787
1788 #ifdef CONFIG_PROC_FS
print_name(const char * i,off_t start_offset,char * buffer,int length,off_t * pos,unsigned int * count)1789 static inline int print_name(const char *i,
1790 off_t start_offset, char *buffer, int length,
1791 off_t *pos, unsigned int *count)
1792 {
1793 if ((*count)++ >= start_offset) {
1794 unsigned int namelen;
1795
1796 namelen = sprintf(buffer + *pos, "%s\n",
1797 i + sizeof(struct list_head));
1798 if (*pos + namelen > length) {
1799 /* Stop iterating */
1800 return 1;
1801 }
1802 *pos += namelen;
1803 }
1804 return 0;
1805 }
1806
print_target(const struct ip6t_target * t,off_t start_offset,char * buffer,int length,off_t * pos,unsigned int * count)1807 static inline int print_target(const struct ip6t_target *t,
1808 off_t start_offset, char *buffer, int length,
1809 off_t *pos, unsigned int *count)
1810 {
1811 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1812 return 0;
1813 return print_name((char *)t, start_offset, buffer, length, pos, count);
1814 }
1815
ip6t_get_tables(char * buffer,char ** start,off_t offset,int length)1816 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1817 {
1818 off_t pos = 0;
1819 unsigned int count = 0;
1820
1821 if (down_interruptible(&ip6t_mutex) != 0)
1822 return 0;
1823
1824 LIST_FIND(&ip6t_tables, print_name, char *,
1825 offset, buffer, length, &pos, &count);
1826
1827 up(&ip6t_mutex);
1828
1829 /* `start' hack - see fs/proc/generic.c line ~105 */
1830 *start=(char *)((unsigned long)count-offset);
1831 return pos;
1832 }
1833
ip6t_get_targets(char * buffer,char ** start,off_t offset,int length)1834 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1835 {
1836 off_t pos = 0;
1837 unsigned int count = 0;
1838
1839 if (down_interruptible(&ip6t_mutex) != 0)
1840 return 0;
1841
1842 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1843 offset, buffer, length, &pos, &count);
1844
1845 up(&ip6t_mutex);
1846
1847 *start = (char *)((unsigned long)count - offset);
1848 return pos;
1849 }
1850
ip6t_get_matches(char * buffer,char ** start,off_t offset,int length)1851 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1852 {
1853 off_t pos = 0;
1854 unsigned int count = 0;
1855
1856 if (down_interruptible(&ip6t_mutex) != 0)
1857 return 0;
1858
1859 LIST_FIND(&ip6t_match, print_name, char *,
1860 offset, buffer, length, &pos, &count);
1861
1862 up(&ip6t_mutex);
1863
1864 *start = (char *)((unsigned long)count - offset);
1865 return pos;
1866 }
1867
1868 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1869 { { "ip6_tables_names", ip6t_get_tables },
1870 { "ip6_tables_targets", ip6t_get_targets },
1871 { "ip6_tables_matches", ip6t_get_matches },
1872 { NULL, NULL} };
1873 #endif /*CONFIG_PROC_FS*/
1874
init(void)1875 static int __init init(void)
1876 {
1877 int ret;
1878
1879 /* Noone else will be downing sem now, so we won't sleep */
1880 down(&ip6t_mutex);
1881 list_append(&ip6t_target, &ip6t_standard_target);
1882 list_append(&ip6t_target, &ip6t_error_target);
1883 list_append(&ip6t_match, &tcp_matchstruct);
1884 list_append(&ip6t_match, &udp_matchstruct);
1885 list_append(&ip6t_match, &icmp6_matchstruct);
1886 up(&ip6t_mutex);
1887
1888 /* Register setsockopt */
1889 ret = nf_register_sockopt(&ip6t_sockopts);
1890 if (ret < 0) {
1891 duprintf("Unable to register sockopts.\n");
1892 return ret;
1893 }
1894
1895 #ifdef CONFIG_PROC_FS
1896 {
1897 struct proc_dir_entry *proc;
1898 int i;
1899
1900 for (i = 0; ip6t_proc_entry[i].name; i++) {
1901 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1902 ip6t_proc_entry[i].get_info);
1903 if (!proc) {
1904 while (--i >= 0)
1905 proc_net_remove(ip6t_proc_entry[i].name);
1906 nf_unregister_sockopt(&ip6t_sockopts);
1907 return -ENOMEM;
1908 }
1909 proc->owner = THIS_MODULE;
1910 }
1911 }
1912 #endif
1913
1914 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1915 return 0;
1916 }
1917
fini(void)1918 static void __exit fini(void)
1919 {
1920 nf_unregister_sockopt(&ip6t_sockopts);
1921 #ifdef CONFIG_PROC_FS
1922 {
1923 int i;
1924 for (i = 0; ip6t_proc_entry[i].name; i++)
1925 proc_net_remove(ip6t_proc_entry[i].name);
1926 }
1927 #endif
1928 }
1929
1930 EXPORT_SYMBOL(ip6t_register_table);
1931 EXPORT_SYMBOL(ip6t_unregister_table);
1932 EXPORT_SYMBOL(ip6t_do_table);
1933 EXPORT_SYMBOL(ip6t_find_target_lock);
1934 EXPORT_SYMBOL(ip6t_register_match);
1935 EXPORT_SYMBOL(ip6t_unregister_match);
1936 EXPORT_SYMBOL(ip6t_register_target);
1937 EXPORT_SYMBOL(ip6t_unregister_target);
1938 EXPORT_SYMBOL(ip6t_ext_hdr);
1939
1940 module_init(init);
1941 module_exit(fini);
1942 MODULE_LICENSE("GPL");
1943