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