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 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
14 * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
15 * - Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
17 #include <linux/cache.h>
18 #include <linux/capability.h>
19 #include <linux/skbuff.h>
20 #include <linux/kmod.h>
21 #include <linux/vmalloc.h>
22 #include <linux/netdevice.h>
23 #include <linux/module.h>
24 #include <linux/icmp.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
33 #include <linux/netfilter/x_tables.h>
34 #include <linux/netfilter_ipv4/ip_tables.h>
36 MODULE_LICENSE("GPL");
37 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
38 MODULE_DESCRIPTION("IPv4 packet filter");
40 /*#define DEBUG_IP_FIREWALL*/
41 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
42 /*#define DEBUG_IP_FIREWALL_USER*/
44 #ifdef DEBUG_IP_FIREWALL
45 #define dprintf(format, args...) printk(format , ## args)
47 #define dprintf(format, args...)
50 #ifdef DEBUG_IP_FIREWALL_USER
51 #define duprintf(format, args...) printk(format , ## args)
53 #define duprintf(format, args...)
56 #ifdef CONFIG_NETFILTER_DEBUG
57 #define IP_NF_ASSERT(x) \
60 printk("IP_NF_ASSERT: %s:%s:%u\n", \
61 __FUNCTION__, __FILE__, __LINE__); \
64 #define IP_NF_ASSERT(x)
68 /* All the better to debug you with... */
74 We keep a set of rules for each CPU, so we can avoid write-locking
75 them in the softirq when updating the counters and therefore
76 only need to read-lock in the softirq; doing a write_lock_bh() in user
77 context stops packets coming through and allows user context to read
78 the counters or update the rules.
80 Hence the start of any table is given by get_table() below. */
82 /* Returns whether matches rule or not. */
84 ip_packet_match(const struct iphdr *ip,
87 const struct ipt_ip *ipinfo,
93 #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
95 if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
97 || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
99 dprintf("Source or dest mismatch.\n");
101 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
103 NIPQUAD(ipinfo->smsk.s_addr),
104 NIPQUAD(ipinfo->src.s_addr),
105 ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
106 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
108 NIPQUAD(ipinfo->dmsk.s_addr),
109 NIPQUAD(ipinfo->dst.s_addr),
110 ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
114 /* Look for ifname matches; this should unroll nicely. */
115 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
116 ret |= (((const unsigned long *)indev)[i]
117 ^ ((const unsigned long *)ipinfo->iniface)[i])
118 & ((const unsigned long *)ipinfo->iniface_mask)[i];
121 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
122 dprintf("VIA in mismatch (%s vs %s).%s\n",
123 indev, ipinfo->iniface,
124 ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
128 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
129 ret |= (((const unsigned long *)outdev)[i]
130 ^ ((const unsigned long *)ipinfo->outiface)[i])
131 & ((const unsigned long *)ipinfo->outiface_mask)[i];
134 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
135 dprintf("VIA out mismatch (%s vs %s).%s\n",
136 outdev, ipinfo->outiface,
137 ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
141 /* Check specific protocol */
143 && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
144 dprintf("Packet protocol %hi does not match %hi.%s\n",
145 ip->protocol, ipinfo->proto,
146 ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
150 /* If we have a fragment rule but the packet is not a fragment
151 * then we return zero */
152 if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
153 dprintf("Fragment rule but not fragment.%s\n",
154 ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
162 ip_checkentry(const struct ipt_ip *ip)
164 if (ip->flags & ~IPT_F_MASK) {
165 duprintf("Unknown flag bits set: %08X\n",
166 ip->flags & ~IPT_F_MASK);
169 if (ip->invflags & ~IPT_INV_MASK) {
170 duprintf("Unknown invflag bits set: %08X\n",
171 ip->invflags & ~IPT_INV_MASK);
178 ipt_error(struct sk_buff **pskb,
179 const struct net_device *in,
180 const struct net_device *out,
181 unsigned int hooknum,
182 const struct xt_target *target,
183 const void *targinfo)
186 printk("ip_tables: error: `%s'\n", (char *)targinfo);
192 int do_match(struct ipt_entry_match *m,
193 const struct sk_buff *skb,
194 const struct net_device *in,
195 const struct net_device *out,
199 /* Stop iteration if it doesn't match */
200 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
201 offset, skb->nh.iph->ihl*4, hotdrop))
207 static inline struct ipt_entry *
208 get_entry(void *base, unsigned int offset)
210 return (struct ipt_entry *)(base + offset);
213 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
215 ipt_do_table(struct sk_buff **pskb,
217 const struct net_device *in,
218 const struct net_device *out,
219 struct ipt_table *table)
221 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
226 /* Initializing verdict to NF_DROP keeps gcc happy. */
227 unsigned int verdict = NF_DROP;
228 const char *indev, *outdev;
230 struct ipt_entry *e, *back;
231 struct xt_table_info *private;
234 ip = (*pskb)->nh.iph;
235 datalen = (*pskb)->len - ip->ihl * 4;
236 indev = in ? in->name : nulldevname;
237 outdev = out ? out->name : nulldevname;
238 /* We handle fragments by dealing with the first fragment as
239 * if it was a normal packet. All other fragments are treated
240 * normally, except that they will NEVER match rules that ask
241 * things we don't know, ie. tcp syn flag or ports). If the
242 * rule is also a fragment-specific rule, non-fragments won't
244 offset = ntohs(ip->frag_off) & IP_OFFSET;
246 read_lock_bh(&table->lock);
247 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
248 private = table->private;
249 table_base = (void *)private->entries[smp_processor_id()];
250 e = get_entry(table_base, private->hook_entry[hook]);
252 /* For return from builtin chain */
253 back = get_entry(table_base, private->underflow[hook]);
258 if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
259 struct ipt_entry_target *t;
261 if (IPT_MATCH_ITERATE(e, do_match,
263 offset, &hotdrop) != 0)
266 ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
268 t = ipt_get_target(e);
269 IP_NF_ASSERT(t->u.kernel.target);
270 /* Standard target? */
271 if (!t->u.kernel.target->target) {
274 v = ((struct ipt_standard_target *)t)->verdict;
276 /* Pop from stack? */
277 if (v != IPT_RETURN) {
278 verdict = (unsigned)(-v) - 1;
282 back = get_entry(table_base,
286 if (table_base + v != (void *)e + e->next_offset
287 && !(e->ip.flags & IPT_F_GOTO)) {
288 /* Save old back ptr in next entry */
289 struct ipt_entry *next
290 = (void *)e + e->next_offset;
292 = (void *)back - table_base;
293 /* set back pointer to next entry */
297 e = get_entry(table_base, v);
299 /* Targets which reenter must return
301 #ifdef CONFIG_NETFILTER_DEBUG
302 ((struct ipt_entry *)table_base)->comefrom
305 verdict = t->u.kernel.target->target(pskb,
311 #ifdef CONFIG_NETFILTER_DEBUG
312 if (((struct ipt_entry *)table_base)->comefrom
314 && verdict == IPT_CONTINUE) {
315 printk("Target %s reentered!\n",
316 t->u.kernel.target->name);
319 ((struct ipt_entry *)table_base)->comefrom
322 /* Target might have changed stuff. */
323 ip = (*pskb)->nh.iph;
324 datalen = (*pskb)->len - ip->ihl * 4;
326 if (verdict == IPT_CONTINUE)
327 e = (void *)e + e->next_offset;
335 e = (void *)e + e->next_offset;
339 read_unlock_bh(&table->lock);
341 #ifdef DEBUG_ALLOW_ALL
350 /* All zeroes == unconditional rule. */
352 unconditional(const struct ipt_ip *ip)
356 for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
357 if (((__u32 *)ip)[i])
363 /* Figures out from what hook each rule can be called: returns 0 if
364 there are loops. Puts hook bitmask in comefrom. */
366 mark_source_chains(struct xt_table_info *newinfo,
367 unsigned int valid_hooks, void *entry0)
371 /* No recursion; use packet counter to save back ptrs (reset
372 to 0 as we leave), and comefrom to save source hook bitmask */
373 for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) {
374 unsigned int pos = newinfo->hook_entry[hook];
376 = (struct ipt_entry *)(entry0 + pos);
378 if (!(valid_hooks & (1 << hook)))
381 /* Set initial back pointer. */
382 e->counters.pcnt = pos;
385 struct ipt_standard_target *t
386 = (void *)ipt_get_target(e);
388 if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
389 printk("iptables: loop hook %u pos %u %08X.\n",
390 hook, pos, e->comefrom);
394 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
396 /* Unconditional return/END. */
397 if (e->target_offset == sizeof(struct ipt_entry)
398 && (strcmp(t->target.u.user.name,
399 IPT_STANDARD_TARGET) == 0)
401 && unconditional(&e->ip)) {
402 unsigned int oldpos, size;
404 if (t->verdict < -NF_MAX_VERDICT - 1) {
405 duprintf("mark_source_chains: bad "
406 "negative verdict (%i)\n",
411 /* Return: backtrack through the last
414 e->comefrom ^= (1<<NF_IP_NUMHOOKS);
415 #ifdef DEBUG_IP_FIREWALL_USER
417 & (1 << NF_IP_NUMHOOKS)) {
418 duprintf("Back unset "
425 pos = e->counters.pcnt;
426 e->counters.pcnt = 0;
428 /* We're at the start. */
432 e = (struct ipt_entry *)
434 } while (oldpos == pos + e->next_offset);
437 size = e->next_offset;
438 e = (struct ipt_entry *)
439 (entry0 + pos + size);
440 e->counters.pcnt = pos;
443 int newpos = t->verdict;
445 if (strcmp(t->target.u.user.name,
446 IPT_STANDARD_TARGET) == 0
448 if (newpos > newinfo->size -
449 sizeof(struct ipt_entry)) {
450 duprintf("mark_source_chains: "
451 "bad verdict (%i)\n",
455 /* This a jump; chase it. */
456 duprintf("Jump rule %u -> %u\n",
459 /* ... this is a fallthru */
460 newpos = pos + e->next_offset;
462 e = (struct ipt_entry *)
464 e->counters.pcnt = pos;
469 duprintf("Finished chain %u\n", hook);
475 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
477 if (i && (*i)-- == 0)
480 if (m->u.kernel.match->destroy)
481 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
482 module_put(m->u.kernel.match->me);
487 check_match(struct ipt_entry_match *m,
489 const struct ipt_ip *ip,
490 unsigned int hookmask,
493 struct ipt_match *match;
496 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
498 "ipt_%s", m->u.user.name);
499 if (IS_ERR(match) || !match) {
500 duprintf("check_match: `%s' not found\n", m->u.user.name);
501 return match ? PTR_ERR(match) : -ENOENT;
503 m->u.kernel.match = match;
505 ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
506 name, hookmask, ip->proto,
507 ip->invflags & IPT_INV_PROTO);
511 if (m->u.kernel.match->checkentry
512 && !m->u.kernel.match->checkentry(name, ip, match, m->data,
514 duprintf("ip_tables: check failed for `%s'.\n",
515 m->u.kernel.match->name);
523 module_put(m->u.kernel.match->me);
527 static struct ipt_target ipt_standard_target;
530 check_entry(struct ipt_entry *e, const char *name, unsigned int size,
533 struct ipt_entry_target *t;
534 struct ipt_target *target;
538 if (!ip_checkentry(&e->ip)) {
539 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
543 if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
547 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
549 goto cleanup_matches;
551 t = ipt_get_target(e);
553 if (e->target_offset + t->u.target_size > e->next_offset)
554 goto cleanup_matches;
555 target = try_then_request_module(xt_find_target(AF_INET,
558 "ipt_%s", t->u.user.name);
559 if (IS_ERR(target) || !target) {
560 duprintf("check_entry: `%s' not found\n", t->u.user.name);
561 ret = target ? PTR_ERR(target) : -ENOENT;
562 goto cleanup_matches;
564 t->u.kernel.target = target;
566 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
567 name, e->comefrom, e->ip.proto,
568 e->ip.invflags & IPT_INV_PROTO);
572 if (t->u.kernel.target->checkentry
573 && !t->u.kernel.target->checkentry(name, e, target, t->data,
575 duprintf("ip_tables: check failed for `%s'.\n",
576 t->u.kernel.target->name);
584 module_put(t->u.kernel.target->me);
586 IPT_MATCH_ITERATE(e, cleanup_match, &j);
591 check_entry_size_and_hooks(struct ipt_entry *e,
592 struct xt_table_info *newinfo,
594 unsigned char *limit,
595 const unsigned int *hook_entries,
596 const unsigned int *underflows,
601 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
602 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
603 duprintf("Bad offset %p\n", e);
608 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
609 duprintf("checking: element %p size %u\n",
614 /* Check hooks & underflows */
615 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
616 if ((unsigned char *)e - base == hook_entries[h])
617 newinfo->hook_entry[h] = hook_entries[h];
618 if ((unsigned char *)e - base == underflows[h])
619 newinfo->underflow[h] = underflows[h];
622 /* FIXME: underflows must be unconditional, standard verdicts
623 < 0 (not IPT_RETURN). --RR */
625 /* Clear counters and comefrom */
626 e->counters = ((struct xt_counters) { 0, 0 });
634 cleanup_entry(struct ipt_entry *e, unsigned int *i)
636 struct ipt_entry_target *t;
638 if (i && (*i)-- == 0)
641 /* Cleanup all matches */
642 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
643 t = ipt_get_target(e);
644 if (t->u.kernel.target->destroy)
645 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
646 module_put(t->u.kernel.target->me);
650 /* Checks and translates the user-supplied table segment (held in
653 translate_table(const char *name,
654 unsigned int valid_hooks,
655 struct xt_table_info *newinfo,
659 const unsigned int *hook_entries,
660 const unsigned int *underflows)
665 newinfo->size = size;
666 newinfo->number = number;
668 /* Init all hooks to impossible value. */
669 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
670 newinfo->hook_entry[i] = 0xFFFFFFFF;
671 newinfo->underflow[i] = 0xFFFFFFFF;
674 duprintf("translate_table: size %u\n", newinfo->size);
676 /* Walk through entries, checking offsets. */
677 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
678 check_entry_size_and_hooks,
682 hook_entries, underflows, &i);
687 duprintf("translate_table: %u not %u entries\n",
692 /* Check hooks all assigned */
693 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
694 /* Only hooks which are valid */
695 if (!(valid_hooks & (1 << i)))
697 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
698 duprintf("Invalid hook entry %u %u\n",
702 if (newinfo->underflow[i] == 0xFFFFFFFF) {
703 duprintf("Invalid underflow %u %u\n",
709 if (!mark_source_chains(newinfo, valid_hooks, entry0))
712 /* Finally, each sanity check must pass */
714 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
715 check_entry, name, size, &i);
718 IPT_ENTRY_ITERATE(entry0, newinfo->size,
723 /* And one copy for every other CPU */
724 for_each_possible_cpu(i) {
725 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
726 memcpy(newinfo->entries[i], entry0, newinfo->size);
734 add_entry_to_counter(const struct ipt_entry *e,
735 struct xt_counters total[],
738 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
745 set_entry_to_counter(const struct ipt_entry *e,
746 struct ipt_counters total[],
749 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
756 get_counters(const struct xt_table_info *t,
757 struct xt_counters counters[])
763 /* Instead of clearing (by a previous call to memset())
764 * the counters and using adds, we set the counters
765 * with data used by 'current' CPU
766 * We dont care about preemption here.
768 curcpu = raw_smp_processor_id();
771 IPT_ENTRY_ITERATE(t->entries[curcpu],
773 set_entry_to_counter,
777 for_each_possible_cpu(cpu) {
781 IPT_ENTRY_ITERATE(t->entries[cpu],
783 add_entry_to_counter,
789 static inline struct xt_counters * alloc_counters(struct ipt_table *table)
791 unsigned int countersize;
792 struct xt_counters *counters;
793 struct xt_table_info *private = table->private;
795 /* We need atomic snapshot of counters: rest doesn't change
796 (other than comefrom, which userspace doesn't care
798 countersize = sizeof(struct xt_counters) * private->number;
799 counters = vmalloc_node(countersize, numa_node_id());
801 if (counters == NULL)
802 return ERR_PTR(-ENOMEM);
804 /* First, sum counters... */
805 write_lock_bh(&table->lock);
806 get_counters(private, counters);
807 write_unlock_bh(&table->lock);
813 copy_entries_to_user(unsigned int total_size,
814 struct ipt_table *table,
815 void __user *userptr)
817 unsigned int off, num;
819 struct xt_counters *counters;
820 struct xt_table_info *private = table->private;
824 counters = alloc_counters(table);
825 if (IS_ERR(counters))
826 return PTR_ERR(counters);
828 /* choose the copy that is on our node/cpu, ...
829 * This choice is lazy (because current thread is
830 * allowed to migrate to another cpu)
832 loc_cpu_entry = private->entries[raw_smp_processor_id()];
833 /* ... then copy entire thing ... */
834 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
839 /* FIXME: use iterator macros --RR */
840 /* ... then go back and fix counters and names */
841 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
843 struct ipt_entry_match *m;
844 struct ipt_entry_target *t;
846 e = (struct ipt_entry *)(loc_cpu_entry + off);
847 if (copy_to_user(userptr + off
848 + offsetof(struct ipt_entry, counters),
850 sizeof(counters[num])) != 0) {
855 for (i = sizeof(struct ipt_entry);
856 i < e->target_offset;
857 i += m->u.match_size) {
860 if (copy_to_user(userptr + off + i
861 + offsetof(struct ipt_entry_match,
863 m->u.kernel.match->name,
864 strlen(m->u.kernel.match->name)+1)
871 t = ipt_get_target(e);
872 if (copy_to_user(userptr + off + e->target_offset
873 + offsetof(struct ipt_entry_target,
875 t->u.kernel.target->name,
876 strlen(t->u.kernel.target->name)+1) != 0) {
888 struct compat_delta {
889 struct compat_delta *next;
894 static struct compat_delta *compat_offsets = NULL;
896 static int compat_add_offset(u_int16_t offset, short delta)
898 struct compat_delta *tmp;
900 tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
903 tmp->offset = offset;
905 if (compat_offsets) {
906 tmp->next = compat_offsets->next;
907 compat_offsets->next = tmp;
909 compat_offsets = tmp;
915 static void compat_flush_offsets(void)
917 struct compat_delta *tmp, *next;
919 if (compat_offsets) {
920 for(tmp = compat_offsets; tmp; tmp = next) {
924 compat_offsets = NULL;
928 static short compat_calc_jump(u_int16_t offset)
930 struct compat_delta *tmp;
933 for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
934 if (tmp->offset < offset)
939 static void compat_standard_from_user(void *dst, void *src)
941 int v = *(compat_int_t *)src;
944 v += compat_calc_jump(v);
945 memcpy(dst, &v, sizeof(v));
948 static int compat_standard_to_user(void __user *dst, void *src)
950 compat_int_t cv = *(int *)src;
953 cv -= compat_calc_jump(cv);
954 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
958 compat_calc_match(struct ipt_entry_match *m, int * size)
960 *size += xt_compat_match_offset(m->u.kernel.match);
964 static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
965 void *base, struct xt_table_info *newinfo)
967 struct ipt_entry_target *t;
968 u_int16_t entry_offset;
972 entry_offset = (void *)e - base;
973 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
974 t = ipt_get_target(e);
975 off += xt_compat_target_offset(t->u.kernel.target);
976 newinfo->size -= off;
977 ret = compat_add_offset(entry_offset, off);
981 for (i = 0; i< NF_IP_NUMHOOKS; i++) {
982 if (info->hook_entry[i] && (e < (struct ipt_entry *)
983 (base + info->hook_entry[i])))
984 newinfo->hook_entry[i] -= off;
985 if (info->underflow[i] && (e < (struct ipt_entry *)
986 (base + info->underflow[i])))
987 newinfo->underflow[i] -= off;
992 static int compat_table_info(struct xt_table_info *info,
993 struct xt_table_info *newinfo)
998 if (!newinfo || !info)
1001 memset(newinfo, 0, sizeof(struct xt_table_info));
1002 newinfo->size = info->size;
1003 newinfo->number = info->number;
1004 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1005 newinfo->hook_entry[i] = info->hook_entry[i];
1006 newinfo->underflow[i] = info->underflow[i];
1008 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1009 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1010 compat_calc_entry, info, loc_cpu_entry, newinfo);
1014 static int get_info(void __user *user, int *len, int compat)
1016 char name[IPT_TABLE_MAXNAMELEN];
1017 struct ipt_table *t;
1020 if (*len != sizeof(struct ipt_getinfo)) {
1021 duprintf("length %u != %u\n", *len,
1022 (unsigned int)sizeof(struct ipt_getinfo));
1026 if (copy_from_user(name, user, sizeof(name)) != 0)
1029 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1030 #ifdef CONFIG_COMPAT
1032 xt_compat_lock(AF_INET);
1034 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1035 "iptable_%s", name);
1036 if (t && !IS_ERR(t)) {
1037 struct ipt_getinfo info;
1038 struct xt_table_info *private = t->private;
1040 #ifdef CONFIG_COMPAT
1042 struct xt_table_info tmp;
1043 ret = compat_table_info(private, &tmp);
1044 compat_flush_offsets();
1048 info.valid_hooks = t->valid_hooks;
1049 memcpy(info.hook_entry, private->hook_entry,
1050 sizeof(info.hook_entry));
1051 memcpy(info.underflow, private->underflow,
1052 sizeof(info.underflow));
1053 info.num_entries = private->number;
1054 info.size = private->size;
1055 strcpy(info.name, name);
1057 if (copy_to_user(user, &info, *len) != 0)
1065 ret = t ? PTR_ERR(t) : -ENOENT;
1066 #ifdef CONFIG_COMPAT
1068 xt_compat_unlock(AF_INET);
1074 get_entries(struct ipt_get_entries __user *uptr, int *len)
1077 struct ipt_get_entries get;
1078 struct ipt_table *t;
1080 if (*len < sizeof(get)) {
1081 duprintf("get_entries: %u < %d\n", *len,
1082 (unsigned int)sizeof(get));
1085 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1087 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1088 duprintf("get_entries: %u != %u\n", *len,
1089 (unsigned int)(sizeof(struct ipt_get_entries) +
1094 t = xt_find_table_lock(AF_INET, get.name);
1095 if (t && !IS_ERR(t)) {
1096 struct xt_table_info *private = t->private;
1097 duprintf("t->private->number = %u\n",
1099 if (get.size == private->size)
1100 ret = copy_entries_to_user(private->size,
1101 t, uptr->entrytable);
1103 duprintf("get_entries: I've got %u not %u!\n",
1111 ret = t ? PTR_ERR(t) : -ENOENT;
1117 __do_replace(const char *name, unsigned int valid_hooks,
1118 struct xt_table_info *newinfo, unsigned int num_counters,
1119 void __user *counters_ptr)
1122 struct ipt_table *t;
1123 struct xt_table_info *oldinfo;
1124 struct xt_counters *counters;
1125 void *loc_cpu_old_entry;
1128 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1134 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1135 "iptable_%s", name);
1136 if (!t || IS_ERR(t)) {
1137 ret = t ? PTR_ERR(t) : -ENOENT;
1138 goto free_newinfo_counters_untrans;
1142 if (valid_hooks != t->valid_hooks) {
1143 duprintf("Valid hook crap: %08X vs %08X\n",
1144 valid_hooks, t->valid_hooks);
1149 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1153 /* Update module usage count based on number of rules */
1154 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1155 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1156 if ((oldinfo->number > oldinfo->initial_entries) ||
1157 (newinfo->number <= oldinfo->initial_entries))
1159 if ((oldinfo->number > oldinfo->initial_entries) &&
1160 (newinfo->number <= oldinfo->initial_entries))
1163 /* Get the old counters. */
1164 get_counters(oldinfo, counters);
1165 /* Decrease module usage counts and free resource */
1166 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1167 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1168 xt_free_table_info(oldinfo);
1169 if (copy_to_user(counters_ptr, counters,
1170 sizeof(struct xt_counters) * num_counters) != 0)
1179 free_newinfo_counters_untrans:
1186 do_replace(void __user *user, unsigned int len)
1189 struct ipt_replace tmp;
1190 struct xt_table_info *newinfo;
1191 void *loc_cpu_entry;
1193 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1196 /* Hack: Causes ipchains to give correct error msg --RR */
1197 if (len != sizeof(tmp) + tmp.size)
1198 return -ENOPROTOOPT;
1200 /* overflow check */
1201 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1204 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1207 newinfo = xt_alloc_table_info(tmp.size);
1211 /* choose the copy that is our node/cpu */
1212 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1213 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1219 ret = translate_table(tmp.name, tmp.valid_hooks,
1220 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1221 tmp.hook_entry, tmp.underflow);
1225 duprintf("ip_tables: Translated table\n");
1227 ret = __do_replace(tmp.name, tmp.valid_hooks,
1228 newinfo, tmp.num_counters,
1231 goto free_newinfo_untrans;
1234 free_newinfo_untrans:
1235 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1237 xt_free_table_info(newinfo);
1241 /* We're lazy, and add to the first CPU; overflow works its fey magic
1242 * and everything is OK. */
1244 add_counter_to_entry(struct ipt_entry *e,
1245 const struct xt_counters addme[],
1249 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1251 (long unsigned int)e->counters.pcnt,
1252 (long unsigned int)e->counters.bcnt,
1253 (long unsigned int)addme[*i].pcnt,
1254 (long unsigned int)addme[*i].bcnt);
1257 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1264 do_add_counters(void __user *user, unsigned int len, int compat)
1267 struct xt_counters_info tmp;
1268 struct xt_counters *paddc;
1269 unsigned int num_counters;
1273 struct ipt_table *t;
1274 struct xt_table_info *private;
1276 void *loc_cpu_entry;
1277 #ifdef CONFIG_COMPAT
1278 struct compat_xt_counters_info compat_tmp;
1282 size = sizeof(struct compat_xt_counters_info);
1287 size = sizeof(struct xt_counters_info);
1290 if (copy_from_user(ptmp, user, size) != 0)
1293 #ifdef CONFIG_COMPAT
1295 num_counters = compat_tmp.num_counters;
1296 name = compat_tmp.name;
1300 num_counters = tmp.num_counters;
1304 if (len != size + num_counters * sizeof(struct xt_counters))
1307 paddc = vmalloc_node(len - size, numa_node_id());
1311 if (copy_from_user(paddc, user + size, len - size) != 0) {
1316 t = xt_find_table_lock(AF_INET, name);
1317 if (!t || IS_ERR(t)) {
1318 ret = t ? PTR_ERR(t) : -ENOENT;
1322 write_lock_bh(&t->lock);
1323 private = t->private;
1324 if (private->number != num_counters) {
1326 goto unlock_up_free;
1330 /* Choose the copy that is on our node */
1331 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1332 IPT_ENTRY_ITERATE(loc_cpu_entry,
1334 add_counter_to_entry,
1338 write_unlock_bh(&t->lock);
1347 #ifdef CONFIG_COMPAT
1348 struct compat_ipt_replace {
1349 char name[IPT_TABLE_MAXNAMELEN];
1353 u32 hook_entry[NF_IP_NUMHOOKS];
1354 u32 underflow[NF_IP_NUMHOOKS];
1356 compat_uptr_t counters; /* struct ipt_counters * */
1357 struct compat_ipt_entry entries[0];
1360 static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1361 void __user **dstptr, compat_uint_t *size)
1363 return xt_compat_match_to_user(m, dstptr, size);
1366 static int compat_copy_entry_to_user(struct ipt_entry *e,
1367 void __user **dstptr, compat_uint_t *size)
1369 struct ipt_entry_target *t;
1370 struct compat_ipt_entry __user *ce;
1371 u_int16_t target_offset, next_offset;
1372 compat_uint_t origsize;
1377 ce = (struct compat_ipt_entry __user *)*dstptr;
1378 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1381 *dstptr += sizeof(struct compat_ipt_entry);
1382 ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1383 target_offset = e->target_offset - (origsize - *size);
1386 t = ipt_get_target(e);
1387 ret = xt_compat_target_to_user(t, dstptr, size);
1391 next_offset = e->next_offset - (origsize - *size);
1392 if (put_user(target_offset, &ce->target_offset))
1394 if (put_user(next_offset, &ce->next_offset))
1402 compat_check_calc_match(struct ipt_entry_match *m,
1404 const struct ipt_ip *ip,
1405 unsigned int hookmask,
1408 struct ipt_match *match;
1410 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1411 m->u.user.revision),
1412 "ipt_%s", m->u.user.name);
1413 if (IS_ERR(match) || !match) {
1414 duprintf("compat_check_calc_match: `%s' not found\n",
1416 return match ? PTR_ERR(match) : -ENOENT;
1418 m->u.kernel.match = match;
1419 *size += xt_compat_match_offset(match);
1426 check_compat_entry_size_and_hooks(struct ipt_entry *e,
1427 struct xt_table_info *newinfo,
1429 unsigned char *base,
1430 unsigned char *limit,
1431 unsigned int *hook_entries,
1432 unsigned int *underflows,
1436 struct ipt_entry_target *t;
1437 struct ipt_target *target;
1438 u_int16_t entry_offset;
1441 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1442 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1443 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1444 duprintf("Bad offset %p, limit = %p\n", e, limit);
1448 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1449 sizeof(struct compat_xt_entry_target)) {
1450 duprintf("checking: element %p size %u\n",
1455 if (!ip_checkentry(&e->ip)) {
1456 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
1460 if (e->target_offset + sizeof(struct compat_xt_entry_target) >
1465 entry_offset = (void *)e - (void *)base;
1467 ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
1468 e->comefrom, &off, &j);
1470 goto cleanup_matches;
1472 t = ipt_get_target(e);
1474 if (e->target_offset + t->u.target_size > e->next_offset)
1475 goto cleanup_matches;
1476 target = try_then_request_module(xt_find_target(AF_INET,
1478 t->u.user.revision),
1479 "ipt_%s", t->u.user.name);
1480 if (IS_ERR(target) || !target) {
1481 duprintf("check_entry: `%s' not found\n", t->u.user.name);
1482 ret = target ? PTR_ERR(target) : -ENOENT;
1483 goto cleanup_matches;
1485 t->u.kernel.target = target;
1487 off += xt_compat_target_offset(target);
1489 ret = compat_add_offset(entry_offset, off);
1493 /* Check hooks & underflows */
1494 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1495 if ((unsigned char *)e - base == hook_entries[h])
1496 newinfo->hook_entry[h] = hook_entries[h];
1497 if ((unsigned char *)e - base == underflows[h])
1498 newinfo->underflow[h] = underflows[h];
1501 /* Clear counters and comefrom */
1502 e->counters = ((struct ipt_counters) { 0, 0 });
1509 module_put(t->u.kernel.target->me);
1511 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1515 static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1516 void **dstptr, compat_uint_t *size, const char *name,
1517 const struct ipt_ip *ip, unsigned int hookmask)
1519 xt_compat_match_from_user(m, dstptr, size);
1523 static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1524 unsigned int *size, const char *name,
1525 struct xt_table_info *newinfo, unsigned char *base)
1527 struct ipt_entry_target *t;
1528 struct ipt_target *target;
1529 struct ipt_entry *de;
1530 unsigned int origsize;
1535 de = (struct ipt_entry *)*dstptr;
1536 memcpy(de, e, sizeof(struct ipt_entry));
1538 *dstptr += sizeof(struct compat_ipt_entry);
1539 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1540 name, &de->ip, de->comefrom);
1543 de->target_offset = e->target_offset - (origsize - *size);
1544 t = ipt_get_target(e);
1545 target = t->u.kernel.target;
1546 xt_compat_target_from_user(t, dstptr, size);
1548 de->next_offset = e->next_offset - (origsize - *size);
1549 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1550 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1551 newinfo->hook_entry[h] -= origsize - *size;
1552 if ((unsigned char *)de - base < newinfo->underflow[h])
1553 newinfo->underflow[h] -= origsize - *size;
1558 static inline int compat_check_match(struct ipt_entry_match *m, const char *name,
1559 const struct ipt_ip *ip, unsigned int hookmask)
1561 struct ipt_match *match;
1564 match = m->u.kernel.match;
1565 ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
1566 name, hookmask, ip->proto,
1567 ip->invflags & IPT_INV_PROTO);
1568 if (!ret && m->u.kernel.match->checkentry
1569 && !m->u.kernel.match->checkentry(name, ip, match, m->data,
1571 duprintf("ip_tables: compat: check failed for `%s'.\n",
1572 m->u.kernel.match->name);
1578 static inline int compat_check_target(struct ipt_entry *e, const char *name)
1580 struct ipt_entry_target *t;
1581 struct ipt_target *target;
1584 t = ipt_get_target(e);
1585 target = t->u.kernel.target;
1586 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
1587 name, e->comefrom, e->ip.proto,
1588 e->ip.invflags & IPT_INV_PROTO);
1589 if (!ret && t->u.kernel.target->checkentry
1590 && !t->u.kernel.target->checkentry(name, e, target,
1591 t->data, e->comefrom)) {
1592 duprintf("ip_tables: compat: check failed for `%s'.\n",
1593 t->u.kernel.target->name);
1599 static inline int compat_check_entry(struct ipt_entry *e, const char *name)
1603 ret = IPT_MATCH_ITERATE(e, compat_check_match, name, &e->ip,
1608 return compat_check_target(e, name);
1612 translate_compat_table(const char *name,
1613 unsigned int valid_hooks,
1614 struct xt_table_info **pinfo,
1616 unsigned int total_size,
1617 unsigned int number,
1618 unsigned int *hook_entries,
1619 unsigned int *underflows)
1622 struct xt_table_info *newinfo, *info;
1623 void *pos, *entry0, *entry1;
1630 info->number = number;
1632 /* Init all hooks to impossible value. */
1633 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1634 info->hook_entry[i] = 0xFFFFFFFF;
1635 info->underflow[i] = 0xFFFFFFFF;
1638 duprintf("translate_compat_table: size %u\n", info->size);
1640 xt_compat_lock(AF_INET);
1641 /* Walk through entries, checking offsets. */
1642 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1643 check_compat_entry_size_and_hooks,
1644 info, &size, entry0,
1645 entry0 + total_size,
1646 hook_entries, underflows, &j, name);
1652 duprintf("translate_compat_table: %u not %u entries\n",
1657 /* Check hooks all assigned */
1658 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1659 /* Only hooks which are valid */
1660 if (!(valid_hooks & (1 << i)))
1662 if (info->hook_entry[i] == 0xFFFFFFFF) {
1663 duprintf("Invalid hook entry %u %u\n",
1664 i, hook_entries[i]);
1667 if (info->underflow[i] == 0xFFFFFFFF) {
1668 duprintf("Invalid underflow %u %u\n",
1675 newinfo = xt_alloc_table_info(size);
1679 newinfo->number = number;
1680 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1681 newinfo->hook_entry[i] = info->hook_entry[i];
1682 newinfo->underflow[i] = info->underflow[i];
1684 entry1 = newinfo->entries[raw_smp_processor_id()];
1687 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1688 compat_copy_entry_from_user, &pos, &size,
1689 name, newinfo, entry1);
1690 compat_flush_offsets();
1691 xt_compat_unlock(AF_INET);
1696 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1699 ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1704 /* And one copy for every other CPU */
1705 for_each_possible_cpu(i)
1706 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1707 memcpy(newinfo->entries[i], entry1, newinfo->size);
1711 xt_free_table_info(info);
1715 xt_free_table_info(newinfo);
1717 IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
1720 compat_flush_offsets();
1721 xt_compat_unlock(AF_INET);
1726 compat_do_replace(void __user *user, unsigned int len)
1729 struct compat_ipt_replace tmp;
1730 struct xt_table_info *newinfo;
1731 void *loc_cpu_entry;
1733 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1736 /* Hack: Causes ipchains to give correct error msg --RR */
1737 if (len != sizeof(tmp) + tmp.size)
1738 return -ENOPROTOOPT;
1740 /* overflow check */
1741 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1744 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1747 newinfo = xt_alloc_table_info(tmp.size);
1751 /* choose the copy that is our node/cpu */
1752 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1753 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1759 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1760 &newinfo, &loc_cpu_entry, tmp.size,
1761 tmp.num_entries, tmp.hook_entry, tmp.underflow);
1765 duprintf("compat_do_replace: Translated table\n");
1767 ret = __do_replace(tmp.name, tmp.valid_hooks,
1768 newinfo, tmp.num_counters,
1769 compat_ptr(tmp.counters));
1771 goto free_newinfo_untrans;
1774 free_newinfo_untrans:
1775 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1777 xt_free_table_info(newinfo);
1782 compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1787 if (!capable(CAP_NET_ADMIN))
1791 case IPT_SO_SET_REPLACE:
1792 ret = compat_do_replace(user, len);
1795 case IPT_SO_SET_ADD_COUNTERS:
1796 ret = do_add_counters(user, len, 1);
1800 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1807 struct compat_ipt_get_entries
1809 char name[IPT_TABLE_MAXNAMELEN];
1811 struct compat_ipt_entry entrytable[0];
1814 static int compat_copy_entries_to_user(unsigned int total_size,
1815 struct ipt_table *table, void __user *userptr)
1817 unsigned int off, num;
1818 struct compat_ipt_entry e;
1819 struct xt_counters *counters;
1820 struct xt_table_info *private = table->private;
1824 void *loc_cpu_entry;
1826 counters = alloc_counters(table);
1827 if (IS_ERR(counters))
1828 return PTR_ERR(counters);
1830 /* choose the copy that is on our node/cpu, ...
1831 * This choice is lazy (because current thread is
1832 * allowed to migrate to another cpu)
1834 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1837 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1838 compat_copy_entry_to_user, &pos, &size);
1842 /* ... then go back and fix counters and names */
1843 for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
1845 struct ipt_entry_match m;
1846 struct ipt_entry_target t;
1849 if (copy_from_user(&e, userptr + off,
1850 sizeof(struct compat_ipt_entry)))
1852 if (copy_to_user(userptr + off +
1853 offsetof(struct compat_ipt_entry, counters),
1854 &counters[num], sizeof(counters[num])))
1857 for (i = sizeof(struct compat_ipt_entry);
1858 i < e.target_offset; i += m.u.match_size) {
1859 if (copy_from_user(&m, userptr + off + i,
1860 sizeof(struct ipt_entry_match)))
1862 if (copy_to_user(userptr + off + i +
1863 offsetof(struct ipt_entry_match, u.user.name),
1864 m.u.kernel.match->name,
1865 strlen(m.u.kernel.match->name) + 1))
1869 if (copy_from_user(&t, userptr + off + e.target_offset,
1870 sizeof(struct ipt_entry_target)))
1872 if (copy_to_user(userptr + off + e.target_offset +
1873 offsetof(struct ipt_entry_target, u.user.name),
1874 t.u.kernel.target->name,
1875 strlen(t.u.kernel.target->name) + 1))
1885 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1888 struct compat_ipt_get_entries get;
1889 struct ipt_table *t;
1892 if (*len < sizeof(get)) {
1893 duprintf("compat_get_entries: %u < %u\n",
1894 *len, (unsigned int)sizeof(get));
1898 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1901 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1902 duprintf("compat_get_entries: %u != %u\n", *len,
1903 (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1908 xt_compat_lock(AF_INET);
1909 t = xt_find_table_lock(AF_INET, get.name);
1910 if (t && !IS_ERR(t)) {
1911 struct xt_table_info *private = t->private;
1912 struct xt_table_info info;
1913 duprintf("t->private->number = %u\n",
1915 ret = compat_table_info(private, &info);
1916 if (!ret && get.size == info.size) {
1917 ret = compat_copy_entries_to_user(private->size,
1918 t, uptr->entrytable);
1920 duprintf("compat_get_entries: I've got %u not %u!\n",
1925 compat_flush_offsets();
1929 ret = t ? PTR_ERR(t) : -ENOENT;
1931 xt_compat_unlock(AF_INET);
1935 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1938 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1942 if (!capable(CAP_NET_ADMIN))
1946 case IPT_SO_GET_INFO:
1947 ret = get_info(user, len, 1);
1949 case IPT_SO_GET_ENTRIES:
1950 ret = compat_get_entries(user, len);
1953 ret = do_ipt_get_ctl(sk, cmd, user, len);
1960 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1964 if (!capable(CAP_NET_ADMIN))
1968 case IPT_SO_SET_REPLACE:
1969 ret = do_replace(user, len);
1972 case IPT_SO_SET_ADD_COUNTERS:
1973 ret = do_add_counters(user, len, 0);
1977 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1985 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1989 if (!capable(CAP_NET_ADMIN))
1993 case IPT_SO_GET_INFO:
1994 ret = get_info(user, len, 0);
1997 case IPT_SO_GET_ENTRIES:
1998 ret = get_entries(user, len);
2001 case IPT_SO_GET_REVISION_MATCH:
2002 case IPT_SO_GET_REVISION_TARGET: {
2003 struct ipt_get_revision rev;
2006 if (*len != sizeof(rev)) {
2010 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2015 if (cmd == IPT_SO_GET_REVISION_TARGET)
2020 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2023 "ipt_%s", rev.name);
2028 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2035 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2038 struct xt_table_info *newinfo;
2039 static struct xt_table_info bootstrap
2040 = { 0, 0, 0, { 0 }, { 0 }, { } };
2041 void *loc_cpu_entry;
2043 newinfo = xt_alloc_table_info(repl->size);
2047 /* choose the copy on our node/cpu
2048 * but dont care of preemption
2050 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2051 memcpy(loc_cpu_entry, repl->entries, repl->size);
2053 ret = translate_table(table->name, table->valid_hooks,
2054 newinfo, loc_cpu_entry, repl->size,
2059 xt_free_table_info(newinfo);
2063 ret = xt_register_table(table, &bootstrap, newinfo);
2065 xt_free_table_info(newinfo);
2072 void ipt_unregister_table(struct ipt_table *table)
2074 struct xt_table_info *private;
2075 void *loc_cpu_entry;
2077 private = xt_unregister_table(table);
2079 /* Decrease module usage counts and free resources */
2080 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2081 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2082 xt_free_table_info(private);
2085 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2087 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2088 u_int8_t type, u_int8_t code,
2091 return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2096 icmp_match(const struct sk_buff *skb,
2097 const struct net_device *in,
2098 const struct net_device *out,
2099 const struct xt_match *match,
2100 const void *matchinfo,
2102 unsigned int protoff,
2105 struct icmphdr _icmph, *ic;
2106 const struct ipt_icmp *icmpinfo = matchinfo;
2108 /* Must not be a fragment. */
2112 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2114 /* We've been asked to examine this packet, and we
2115 * can't. Hence, no choice but to drop.
2117 duprintf("Dropping evil ICMP tinygram.\n");
2122 return icmp_type_code_match(icmpinfo->type,
2126 !!(icmpinfo->invflags&IPT_ICMP_INV));
2129 /* Called when user tries to insert an entry of this type. */
2131 icmp_checkentry(const char *tablename,
2133 const struct xt_match *match,
2135 unsigned int hook_mask)
2137 const struct ipt_icmp *icmpinfo = matchinfo;
2139 /* Must specify no unknown invflags */
2140 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2143 /* The built-in targets: standard (NULL) and error. */
2144 static struct ipt_target ipt_standard_target = {
2145 .name = IPT_STANDARD_TARGET,
2146 .targetsize = sizeof(int),
2148 #ifdef CONFIG_COMPAT
2149 .compatsize = sizeof(compat_int_t),
2150 .compat_from_user = compat_standard_from_user,
2151 .compat_to_user = compat_standard_to_user,
2155 static struct ipt_target ipt_error_target = {
2156 .name = IPT_ERROR_TARGET,
2157 .target = ipt_error,
2158 .targetsize = IPT_FUNCTION_MAXNAMELEN,
2162 static struct nf_sockopt_ops ipt_sockopts = {
2164 .set_optmin = IPT_BASE_CTL,
2165 .set_optmax = IPT_SO_SET_MAX+1,
2166 .set = do_ipt_set_ctl,
2167 #ifdef CONFIG_COMPAT
2168 .compat_set = compat_do_ipt_set_ctl,
2170 .get_optmin = IPT_BASE_CTL,
2171 .get_optmax = IPT_SO_GET_MAX+1,
2172 .get = do_ipt_get_ctl,
2173 #ifdef CONFIG_COMPAT
2174 .compat_get = compat_do_ipt_get_ctl,
2178 static struct ipt_match icmp_matchstruct = {
2180 .match = icmp_match,
2181 .matchsize = sizeof(struct ipt_icmp),
2182 .proto = IPPROTO_ICMP,
2184 .checkentry = icmp_checkentry,
2187 static int __init ip_tables_init(void)
2191 ret = xt_proto_init(AF_INET);
2195 /* Noone else will be downing sem now, so we won't sleep */
2196 ret = xt_register_target(&ipt_standard_target);
2199 ret = xt_register_target(&ipt_error_target);
2202 ret = xt_register_match(&icmp_matchstruct);
2206 /* Register setsockopt */
2207 ret = nf_register_sockopt(&ipt_sockopts);
2211 printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2215 xt_unregister_match(&icmp_matchstruct);
2217 xt_unregister_target(&ipt_error_target);
2219 xt_unregister_target(&ipt_standard_target);
2221 xt_proto_fini(AF_INET);
2226 static void __exit ip_tables_fini(void)
2228 nf_unregister_sockopt(&ipt_sockopts);
2230 xt_unregister_match(&icmp_matchstruct);
2231 xt_unregister_target(&ipt_error_target);
2232 xt_unregister_target(&ipt_standard_target);
2234 xt_proto_fini(AF_INET);
2237 EXPORT_SYMBOL(ipt_register_table);
2238 EXPORT_SYMBOL(ipt_unregister_table);
2239 EXPORT_SYMBOL(ipt_do_table);
2240 module_init(ip_tables_init);
2241 module_exit(ip_tables_fini);