Merge branch 'mac80211-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / net / ipv4 / netfilter / ip_tables.c
1 /*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11 #include <linux/cache.h>
12 #include <linux/capability.h>
13 #include <linux/skbuff.h>
14 #include <linux/kmod.h>
15 #include <linux/vmalloc.h>
16 #include <linux/netdevice.h>
17 #include <linux/module.h>
18 #include <linux/icmp.h>
19 #include <net/ip.h>
20 #include <net/compat.h>
21 #include <asm/uaccess.h>
22 #include <linux/mutex.h>
23 #include <linux/proc_fs.h>
24 #include <linux/err.h>
25 #include <linux/cpumask.h>
26
27 #include <linux/netfilter/x_tables.h>
28 #include <linux/netfilter_ipv4/ip_tables.h>
29
30 MODULE_LICENSE("GPL");
31 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
32 MODULE_DESCRIPTION("IPv4 packet filter");
33
34 /*#define DEBUG_IP_FIREWALL*/
35 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
36 /*#define DEBUG_IP_FIREWALL_USER*/
37
38 #ifdef DEBUG_IP_FIREWALL
39 #define dprintf(format, args...) printk(format , ## args)
40 #else
41 #define dprintf(format, args...)
42 #endif
43
44 #ifdef DEBUG_IP_FIREWALL_USER
45 #define duprintf(format, args...) printk(format , ## args)
46 #else
47 #define duprintf(format, args...)
48 #endif
49
50 #ifdef CONFIG_NETFILTER_DEBUG
51 #define IP_NF_ASSERT(x) \
52 do { \
53 if (!(x)) \
54 printk("IP_NF_ASSERT: %s:%s:%u\n", \
55 __FUNCTION__, __FILE__, __LINE__); \
56 } while(0)
57 #else
58 #define IP_NF_ASSERT(x)
59 #endif
60
61 #if 0
62 /* All the better to debug you with... */
63 #define static
64 #define inline
65 #endif
66
67 /*
68 We keep a set of rules for each CPU, so we can avoid write-locking
69 them in the softirq when updating the counters and therefore
70 only need to read-lock in the softirq; doing a write_lock_bh() in user
71 context stops packets coming through and allows user context to read
72 the counters or update the rules.
73
74 Hence the start of any table is given by get_table() below. */
75
76 /* Returns whether matches rule or not. */
77 static inline int
78 ip_packet_match(const struct iphdr *ip,
79 const char *indev,
80 const char *outdev,
81 const struct ipt_ip *ipinfo,
82 int isfrag)
83 {
84 size_t i;
85 unsigned long ret;
86
87 #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
88
89 if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
90 IPT_INV_SRCIP)
91 || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
92 IPT_INV_DSTIP)) {
93 dprintf("Source or dest mismatch.\n");
94
95 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
96 NIPQUAD(ip->saddr),
97 NIPQUAD(ipinfo->smsk.s_addr),
98 NIPQUAD(ipinfo->src.s_addr),
99 ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
100 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
101 NIPQUAD(ip->daddr),
102 NIPQUAD(ipinfo->dmsk.s_addr),
103 NIPQUAD(ipinfo->dst.s_addr),
104 ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
105 return 0;
106 }
107
108 /* Look for ifname matches; this should unroll nicely. */
109 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
110 ret |= (((const unsigned long *)indev)[i]
111 ^ ((const unsigned long *)ipinfo->iniface)[i])
112 & ((const unsigned long *)ipinfo->iniface_mask)[i];
113 }
114
115 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
116 dprintf("VIA in mismatch (%s vs %s).%s\n",
117 indev, ipinfo->iniface,
118 ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
119 return 0;
120 }
121
122 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
123 ret |= (((const unsigned long *)outdev)[i]
124 ^ ((const unsigned long *)ipinfo->outiface)[i])
125 & ((const unsigned long *)ipinfo->outiface_mask)[i];
126 }
127
128 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
129 dprintf("VIA out mismatch (%s vs %s).%s\n",
130 outdev, ipinfo->outiface,
131 ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
132 return 0;
133 }
134
135 /* Check specific protocol */
136 if (ipinfo->proto
137 && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
138 dprintf("Packet protocol %hi does not match %hi.%s\n",
139 ip->protocol, ipinfo->proto,
140 ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
141 return 0;
142 }
143
144 /* If we have a fragment rule but the packet is not a fragment
145 * then we return zero */
146 if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
147 dprintf("Fragment rule but not fragment.%s\n",
148 ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
149 return 0;
150 }
151
152 return 1;
153 }
154
155 static inline int
156 ip_checkentry(const struct ipt_ip *ip)
157 {
158 if (ip->flags & ~IPT_F_MASK) {
159 duprintf("Unknown flag bits set: %08X\n",
160 ip->flags & ~IPT_F_MASK);
161 return 0;
162 }
163 if (ip->invflags & ~IPT_INV_MASK) {
164 duprintf("Unknown invflag bits set: %08X\n",
165 ip->invflags & ~IPT_INV_MASK);
166 return 0;
167 }
168 return 1;
169 }
170
171 static unsigned int
172 ipt_error(struct sk_buff **pskb,
173 const struct net_device *in,
174 const struct net_device *out,
175 unsigned int hooknum,
176 const struct xt_target *target,
177 const void *targinfo)
178 {
179 if (net_ratelimit())
180 printk("ip_tables: error: `%s'\n", (char *)targinfo);
181
182 return NF_DROP;
183 }
184
185 static inline
186 int do_match(struct ipt_entry_match *m,
187 const struct sk_buff *skb,
188 const struct net_device *in,
189 const struct net_device *out,
190 int offset,
191 int *hotdrop)
192 {
193 /* Stop iteration if it doesn't match */
194 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
195 offset, ip_hdrlen(skb), hotdrop))
196 return 1;
197 else
198 return 0;
199 }
200
201 static inline struct ipt_entry *
202 get_entry(void *base, unsigned int offset)
203 {
204 return (struct ipt_entry *)(base + offset);
205 }
206
207 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
208 unsigned int
209 ipt_do_table(struct sk_buff **pskb,
210 unsigned int hook,
211 const struct net_device *in,
212 const struct net_device *out,
213 struct xt_table *table)
214 {
215 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
216 u_int16_t offset;
217 struct iphdr *ip;
218 u_int16_t datalen;
219 int hotdrop = 0;
220 /* Initializing verdict to NF_DROP keeps gcc happy. */
221 unsigned int verdict = NF_DROP;
222 const char *indev, *outdev;
223 void *table_base;
224 struct ipt_entry *e, *back;
225 struct xt_table_info *private;
226
227 /* Initialization */
228 ip = ip_hdr(*pskb);
229 datalen = (*pskb)->len - ip->ihl * 4;
230 indev = in ? in->name : nulldevname;
231 outdev = out ? out->name : nulldevname;
232 /* We handle fragments by dealing with the first fragment as
233 * if it was a normal packet. All other fragments are treated
234 * normally, except that they will NEVER match rules that ask
235 * things we don't know, ie. tcp syn flag or ports). If the
236 * rule is also a fragment-specific rule, non-fragments won't
237 * match it. */
238 offset = ntohs(ip->frag_off) & IP_OFFSET;
239
240 read_lock_bh(&table->lock);
241 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
242 private = table->private;
243 table_base = (void *)private->entries[smp_processor_id()];
244 e = get_entry(table_base, private->hook_entry[hook]);
245
246 /* For return from builtin chain */
247 back = get_entry(table_base, private->underflow[hook]);
248
249 do {
250 IP_NF_ASSERT(e);
251 IP_NF_ASSERT(back);
252 if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
253 struct ipt_entry_target *t;
254
255 if (IPT_MATCH_ITERATE(e, do_match,
256 *pskb, in, out,
257 offset, &hotdrop) != 0)
258 goto no_match;
259
260 ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
261
262 t = ipt_get_target(e);
263 IP_NF_ASSERT(t->u.kernel.target);
264 /* Standard target? */
265 if (!t->u.kernel.target->target) {
266 int v;
267
268 v = ((struct ipt_standard_target *)t)->verdict;
269 if (v < 0) {
270 /* Pop from stack? */
271 if (v != IPT_RETURN) {
272 verdict = (unsigned)(-v) - 1;
273 break;
274 }
275 e = back;
276 back = get_entry(table_base,
277 back->comefrom);
278 continue;
279 }
280 if (table_base + v != (void *)e + e->next_offset
281 && !(e->ip.flags & IPT_F_GOTO)) {
282 /* Save old back ptr in next entry */
283 struct ipt_entry *next
284 = (void *)e + e->next_offset;
285 next->comefrom
286 = (void *)back - table_base;
287 /* set back pointer to next entry */
288 back = next;
289 }
290
291 e = get_entry(table_base, v);
292 } else {
293 /* Targets which reenter must return
294 abs. verdicts */
295 #ifdef CONFIG_NETFILTER_DEBUG
296 ((struct ipt_entry *)table_base)->comefrom
297 = 0xeeeeeeec;
298 #endif
299 verdict = t->u.kernel.target->target(pskb,
300 in, out,
301 hook,
302 t->u.kernel.target,
303 t->data);
304
305 #ifdef CONFIG_NETFILTER_DEBUG
306 if (((struct ipt_entry *)table_base)->comefrom
307 != 0xeeeeeeec
308 && verdict == IPT_CONTINUE) {
309 printk("Target %s reentered!\n",
310 t->u.kernel.target->name);
311 verdict = NF_DROP;
312 }
313 ((struct ipt_entry *)table_base)->comefrom
314 = 0x57acc001;
315 #endif
316 /* Target might have changed stuff. */
317 ip = ip_hdr(*pskb);
318 datalen = (*pskb)->len - ip->ihl * 4;
319
320 if (verdict == IPT_CONTINUE)
321 e = (void *)e + e->next_offset;
322 else
323 /* Verdict */
324 break;
325 }
326 } else {
327
328 no_match:
329 e = (void *)e + e->next_offset;
330 }
331 } while (!hotdrop);
332
333 read_unlock_bh(&table->lock);
334
335 #ifdef DEBUG_ALLOW_ALL
336 return NF_ACCEPT;
337 #else
338 if (hotdrop)
339 return NF_DROP;
340 else return verdict;
341 #endif
342 }
343
344 /* All zeroes == unconditional rule. */
345 static inline int
346 unconditional(const struct ipt_ip *ip)
347 {
348 unsigned int i;
349
350 for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
351 if (((__u32 *)ip)[i])
352 return 0;
353
354 return 1;
355 }
356
357 /* Figures out from what hook each rule can be called: returns 0 if
358 there are loops. Puts hook bitmask in comefrom. */
359 static int
360 mark_source_chains(struct xt_table_info *newinfo,
361 unsigned int valid_hooks, void *entry0)
362 {
363 unsigned int hook;
364
365 /* No recursion; use packet counter to save back ptrs (reset
366 to 0 as we leave), and comefrom to save source hook bitmask */
367 for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) {
368 unsigned int pos = newinfo->hook_entry[hook];
369 struct ipt_entry *e
370 = (struct ipt_entry *)(entry0 + pos);
371
372 if (!(valid_hooks & (1 << hook)))
373 continue;
374
375 /* Set initial back pointer. */
376 e->counters.pcnt = pos;
377
378 for (;;) {
379 struct ipt_standard_target *t
380 = (void *)ipt_get_target(e);
381 int visited = e->comefrom & (1 << hook);
382
383 if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
384 printk("iptables: loop hook %u pos %u %08X.\n",
385 hook, pos, e->comefrom);
386 return 0;
387 }
388 e->comefrom
389 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
390
391 /* Unconditional return/END. */
392 if ((e->target_offset == sizeof(struct ipt_entry)
393 && (strcmp(t->target.u.user.name,
394 IPT_STANDARD_TARGET) == 0)
395 && t->verdict < 0
396 && unconditional(&e->ip)) || visited) {
397 unsigned int oldpos, size;
398
399 if (t->verdict < -NF_MAX_VERDICT - 1) {
400 duprintf("mark_source_chains: bad "
401 "negative verdict (%i)\n",
402 t->verdict);
403 return 0;
404 }
405
406 /* Return: backtrack through the last
407 big jump. */
408 do {
409 e->comefrom ^= (1<<NF_IP_NUMHOOKS);
410 #ifdef DEBUG_IP_FIREWALL_USER
411 if (e->comefrom
412 & (1 << NF_IP_NUMHOOKS)) {
413 duprintf("Back unset "
414 "on hook %u "
415 "rule %u\n",
416 hook, pos);
417 }
418 #endif
419 oldpos = pos;
420 pos = e->counters.pcnt;
421 e->counters.pcnt = 0;
422
423 /* We're at the start. */
424 if (pos == oldpos)
425 goto next;
426
427 e = (struct ipt_entry *)
428 (entry0 + pos);
429 } while (oldpos == pos + e->next_offset);
430
431 /* Move along one */
432 size = e->next_offset;
433 e = (struct ipt_entry *)
434 (entry0 + pos + size);
435 e->counters.pcnt = pos;
436 pos += size;
437 } else {
438 int newpos = t->verdict;
439
440 if (strcmp(t->target.u.user.name,
441 IPT_STANDARD_TARGET) == 0
442 && newpos >= 0) {
443 if (newpos > newinfo->size -
444 sizeof(struct ipt_entry)) {
445 duprintf("mark_source_chains: "
446 "bad verdict (%i)\n",
447 newpos);
448 return 0;
449 }
450 /* This a jump; chase it. */
451 duprintf("Jump rule %u -> %u\n",
452 pos, newpos);
453 } else {
454 /* ... this is a fallthru */
455 newpos = pos + e->next_offset;
456 }
457 e = (struct ipt_entry *)
458 (entry0 + newpos);
459 e->counters.pcnt = pos;
460 pos = newpos;
461 }
462 }
463 next:
464 duprintf("Finished chain %u\n", hook);
465 }
466 return 1;
467 }
468
469 static inline int
470 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
471 {
472 if (i && (*i)-- == 0)
473 return 1;
474
475 if (m->u.kernel.match->destroy)
476 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
477 module_put(m->u.kernel.match->me);
478 return 0;
479 }
480
481 static inline int
482 check_entry(struct ipt_entry *e, const char *name)
483 {
484 struct ipt_entry_target *t;
485
486 if (!ip_checkentry(&e->ip)) {
487 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
488 return -EINVAL;
489 }
490
491 if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
492 return -EINVAL;
493
494 t = ipt_get_target(e);
495 if (e->target_offset + t->u.target_size > e->next_offset)
496 return -EINVAL;
497
498 return 0;
499 }
500
501 static inline int check_match(struct ipt_entry_match *m, const char *name,
502 const struct ipt_ip *ip, unsigned int hookmask,
503 unsigned int *i)
504 {
505 struct xt_match *match;
506 int ret;
507
508 match = m->u.kernel.match;
509 ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
510 name, hookmask, ip->proto,
511 ip->invflags & IPT_INV_PROTO);
512 if (!ret && m->u.kernel.match->checkentry
513 && !m->u.kernel.match->checkentry(name, ip, match, m->data,
514 hookmask)) {
515 duprintf("ip_tables: check failed for `%s'.\n",
516 m->u.kernel.match->name);
517 ret = -EINVAL;
518 }
519 if (!ret)
520 (*i)++;
521 return ret;
522 }
523
524 static inline int
525 find_check_match(struct ipt_entry_match *m,
526 const char *name,
527 const struct ipt_ip *ip,
528 unsigned int hookmask,
529 unsigned int *i)
530 {
531 struct xt_match *match;
532 int ret;
533
534 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
535 m->u.user.revision),
536 "ipt_%s", m->u.user.name);
537 if (IS_ERR(match) || !match) {
538 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
539 return match ? PTR_ERR(match) : -ENOENT;
540 }
541 m->u.kernel.match = match;
542
543 ret = check_match(m, name, ip, hookmask, i);
544 if (ret)
545 goto err;
546
547 return 0;
548 err:
549 module_put(m->u.kernel.match->me);
550 return ret;
551 }
552
553 static inline int check_target(struct ipt_entry *e, const char *name)
554 {
555 struct ipt_entry_target *t;
556 struct xt_target *target;
557 int ret;
558
559 t = ipt_get_target(e);
560 target = t->u.kernel.target;
561 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
562 name, e->comefrom, e->ip.proto,
563 e->ip.invflags & IPT_INV_PROTO);
564 if (!ret && t->u.kernel.target->checkentry
565 && !t->u.kernel.target->checkentry(name, e, target,
566 t->data, e->comefrom)) {
567 duprintf("ip_tables: check failed for `%s'.\n",
568 t->u.kernel.target->name);
569 ret = -EINVAL;
570 }
571 return ret;
572 }
573
574 static inline int
575 find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
576 unsigned int *i)
577 {
578 struct ipt_entry_target *t;
579 struct xt_target *target;
580 int ret;
581 unsigned int j;
582
583 ret = check_entry(e, name);
584 if (ret)
585 return ret;
586
587 j = 0;
588 ret = IPT_MATCH_ITERATE(e, find_check_match, name, &e->ip,
589 e->comefrom, &j);
590 if (ret != 0)
591 goto cleanup_matches;
592
593 t = ipt_get_target(e);
594 target = try_then_request_module(xt_find_target(AF_INET,
595 t->u.user.name,
596 t->u.user.revision),
597 "ipt_%s", t->u.user.name);
598 if (IS_ERR(target) || !target) {
599 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
600 ret = target ? PTR_ERR(target) : -ENOENT;
601 goto cleanup_matches;
602 }
603 t->u.kernel.target = target;
604
605 ret = check_target(e, name);
606 if (ret)
607 goto err;
608
609 (*i)++;
610 return 0;
611 err:
612 module_put(t->u.kernel.target->me);
613 cleanup_matches:
614 IPT_MATCH_ITERATE(e, cleanup_match, &j);
615 return ret;
616 }
617
618 static inline int
619 check_entry_size_and_hooks(struct ipt_entry *e,
620 struct xt_table_info *newinfo,
621 unsigned char *base,
622 unsigned char *limit,
623 const unsigned int *hook_entries,
624 const unsigned int *underflows,
625 unsigned int *i)
626 {
627 unsigned int h;
628
629 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
630 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
631 duprintf("Bad offset %p\n", e);
632 return -EINVAL;
633 }
634
635 if (e->next_offset
636 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
637 duprintf("checking: element %p size %u\n",
638 e, e->next_offset);
639 return -EINVAL;
640 }
641
642 /* Check hooks & underflows */
643 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
644 if ((unsigned char *)e - base == hook_entries[h])
645 newinfo->hook_entry[h] = hook_entries[h];
646 if ((unsigned char *)e - base == underflows[h])
647 newinfo->underflow[h] = underflows[h];
648 }
649
650 /* FIXME: underflows must be unconditional, standard verdicts
651 < 0 (not IPT_RETURN). --RR */
652
653 /* Clear counters and comefrom */
654 e->counters = ((struct xt_counters) { 0, 0 });
655 e->comefrom = 0;
656
657 (*i)++;
658 return 0;
659 }
660
661 static inline int
662 cleanup_entry(struct ipt_entry *e, unsigned int *i)
663 {
664 struct ipt_entry_target *t;
665
666 if (i && (*i)-- == 0)
667 return 1;
668
669 /* Cleanup all matches */
670 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
671 t = ipt_get_target(e);
672 if (t->u.kernel.target->destroy)
673 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
674 module_put(t->u.kernel.target->me);
675 return 0;
676 }
677
678 /* Checks and translates the user-supplied table segment (held in
679 newinfo) */
680 static int
681 translate_table(const char *name,
682 unsigned int valid_hooks,
683 struct xt_table_info *newinfo,
684 void *entry0,
685 unsigned int size,
686 unsigned int number,
687 const unsigned int *hook_entries,
688 const unsigned int *underflows)
689 {
690 unsigned int i;
691 int ret;
692
693 newinfo->size = size;
694 newinfo->number = number;
695
696 /* Init all hooks to impossible value. */
697 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
698 newinfo->hook_entry[i] = 0xFFFFFFFF;
699 newinfo->underflow[i] = 0xFFFFFFFF;
700 }
701
702 duprintf("translate_table: size %u\n", newinfo->size);
703 i = 0;
704 /* Walk through entries, checking offsets. */
705 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
706 check_entry_size_and_hooks,
707 newinfo,
708 entry0,
709 entry0 + size,
710 hook_entries, underflows, &i);
711 if (ret != 0)
712 return ret;
713
714 if (i != number) {
715 duprintf("translate_table: %u not %u entries\n",
716 i, number);
717 return -EINVAL;
718 }
719
720 /* Check hooks all assigned */
721 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
722 /* Only hooks which are valid */
723 if (!(valid_hooks & (1 << i)))
724 continue;
725 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
726 duprintf("Invalid hook entry %u %u\n",
727 i, hook_entries[i]);
728 return -EINVAL;
729 }
730 if (newinfo->underflow[i] == 0xFFFFFFFF) {
731 duprintf("Invalid underflow %u %u\n",
732 i, underflows[i]);
733 return -EINVAL;
734 }
735 }
736
737 if (!mark_source_chains(newinfo, valid_hooks, entry0))
738 return -ELOOP;
739
740 /* Finally, each sanity check must pass */
741 i = 0;
742 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
743 find_check_entry, name, size, &i);
744
745 if (ret != 0) {
746 IPT_ENTRY_ITERATE(entry0, newinfo->size,
747 cleanup_entry, &i);
748 return ret;
749 }
750
751 /* And one copy for every other CPU */
752 for_each_possible_cpu(i) {
753 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
754 memcpy(newinfo->entries[i], entry0, newinfo->size);
755 }
756
757 return ret;
758 }
759
760 /* Gets counters. */
761 static inline int
762 add_entry_to_counter(const struct ipt_entry *e,
763 struct xt_counters total[],
764 unsigned int *i)
765 {
766 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
767
768 (*i)++;
769 return 0;
770 }
771
772 static inline int
773 set_entry_to_counter(const struct ipt_entry *e,
774 struct ipt_counters total[],
775 unsigned int *i)
776 {
777 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
778
779 (*i)++;
780 return 0;
781 }
782
783 static void
784 get_counters(const struct xt_table_info *t,
785 struct xt_counters counters[])
786 {
787 unsigned int cpu;
788 unsigned int i;
789 unsigned int curcpu;
790
791 /* Instead of clearing (by a previous call to memset())
792 * the counters and using adds, we set the counters
793 * with data used by 'current' CPU
794 * We dont care about preemption here.
795 */
796 curcpu = raw_smp_processor_id();
797
798 i = 0;
799 IPT_ENTRY_ITERATE(t->entries[curcpu],
800 t->size,
801 set_entry_to_counter,
802 counters,
803 &i);
804
805 for_each_possible_cpu(cpu) {
806 if (cpu == curcpu)
807 continue;
808 i = 0;
809 IPT_ENTRY_ITERATE(t->entries[cpu],
810 t->size,
811 add_entry_to_counter,
812 counters,
813 &i);
814 }
815 }
816
817 static inline struct xt_counters * alloc_counters(struct xt_table *table)
818 {
819 unsigned int countersize;
820 struct xt_counters *counters;
821 struct xt_table_info *private = table->private;
822
823 /* We need atomic snapshot of counters: rest doesn't change
824 (other than comefrom, which userspace doesn't care
825 about). */
826 countersize = sizeof(struct xt_counters) * private->number;
827 counters = vmalloc_node(countersize, numa_node_id());
828
829 if (counters == NULL)
830 return ERR_PTR(-ENOMEM);
831
832 /* First, sum counters... */
833 write_lock_bh(&table->lock);
834 get_counters(private, counters);
835 write_unlock_bh(&table->lock);
836
837 return counters;
838 }
839
840 static int
841 copy_entries_to_user(unsigned int total_size,
842 struct xt_table *table,
843 void __user *userptr)
844 {
845 unsigned int off, num;
846 struct ipt_entry *e;
847 struct xt_counters *counters;
848 struct xt_table_info *private = table->private;
849 int ret = 0;
850 void *loc_cpu_entry;
851
852 counters = alloc_counters(table);
853 if (IS_ERR(counters))
854 return PTR_ERR(counters);
855
856 /* choose the copy that is on our node/cpu, ...
857 * This choice is lazy (because current thread is
858 * allowed to migrate to another cpu)
859 */
860 loc_cpu_entry = private->entries[raw_smp_processor_id()];
861 /* ... then copy entire thing ... */
862 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
863 ret = -EFAULT;
864 goto free_counters;
865 }
866
867 /* FIXME: use iterator macros --RR */
868 /* ... then go back and fix counters and names */
869 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
870 unsigned int i;
871 struct ipt_entry_match *m;
872 struct ipt_entry_target *t;
873
874 e = (struct ipt_entry *)(loc_cpu_entry + off);
875 if (copy_to_user(userptr + off
876 + offsetof(struct ipt_entry, counters),
877 &counters[num],
878 sizeof(counters[num])) != 0) {
879 ret = -EFAULT;
880 goto free_counters;
881 }
882
883 for (i = sizeof(struct ipt_entry);
884 i < e->target_offset;
885 i += m->u.match_size) {
886 m = (void *)e + i;
887
888 if (copy_to_user(userptr + off + i
889 + offsetof(struct ipt_entry_match,
890 u.user.name),
891 m->u.kernel.match->name,
892 strlen(m->u.kernel.match->name)+1)
893 != 0) {
894 ret = -EFAULT;
895 goto free_counters;
896 }
897 }
898
899 t = ipt_get_target(e);
900 if (copy_to_user(userptr + off + e->target_offset
901 + offsetof(struct ipt_entry_target,
902 u.user.name),
903 t->u.kernel.target->name,
904 strlen(t->u.kernel.target->name)+1) != 0) {
905 ret = -EFAULT;
906 goto free_counters;
907 }
908 }
909
910 free_counters:
911 vfree(counters);
912 return ret;
913 }
914
915 #ifdef CONFIG_COMPAT
916 struct compat_delta {
917 struct compat_delta *next;
918 unsigned int offset;
919 short delta;
920 };
921
922 static struct compat_delta *compat_offsets = NULL;
923
924 static int compat_add_offset(unsigned int offset, short delta)
925 {
926 struct compat_delta *tmp;
927
928 tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
929 if (!tmp)
930 return -ENOMEM;
931 tmp->offset = offset;
932 tmp->delta = delta;
933 if (compat_offsets) {
934 tmp->next = compat_offsets->next;
935 compat_offsets->next = tmp;
936 } else {
937 compat_offsets = tmp;
938 tmp->next = NULL;
939 }
940 return 0;
941 }
942
943 static void compat_flush_offsets(void)
944 {
945 struct compat_delta *tmp, *next;
946
947 if (compat_offsets) {
948 for(tmp = compat_offsets; tmp; tmp = next) {
949 next = tmp->next;
950 kfree(tmp);
951 }
952 compat_offsets = NULL;
953 }
954 }
955
956 static short compat_calc_jump(unsigned int offset)
957 {
958 struct compat_delta *tmp;
959 short delta;
960
961 for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
962 if (tmp->offset < offset)
963 delta += tmp->delta;
964 return delta;
965 }
966
967 static void compat_standard_from_user(void *dst, void *src)
968 {
969 int v = *(compat_int_t *)src;
970
971 if (v > 0)
972 v += compat_calc_jump(v);
973 memcpy(dst, &v, sizeof(v));
974 }
975
976 static int compat_standard_to_user(void __user *dst, void *src)
977 {
978 compat_int_t cv = *(int *)src;
979
980 if (cv > 0)
981 cv -= compat_calc_jump(cv);
982 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
983 }
984
985 static inline int
986 compat_calc_match(struct ipt_entry_match *m, int * size)
987 {
988 *size += xt_compat_match_offset(m->u.kernel.match);
989 return 0;
990 }
991
992 static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
993 void *base, struct xt_table_info *newinfo)
994 {
995 struct ipt_entry_target *t;
996 unsigned int entry_offset;
997 int off, i, ret;
998
999 off = 0;
1000 entry_offset = (void *)e - base;
1001 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1002 t = ipt_get_target(e);
1003 off += xt_compat_target_offset(t->u.kernel.target);
1004 newinfo->size -= off;
1005 ret = compat_add_offset(entry_offset, off);
1006 if (ret)
1007 return ret;
1008
1009 for (i = 0; i< NF_IP_NUMHOOKS; i++) {
1010 if (info->hook_entry[i] && (e < (struct ipt_entry *)
1011 (base + info->hook_entry[i])))
1012 newinfo->hook_entry[i] -= off;
1013 if (info->underflow[i] && (e < (struct ipt_entry *)
1014 (base + info->underflow[i])))
1015 newinfo->underflow[i] -= off;
1016 }
1017 return 0;
1018 }
1019
1020 static int compat_table_info(struct xt_table_info *info,
1021 struct xt_table_info *newinfo)
1022 {
1023 void *loc_cpu_entry;
1024 int i;
1025
1026 if (!newinfo || !info)
1027 return -EINVAL;
1028
1029 memset(newinfo, 0, sizeof(struct xt_table_info));
1030 newinfo->size = info->size;
1031 newinfo->number = info->number;
1032 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1033 newinfo->hook_entry[i] = info->hook_entry[i];
1034 newinfo->underflow[i] = info->underflow[i];
1035 }
1036 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1037 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1038 compat_calc_entry, info, loc_cpu_entry, newinfo);
1039 }
1040 #endif
1041
1042 static int get_info(void __user *user, int *len, int compat)
1043 {
1044 char name[IPT_TABLE_MAXNAMELEN];
1045 struct xt_table *t;
1046 int ret;
1047
1048 if (*len != sizeof(struct ipt_getinfo)) {
1049 duprintf("length %u != %u\n", *len,
1050 (unsigned int)sizeof(struct ipt_getinfo));
1051 return -EINVAL;
1052 }
1053
1054 if (copy_from_user(name, user, sizeof(name)) != 0)
1055 return -EFAULT;
1056
1057 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1058 #ifdef CONFIG_COMPAT
1059 if (compat)
1060 xt_compat_lock(AF_INET);
1061 #endif
1062 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1063 "iptable_%s", name);
1064 if (t && !IS_ERR(t)) {
1065 struct ipt_getinfo info;
1066 struct xt_table_info *private = t->private;
1067
1068 #ifdef CONFIG_COMPAT
1069 if (compat) {
1070 struct xt_table_info tmp;
1071 ret = compat_table_info(private, &tmp);
1072 compat_flush_offsets();
1073 private = &tmp;
1074 }
1075 #endif
1076 info.valid_hooks = t->valid_hooks;
1077 memcpy(info.hook_entry, private->hook_entry,
1078 sizeof(info.hook_entry));
1079 memcpy(info.underflow, private->underflow,
1080 sizeof(info.underflow));
1081 info.num_entries = private->number;
1082 info.size = private->size;
1083 strcpy(info.name, name);
1084
1085 if (copy_to_user(user, &info, *len) != 0)
1086 ret = -EFAULT;
1087 else
1088 ret = 0;
1089
1090 xt_table_unlock(t);
1091 module_put(t->me);
1092 } else
1093 ret = t ? PTR_ERR(t) : -ENOENT;
1094 #ifdef CONFIG_COMPAT
1095 if (compat)
1096 xt_compat_unlock(AF_INET);
1097 #endif
1098 return ret;
1099 }
1100
1101 static int
1102 get_entries(struct ipt_get_entries __user *uptr, int *len)
1103 {
1104 int ret;
1105 struct ipt_get_entries get;
1106 struct xt_table *t;
1107
1108 if (*len < sizeof(get)) {
1109 duprintf("get_entries: %u < %d\n", *len,
1110 (unsigned int)sizeof(get));
1111 return -EINVAL;
1112 }
1113 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1114 return -EFAULT;
1115 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1116 duprintf("get_entries: %u != %u\n", *len,
1117 (unsigned int)(sizeof(struct ipt_get_entries) +
1118 get.size));
1119 return -EINVAL;
1120 }
1121
1122 t = xt_find_table_lock(AF_INET, get.name);
1123 if (t && !IS_ERR(t)) {
1124 struct xt_table_info *private = t->private;
1125 duprintf("t->private->number = %u\n",
1126 private->number);
1127 if (get.size == private->size)
1128 ret = copy_entries_to_user(private->size,
1129 t, uptr->entrytable);
1130 else {
1131 duprintf("get_entries: I've got %u not %u!\n",
1132 private->size,
1133 get.size);
1134 ret = -EINVAL;
1135 }
1136 module_put(t->me);
1137 xt_table_unlock(t);
1138 } else
1139 ret = t ? PTR_ERR(t) : -ENOENT;
1140
1141 return ret;
1142 }
1143
1144 static int
1145 __do_replace(const char *name, unsigned int valid_hooks,
1146 struct xt_table_info *newinfo, unsigned int num_counters,
1147 void __user *counters_ptr)
1148 {
1149 int ret;
1150 struct xt_table *t;
1151 struct xt_table_info *oldinfo;
1152 struct xt_counters *counters;
1153 void *loc_cpu_old_entry;
1154
1155 ret = 0;
1156 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1157 if (!counters) {
1158 ret = -ENOMEM;
1159 goto out;
1160 }
1161
1162 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1163 "iptable_%s", name);
1164 if (!t || IS_ERR(t)) {
1165 ret = t ? PTR_ERR(t) : -ENOENT;
1166 goto free_newinfo_counters_untrans;
1167 }
1168
1169 /* You lied! */
1170 if (valid_hooks != t->valid_hooks) {
1171 duprintf("Valid hook crap: %08X vs %08X\n",
1172 valid_hooks, t->valid_hooks);
1173 ret = -EINVAL;
1174 goto put_module;
1175 }
1176
1177 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1178 if (!oldinfo)
1179 goto put_module;
1180
1181 /* Update module usage count based on number of rules */
1182 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1183 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1184 if ((oldinfo->number > oldinfo->initial_entries) ||
1185 (newinfo->number <= oldinfo->initial_entries))
1186 module_put(t->me);
1187 if ((oldinfo->number > oldinfo->initial_entries) &&
1188 (newinfo->number <= oldinfo->initial_entries))
1189 module_put(t->me);
1190
1191 /* Get the old counters. */
1192 get_counters(oldinfo, counters);
1193 /* Decrease module usage counts and free resource */
1194 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1195 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1196 xt_free_table_info(oldinfo);
1197 if (copy_to_user(counters_ptr, counters,
1198 sizeof(struct xt_counters) * num_counters) != 0)
1199 ret = -EFAULT;
1200 vfree(counters);
1201 xt_table_unlock(t);
1202 return ret;
1203
1204 put_module:
1205 module_put(t->me);
1206 xt_table_unlock(t);
1207 free_newinfo_counters_untrans:
1208 vfree(counters);
1209 out:
1210 return ret;
1211 }
1212
1213 static int
1214 do_replace(void __user *user, unsigned int len)
1215 {
1216 int ret;
1217 struct ipt_replace tmp;
1218 struct xt_table_info *newinfo;
1219 void *loc_cpu_entry;
1220
1221 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1222 return -EFAULT;
1223
1224 /* Hack: Causes ipchains to give correct error msg --RR */
1225 if (len != sizeof(tmp) + tmp.size)
1226 return -ENOPROTOOPT;
1227
1228 /* overflow check */
1229 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1230 SMP_CACHE_BYTES)
1231 return -ENOMEM;
1232 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1233 return -ENOMEM;
1234
1235 newinfo = xt_alloc_table_info(tmp.size);
1236 if (!newinfo)
1237 return -ENOMEM;
1238
1239 /* choose the copy that is our node/cpu */
1240 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1241 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1242 tmp.size) != 0) {
1243 ret = -EFAULT;
1244 goto free_newinfo;
1245 }
1246
1247 ret = translate_table(tmp.name, tmp.valid_hooks,
1248 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1249 tmp.hook_entry, tmp.underflow);
1250 if (ret != 0)
1251 goto free_newinfo;
1252
1253 duprintf("ip_tables: Translated table\n");
1254
1255 ret = __do_replace(tmp.name, tmp.valid_hooks,
1256 newinfo, tmp.num_counters,
1257 tmp.counters);
1258 if (ret)
1259 goto free_newinfo_untrans;
1260 return 0;
1261
1262 free_newinfo_untrans:
1263 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1264 free_newinfo:
1265 xt_free_table_info(newinfo);
1266 return ret;
1267 }
1268
1269 /* We're lazy, and add to the first CPU; overflow works its fey magic
1270 * and everything is OK. */
1271 static inline int
1272 add_counter_to_entry(struct ipt_entry *e,
1273 const struct xt_counters addme[],
1274 unsigned int *i)
1275 {
1276 #if 0
1277 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1278 *i,
1279 (long unsigned int)e->counters.pcnt,
1280 (long unsigned int)e->counters.bcnt,
1281 (long unsigned int)addme[*i].pcnt,
1282 (long unsigned int)addme[*i].bcnt);
1283 #endif
1284
1285 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1286
1287 (*i)++;
1288 return 0;
1289 }
1290
1291 static int
1292 do_add_counters(void __user *user, unsigned int len, int compat)
1293 {
1294 unsigned int i;
1295 struct xt_counters_info tmp;
1296 struct xt_counters *paddc;
1297 unsigned int num_counters;
1298 char *name;
1299 int size;
1300 void *ptmp;
1301 struct xt_table *t;
1302 struct xt_table_info *private;
1303 int ret = 0;
1304 void *loc_cpu_entry;
1305 #ifdef CONFIG_COMPAT
1306 struct compat_xt_counters_info compat_tmp;
1307
1308 if (compat) {
1309 ptmp = &compat_tmp;
1310 size = sizeof(struct compat_xt_counters_info);
1311 } else
1312 #endif
1313 {
1314 ptmp = &tmp;
1315 size = sizeof(struct xt_counters_info);
1316 }
1317
1318 if (copy_from_user(ptmp, user, size) != 0)
1319 return -EFAULT;
1320
1321 #ifdef CONFIG_COMPAT
1322 if (compat) {
1323 num_counters = compat_tmp.num_counters;
1324 name = compat_tmp.name;
1325 } else
1326 #endif
1327 {
1328 num_counters = tmp.num_counters;
1329 name = tmp.name;
1330 }
1331
1332 if (len != size + num_counters * sizeof(struct xt_counters))
1333 return -EINVAL;
1334
1335 paddc = vmalloc_node(len - size, numa_node_id());
1336 if (!paddc)
1337 return -ENOMEM;
1338
1339 if (copy_from_user(paddc, user + size, len - size) != 0) {
1340 ret = -EFAULT;
1341 goto free;
1342 }
1343
1344 t = xt_find_table_lock(AF_INET, name);
1345 if (!t || IS_ERR(t)) {
1346 ret = t ? PTR_ERR(t) : -ENOENT;
1347 goto free;
1348 }
1349
1350 write_lock_bh(&t->lock);
1351 private = t->private;
1352 if (private->number != num_counters) {
1353 ret = -EINVAL;
1354 goto unlock_up_free;
1355 }
1356
1357 i = 0;
1358 /* Choose the copy that is on our node */
1359 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1360 IPT_ENTRY_ITERATE(loc_cpu_entry,
1361 private->size,
1362 add_counter_to_entry,
1363 paddc,
1364 &i);
1365 unlock_up_free:
1366 write_unlock_bh(&t->lock);
1367 xt_table_unlock(t);
1368 module_put(t->me);
1369 free:
1370 vfree(paddc);
1371
1372 return ret;
1373 }
1374
1375 #ifdef CONFIG_COMPAT
1376 struct compat_ipt_replace {
1377 char name[IPT_TABLE_MAXNAMELEN];
1378 u32 valid_hooks;
1379 u32 num_entries;
1380 u32 size;
1381 u32 hook_entry[NF_IP_NUMHOOKS];
1382 u32 underflow[NF_IP_NUMHOOKS];
1383 u32 num_counters;
1384 compat_uptr_t counters; /* struct ipt_counters * */
1385 struct compat_ipt_entry entries[0];
1386 };
1387
1388 static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1389 void __user **dstptr, compat_uint_t *size)
1390 {
1391 return xt_compat_match_to_user(m, dstptr, size);
1392 }
1393
1394 static int compat_copy_entry_to_user(struct ipt_entry *e,
1395 void __user **dstptr, compat_uint_t *size)
1396 {
1397 struct ipt_entry_target *t;
1398 struct compat_ipt_entry __user *ce;
1399 u_int16_t target_offset, next_offset;
1400 compat_uint_t origsize;
1401 int ret;
1402
1403 ret = -EFAULT;
1404 origsize = *size;
1405 ce = (struct compat_ipt_entry __user *)*dstptr;
1406 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1407 goto out;
1408
1409 *dstptr += sizeof(struct compat_ipt_entry);
1410 ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1411 target_offset = e->target_offset - (origsize - *size);
1412 if (ret)
1413 goto out;
1414 t = ipt_get_target(e);
1415 ret = xt_compat_target_to_user(t, dstptr, size);
1416 if (ret)
1417 goto out;
1418 ret = -EFAULT;
1419 next_offset = e->next_offset - (origsize - *size);
1420 if (put_user(target_offset, &ce->target_offset))
1421 goto out;
1422 if (put_user(next_offset, &ce->next_offset))
1423 goto out;
1424 return 0;
1425 out:
1426 return ret;
1427 }
1428
1429 static inline int
1430 compat_find_calc_match(struct ipt_entry_match *m,
1431 const char *name,
1432 const struct ipt_ip *ip,
1433 unsigned int hookmask,
1434 int *size, int *i)
1435 {
1436 struct xt_match *match;
1437
1438 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1439 m->u.user.revision),
1440 "ipt_%s", m->u.user.name);
1441 if (IS_ERR(match) || !match) {
1442 duprintf("compat_check_calc_match: `%s' not found\n",
1443 m->u.user.name);
1444 return match ? PTR_ERR(match) : -ENOENT;
1445 }
1446 m->u.kernel.match = match;
1447 *size += xt_compat_match_offset(match);
1448
1449 (*i)++;
1450 return 0;
1451 }
1452
1453 static inline int
1454 compat_release_match(struct ipt_entry_match *m, unsigned int *i)
1455 {
1456 if (i && (*i)-- == 0)
1457 return 1;
1458
1459 module_put(m->u.kernel.match->me);
1460 return 0;
1461 }
1462
1463 static inline int
1464 compat_release_entry(struct ipt_entry *e, unsigned int *i)
1465 {
1466 struct ipt_entry_target *t;
1467
1468 if (i && (*i)-- == 0)
1469 return 1;
1470
1471 /* Cleanup all matches */
1472 IPT_MATCH_ITERATE(e, compat_release_match, NULL);
1473 t = ipt_get_target(e);
1474 module_put(t->u.kernel.target->me);
1475 return 0;
1476 }
1477
1478 static inline int
1479 check_compat_entry_size_and_hooks(struct ipt_entry *e,
1480 struct xt_table_info *newinfo,
1481 unsigned int *size,
1482 unsigned char *base,
1483 unsigned char *limit,
1484 unsigned int *hook_entries,
1485 unsigned int *underflows,
1486 unsigned int *i,
1487 const char *name)
1488 {
1489 struct ipt_entry_target *t;
1490 struct xt_target *target;
1491 unsigned int entry_offset;
1492 int ret, off, h, j;
1493
1494 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1495 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1496 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1497 duprintf("Bad offset %p, limit = %p\n", e, limit);
1498 return -EINVAL;
1499 }
1500
1501 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1502 sizeof(struct compat_xt_entry_target)) {
1503 duprintf("checking: element %p size %u\n",
1504 e, e->next_offset);
1505 return -EINVAL;
1506 }
1507
1508 ret = check_entry(e, name);
1509 if (ret)
1510 return ret;
1511
1512 off = 0;
1513 entry_offset = (void *)e - (void *)base;
1514 j = 0;
1515 ret = IPT_MATCH_ITERATE(e, compat_find_calc_match, name, &e->ip,
1516 e->comefrom, &off, &j);
1517 if (ret != 0)
1518 goto release_matches;
1519
1520 t = ipt_get_target(e);
1521 target = try_then_request_module(xt_find_target(AF_INET,
1522 t->u.user.name,
1523 t->u.user.revision),
1524 "ipt_%s", t->u.user.name);
1525 if (IS_ERR(target) || !target) {
1526 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1527 t->u.user.name);
1528 ret = target ? PTR_ERR(target) : -ENOENT;
1529 goto release_matches;
1530 }
1531 t->u.kernel.target = target;
1532
1533 off += xt_compat_target_offset(target);
1534 *size += off;
1535 ret = compat_add_offset(entry_offset, off);
1536 if (ret)
1537 goto out;
1538
1539 /* Check hooks & underflows */
1540 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1541 if ((unsigned char *)e - base == hook_entries[h])
1542 newinfo->hook_entry[h] = hook_entries[h];
1543 if ((unsigned char *)e - base == underflows[h])
1544 newinfo->underflow[h] = underflows[h];
1545 }
1546
1547 /* Clear counters and comefrom */
1548 e->counters = ((struct ipt_counters) { 0, 0 });
1549 e->comefrom = 0;
1550
1551 (*i)++;
1552 return 0;
1553
1554 out:
1555 module_put(t->u.kernel.target->me);
1556 release_matches:
1557 IPT_MATCH_ITERATE(e, compat_release_match, &j);
1558 return ret;
1559 }
1560
1561 static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1562 void **dstptr, compat_uint_t *size, const char *name,
1563 const struct ipt_ip *ip, unsigned int hookmask)
1564 {
1565 xt_compat_match_from_user(m, dstptr, size);
1566 return 0;
1567 }
1568
1569 static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1570 unsigned int *size, const char *name,
1571 struct xt_table_info *newinfo, unsigned char *base)
1572 {
1573 struct ipt_entry_target *t;
1574 struct xt_target *target;
1575 struct ipt_entry *de;
1576 unsigned int origsize;
1577 int ret, h;
1578
1579 ret = 0;
1580 origsize = *size;
1581 de = (struct ipt_entry *)*dstptr;
1582 memcpy(de, e, sizeof(struct ipt_entry));
1583
1584 *dstptr += sizeof(struct compat_ipt_entry);
1585 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1586 name, &de->ip, de->comefrom);
1587 if (ret)
1588 return ret;
1589 de->target_offset = e->target_offset - (origsize - *size);
1590 t = ipt_get_target(e);
1591 target = t->u.kernel.target;
1592 xt_compat_target_from_user(t, dstptr, size);
1593
1594 de->next_offset = e->next_offset - (origsize - *size);
1595 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1596 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1597 newinfo->hook_entry[h] -= origsize - *size;
1598 if ((unsigned char *)de - base < newinfo->underflow[h])
1599 newinfo->underflow[h] -= origsize - *size;
1600 }
1601 return ret;
1602 }
1603
1604 static inline int compat_check_entry(struct ipt_entry *e, const char *name,
1605 unsigned int *i)
1606 {
1607 int j, ret;
1608
1609 j = 0;
1610 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
1611 if (ret)
1612 goto cleanup_matches;
1613
1614 ret = check_target(e, name);
1615 if (ret)
1616 goto cleanup_matches;
1617
1618 (*i)++;
1619 return 0;
1620
1621 cleanup_matches:
1622 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1623 return ret;
1624 }
1625
1626 static int
1627 translate_compat_table(const char *name,
1628 unsigned int valid_hooks,
1629 struct xt_table_info **pinfo,
1630 void **pentry0,
1631 unsigned int total_size,
1632 unsigned int number,
1633 unsigned int *hook_entries,
1634 unsigned int *underflows)
1635 {
1636 unsigned int i, j;
1637 struct xt_table_info *newinfo, *info;
1638 void *pos, *entry0, *entry1;
1639 unsigned int size;
1640 int ret;
1641
1642 info = *pinfo;
1643 entry0 = *pentry0;
1644 size = total_size;
1645 info->number = number;
1646
1647 /* Init all hooks to impossible value. */
1648 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1649 info->hook_entry[i] = 0xFFFFFFFF;
1650 info->underflow[i] = 0xFFFFFFFF;
1651 }
1652
1653 duprintf("translate_compat_table: size %u\n", info->size);
1654 j = 0;
1655 xt_compat_lock(AF_INET);
1656 /* Walk through entries, checking offsets. */
1657 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1658 check_compat_entry_size_and_hooks,
1659 info, &size, entry0,
1660 entry0 + total_size,
1661 hook_entries, underflows, &j, name);
1662 if (ret != 0)
1663 goto out_unlock;
1664
1665 ret = -EINVAL;
1666 if (j != number) {
1667 duprintf("translate_compat_table: %u not %u entries\n",
1668 j, number);
1669 goto out_unlock;
1670 }
1671
1672 /* Check hooks all assigned */
1673 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1674 /* Only hooks which are valid */
1675 if (!(valid_hooks & (1 << i)))
1676 continue;
1677 if (info->hook_entry[i] == 0xFFFFFFFF) {
1678 duprintf("Invalid hook entry %u %u\n",
1679 i, hook_entries[i]);
1680 goto out_unlock;
1681 }
1682 if (info->underflow[i] == 0xFFFFFFFF) {
1683 duprintf("Invalid underflow %u %u\n",
1684 i, underflows[i]);
1685 goto out_unlock;
1686 }
1687 }
1688
1689 ret = -ENOMEM;
1690 newinfo = xt_alloc_table_info(size);
1691 if (!newinfo)
1692 goto out_unlock;
1693
1694 newinfo->number = number;
1695 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1696 newinfo->hook_entry[i] = info->hook_entry[i];
1697 newinfo->underflow[i] = info->underflow[i];
1698 }
1699 entry1 = newinfo->entries[raw_smp_processor_id()];
1700 pos = entry1;
1701 size = total_size;
1702 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1703 compat_copy_entry_from_user, &pos, &size,
1704 name, newinfo, entry1);
1705 compat_flush_offsets();
1706 xt_compat_unlock(AF_INET);
1707 if (ret)
1708 goto free_newinfo;
1709
1710 ret = -ELOOP;
1711 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1712 goto free_newinfo;
1713
1714 i = 0;
1715 ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1716 name, &i);
1717 if (ret) {
1718 j -= i;
1719 IPT_ENTRY_ITERATE_CONTINUE(entry1, newinfo->size, i,
1720 compat_release_entry, &j);
1721 IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1722 xt_free_table_info(newinfo);
1723 return ret;
1724 }
1725
1726 /* And one copy for every other CPU */
1727 for_each_possible_cpu(i)
1728 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1729 memcpy(newinfo->entries[i], entry1, newinfo->size);
1730
1731 *pinfo = newinfo;
1732 *pentry0 = entry1;
1733 xt_free_table_info(info);
1734 return 0;
1735
1736 free_newinfo:
1737 xt_free_table_info(newinfo);
1738 out:
1739 IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1740 return ret;
1741 out_unlock:
1742 compat_flush_offsets();
1743 xt_compat_unlock(AF_INET);
1744 goto out;
1745 }
1746
1747 static int
1748 compat_do_replace(void __user *user, unsigned int len)
1749 {
1750 int ret;
1751 struct compat_ipt_replace tmp;
1752 struct xt_table_info *newinfo;
1753 void *loc_cpu_entry;
1754
1755 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1756 return -EFAULT;
1757
1758 /* Hack: Causes ipchains to give correct error msg --RR */
1759 if (len != sizeof(tmp) + tmp.size)
1760 return -ENOPROTOOPT;
1761
1762 /* overflow check */
1763 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1764 SMP_CACHE_BYTES)
1765 return -ENOMEM;
1766 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1767 return -ENOMEM;
1768
1769 newinfo = xt_alloc_table_info(tmp.size);
1770 if (!newinfo)
1771 return -ENOMEM;
1772
1773 /* choose the copy that is our node/cpu */
1774 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1775 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1776 tmp.size) != 0) {
1777 ret = -EFAULT;
1778 goto free_newinfo;
1779 }
1780
1781 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1782 &newinfo, &loc_cpu_entry, tmp.size,
1783 tmp.num_entries, tmp.hook_entry, tmp.underflow);
1784 if (ret != 0)
1785 goto free_newinfo;
1786
1787 duprintf("compat_do_replace: Translated table\n");
1788
1789 ret = __do_replace(tmp.name, tmp.valid_hooks,
1790 newinfo, tmp.num_counters,
1791 compat_ptr(tmp.counters));
1792 if (ret)
1793 goto free_newinfo_untrans;
1794 return 0;
1795
1796 free_newinfo_untrans:
1797 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1798 free_newinfo:
1799 xt_free_table_info(newinfo);
1800 return ret;
1801 }
1802
1803 static int
1804 compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1805 unsigned int len)
1806 {
1807 int ret;
1808
1809 if (!capable(CAP_NET_ADMIN))
1810 return -EPERM;
1811
1812 switch (cmd) {
1813 case IPT_SO_SET_REPLACE:
1814 ret = compat_do_replace(user, len);
1815 break;
1816
1817 case IPT_SO_SET_ADD_COUNTERS:
1818 ret = do_add_counters(user, len, 1);
1819 break;
1820
1821 default:
1822 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1823 ret = -EINVAL;
1824 }
1825
1826 return ret;
1827 }
1828
1829 struct compat_ipt_get_entries
1830 {
1831 char name[IPT_TABLE_MAXNAMELEN];
1832 compat_uint_t size;
1833 struct compat_ipt_entry entrytable[0];
1834 };
1835
1836 static int compat_copy_entries_to_user(unsigned int total_size,
1837 struct xt_table *table, void __user *userptr)
1838 {
1839 unsigned int off, num;
1840 struct compat_ipt_entry e;
1841 struct xt_counters *counters;
1842 struct xt_table_info *private = table->private;
1843 void __user *pos;
1844 unsigned int size;
1845 int ret = 0;
1846 void *loc_cpu_entry;
1847
1848 counters = alloc_counters(table);
1849 if (IS_ERR(counters))
1850 return PTR_ERR(counters);
1851
1852 /* choose the copy that is on our node/cpu, ...
1853 * This choice is lazy (because current thread is
1854 * allowed to migrate to another cpu)
1855 */
1856 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1857 pos = userptr;
1858 size = total_size;
1859 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1860 compat_copy_entry_to_user, &pos, &size);
1861 if (ret)
1862 goto free_counters;
1863
1864 /* ... then go back and fix counters and names */
1865 for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
1866 unsigned int i;
1867 struct ipt_entry_match m;
1868 struct ipt_entry_target t;
1869
1870 ret = -EFAULT;
1871 if (copy_from_user(&e, userptr + off,
1872 sizeof(struct compat_ipt_entry)))
1873 goto free_counters;
1874 if (copy_to_user(userptr + off +
1875 offsetof(struct compat_ipt_entry, counters),
1876 &counters[num], sizeof(counters[num])))
1877 goto free_counters;
1878
1879 for (i = sizeof(struct compat_ipt_entry);
1880 i < e.target_offset; i += m.u.match_size) {
1881 if (copy_from_user(&m, userptr + off + i,
1882 sizeof(struct ipt_entry_match)))
1883 goto free_counters;
1884 if (copy_to_user(userptr + off + i +
1885 offsetof(struct ipt_entry_match, u.user.name),
1886 m.u.kernel.match->name,
1887 strlen(m.u.kernel.match->name) + 1))
1888 goto free_counters;
1889 }
1890
1891 if (copy_from_user(&t, userptr + off + e.target_offset,
1892 sizeof(struct ipt_entry_target)))
1893 goto free_counters;
1894 if (copy_to_user(userptr + off + e.target_offset +
1895 offsetof(struct ipt_entry_target, u.user.name),
1896 t.u.kernel.target->name,
1897 strlen(t.u.kernel.target->name) + 1))
1898 goto free_counters;
1899 }
1900 ret = 0;
1901 free_counters:
1902 vfree(counters);
1903 return ret;
1904 }
1905
1906 static int
1907 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1908 {
1909 int ret;
1910 struct compat_ipt_get_entries get;
1911 struct xt_table *t;
1912
1913
1914 if (*len < sizeof(get)) {
1915 duprintf("compat_get_entries: %u < %u\n",
1916 *len, (unsigned int)sizeof(get));
1917 return -EINVAL;
1918 }
1919
1920 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1921 return -EFAULT;
1922
1923 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1924 duprintf("compat_get_entries: %u != %u\n", *len,
1925 (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1926 get.size));
1927 return -EINVAL;
1928 }
1929
1930 xt_compat_lock(AF_INET);
1931 t = xt_find_table_lock(AF_INET, get.name);
1932 if (t && !IS_ERR(t)) {
1933 struct xt_table_info *private = t->private;
1934 struct xt_table_info info;
1935 duprintf("t->private->number = %u\n",
1936 private->number);
1937 ret = compat_table_info(private, &info);
1938 if (!ret && get.size == info.size) {
1939 ret = compat_copy_entries_to_user(private->size,
1940 t, uptr->entrytable);
1941 } else if (!ret) {
1942 duprintf("compat_get_entries: I've got %u not %u!\n",
1943 private->size,
1944 get.size);
1945 ret = -EINVAL;
1946 }
1947 compat_flush_offsets();
1948 module_put(t->me);
1949 xt_table_unlock(t);
1950 } else
1951 ret = t ? PTR_ERR(t) : -ENOENT;
1952
1953 xt_compat_unlock(AF_INET);
1954 return ret;
1955 }
1956
1957 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1958
1959 static int
1960 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1961 {
1962 int ret;
1963
1964 if (!capable(CAP_NET_ADMIN))
1965 return -EPERM;
1966
1967 switch (cmd) {
1968 case IPT_SO_GET_INFO:
1969 ret = get_info(user, len, 1);
1970 break;
1971 case IPT_SO_GET_ENTRIES:
1972 ret = compat_get_entries(user, len);
1973 break;
1974 default:
1975 ret = do_ipt_get_ctl(sk, cmd, user, len);
1976 }
1977 return ret;
1978 }
1979 #endif
1980
1981 static int
1982 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1983 {
1984 int ret;
1985
1986 if (!capable(CAP_NET_ADMIN))
1987 return -EPERM;
1988
1989 switch (cmd) {
1990 case IPT_SO_SET_REPLACE:
1991 ret = do_replace(user, len);
1992 break;
1993
1994 case IPT_SO_SET_ADD_COUNTERS:
1995 ret = do_add_counters(user, len, 0);
1996 break;
1997
1998 default:
1999 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
2000 ret = -EINVAL;
2001 }
2002
2003 return ret;
2004 }
2005
2006 static int
2007 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2008 {
2009 int ret;
2010
2011 if (!capable(CAP_NET_ADMIN))
2012 return -EPERM;
2013
2014 switch (cmd) {
2015 case IPT_SO_GET_INFO:
2016 ret = get_info(user, len, 0);
2017 break;
2018
2019 case IPT_SO_GET_ENTRIES:
2020 ret = get_entries(user, len);
2021 break;
2022
2023 case IPT_SO_GET_REVISION_MATCH:
2024 case IPT_SO_GET_REVISION_TARGET: {
2025 struct ipt_get_revision rev;
2026 int target;
2027
2028 if (*len != sizeof(rev)) {
2029 ret = -EINVAL;
2030 break;
2031 }
2032 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2033 ret = -EFAULT;
2034 break;
2035 }
2036
2037 if (cmd == IPT_SO_GET_REVISION_TARGET)
2038 target = 1;
2039 else
2040 target = 0;
2041
2042 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2043 rev.revision,
2044 target, &ret),
2045 "ipt_%s", rev.name);
2046 break;
2047 }
2048
2049 default:
2050 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2051 ret = -EINVAL;
2052 }
2053
2054 return ret;
2055 }
2056
2057 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2058 {
2059 int ret;
2060 struct xt_table_info *newinfo;
2061 static struct xt_table_info bootstrap
2062 = { 0, 0, 0, { 0 }, { 0 }, { } };
2063 void *loc_cpu_entry;
2064
2065 newinfo = xt_alloc_table_info(repl->size);
2066 if (!newinfo)
2067 return -ENOMEM;
2068
2069 /* choose the copy on our node/cpu
2070 * but dont care of preemption
2071 */
2072 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2073 memcpy(loc_cpu_entry, repl->entries, repl->size);
2074
2075 ret = translate_table(table->name, table->valid_hooks,
2076 newinfo, loc_cpu_entry, repl->size,
2077 repl->num_entries,
2078 repl->hook_entry,
2079 repl->underflow);
2080 if (ret != 0) {
2081 xt_free_table_info(newinfo);
2082 return ret;
2083 }
2084
2085 ret = xt_register_table(table, &bootstrap, newinfo);
2086 if (ret != 0) {
2087 xt_free_table_info(newinfo);
2088 return ret;
2089 }
2090
2091 return 0;
2092 }
2093
2094 void ipt_unregister_table(struct xt_table *table)
2095 {
2096 struct xt_table_info *private;
2097 void *loc_cpu_entry;
2098
2099 private = xt_unregister_table(table);
2100
2101 /* Decrease module usage counts and free resources */
2102 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2103 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2104 xt_free_table_info(private);
2105 }
2106
2107 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2108 static inline int
2109 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2110 u_int8_t type, u_int8_t code,
2111 int invert)
2112 {
2113 return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2114 ^ invert;
2115 }
2116
2117 static int
2118 icmp_match(const struct sk_buff *skb,
2119 const struct net_device *in,
2120 const struct net_device *out,
2121 const struct xt_match *match,
2122 const void *matchinfo,
2123 int offset,
2124 unsigned int protoff,
2125 int *hotdrop)
2126 {
2127 struct icmphdr _icmph, *ic;
2128 const struct ipt_icmp *icmpinfo = matchinfo;
2129
2130 /* Must not be a fragment. */
2131 if (offset)
2132 return 0;
2133
2134 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2135 if (ic == NULL) {
2136 /* We've been asked to examine this packet, and we
2137 * can't. Hence, no choice but to drop.
2138 */
2139 duprintf("Dropping evil ICMP tinygram.\n");
2140 *hotdrop = 1;
2141 return 0;
2142 }
2143
2144 return icmp_type_code_match(icmpinfo->type,
2145 icmpinfo->code[0],
2146 icmpinfo->code[1],
2147 ic->type, ic->code,
2148 !!(icmpinfo->invflags&IPT_ICMP_INV));
2149 }
2150
2151 /* Called when user tries to insert an entry of this type. */
2152 static int
2153 icmp_checkentry(const char *tablename,
2154 const void *info,
2155 const struct xt_match *match,
2156 void *matchinfo,
2157 unsigned int hook_mask)
2158 {
2159 const struct ipt_icmp *icmpinfo = matchinfo;
2160
2161 /* Must specify no unknown invflags */
2162 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2163 }
2164
2165 /* The built-in targets: standard (NULL) and error. */
2166 static struct xt_target ipt_standard_target = {
2167 .name = IPT_STANDARD_TARGET,
2168 .targetsize = sizeof(int),
2169 .family = AF_INET,
2170 #ifdef CONFIG_COMPAT
2171 .compatsize = sizeof(compat_int_t),
2172 .compat_from_user = compat_standard_from_user,
2173 .compat_to_user = compat_standard_to_user,
2174 #endif
2175 };
2176
2177 static struct xt_target ipt_error_target = {
2178 .name = IPT_ERROR_TARGET,
2179 .target = ipt_error,
2180 .targetsize = IPT_FUNCTION_MAXNAMELEN,
2181 .family = AF_INET,
2182 };
2183
2184 static struct nf_sockopt_ops ipt_sockopts = {
2185 .pf = PF_INET,
2186 .set_optmin = IPT_BASE_CTL,
2187 .set_optmax = IPT_SO_SET_MAX+1,
2188 .set = do_ipt_set_ctl,
2189 #ifdef CONFIG_COMPAT
2190 .compat_set = compat_do_ipt_set_ctl,
2191 #endif
2192 .get_optmin = IPT_BASE_CTL,
2193 .get_optmax = IPT_SO_GET_MAX+1,
2194 .get = do_ipt_get_ctl,
2195 #ifdef CONFIG_COMPAT
2196 .compat_get = compat_do_ipt_get_ctl,
2197 #endif
2198 };
2199
2200 static struct xt_match icmp_matchstruct = {
2201 .name = "icmp",
2202 .match = icmp_match,
2203 .matchsize = sizeof(struct ipt_icmp),
2204 .proto = IPPROTO_ICMP,
2205 .family = AF_INET,
2206 .checkentry = icmp_checkentry,
2207 };
2208
2209 static int __init ip_tables_init(void)
2210 {
2211 int ret;
2212
2213 ret = xt_proto_init(AF_INET);
2214 if (ret < 0)
2215 goto err1;
2216
2217 /* Noone else will be downing sem now, so we won't sleep */
2218 ret = xt_register_target(&ipt_standard_target);
2219 if (ret < 0)
2220 goto err2;
2221 ret = xt_register_target(&ipt_error_target);
2222 if (ret < 0)
2223 goto err3;
2224 ret = xt_register_match(&icmp_matchstruct);
2225 if (ret < 0)
2226 goto err4;
2227
2228 /* Register setsockopt */
2229 ret = nf_register_sockopt(&ipt_sockopts);
2230 if (ret < 0)
2231 goto err5;
2232
2233 printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2234 return 0;
2235
2236 err5:
2237 xt_unregister_match(&icmp_matchstruct);
2238 err4:
2239 xt_unregister_target(&ipt_error_target);
2240 err3:
2241 xt_unregister_target(&ipt_standard_target);
2242 err2:
2243 xt_proto_fini(AF_INET);
2244 err1:
2245 return ret;
2246 }
2247
2248 static void __exit ip_tables_fini(void)
2249 {
2250 nf_unregister_sockopt(&ipt_sockopts);
2251
2252 xt_unregister_match(&icmp_matchstruct);
2253 xt_unregister_target(&ipt_error_target);
2254 xt_unregister_target(&ipt_standard_target);
2255
2256 xt_proto_fini(AF_INET);
2257 }
2258
2259 EXPORT_SYMBOL(ipt_register_table);
2260 EXPORT_SYMBOL(ipt_unregister_table);
2261 EXPORT_SYMBOL(ipt_do_table);
2262 module_init(ip_tables_init);
2263 module_exit(ip_tables_fini);