2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #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>
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>
27 #include <linux/netfilter/x_tables.h>
28 #include <linux/netfilter_ipv4/ip_tables.h>
29 #include <net/netfilter/nf_log.h>
31 MODULE_LICENSE("GPL");
32 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
33 MODULE_DESCRIPTION("IPv4 packet filter");
35 /*#define DEBUG_IP_FIREWALL*/
36 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
37 /*#define DEBUG_IP_FIREWALL_USER*/
39 #ifdef DEBUG_IP_FIREWALL
40 #define dprintf(format, args...) printk(format , ## args)
42 #define dprintf(format, args...)
45 #ifdef DEBUG_IP_FIREWALL_USER
46 #define duprintf(format, args...) printk(format , ## args)
48 #define duprintf(format, args...)
51 #ifdef CONFIG_NETFILTER_DEBUG
52 #define IP_NF_ASSERT(x) \
55 printk("IP_NF_ASSERT: %s:%s:%u\n", \
56 __func__, __FILE__, __LINE__); \
59 #define IP_NF_ASSERT(x)
63 /* All the better to debug you with... */
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.
75 Hence the start of any table is given by get_table() below. */
77 /* Returns whether matches rule or not. */
78 /* Performance critical - called for every packet */
80 ip_packet_match(const struct iphdr *ip,
83 const struct ipt_ip *ipinfo,
89 #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
91 if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
93 || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
95 dprintf("Source or dest mismatch.\n");
97 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
99 NIPQUAD(ipinfo->smsk.s_addr),
100 NIPQUAD(ipinfo->src.s_addr),
101 ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
102 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
104 NIPQUAD(ipinfo->dmsk.s_addr),
105 NIPQUAD(ipinfo->dst.s_addr),
106 ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
110 /* Look for ifname matches; this should unroll nicely. */
111 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
112 ret |= (((const unsigned long *)indev)[i]
113 ^ ((const unsigned long *)ipinfo->iniface)[i])
114 & ((const unsigned long *)ipinfo->iniface_mask)[i];
117 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
118 dprintf("VIA in mismatch (%s vs %s).%s\n",
119 indev, ipinfo->iniface,
120 ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
124 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
125 ret |= (((const unsigned long *)outdev)[i]
126 ^ ((const unsigned long *)ipinfo->outiface)[i])
127 & ((const unsigned long *)ipinfo->outiface_mask)[i];
130 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
131 dprintf("VIA out mismatch (%s vs %s).%s\n",
132 outdev, ipinfo->outiface,
133 ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
137 /* Check specific protocol */
139 && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
140 dprintf("Packet protocol %hi does not match %hi.%s\n",
141 ip->protocol, ipinfo->proto,
142 ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
146 /* If we have a fragment rule but the packet is not a fragment
147 * then we return zero */
148 if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
149 dprintf("Fragment rule but not fragment.%s\n",
150 ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
158 ip_checkentry(const struct ipt_ip *ip)
160 if (ip->flags & ~IPT_F_MASK) {
161 duprintf("Unknown flag bits set: %08X\n",
162 ip->flags & ~IPT_F_MASK);
165 if (ip->invflags & ~IPT_INV_MASK) {
166 duprintf("Unknown invflag bits set: %08X\n",
167 ip->invflags & ~IPT_INV_MASK);
174 ipt_error(struct sk_buff *skb,
175 const struct net_device *in,
176 const struct net_device *out,
177 unsigned int hooknum,
178 const struct xt_target *target,
179 const void *targinfo)
182 printk("ip_tables: error: `%s'\n", (char *)targinfo);
187 /* Performance critical - called for every packet */
189 do_match(struct ipt_entry_match *m,
190 const struct sk_buff *skb,
191 const struct net_device *in,
192 const struct net_device *out,
196 /* Stop iteration if it doesn't match */
197 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
198 offset, ip_hdrlen(skb), hotdrop))
204 /* Performance critical */
205 static inline struct ipt_entry *
206 get_entry(void *base, unsigned int offset)
208 return (struct ipt_entry *)(base + offset);
211 /* All zeroes == unconditional rule. */
212 /* Mildly perf critical (only if packet tracing is on) */
214 unconditional(const struct ipt_ip *ip)
218 for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
219 if (((__u32 *)ip)[i])
226 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
227 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
228 static const char *const hooknames[] = {
229 [NF_INET_PRE_ROUTING] = "PREROUTING",
230 [NF_INET_LOCAL_IN] = "INPUT",
231 [NF_INET_FORWARD] = "FORWARD",
232 [NF_INET_LOCAL_OUT] = "OUTPUT",
233 [NF_INET_POST_ROUTING] = "POSTROUTING",
236 enum nf_ip_trace_comments {
237 NF_IP_TRACE_COMMENT_RULE,
238 NF_IP_TRACE_COMMENT_RETURN,
239 NF_IP_TRACE_COMMENT_POLICY,
242 static const char *const comments[] = {
243 [NF_IP_TRACE_COMMENT_RULE] = "rule",
244 [NF_IP_TRACE_COMMENT_RETURN] = "return",
245 [NF_IP_TRACE_COMMENT_POLICY] = "policy",
248 static struct nf_loginfo trace_loginfo = {
249 .type = NF_LOG_TYPE_LOG,
253 .logflags = NF_LOG_MASK,
258 /* Mildly perf critical (only if packet tracing is on) */
260 get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
261 char *hookname, char **chainname,
262 char **comment, unsigned int *rulenum)
264 struct ipt_standard_target *t = (void *)ipt_get_target(s);
266 if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
267 /* Head of user chain: ERROR target with chainname */
268 *chainname = t->target.data;
273 if (s->target_offset == sizeof(struct ipt_entry)
274 && strcmp(t->target.u.kernel.target->name,
275 IPT_STANDARD_TARGET) == 0
277 && unconditional(&s->ip)) {
278 /* Tail of chains: STANDARD target (return/policy) */
279 *comment = *chainname == hookname
280 ? (char *)comments[NF_IP_TRACE_COMMENT_POLICY]
281 : (char *)comments[NF_IP_TRACE_COMMENT_RETURN];
290 static void trace_packet(struct sk_buff *skb,
292 const struct net_device *in,
293 const struct net_device *out,
294 const char *tablename,
295 struct xt_table_info *private,
299 const struct ipt_entry *root;
300 char *hookname, *chainname, *comment;
301 unsigned int rulenum = 0;
303 table_base = (void *)private->entries[smp_processor_id()];
304 root = get_entry(table_base, private->hook_entry[hook]);
306 hookname = chainname = (char *)hooknames[hook];
307 comment = (char *)comments[NF_IP_TRACE_COMMENT_RULE];
309 IPT_ENTRY_ITERATE(root,
310 private->size - private->hook_entry[hook],
311 get_chainname_rulenum,
312 e, hookname, &chainname, &comment, &rulenum);
314 nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo,
315 "TRACE: %s:%s:%s:%u ",
316 tablename, chainname, comment, rulenum);
320 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
322 ipt_do_table(struct sk_buff *skb,
324 const struct net_device *in,
325 const struct net_device *out,
326 struct xt_table *table)
328 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
330 const struct iphdr *ip;
332 bool hotdrop = false;
333 /* Initializing verdict to NF_DROP keeps gcc happy. */
334 unsigned int verdict = NF_DROP;
335 const char *indev, *outdev;
337 struct ipt_entry *e, *back;
338 struct xt_table_info *private;
342 datalen = skb->len - ip->ihl * 4;
343 indev = in ? in->name : nulldevname;
344 outdev = out ? out->name : nulldevname;
345 /* We handle fragments by dealing with the first fragment as
346 * if it was a normal packet. All other fragments are treated
347 * normally, except that they will NEVER match rules that ask
348 * things we don't know, ie. tcp syn flag or ports). If the
349 * rule is also a fragment-specific rule, non-fragments won't
351 offset = ntohs(ip->frag_off) & IP_OFFSET;
353 read_lock_bh(&table->lock);
354 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
355 private = table->private;
356 table_base = (void *)private->entries[smp_processor_id()];
357 e = get_entry(table_base, private->hook_entry[hook]);
359 /* For return from builtin chain */
360 back = get_entry(table_base, private->underflow[hook]);
365 if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
366 struct ipt_entry_target *t;
368 if (IPT_MATCH_ITERATE(e, do_match,
370 offset, &hotdrop) != 0)
373 ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
375 t = ipt_get_target(e);
376 IP_NF_ASSERT(t->u.kernel.target);
378 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
379 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
380 /* The packet is traced: log it */
381 if (unlikely(skb->nf_trace))
382 trace_packet(skb, hook, in, out,
383 table->name, private, e);
385 /* Standard target? */
386 if (!t->u.kernel.target->target) {
389 v = ((struct ipt_standard_target *)t)->verdict;
391 /* Pop from stack? */
392 if (v != IPT_RETURN) {
393 verdict = (unsigned)(-v) - 1;
397 back = get_entry(table_base,
401 if (table_base + v != (void *)e + e->next_offset
402 && !(e->ip.flags & IPT_F_GOTO)) {
403 /* Save old back ptr in next entry */
404 struct ipt_entry *next
405 = (void *)e + e->next_offset;
407 = (void *)back - table_base;
408 /* set back pointer to next entry */
412 e = get_entry(table_base, v);
414 /* Targets which reenter must return
416 #ifdef CONFIG_NETFILTER_DEBUG
417 ((struct ipt_entry *)table_base)->comefrom
420 verdict = t->u.kernel.target->target(skb,
426 #ifdef CONFIG_NETFILTER_DEBUG
427 if (((struct ipt_entry *)table_base)->comefrom
429 && verdict == IPT_CONTINUE) {
430 printk("Target %s reentered!\n",
431 t->u.kernel.target->name);
434 ((struct ipt_entry *)table_base)->comefrom
437 /* Target might have changed stuff. */
439 datalen = skb->len - ip->ihl * 4;
441 if (verdict == IPT_CONTINUE)
442 e = (void *)e + e->next_offset;
450 e = (void *)e + e->next_offset;
454 read_unlock_bh(&table->lock);
456 #ifdef DEBUG_ALLOW_ALL
465 /* Figures out from what hook each rule can be called: returns 0 if
466 there are loops. Puts hook bitmask in comefrom. */
468 mark_source_chains(struct xt_table_info *newinfo,
469 unsigned int valid_hooks, void *entry0)
473 /* No recursion; use packet counter to save back ptrs (reset
474 to 0 as we leave), and comefrom to save source hook bitmask */
475 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
476 unsigned int pos = newinfo->hook_entry[hook];
477 struct ipt_entry *e = (struct ipt_entry *)(entry0 + pos);
479 if (!(valid_hooks & (1 << hook)))
482 /* Set initial back pointer. */
483 e->counters.pcnt = pos;
486 struct ipt_standard_target *t
487 = (void *)ipt_get_target(e);
488 int visited = e->comefrom & (1 << hook);
490 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
491 printk("iptables: loop hook %u pos %u %08X.\n",
492 hook, pos, e->comefrom);
495 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
497 /* Unconditional return/END. */
498 if ((e->target_offset == sizeof(struct ipt_entry)
499 && (strcmp(t->target.u.user.name,
500 IPT_STANDARD_TARGET) == 0)
502 && unconditional(&e->ip)) || visited) {
503 unsigned int oldpos, size;
505 if (t->verdict < -NF_MAX_VERDICT - 1) {
506 duprintf("mark_source_chains: bad "
507 "negative verdict (%i)\n",
512 /* Return: backtrack through the last
515 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
516 #ifdef DEBUG_IP_FIREWALL_USER
518 & (1 << NF_INET_NUMHOOKS)) {
519 duprintf("Back unset "
526 pos = e->counters.pcnt;
527 e->counters.pcnt = 0;
529 /* We're at the start. */
533 e = (struct ipt_entry *)
535 } while (oldpos == pos + e->next_offset);
538 size = e->next_offset;
539 e = (struct ipt_entry *)
540 (entry0 + pos + size);
541 e->counters.pcnt = pos;
544 int newpos = t->verdict;
546 if (strcmp(t->target.u.user.name,
547 IPT_STANDARD_TARGET) == 0
549 if (newpos > newinfo->size -
550 sizeof(struct ipt_entry)) {
551 duprintf("mark_source_chains: "
552 "bad verdict (%i)\n",
556 /* This a jump; chase it. */
557 duprintf("Jump rule %u -> %u\n",
560 /* ... this is a fallthru */
561 newpos = pos + e->next_offset;
563 e = (struct ipt_entry *)
565 e->counters.pcnt = pos;
570 duprintf("Finished chain %u\n", hook);
576 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
578 if (i && (*i)-- == 0)
581 if (m->u.kernel.match->destroy)
582 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
583 module_put(m->u.kernel.match->me);
588 check_entry(struct ipt_entry *e, const char *name)
590 struct ipt_entry_target *t;
592 if (!ip_checkentry(&e->ip)) {
593 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
597 if (e->target_offset + sizeof(struct ipt_entry_target) >
601 t = ipt_get_target(e);
602 if (e->target_offset + t->u.target_size > e->next_offset)
609 check_match(struct ipt_entry_match *m, const char *name,
610 const struct ipt_ip *ip,
611 unsigned int hookmask, unsigned int *i)
613 struct xt_match *match;
616 match = m->u.kernel.match;
617 ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
618 name, hookmask, ip->proto,
619 ip->invflags & IPT_INV_PROTO, ip, m->data);
621 duprintf("ip_tables: check failed for `%s'.\n",
622 m->u.kernel.match->name);
630 find_check_match(struct ipt_entry_match *m,
632 const struct ipt_ip *ip,
633 unsigned int hookmask,
636 struct xt_match *match;
639 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
641 "ipt_%s", m->u.user.name);
642 if (IS_ERR(match) || !match) {
643 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
644 return match ? PTR_ERR(match) : -ENOENT;
646 m->u.kernel.match = match;
648 ret = check_match(m, name, ip, hookmask, i);
654 module_put(m->u.kernel.match->me);
658 static int check_target(struct ipt_entry *e, const char *name)
660 struct ipt_entry_target *t;
661 struct xt_target *target;
664 t = ipt_get_target(e);
665 target = t->u.kernel.target;
666 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
667 name, e->comefrom, e->ip.proto,
668 e->ip.invflags & IPT_INV_PROTO, e, t->data);
670 duprintf("ip_tables: check failed for `%s'.\n",
671 t->u.kernel.target->name);
678 find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
681 struct ipt_entry_target *t;
682 struct xt_target *target;
686 ret = check_entry(e, name);
691 ret = IPT_MATCH_ITERATE(e, find_check_match, name, &e->ip,
694 goto cleanup_matches;
696 t = ipt_get_target(e);
697 target = try_then_request_module(xt_find_target(AF_INET,
700 "ipt_%s", t->u.user.name);
701 if (IS_ERR(target) || !target) {
702 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
703 ret = target ? PTR_ERR(target) : -ENOENT;
704 goto cleanup_matches;
706 t->u.kernel.target = target;
708 ret = check_target(e, name);
715 module_put(t->u.kernel.target->me);
717 IPT_MATCH_ITERATE(e, cleanup_match, &j);
722 check_entry_size_and_hooks(struct ipt_entry *e,
723 struct xt_table_info *newinfo,
725 unsigned char *limit,
726 const unsigned int *hook_entries,
727 const unsigned int *underflows,
732 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
733 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
734 duprintf("Bad offset %p\n", e);
739 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
740 duprintf("checking: element %p size %u\n",
745 /* Check hooks & underflows */
746 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
747 if ((unsigned char *)e - base == hook_entries[h])
748 newinfo->hook_entry[h] = hook_entries[h];
749 if ((unsigned char *)e - base == underflows[h])
750 newinfo->underflow[h] = underflows[h];
753 /* FIXME: underflows must be unconditional, standard verdicts
754 < 0 (not IPT_RETURN). --RR */
756 /* Clear counters and comefrom */
757 e->counters = ((struct xt_counters) { 0, 0 });
765 cleanup_entry(struct ipt_entry *e, unsigned int *i)
767 struct ipt_entry_target *t;
769 if (i && (*i)-- == 0)
772 /* Cleanup all matches */
773 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
774 t = ipt_get_target(e);
775 if (t->u.kernel.target->destroy)
776 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
777 module_put(t->u.kernel.target->me);
781 /* Checks and translates the user-supplied table segment (held in
784 translate_table(const char *name,
785 unsigned int valid_hooks,
786 struct xt_table_info *newinfo,
790 const unsigned int *hook_entries,
791 const unsigned int *underflows)
796 newinfo->size = size;
797 newinfo->number = number;
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;
805 duprintf("translate_table: size %u\n", newinfo->size);
807 /* Walk through entries, checking offsets. */
808 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
809 check_entry_size_and_hooks,
813 hook_entries, underflows, &i);
818 duprintf("translate_table: %u not %u entries\n",
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)))
828 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
829 duprintf("Invalid hook entry %u %u\n",
833 if (newinfo->underflow[i] == 0xFFFFFFFF) {
834 duprintf("Invalid underflow %u %u\n",
840 if (!mark_source_chains(newinfo, valid_hooks, entry0))
843 /* Finally, each sanity check must pass */
845 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
846 find_check_entry, name, size, &i);
849 IPT_ENTRY_ITERATE(entry0, newinfo->size,
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);
865 add_entry_to_counter(const struct ipt_entry *e,
866 struct xt_counters total[],
869 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
876 set_entry_to_counter(const struct ipt_entry *e,
877 struct ipt_counters total[],
880 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
887 get_counters(const struct xt_table_info *t,
888 struct xt_counters counters[])
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 * We dont care about preemption here.
899 curcpu = raw_smp_processor_id();
902 IPT_ENTRY_ITERATE(t->entries[curcpu],
904 set_entry_to_counter,
908 for_each_possible_cpu(cpu) {
912 IPT_ENTRY_ITERATE(t->entries[cpu],
914 add_entry_to_counter,
920 static struct xt_counters * alloc_counters(struct xt_table *table)
922 unsigned int countersize;
923 struct xt_counters *counters;
924 const struct xt_table_info *private = table->private;
926 /* We need atomic snapshot of counters: rest doesn't change
927 (other than comefrom, which userspace doesn't care
929 countersize = sizeof(struct xt_counters) * private->number;
930 counters = vmalloc_node(countersize, numa_node_id());
932 if (counters == NULL)
933 return ERR_PTR(-ENOMEM);
935 /* First, sum counters... */
936 write_lock_bh(&table->lock);
937 get_counters(private, counters);
938 write_unlock_bh(&table->lock);
944 copy_entries_to_user(unsigned int total_size,
945 struct xt_table *table,
946 void __user *userptr)
948 unsigned int off, num;
950 struct xt_counters *counters;
951 const struct xt_table_info *private = table->private;
953 const void *loc_cpu_entry;
955 counters = alloc_counters(table);
956 if (IS_ERR(counters))
957 return PTR_ERR(counters);
959 /* choose the copy that is on our node/cpu, ...
960 * This choice is lazy (because current thread is
961 * allowed to migrate to another cpu)
963 loc_cpu_entry = private->entries[raw_smp_processor_id()];
964 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
969 /* FIXME: use iterator macros --RR */
970 /* ... then go back and fix counters and names */
971 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
973 const struct ipt_entry_match *m;
974 const struct ipt_entry_target *t;
976 e = (struct ipt_entry *)(loc_cpu_entry + off);
977 if (copy_to_user(userptr + off
978 + offsetof(struct ipt_entry, counters),
980 sizeof(counters[num])) != 0) {
985 for (i = sizeof(struct ipt_entry);
986 i < e->target_offset;
987 i += m->u.match_size) {
990 if (copy_to_user(userptr + off + i
991 + offsetof(struct ipt_entry_match,
993 m->u.kernel.match->name,
994 strlen(m->u.kernel.match->name)+1)
1001 t = ipt_get_target(e);
1002 if (copy_to_user(userptr + off + e->target_offset
1003 + offsetof(struct ipt_entry_target,
1005 t->u.kernel.target->name,
1006 strlen(t->u.kernel.target->name)+1) != 0) {
1017 #ifdef CONFIG_COMPAT
1018 static void compat_standard_from_user(void *dst, void *src)
1020 int v = *(compat_int_t *)src;
1023 v += xt_compat_calc_jump(AF_INET, v);
1024 memcpy(dst, &v, sizeof(v));
1027 static int compat_standard_to_user(void __user *dst, void *src)
1029 compat_int_t cv = *(int *)src;
1032 cv -= xt_compat_calc_jump(AF_INET, cv);
1033 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1037 compat_calc_match(struct ipt_entry_match *m, int *size)
1039 *size += xt_compat_match_offset(m->u.kernel.match);
1043 static int compat_calc_entry(struct ipt_entry *e,
1044 const struct xt_table_info *info,
1045 void *base, struct xt_table_info *newinfo)
1047 struct ipt_entry_target *t;
1048 unsigned int entry_offset;
1051 off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1052 entry_offset = (void *)e - base;
1053 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1054 t = ipt_get_target(e);
1055 off += xt_compat_target_offset(t->u.kernel.target);
1056 newinfo->size -= off;
1057 ret = xt_compat_add_offset(AF_INET, entry_offset, off);
1061 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1062 if (info->hook_entry[i] &&
1063 (e < (struct ipt_entry *)(base + info->hook_entry[i])))
1064 newinfo->hook_entry[i] -= off;
1065 if (info->underflow[i] &&
1066 (e < (struct ipt_entry *)(base + info->underflow[i])))
1067 newinfo->underflow[i] -= off;
1072 static int compat_table_info(const struct xt_table_info *info,
1073 struct xt_table_info *newinfo)
1075 void *loc_cpu_entry;
1077 if (!newinfo || !info)
1080 /* we dont care about newinfo->entries[] */
1081 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1082 newinfo->initial_entries = 0;
1083 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1084 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1085 compat_calc_entry, info, loc_cpu_entry,
1090 static int get_info(struct net *net, void __user *user, int *len, int compat)
1092 char name[IPT_TABLE_MAXNAMELEN];
1096 if (*len != sizeof(struct ipt_getinfo)) {
1097 duprintf("length %u != %zu\n", *len,
1098 sizeof(struct ipt_getinfo));
1102 if (copy_from_user(name, user, sizeof(name)) != 0)
1105 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1106 #ifdef CONFIG_COMPAT
1108 xt_compat_lock(AF_INET);
1110 t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
1111 "iptable_%s", name);
1112 if (t && !IS_ERR(t)) {
1113 struct ipt_getinfo info;
1114 const struct xt_table_info *private = t->private;
1116 #ifdef CONFIG_COMPAT
1118 struct xt_table_info tmp;
1119 ret = compat_table_info(private, &tmp);
1120 xt_compat_flush_offsets(AF_INET);
1124 info.valid_hooks = t->valid_hooks;
1125 memcpy(info.hook_entry, private->hook_entry,
1126 sizeof(info.hook_entry));
1127 memcpy(info.underflow, private->underflow,
1128 sizeof(info.underflow));
1129 info.num_entries = private->number;
1130 info.size = private->size;
1131 strcpy(info.name, name);
1133 if (copy_to_user(user, &info, *len) != 0)
1141 ret = t ? PTR_ERR(t) : -ENOENT;
1142 #ifdef CONFIG_COMPAT
1144 xt_compat_unlock(AF_INET);
1150 get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
1153 struct ipt_get_entries get;
1156 if (*len < sizeof(get)) {
1157 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1160 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1162 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1163 duprintf("get_entries: %u != %zu\n",
1164 *len, sizeof(get) + get.size);
1168 t = xt_find_table_lock(net, AF_INET, get.name);
1169 if (t && !IS_ERR(t)) {
1170 const struct xt_table_info *private = t->private;
1171 duprintf("t->private->number = %u\n", private->number);
1172 if (get.size == private->size)
1173 ret = copy_entries_to_user(private->size,
1174 t, uptr->entrytable);
1176 duprintf("get_entries: I've got %u not %u!\n",
1177 private->size, get.size);
1183 ret = t ? PTR_ERR(t) : -ENOENT;
1189 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1190 struct xt_table_info *newinfo, unsigned int num_counters,
1191 void __user *counters_ptr)
1195 struct xt_table_info *oldinfo;
1196 struct xt_counters *counters;
1197 void *loc_cpu_old_entry;
1200 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1206 t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
1207 "iptable_%s", name);
1208 if (!t || IS_ERR(t)) {
1209 ret = t ? PTR_ERR(t) : -ENOENT;
1210 goto free_newinfo_counters_untrans;
1214 if (valid_hooks != t->valid_hooks) {
1215 duprintf("Valid hook crap: %08X vs %08X\n",
1216 valid_hooks, t->valid_hooks);
1221 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1225 /* Update module usage count based on number of rules */
1226 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1227 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1228 if ((oldinfo->number > oldinfo->initial_entries) ||
1229 (newinfo->number <= oldinfo->initial_entries))
1231 if ((oldinfo->number > oldinfo->initial_entries) &&
1232 (newinfo->number <= oldinfo->initial_entries))
1235 /* Get the old counters. */
1236 get_counters(oldinfo, counters);
1237 /* Decrease module usage counts and free resource */
1238 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1239 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
1241 xt_free_table_info(oldinfo);
1242 if (copy_to_user(counters_ptr, counters,
1243 sizeof(struct xt_counters) * num_counters) != 0)
1252 free_newinfo_counters_untrans:
1259 do_replace(struct net *net, void __user *user, unsigned int len)
1262 struct ipt_replace tmp;
1263 struct xt_table_info *newinfo;
1264 void *loc_cpu_entry;
1266 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1269 /* overflow check */
1270 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1273 newinfo = xt_alloc_table_info(tmp.size);
1277 /* choose the copy that is on our node/cpu */
1278 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1279 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1285 ret = translate_table(tmp.name, tmp.valid_hooks,
1286 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1287 tmp.hook_entry, tmp.underflow);
1291 duprintf("ip_tables: Translated table\n");
1293 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1294 tmp.num_counters, tmp.counters);
1296 goto free_newinfo_untrans;
1299 free_newinfo_untrans:
1300 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1302 xt_free_table_info(newinfo);
1306 /* We're lazy, and add to the first CPU; overflow works its fey magic
1307 * and everything is OK. */
1309 add_counter_to_entry(struct ipt_entry *e,
1310 const struct xt_counters addme[],
1314 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1316 (long unsigned int)e->counters.pcnt,
1317 (long unsigned int)e->counters.bcnt,
1318 (long unsigned int)addme[*i].pcnt,
1319 (long unsigned int)addme[*i].bcnt);
1322 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1329 do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
1332 struct xt_counters_info tmp;
1333 struct xt_counters *paddc;
1334 unsigned int num_counters;
1339 const struct xt_table_info *private;
1341 void *loc_cpu_entry;
1342 #ifdef CONFIG_COMPAT
1343 struct compat_xt_counters_info compat_tmp;
1347 size = sizeof(struct compat_xt_counters_info);
1352 size = sizeof(struct xt_counters_info);
1355 if (copy_from_user(ptmp, user, size) != 0)
1358 #ifdef CONFIG_COMPAT
1360 num_counters = compat_tmp.num_counters;
1361 name = compat_tmp.name;
1365 num_counters = tmp.num_counters;
1369 if (len != size + num_counters * sizeof(struct xt_counters))
1372 paddc = vmalloc_node(len - size, numa_node_id());
1376 if (copy_from_user(paddc, user + size, len - size) != 0) {
1381 t = xt_find_table_lock(net, AF_INET, name);
1382 if (!t || IS_ERR(t)) {
1383 ret = t ? PTR_ERR(t) : -ENOENT;
1387 write_lock_bh(&t->lock);
1388 private = t->private;
1389 if (private->number != num_counters) {
1391 goto unlock_up_free;
1395 /* Choose the copy that is on our node */
1396 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1397 IPT_ENTRY_ITERATE(loc_cpu_entry,
1399 add_counter_to_entry,
1403 write_unlock_bh(&t->lock);
1412 #ifdef CONFIG_COMPAT
1413 struct compat_ipt_replace {
1414 char name[IPT_TABLE_MAXNAMELEN];
1418 u32 hook_entry[NF_INET_NUMHOOKS];
1419 u32 underflow[NF_INET_NUMHOOKS];
1421 compat_uptr_t counters; /* struct ipt_counters * */
1422 struct compat_ipt_entry entries[0];
1426 compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
1427 unsigned int *size, struct xt_counters *counters,
1430 struct ipt_entry_target *t;
1431 struct compat_ipt_entry __user *ce;
1432 u_int16_t target_offset, next_offset;
1433 compat_uint_t origsize;
1438 ce = (struct compat_ipt_entry __user *)*dstptr;
1439 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1442 if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1445 *dstptr += sizeof(struct compat_ipt_entry);
1446 *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1448 ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size);
1449 target_offset = e->target_offset - (origsize - *size);
1452 t = ipt_get_target(e);
1453 ret = xt_compat_target_to_user(t, dstptr, size);
1457 next_offset = e->next_offset - (origsize - *size);
1458 if (put_user(target_offset, &ce->target_offset))
1460 if (put_user(next_offset, &ce->next_offset))
1470 compat_find_calc_match(struct ipt_entry_match *m,
1472 const struct ipt_ip *ip,
1473 unsigned int hookmask,
1474 int *size, unsigned int *i)
1476 struct xt_match *match;
1478 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1479 m->u.user.revision),
1480 "ipt_%s", m->u.user.name);
1481 if (IS_ERR(match) || !match) {
1482 duprintf("compat_check_calc_match: `%s' not found\n",
1484 return match ? PTR_ERR(match) : -ENOENT;
1486 m->u.kernel.match = match;
1487 *size += xt_compat_match_offset(match);
1494 compat_release_match(struct ipt_entry_match *m, unsigned int *i)
1496 if (i && (*i)-- == 0)
1499 module_put(m->u.kernel.match->me);
1504 compat_release_entry(struct compat_ipt_entry *e, unsigned int *i)
1506 struct ipt_entry_target *t;
1508 if (i && (*i)-- == 0)
1511 /* Cleanup all matches */
1512 COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL);
1513 t = compat_ipt_get_target(e);
1514 module_put(t->u.kernel.target->me);
1519 check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
1520 struct xt_table_info *newinfo,
1522 unsigned char *base,
1523 unsigned char *limit,
1524 unsigned int *hook_entries,
1525 unsigned int *underflows,
1529 struct ipt_entry_target *t;
1530 struct xt_target *target;
1531 unsigned int entry_offset;
1535 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1536 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1537 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1538 duprintf("Bad offset %p, limit = %p\n", e, limit);
1542 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1543 sizeof(struct compat_xt_entry_target)) {
1544 duprintf("checking: element %p size %u\n",
1549 /* For purposes of check_entry casting the compat entry is fine */
1550 ret = check_entry((struct ipt_entry *)e, name);
1554 off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1555 entry_offset = (void *)e - (void *)base;
1557 ret = COMPAT_IPT_MATCH_ITERATE(e, compat_find_calc_match, name,
1558 &e->ip, e->comefrom, &off, &j);
1560 goto release_matches;
1562 t = compat_ipt_get_target(e);
1563 target = try_then_request_module(xt_find_target(AF_INET,
1565 t->u.user.revision),
1566 "ipt_%s", t->u.user.name);
1567 if (IS_ERR(target) || !target) {
1568 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1570 ret = target ? PTR_ERR(target) : -ENOENT;
1571 goto release_matches;
1573 t->u.kernel.target = target;
1575 off += xt_compat_target_offset(target);
1577 ret = xt_compat_add_offset(AF_INET, entry_offset, off);
1581 /* Check hooks & underflows */
1582 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1583 if ((unsigned char *)e - base == hook_entries[h])
1584 newinfo->hook_entry[h] = hook_entries[h];
1585 if ((unsigned char *)e - base == underflows[h])
1586 newinfo->underflow[h] = underflows[h];
1589 /* Clear counters and comefrom */
1590 memset(&e->counters, 0, sizeof(e->counters));
1597 module_put(t->u.kernel.target->me);
1599 IPT_MATCH_ITERATE(e, compat_release_match, &j);
1604 compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr,
1605 unsigned int *size, const char *name,
1606 struct xt_table_info *newinfo, unsigned char *base)
1608 struct ipt_entry_target *t;
1609 struct xt_target *target;
1610 struct ipt_entry *de;
1611 unsigned int origsize;
1616 de = (struct ipt_entry *)*dstptr;
1617 memcpy(de, e, sizeof(struct ipt_entry));
1618 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1620 *dstptr += sizeof(struct ipt_entry);
1621 *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1623 ret = COMPAT_IPT_MATCH_ITERATE(e, xt_compat_match_from_user,
1627 de->target_offset = e->target_offset - (origsize - *size);
1628 t = compat_ipt_get_target(e);
1629 target = t->u.kernel.target;
1630 xt_compat_target_from_user(t, dstptr, size);
1632 de->next_offset = e->next_offset - (origsize - *size);
1633 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1634 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1635 newinfo->hook_entry[h] -= origsize - *size;
1636 if ((unsigned char *)de - base < newinfo->underflow[h])
1637 newinfo->underflow[h] -= origsize - *size;
1643 compat_check_entry(struct ipt_entry *e, const char *name,
1650 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip,
1653 goto cleanup_matches;
1655 ret = check_target(e, name);
1657 goto cleanup_matches;
1663 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1668 translate_compat_table(const char *name,
1669 unsigned int valid_hooks,
1670 struct xt_table_info **pinfo,
1672 unsigned int total_size,
1673 unsigned int number,
1674 unsigned int *hook_entries,
1675 unsigned int *underflows)
1678 struct xt_table_info *newinfo, *info;
1679 void *pos, *entry0, *entry1;
1686 info->number = number;
1688 /* Init all hooks to impossible value. */
1689 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1690 info->hook_entry[i] = 0xFFFFFFFF;
1691 info->underflow[i] = 0xFFFFFFFF;
1694 duprintf("translate_compat_table: size %u\n", info->size);
1696 xt_compat_lock(AF_INET);
1697 /* Walk through entries, checking offsets. */
1698 ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size,
1699 check_compat_entry_size_and_hooks,
1700 info, &size, entry0,
1701 entry0 + total_size,
1702 hook_entries, underflows, &j, name);
1708 duprintf("translate_compat_table: %u not %u entries\n",
1713 /* Check hooks all assigned */
1714 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1715 /* Only hooks which are valid */
1716 if (!(valid_hooks & (1 << i)))
1718 if (info->hook_entry[i] == 0xFFFFFFFF) {
1719 duprintf("Invalid hook entry %u %u\n",
1720 i, hook_entries[i]);
1723 if (info->underflow[i] == 0xFFFFFFFF) {
1724 duprintf("Invalid underflow %u %u\n",
1731 newinfo = xt_alloc_table_info(size);
1735 newinfo->number = number;
1736 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1737 newinfo->hook_entry[i] = info->hook_entry[i];
1738 newinfo->underflow[i] = info->underflow[i];
1740 entry1 = newinfo->entries[raw_smp_processor_id()];
1743 ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size,
1744 compat_copy_entry_from_user,
1745 &pos, &size, name, newinfo, entry1);
1746 xt_compat_flush_offsets(AF_INET);
1747 xt_compat_unlock(AF_INET);
1752 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1756 ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1760 COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
1761 compat_release_entry, &j);
1762 IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1763 xt_free_table_info(newinfo);
1767 /* And one copy for every other CPU */
1768 for_each_possible_cpu(i)
1769 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1770 memcpy(newinfo->entries[i], entry1, newinfo->size);
1774 xt_free_table_info(info);
1778 xt_free_table_info(newinfo);
1780 COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1783 xt_compat_flush_offsets(AF_INET);
1784 xt_compat_unlock(AF_INET);
1789 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1792 struct compat_ipt_replace tmp;
1793 struct xt_table_info *newinfo;
1794 void *loc_cpu_entry;
1796 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1799 /* overflow check */
1800 if (tmp.size >= INT_MAX / num_possible_cpus())
1802 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1805 newinfo = xt_alloc_table_info(tmp.size);
1809 /* choose the copy that is on our node/cpu */
1810 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1811 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1817 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1818 &newinfo, &loc_cpu_entry, tmp.size,
1819 tmp.num_entries, tmp.hook_entry,
1824 duprintf("compat_do_replace: Translated table\n");
1826 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1827 tmp.num_counters, compat_ptr(tmp.counters));
1829 goto free_newinfo_untrans;
1832 free_newinfo_untrans:
1833 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1835 xt_free_table_info(newinfo);
1840 compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1845 if (!capable(CAP_NET_ADMIN))
1849 case IPT_SO_SET_REPLACE:
1850 ret = compat_do_replace(sock_net(sk), user, len);
1853 case IPT_SO_SET_ADD_COUNTERS:
1854 ret = do_add_counters(sock_net(sk), user, len, 1);
1858 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1865 struct compat_ipt_get_entries {
1866 char name[IPT_TABLE_MAXNAMELEN];
1868 struct compat_ipt_entry entrytable[0];
1872 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1873 void __user *userptr)
1875 struct xt_counters *counters;
1876 const struct xt_table_info *private = table->private;
1880 const void *loc_cpu_entry;
1883 counters = alloc_counters(table);
1884 if (IS_ERR(counters))
1885 return PTR_ERR(counters);
1887 /* choose the copy that is on our node/cpu, ...
1888 * This choice is lazy (because current thread is
1889 * allowed to migrate to another cpu)
1891 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1894 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1895 compat_copy_entry_to_user,
1896 &pos, &size, counters, &i);
1903 compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
1907 struct compat_ipt_get_entries get;
1910 if (*len < sizeof(get)) {
1911 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1915 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1918 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1919 duprintf("compat_get_entries: %u != %zu\n",
1920 *len, sizeof(get) + get.size);
1924 xt_compat_lock(AF_INET);
1925 t = xt_find_table_lock(net, AF_INET, get.name);
1926 if (t && !IS_ERR(t)) {
1927 const struct xt_table_info *private = t->private;
1928 struct xt_table_info info;
1929 duprintf("t->private->number = %u\n", private->number);
1930 ret = compat_table_info(private, &info);
1931 if (!ret && get.size == info.size) {
1932 ret = compat_copy_entries_to_user(private->size,
1933 t, uptr->entrytable);
1935 duprintf("compat_get_entries: I've got %u not %u!\n",
1936 private->size, get.size);
1939 xt_compat_flush_offsets(AF_INET);
1943 ret = t ? PTR_ERR(t) : -ENOENT;
1945 xt_compat_unlock(AF_INET);
1949 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1952 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1956 if (!capable(CAP_NET_ADMIN))
1960 case IPT_SO_GET_INFO:
1961 ret = get_info(sock_net(sk), user, len, 1);
1963 case IPT_SO_GET_ENTRIES:
1964 ret = compat_get_entries(sock_net(sk), user, len);
1967 ret = do_ipt_get_ctl(sk, cmd, user, len);
1974 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1978 if (!capable(CAP_NET_ADMIN))
1982 case IPT_SO_SET_REPLACE:
1983 ret = do_replace(sock_net(sk), user, len);
1986 case IPT_SO_SET_ADD_COUNTERS:
1987 ret = do_add_counters(sock_net(sk), user, len, 0);
1991 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1999 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2003 if (!capable(CAP_NET_ADMIN))
2007 case IPT_SO_GET_INFO:
2008 ret = get_info(sock_net(sk), user, len, 0);
2011 case IPT_SO_GET_ENTRIES:
2012 ret = get_entries(sock_net(sk), user, len);
2015 case IPT_SO_GET_REVISION_MATCH:
2016 case IPT_SO_GET_REVISION_TARGET: {
2017 struct ipt_get_revision rev;
2020 if (*len != sizeof(rev)) {
2024 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2029 if (cmd == IPT_SO_GET_REVISION_TARGET)
2034 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2037 "ipt_%s", rev.name);
2042 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2049 struct xt_table *ipt_register_table(struct net *net, struct xt_table *table,
2050 const struct ipt_replace *repl)
2053 struct xt_table_info *newinfo;
2054 struct xt_table_info bootstrap
2055 = { 0, 0, 0, { 0 }, { 0 }, { } };
2056 void *loc_cpu_entry;
2057 struct xt_table *new_table;
2059 newinfo = xt_alloc_table_info(repl->size);
2065 /* choose the copy on our node/cpu, but dont care about preemption */
2066 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2067 memcpy(loc_cpu_entry, repl->entries, repl->size);
2069 ret = translate_table(table->name, table->valid_hooks,
2070 newinfo, loc_cpu_entry, repl->size,
2077 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2078 if (IS_ERR(new_table)) {
2079 ret = PTR_ERR(new_table);
2086 xt_free_table_info(newinfo);
2088 return ERR_PTR(ret);
2091 void ipt_unregister_table(struct xt_table *table)
2093 struct xt_table_info *private;
2094 void *loc_cpu_entry;
2095 struct module *table_owner = table->me;
2097 private = xt_unregister_table(table);
2099 /* Decrease module usage counts and free resources */
2100 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2101 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2102 if (private->number > private->initial_entries)
2103 module_put(table_owner);
2104 xt_free_table_info(private);
2107 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
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,
2113 return ((test_type == 0xFF) ||
2114 (type == test_type && code >= min_code && code <= max_code))
2119 icmp_match(const struct sk_buff *skb,
2120 const struct net_device *in,
2121 const struct net_device *out,
2122 const struct xt_match *match,
2123 const void *matchinfo,
2125 unsigned int protoff,
2128 const struct icmphdr *ic;
2129 struct icmphdr _icmph;
2130 const struct ipt_icmp *icmpinfo = matchinfo;
2132 /* Must not be a fragment. */
2136 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2138 /* We've been asked to examine this packet, and we
2139 * can't. Hence, no choice but to drop.
2141 duprintf("Dropping evil ICMP tinygram.\n");
2146 return icmp_type_code_match(icmpinfo->type,
2150 !!(icmpinfo->invflags&IPT_ICMP_INV));
2153 /* Called when user tries to insert an entry of this type. */
2155 icmp_checkentry(const char *tablename,
2157 const struct xt_match *match,
2159 unsigned int hook_mask)
2161 const struct ipt_icmp *icmpinfo = matchinfo;
2163 /* Must specify no unknown invflags */
2164 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2167 /* The built-in targets: standard (NULL) and error. */
2168 static struct xt_target ipt_standard_target __read_mostly = {
2169 .name = IPT_STANDARD_TARGET,
2170 .targetsize = sizeof(int),
2172 #ifdef CONFIG_COMPAT
2173 .compatsize = sizeof(compat_int_t),
2174 .compat_from_user = compat_standard_from_user,
2175 .compat_to_user = compat_standard_to_user,
2179 static struct xt_target ipt_error_target __read_mostly = {
2180 .name = IPT_ERROR_TARGET,
2181 .target = ipt_error,
2182 .targetsize = IPT_FUNCTION_MAXNAMELEN,
2186 static struct nf_sockopt_ops ipt_sockopts = {
2188 .set_optmin = IPT_BASE_CTL,
2189 .set_optmax = IPT_SO_SET_MAX+1,
2190 .set = do_ipt_set_ctl,
2191 #ifdef CONFIG_COMPAT
2192 .compat_set = compat_do_ipt_set_ctl,
2194 .get_optmin = IPT_BASE_CTL,
2195 .get_optmax = IPT_SO_GET_MAX+1,
2196 .get = do_ipt_get_ctl,
2197 #ifdef CONFIG_COMPAT
2198 .compat_get = compat_do_ipt_get_ctl,
2200 .owner = THIS_MODULE,
2203 static struct xt_match icmp_matchstruct __read_mostly = {
2205 .match = icmp_match,
2206 .matchsize = sizeof(struct ipt_icmp),
2207 .checkentry = icmp_checkentry,
2208 .proto = IPPROTO_ICMP,
2212 static int __net_init ip_tables_net_init(struct net *net)
2214 return xt_proto_init(net, AF_INET);
2217 static void __net_exit ip_tables_net_exit(struct net *net)
2219 xt_proto_fini(net, AF_INET);
2222 static struct pernet_operations ip_tables_net_ops = {
2223 .init = ip_tables_net_init,
2224 .exit = ip_tables_net_exit,
2227 static int __init ip_tables_init(void)
2231 ret = register_pernet_subsys(&ip_tables_net_ops);
2235 /* Noone else will be downing sem now, so we won't sleep */
2236 ret = xt_register_target(&ipt_standard_target);
2239 ret = xt_register_target(&ipt_error_target);
2242 ret = xt_register_match(&icmp_matchstruct);
2246 /* Register setsockopt */
2247 ret = nf_register_sockopt(&ipt_sockopts);
2251 printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2255 xt_unregister_match(&icmp_matchstruct);
2257 xt_unregister_target(&ipt_error_target);
2259 xt_unregister_target(&ipt_standard_target);
2261 unregister_pernet_subsys(&ip_tables_net_ops);
2266 static void __exit ip_tables_fini(void)
2268 nf_unregister_sockopt(&ipt_sockopts);
2270 xt_unregister_match(&icmp_matchstruct);
2271 xt_unregister_target(&ipt_error_target);
2272 xt_unregister_target(&ipt_standard_target);
2274 unregister_pernet_subsys(&ip_tables_net_ops);
2277 EXPORT_SYMBOL(ipt_register_table);
2278 EXPORT_SYMBOL(ipt_unregister_table);
2279 EXPORT_SYMBOL(ipt_do_table);
2280 module_init(ip_tables_init);
2281 module_exit(ip_tables_fini);