diff options
author | David S. Miller <davem@davemloft.net> | 2009-03-24 16:24:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-24 16:24:36 -0400 |
commit | b5bb14386eabcb4229ade2bc0a2b237ca166d37d (patch) | |
tree | 1966e65479f0d12cec0a204443a95b8eb57946db /net | |
parent | bb4f92b3a33bfc31f55098da85be44702bea2d16 (diff) | |
parent | 1d45209d89e647e9f27e4afa1f47338df73bc112 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net')
58 files changed, 1555 insertions, 756 deletions
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index 8604dfc1fc3b..c751111440f8 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c | |||
@@ -46,7 +46,6 @@ static struct ebt_table broute_table = | |||
46 | .name = "broute", | 46 | .name = "broute", |
47 | .table = &initial_table, | 47 | .table = &initial_table, |
48 | .valid_hooks = 1 << NF_BR_BROUTING, | 48 | .valid_hooks = 1 << NF_BR_BROUTING, |
49 | .lock = __RW_LOCK_UNLOCKED(broute_table.lock), | ||
50 | .check = check, | 49 | .check = check, |
51 | .me = THIS_MODULE, | 50 | .me = THIS_MODULE, |
52 | }; | 51 | }; |
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index 2b2e8040a9c6..a5eea72938a6 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c | |||
@@ -55,7 +55,6 @@ static struct ebt_table frame_filter = | |||
55 | .name = "filter", | 55 | .name = "filter", |
56 | .table = &initial_table, | 56 | .table = &initial_table, |
57 | .valid_hooks = FILTER_VALID_HOOKS, | 57 | .valid_hooks = FILTER_VALID_HOOKS, |
58 | .lock = __RW_LOCK_UNLOCKED(frame_filter.lock), | ||
59 | .check = check, | 58 | .check = check, |
60 | .me = THIS_MODULE, | 59 | .me = THIS_MODULE, |
61 | }; | 60 | }; |
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index 3fe1ae87e35f..6024c551f9a9 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c | |||
@@ -55,7 +55,6 @@ static struct ebt_table frame_nat = | |||
55 | .name = "nat", | 55 | .name = "nat", |
56 | .table = &initial_table, | 56 | .table = &initial_table, |
57 | .valid_hooks = NAT_VALID_HOOKS, | 57 | .valid_hooks = NAT_VALID_HOOKS, |
58 | .lock = __RW_LOCK_UNLOCKED(frame_nat.lock), | ||
59 | .check = check, | 58 | .check = check, |
60 | .me = THIS_MODULE, | 59 | .me = THIS_MODULE, |
61 | }; | 60 | }; |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 3816e1dc9295..1833bdbf9805 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -31,7 +31,7 @@ config NF_CONNTRACK_PROC_COMPAT | |||
31 | default y | 31 | default y |
32 | help | 32 | help |
33 | This option enables /proc and sysctl compatibility with the old | 33 | This option enables /proc and sysctl compatibility with the old |
34 | layer 3 dependant connection tracking. This is needed to keep | 34 | layer 3 dependent connection tracking. This is needed to keep |
35 | old programs that have not been adapted to the new names working. | 35 | old programs that have not been adapted to the new names working. |
36 | 36 | ||
37 | If unsure, say Y. | 37 | If unsure, say Y. |
@@ -95,11 +95,11 @@ config IP_NF_MATCH_ECN | |||
95 | config IP_NF_MATCH_TTL | 95 | config IP_NF_MATCH_TTL |
96 | tristate '"ttl" match support' | 96 | tristate '"ttl" match support' |
97 | depends on NETFILTER_ADVANCED | 97 | depends on NETFILTER_ADVANCED |
98 | help | 98 | select NETFILTER_XT_MATCH_HL |
99 | This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user | 99 | ---help--- |
100 | to match packets by their TTL value. | 100 | This is a backwards-compat option for the user's convenience |
101 | 101 | (e.g. when running oldconfig). It selects | |
102 | To compile it as a module, choose M here. If unsure, say N. | 102 | CONFIG_NETFILTER_XT_MATCH_HL. |
103 | 103 | ||
104 | # `filter', generic and specific targets | 104 | # `filter', generic and specific targets |
105 | config IP_NF_FILTER | 105 | config IP_NF_FILTER |
@@ -323,19 +323,13 @@ config IP_NF_TARGET_ECN | |||
323 | To compile it as a module, choose M here. If unsure, say N. | 323 | To compile it as a module, choose M here. If unsure, say N. |
324 | 324 | ||
325 | config IP_NF_TARGET_TTL | 325 | config IP_NF_TARGET_TTL |
326 | tristate 'TTL target support' | 326 | tristate '"TTL" target support' |
327 | depends on IP_NF_MANGLE | ||
328 | depends on NETFILTER_ADVANCED | 327 | depends on NETFILTER_ADVANCED |
329 | help | 328 | select NETFILTER_XT_TARGET_HL |
330 | This option adds a `TTL' target, which enables the user to modify | 329 | ---help--- |
331 | the TTL value of the IP header. | 330 | This is a backwards-compat option for the user's convenience |
332 | 331 | (e.g. when running oldconfig). It selects | |
333 | While it is safe to decrement/lower the TTL, this target also enables | 332 | CONFIG_NETFILTER_XT_TARGET_HL. |
334 | functionality to increment and set the TTL value of the IP header to | ||
335 | arbitrary values. This is EXTREMELY DANGEROUS since you can easily | ||
336 | create immortal packets that loop forever on the network. | ||
337 | |||
338 | To compile it as a module, choose M here. If unsure, say N. | ||
339 | 333 | ||
340 | # raw + specific targets | 334 | # raw + specific targets |
341 | config IP_NF_RAW | 335 | config IP_NF_RAW |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 5f9b650d90fc..48111594ee9b 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -51,7 +51,6 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o | |||
51 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o | 51 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o |
52 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o | 52 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o |
53 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o | 53 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o |
54 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o | ||
55 | 54 | ||
56 | # targets | 55 | # targets |
57 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o | 56 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o |
@@ -61,7 +60,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o | |||
61 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o | 60 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o |
62 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o | 61 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o |
63 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o | 62 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o |
64 | obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o | ||
65 | obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o | 63 | obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o |
66 | 64 | ||
67 | # generic ARP tables | 65 | # generic ARP tables |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7ea88b61cb0d..64a7c6ce0b98 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -73,6 +73,36 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, | |||
73 | return (ret != 0); | 73 | return (ret != 0); |
74 | } | 74 | } |
75 | 75 | ||
76 | /* | ||
77 | * Unfortunatly, _b and _mask are not aligned to an int (or long int) | ||
78 | * Some arches dont care, unrolling the loop is a win on them. | ||
79 | */ | ||
80 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | ||
81 | { | ||
82 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | ||
83 | const unsigned long *a = (const unsigned long *)_a; | ||
84 | const unsigned long *b = (const unsigned long *)_b; | ||
85 | const unsigned long *mask = (const unsigned long *)_mask; | ||
86 | unsigned long ret; | ||
87 | |||
88 | ret = (a[0] ^ b[0]) & mask[0]; | ||
89 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
90 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
91 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
92 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
93 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
94 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
95 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
96 | #else | ||
97 | unsigned long ret = 0; | ||
98 | int i; | ||
99 | |||
100 | for (i = 0; i < IFNAMSIZ; i++) | ||
101 | ret |= (_a[i] ^ _b[i]) & _mask[i]; | ||
102 | #endif | ||
103 | return ret; | ||
104 | } | ||
105 | |||
76 | /* Returns whether packet matches rule or not. */ | 106 | /* Returns whether packet matches rule or not. */ |
77 | static inline int arp_packet_match(const struct arphdr *arphdr, | 107 | static inline int arp_packet_match(const struct arphdr *arphdr, |
78 | struct net_device *dev, | 108 | struct net_device *dev, |
@@ -83,7 +113,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, | |||
83 | const char *arpptr = (char *)(arphdr + 1); | 113 | const char *arpptr = (char *)(arphdr + 1); |
84 | const char *src_devaddr, *tgt_devaddr; | 114 | const char *src_devaddr, *tgt_devaddr; |
85 | __be32 src_ipaddr, tgt_ipaddr; | 115 | __be32 src_ipaddr, tgt_ipaddr; |
86 | int i, ret; | 116 | long ret; |
87 | 117 | ||
88 | #define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) | 118 | #define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) |
89 | 119 | ||
@@ -156,10 +186,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, | |||
156 | } | 186 | } |
157 | 187 | ||
158 | /* Look for ifname matches. */ | 188 | /* Look for ifname matches. */ |
159 | for (i = 0, ret = 0; i < IFNAMSIZ; i++) { | 189 | ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask); |
160 | ret |= (indev[i] ^ arpinfo->iniface[i]) | ||
161 | & arpinfo->iniface_mask[i]; | ||
162 | } | ||
163 | 190 | ||
164 | if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { | 191 | if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { |
165 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 192 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -168,10 +195,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, | |||
168 | return 0; | 195 | return 0; |
169 | } | 196 | } |
170 | 197 | ||
171 | for (i = 0, ret = 0; i < IFNAMSIZ; i++) { | 198 | ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask); |
172 | ret |= (outdev[i] ^ arpinfo->outiface[i]) | ||
173 | & arpinfo->outiface_mask[i]; | ||
174 | } | ||
175 | 199 | ||
176 | if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) { | 200 | if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) { |
177 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 201 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
@@ -221,7 +245,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, | |||
221 | const struct net_device *out, | 245 | const struct net_device *out, |
222 | struct xt_table *table) | 246 | struct xt_table *table) |
223 | { | 247 | { |
224 | static const char nulldevname[IFNAMSIZ]; | 248 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); |
225 | unsigned int verdict = NF_DROP; | 249 | unsigned int verdict = NF_DROP; |
226 | const struct arphdr *arp; | 250 | const struct arphdr *arp; |
227 | bool hotdrop = false; | 251 | bool hotdrop = false; |
@@ -237,9 +261,10 @@ unsigned int arpt_do_table(struct sk_buff *skb, | |||
237 | indev = in ? in->name : nulldevname; | 261 | indev = in ? in->name : nulldevname; |
238 | outdev = out ? out->name : nulldevname; | 262 | outdev = out ? out->name : nulldevname; |
239 | 263 | ||
240 | read_lock_bh(&table->lock); | 264 | rcu_read_lock(); |
241 | private = table->private; | 265 | private = rcu_dereference(table->private); |
242 | table_base = (void *)private->entries[smp_processor_id()]; | 266 | table_base = rcu_dereference(private->entries[smp_processor_id()]); |
267 | |||
243 | e = get_entry(table_base, private->hook_entry[hook]); | 268 | e = get_entry(table_base, private->hook_entry[hook]); |
244 | back = get_entry(table_base, private->underflow[hook]); | 269 | back = get_entry(table_base, private->underflow[hook]); |
245 | 270 | ||
@@ -311,7 +336,8 @@ unsigned int arpt_do_table(struct sk_buff *skb, | |||
311 | e = (void *)e + e->next_offset; | 336 | e = (void *)e + e->next_offset; |
312 | } | 337 | } |
313 | } while (!hotdrop); | 338 | } while (!hotdrop); |
314 | read_unlock_bh(&table->lock); | 339 | |
340 | rcu_read_unlock(); | ||
315 | 341 | ||
316 | if (hotdrop) | 342 | if (hotdrop) |
317 | return NF_DROP; | 343 | return NF_DROP; |
@@ -714,11 +740,65 @@ static void get_counters(const struct xt_table_info *t, | |||
714 | } | 740 | } |
715 | } | 741 | } |
716 | 742 | ||
717 | static inline struct xt_counters *alloc_counters(struct xt_table *table) | 743 | |
744 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
745 | * and everything is OK. */ | ||
746 | static int | ||
747 | add_counter_to_entry(struct arpt_entry *e, | ||
748 | const struct xt_counters addme[], | ||
749 | unsigned int *i) | ||
750 | { | ||
751 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
752 | |||
753 | (*i)++; | ||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | /* Take values from counters and add them back onto the current cpu */ | ||
758 | static void put_counters(struct xt_table_info *t, | ||
759 | const struct xt_counters counters[]) | ||
760 | { | ||
761 | unsigned int i, cpu; | ||
762 | |||
763 | local_bh_disable(); | ||
764 | cpu = smp_processor_id(); | ||
765 | i = 0; | ||
766 | ARPT_ENTRY_ITERATE(t->entries[cpu], | ||
767 | t->size, | ||
768 | add_counter_to_entry, | ||
769 | counters, | ||
770 | &i); | ||
771 | local_bh_enable(); | ||
772 | } | ||
773 | |||
774 | static inline int | ||
775 | zero_entry_counter(struct arpt_entry *e, void *arg) | ||
776 | { | ||
777 | e->counters.bcnt = 0; | ||
778 | e->counters.pcnt = 0; | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static void | ||
783 | clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | ||
784 | { | ||
785 | unsigned int cpu; | ||
786 | const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | ||
787 | |||
788 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | ||
789 | for_each_possible_cpu(cpu) { | ||
790 | memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | ||
791 | ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | ||
792 | zero_entry_counter, NULL); | ||
793 | } | ||
794 | } | ||
795 | |||
796 | static struct xt_counters *alloc_counters(struct xt_table *table) | ||
718 | { | 797 | { |
719 | unsigned int countersize; | 798 | unsigned int countersize; |
720 | struct xt_counters *counters; | 799 | struct xt_counters *counters; |
721 | const struct xt_table_info *private = table->private; | 800 | struct xt_table_info *private = table->private; |
801 | struct xt_table_info *info; | ||
722 | 802 | ||
723 | /* We need atomic snapshot of counters: rest doesn't change | 803 | /* We need atomic snapshot of counters: rest doesn't change |
724 | * (other than comefrom, which userspace doesn't care | 804 | * (other than comefrom, which userspace doesn't care |
@@ -728,14 +808,30 @@ static inline struct xt_counters *alloc_counters(struct xt_table *table) | |||
728 | counters = vmalloc_node(countersize, numa_node_id()); | 808 | counters = vmalloc_node(countersize, numa_node_id()); |
729 | 809 | ||
730 | if (counters == NULL) | 810 | if (counters == NULL) |
731 | return ERR_PTR(-ENOMEM); | 811 | goto nomem; |
812 | |||
813 | info = xt_alloc_table_info(private->size); | ||
814 | if (!info) | ||
815 | goto free_counters; | ||
816 | |||
817 | clone_counters(info, private); | ||
818 | |||
819 | mutex_lock(&table->lock); | ||
820 | xt_table_entry_swap_rcu(private, info); | ||
821 | synchronize_net(); /* Wait until smoke has cleared */ | ||
822 | |||
823 | get_counters(info, counters); | ||
824 | put_counters(private, counters); | ||
825 | mutex_unlock(&table->lock); | ||
732 | 826 | ||
733 | /* First, sum counters... */ | 827 | xt_free_table_info(info); |
734 | write_lock_bh(&table->lock); | ||
735 | get_counters(private, counters); | ||
736 | write_unlock_bh(&table->lock); | ||
737 | 828 | ||
738 | return counters; | 829 | return counters; |
830 | |||
831 | free_counters: | ||
832 | vfree(counters); | ||
833 | nomem: | ||
834 | return ERR_PTR(-ENOMEM); | ||
739 | } | 835 | } |
740 | 836 | ||
741 | static int copy_entries_to_user(unsigned int total_size, | 837 | static int copy_entries_to_user(unsigned int total_size, |
@@ -1075,20 +1171,6 @@ static int do_replace(struct net *net, void __user *user, unsigned int len) | |||
1075 | return ret; | 1171 | return ret; |
1076 | } | 1172 | } |
1077 | 1173 | ||
1078 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1079 | * and everything is OK. | ||
1080 | */ | ||
1081 | static inline int add_counter_to_entry(struct arpt_entry *e, | ||
1082 | const struct xt_counters addme[], | ||
1083 | unsigned int *i) | ||
1084 | { | ||
1085 | |||
1086 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1087 | |||
1088 | (*i)++; | ||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | static int do_add_counters(struct net *net, void __user *user, unsigned int len, | 1174 | static int do_add_counters(struct net *net, void __user *user, unsigned int len, |
1093 | int compat) | 1175 | int compat) |
1094 | { | 1176 | { |
@@ -1148,13 +1230,14 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
1148 | goto free; | 1230 | goto free; |
1149 | } | 1231 | } |
1150 | 1232 | ||
1151 | write_lock_bh(&t->lock); | 1233 | mutex_lock(&t->lock); |
1152 | private = t->private; | 1234 | private = t->private; |
1153 | if (private->number != num_counters) { | 1235 | if (private->number != num_counters) { |
1154 | ret = -EINVAL; | 1236 | ret = -EINVAL; |
1155 | goto unlock_up_free; | 1237 | goto unlock_up_free; |
1156 | } | 1238 | } |
1157 | 1239 | ||
1240 | preempt_disable(); | ||
1158 | i = 0; | 1241 | i = 0; |
1159 | /* Choose the copy that is on our node */ | 1242 | /* Choose the copy that is on our node */ |
1160 | loc_cpu_entry = private->entries[smp_processor_id()]; | 1243 | loc_cpu_entry = private->entries[smp_processor_id()]; |
@@ -1163,8 +1246,10 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
1163 | add_counter_to_entry, | 1246 | add_counter_to_entry, |
1164 | paddc, | 1247 | paddc, |
1165 | &i); | 1248 | &i); |
1249 | preempt_enable(); | ||
1166 | unlock_up_free: | 1250 | unlock_up_free: |
1167 | write_unlock_bh(&t->lock); | 1251 | mutex_unlock(&t->lock); |
1252 | |||
1168 | xt_table_unlock(t); | 1253 | xt_table_unlock(t); |
1169 | module_put(t->me); | 1254 | module_put(t->me); |
1170 | free: | 1255 | free: |
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index e091187e864f..6ecfdae7c589 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c | |||
@@ -48,8 +48,6 @@ static struct | |||
48 | static struct xt_table packet_filter = { | 48 | static struct xt_table packet_filter = { |
49 | .name = "filter", | 49 | .name = "filter", |
50 | .valid_hooks = FILTER_VALID_HOOKS, | 50 | .valid_hooks = FILTER_VALID_HOOKS, |
51 | .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), | ||
52 | .private = NULL, | ||
53 | .me = THIS_MODULE, | 51 | .me = THIS_MODULE, |
54 | .af = NFPROTO_ARP, | 52 | .af = NFPROTO_ARP, |
55 | }; | 53 | }; |
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 432ce9d1c11c..5f22c91c6e15 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/proc_fs.h> | 24 | #include <linux/proc_fs.h> |
25 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
26 | #include <linux/security.h> | 26 | #include <linux/security.h> |
27 | #include <linux/net.h> | ||
27 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
28 | #include <net/net_namespace.h> | 29 | #include <net/net_namespace.h> |
29 | #include <net/sock.h> | 30 | #include <net/sock.h> |
@@ -640,6 +641,7 @@ static void __exit ip_queue_fini(void) | |||
640 | MODULE_DESCRIPTION("IPv4 packet queue handler"); | 641 | MODULE_DESCRIPTION("IPv4 packet queue handler"); |
641 | MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); | 642 | MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); |
642 | MODULE_LICENSE("GPL"); | 643 | MODULE_LICENSE("GPL"); |
644 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_FIREWALL); | ||
643 | 645 | ||
644 | module_init(ip_queue_init); | 646 | module_init(ip_queue_init); |
645 | module_exit(ip_queue_fini); | 647 | module_exit(ip_queue_fini); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index ef8b6ca068b2..e5294aec967d 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -74,6 +74,25 @@ do { \ | |||
74 | 74 | ||
75 | Hence the start of any table is given by get_table() below. */ | 75 | Hence the start of any table is given by get_table() below. */ |
76 | 76 | ||
77 | static unsigned long ifname_compare(const char *_a, const char *_b, | ||
78 | const unsigned char *_mask) | ||
79 | { | ||
80 | const unsigned long *a = (const unsigned long *)_a; | ||
81 | const unsigned long *b = (const unsigned long *)_b; | ||
82 | const unsigned long *mask = (const unsigned long *)_mask; | ||
83 | unsigned long ret; | ||
84 | |||
85 | ret = (a[0] ^ b[0]) & mask[0]; | ||
86 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
87 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
88 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
89 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
90 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
91 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
92 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
77 | /* Returns whether matches rule or not. */ | 96 | /* Returns whether matches rule or not. */ |
78 | /* Performance critical - called for every packet */ | 97 | /* Performance critical - called for every packet */ |
79 | static inline bool | 98 | static inline bool |
@@ -83,7 +102,6 @@ ip_packet_match(const struct iphdr *ip, | |||
83 | const struct ipt_ip *ipinfo, | 102 | const struct ipt_ip *ipinfo, |
84 | int isfrag) | 103 | int isfrag) |
85 | { | 104 | { |
86 | size_t i; | ||
87 | unsigned long ret; | 105 | unsigned long ret; |
88 | 106 | ||
89 | #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) | 107 | #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) |
@@ -103,12 +121,7 @@ ip_packet_match(const struct iphdr *ip, | |||
103 | return false; | 121 | return false; |
104 | } | 122 | } |
105 | 123 | ||
106 | /* Look for ifname matches; this should unroll nicely. */ | 124 | ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask); |
107 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | ||
108 | ret |= (((const unsigned long *)indev)[i] | ||
109 | ^ ((const unsigned long *)ipinfo->iniface)[i]) | ||
110 | & ((const unsigned long *)ipinfo->iniface_mask)[i]; | ||
111 | } | ||
112 | 125 | ||
113 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { | 126 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { |
114 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 127 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -117,11 +130,7 @@ ip_packet_match(const struct iphdr *ip, | |||
117 | return false; | 130 | return false; |
118 | } | 131 | } |
119 | 132 | ||
120 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | 133 | ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask); |
121 | ret |= (((const unsigned long *)outdev)[i] | ||
122 | ^ ((const unsigned long *)ipinfo->outiface)[i]) | ||
123 | & ((const unsigned long *)ipinfo->outiface_mask)[i]; | ||
124 | } | ||
125 | 134 | ||
126 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { | 135 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { |
127 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 136 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
@@ -347,10 +356,12 @@ ipt_do_table(struct sk_buff *skb, | |||
347 | mtpar.family = tgpar.family = NFPROTO_IPV4; | 356 | mtpar.family = tgpar.family = NFPROTO_IPV4; |
348 | tgpar.hooknum = hook; | 357 | tgpar.hooknum = hook; |
349 | 358 | ||
350 | read_lock_bh(&table->lock); | ||
351 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); | 359 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
352 | private = table->private; | 360 | |
353 | table_base = (void *)private->entries[smp_processor_id()]; | 361 | rcu_read_lock(); |
362 | private = rcu_dereference(table->private); | ||
363 | table_base = rcu_dereference(private->entries[smp_processor_id()]); | ||
364 | |||
354 | e = get_entry(table_base, private->hook_entry[hook]); | 365 | e = get_entry(table_base, private->hook_entry[hook]); |
355 | 366 | ||
356 | /* For return from builtin chain */ | 367 | /* For return from builtin chain */ |
@@ -445,7 +456,7 @@ ipt_do_table(struct sk_buff *skb, | |||
445 | } | 456 | } |
446 | } while (!hotdrop); | 457 | } while (!hotdrop); |
447 | 458 | ||
448 | read_unlock_bh(&table->lock); | 459 | rcu_read_unlock(); |
449 | 460 | ||
450 | #ifdef DEBUG_ALLOW_ALL | 461 | #ifdef DEBUG_ALLOW_ALL |
451 | return NF_ACCEPT; | 462 | return NF_ACCEPT; |
@@ -924,13 +935,68 @@ get_counters(const struct xt_table_info *t, | |||
924 | counters, | 935 | counters, |
925 | &i); | 936 | &i); |
926 | } | 937 | } |
938 | |||
939 | } | ||
940 | |||
941 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
942 | * and everything is OK. */ | ||
943 | static int | ||
944 | add_counter_to_entry(struct ipt_entry *e, | ||
945 | const struct xt_counters addme[], | ||
946 | unsigned int *i) | ||
947 | { | ||
948 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
949 | |||
950 | (*i)++; | ||
951 | return 0; | ||
952 | } | ||
953 | |||
954 | /* Take values from counters and add them back onto the current cpu */ | ||
955 | static void put_counters(struct xt_table_info *t, | ||
956 | const struct xt_counters counters[]) | ||
957 | { | ||
958 | unsigned int i, cpu; | ||
959 | |||
960 | local_bh_disable(); | ||
961 | cpu = smp_processor_id(); | ||
962 | i = 0; | ||
963 | IPT_ENTRY_ITERATE(t->entries[cpu], | ||
964 | t->size, | ||
965 | add_counter_to_entry, | ||
966 | counters, | ||
967 | &i); | ||
968 | local_bh_enable(); | ||
969 | } | ||
970 | |||
971 | |||
972 | static inline int | ||
973 | zero_entry_counter(struct ipt_entry *e, void *arg) | ||
974 | { | ||
975 | e->counters.bcnt = 0; | ||
976 | e->counters.pcnt = 0; | ||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | static void | ||
981 | clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | ||
982 | { | ||
983 | unsigned int cpu; | ||
984 | const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | ||
985 | |||
986 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | ||
987 | for_each_possible_cpu(cpu) { | ||
988 | memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | ||
989 | IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | ||
990 | zero_entry_counter, NULL); | ||
991 | } | ||
927 | } | 992 | } |
928 | 993 | ||
929 | static struct xt_counters * alloc_counters(struct xt_table *table) | 994 | static struct xt_counters * alloc_counters(struct xt_table *table) |
930 | { | 995 | { |
931 | unsigned int countersize; | 996 | unsigned int countersize; |
932 | struct xt_counters *counters; | 997 | struct xt_counters *counters; |
933 | const struct xt_table_info *private = table->private; | 998 | struct xt_table_info *private = table->private; |
999 | struct xt_table_info *info; | ||
934 | 1000 | ||
935 | /* We need atomic snapshot of counters: rest doesn't change | 1001 | /* We need atomic snapshot of counters: rest doesn't change |
936 | (other than comefrom, which userspace doesn't care | 1002 | (other than comefrom, which userspace doesn't care |
@@ -939,14 +1005,30 @@ static struct xt_counters * alloc_counters(struct xt_table *table) | |||
939 | counters = vmalloc_node(countersize, numa_node_id()); | 1005 | counters = vmalloc_node(countersize, numa_node_id()); |
940 | 1006 | ||
941 | if (counters == NULL) | 1007 | if (counters == NULL) |
942 | return ERR_PTR(-ENOMEM); | 1008 | goto nomem; |
1009 | |||
1010 | info = xt_alloc_table_info(private->size); | ||
1011 | if (!info) | ||
1012 | goto free_counters; | ||
943 | 1013 | ||
944 | /* First, sum counters... */ | 1014 | clone_counters(info, private); |
945 | write_lock_bh(&table->lock); | 1015 | |
946 | get_counters(private, counters); | 1016 | mutex_lock(&table->lock); |
947 | write_unlock_bh(&table->lock); | 1017 | xt_table_entry_swap_rcu(private, info); |
1018 | synchronize_net(); /* Wait until smoke has cleared */ | ||
1019 | |||
1020 | get_counters(info, counters); | ||
1021 | put_counters(private, counters); | ||
1022 | mutex_unlock(&table->lock); | ||
1023 | |||
1024 | xt_free_table_info(info); | ||
948 | 1025 | ||
949 | return counters; | 1026 | return counters; |
1027 | |||
1028 | free_counters: | ||
1029 | vfree(counters); | ||
1030 | nomem: | ||
1031 | return ERR_PTR(-ENOMEM); | ||
950 | } | 1032 | } |
951 | 1033 | ||
952 | static int | 1034 | static int |
@@ -1312,27 +1394,6 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
1312 | return ret; | 1394 | return ret; |
1313 | } | 1395 | } |
1314 | 1396 | ||
1315 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1316 | * and everything is OK. */ | ||
1317 | static int | ||
1318 | add_counter_to_entry(struct ipt_entry *e, | ||
1319 | const struct xt_counters addme[], | ||
1320 | unsigned int *i) | ||
1321 | { | ||
1322 | #if 0 | ||
1323 | duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n", | ||
1324 | *i, | ||
1325 | (long unsigned int)e->counters.pcnt, | ||
1326 | (long unsigned int)e->counters.bcnt, | ||
1327 | (long unsigned int)addme[*i].pcnt, | ||
1328 | (long unsigned int)addme[*i].bcnt); | ||
1329 | #endif | ||
1330 | |||
1331 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1332 | |||
1333 | (*i)++; | ||
1334 | return 0; | ||
1335 | } | ||
1336 | 1397 | ||
1337 | static int | 1398 | static int |
1338 | do_add_counters(struct net *net, void __user *user, unsigned int len, int compat) | 1399 | do_add_counters(struct net *net, void __user *user, unsigned int len, int compat) |
@@ -1393,13 +1454,14 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat | |||
1393 | goto free; | 1454 | goto free; |
1394 | } | 1455 | } |
1395 | 1456 | ||
1396 | write_lock_bh(&t->lock); | 1457 | mutex_lock(&t->lock); |
1397 | private = t->private; | 1458 | private = t->private; |
1398 | if (private->number != num_counters) { | 1459 | if (private->number != num_counters) { |
1399 | ret = -EINVAL; | 1460 | ret = -EINVAL; |
1400 | goto unlock_up_free; | 1461 | goto unlock_up_free; |
1401 | } | 1462 | } |
1402 | 1463 | ||
1464 | preempt_disable(); | ||
1403 | i = 0; | 1465 | i = 0; |
1404 | /* Choose the copy that is on our node */ | 1466 | /* Choose the copy that is on our node */ |
1405 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1467 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
@@ -1408,8 +1470,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat | |||
1408 | add_counter_to_entry, | 1470 | add_counter_to_entry, |
1409 | paddc, | 1471 | paddc, |
1410 | &i); | 1472 | &i); |
1473 | preempt_enable(); | ||
1411 | unlock_up_free: | 1474 | unlock_up_free: |
1412 | write_unlock_bh(&t->lock); | 1475 | mutex_unlock(&t->lock); |
1413 | xt_table_unlock(t); | 1476 | xt_table_unlock(t); |
1414 | module_put(t->me); | 1477 | module_put(t->me); |
1415 | free: | 1478 | free: |
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 27a78fbbd92b..acc44c69eb68 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c | |||
@@ -464,7 +464,7 @@ static struct xt_target log_tg_reg __read_mostly = { | |||
464 | .me = THIS_MODULE, | 464 | .me = THIS_MODULE, |
465 | }; | 465 | }; |
466 | 466 | ||
467 | static const struct nf_logger ipt_log_logger ={ | 467 | static struct nf_logger ipt_log_logger __read_mostly = { |
468 | .name = "ipt_LOG", | 468 | .name = "ipt_LOG", |
469 | .logfn = &ipt_log_packet, | 469 | .logfn = &ipt_log_packet, |
470 | .me = THIS_MODULE, | 470 | .me = THIS_MODULE, |
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c deleted file mode 100644 index 6d76aae90cc0..000000000000 --- a/net/ipv4/netfilter/ipt_TTL.c +++ /dev/null | |||
@@ -1,97 +0,0 @@ | |||
1 | /* TTL modification target for IP tables | ||
2 | * (C) 2000,2005 by Harald Welte <laforge@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | #include <linux/ip.h> | ||
13 | #include <net/checksum.h> | ||
14 | |||
15 | #include <linux/netfilter/x_tables.h> | ||
16 | #include <linux/netfilter_ipv4/ipt_TTL.h> | ||
17 | |||
18 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
19 | MODULE_DESCRIPTION("Xtables: IPv4 TTL field modification target"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | |||
22 | static unsigned int | ||
23 | ttl_tg(struct sk_buff *skb, const struct xt_target_param *par) | ||
24 | { | ||
25 | struct iphdr *iph; | ||
26 | const struct ipt_TTL_info *info = par->targinfo; | ||
27 | int new_ttl; | ||
28 | |||
29 | if (!skb_make_writable(skb, skb->len)) | ||
30 | return NF_DROP; | ||
31 | |||
32 | iph = ip_hdr(skb); | ||
33 | |||
34 | switch (info->mode) { | ||
35 | case IPT_TTL_SET: | ||
36 | new_ttl = info->ttl; | ||
37 | break; | ||
38 | case IPT_TTL_INC: | ||
39 | new_ttl = iph->ttl + info->ttl; | ||
40 | if (new_ttl > 255) | ||
41 | new_ttl = 255; | ||
42 | break; | ||
43 | case IPT_TTL_DEC: | ||
44 | new_ttl = iph->ttl - info->ttl; | ||
45 | if (new_ttl < 0) | ||
46 | new_ttl = 0; | ||
47 | break; | ||
48 | default: | ||
49 | new_ttl = iph->ttl; | ||
50 | break; | ||
51 | } | ||
52 | |||
53 | if (new_ttl != iph->ttl) { | ||
54 | csum_replace2(&iph->check, htons(iph->ttl << 8), | ||
55 | htons(new_ttl << 8)); | ||
56 | iph->ttl = new_ttl; | ||
57 | } | ||
58 | |||
59 | return XT_CONTINUE; | ||
60 | } | ||
61 | |||
62 | static bool ttl_tg_check(const struct xt_tgchk_param *par) | ||
63 | { | ||
64 | const struct ipt_TTL_info *info = par->targinfo; | ||
65 | |||
66 | if (info->mode > IPT_TTL_MAXMODE) { | ||
67 | printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", | ||
68 | info->mode); | ||
69 | return false; | ||
70 | } | ||
71 | if (info->mode != IPT_TTL_SET && info->ttl == 0) | ||
72 | return false; | ||
73 | return true; | ||
74 | } | ||
75 | |||
76 | static struct xt_target ttl_tg_reg __read_mostly = { | ||
77 | .name = "TTL", | ||
78 | .family = NFPROTO_IPV4, | ||
79 | .target = ttl_tg, | ||
80 | .targetsize = sizeof(struct ipt_TTL_info), | ||
81 | .table = "mangle", | ||
82 | .checkentry = ttl_tg_check, | ||
83 | .me = THIS_MODULE, | ||
84 | }; | ||
85 | |||
86 | static int __init ttl_tg_init(void) | ||
87 | { | ||
88 | return xt_register_target(&ttl_tg_reg); | ||
89 | } | ||
90 | |||
91 | static void __exit ttl_tg_exit(void) | ||
92 | { | ||
93 | xt_unregister_target(&ttl_tg_reg); | ||
94 | } | ||
95 | |||
96 | module_init(ttl_tg_init); | ||
97 | module_exit(ttl_tg_exit); | ||
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 18a2826b57c6..d32cc4bb328a 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c | |||
@@ -379,7 +379,7 @@ static struct xt_target ulog_tg_reg __read_mostly = { | |||
379 | .me = THIS_MODULE, | 379 | .me = THIS_MODULE, |
380 | }; | 380 | }; |
381 | 381 | ||
382 | static struct nf_logger ipt_ulog_logger = { | 382 | static struct nf_logger ipt_ulog_logger __read_mostly = { |
383 | .name = "ipt_ULOG", | 383 | .name = "ipt_ULOG", |
384 | .logfn = ipt_logfn, | 384 | .logfn = ipt_logfn, |
385 | .me = THIS_MODULE, | 385 | .me = THIS_MODULE, |
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c deleted file mode 100644 index 297f1cbf4ff5..000000000000 --- a/net/ipv4/netfilter/ipt_ttl.c +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | /* IP tables module for matching the value of the TTL | ||
2 | * | ||
3 | * (C) 2000,2001 by Harald Welte <laforge@netfilter.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/ip.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | |||
14 | #include <linux/netfilter_ipv4/ipt_ttl.h> | ||
15 | #include <linux/netfilter/x_tables.h> | ||
16 | |||
17 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
18 | MODULE_DESCRIPTION("Xtables: IPv4 TTL field match"); | ||
19 | MODULE_LICENSE("GPL"); | ||
20 | |||
21 | static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par) | ||
22 | { | ||
23 | const struct ipt_ttl_info *info = par->matchinfo; | ||
24 | const u8 ttl = ip_hdr(skb)->ttl; | ||
25 | |||
26 | switch (info->mode) { | ||
27 | case IPT_TTL_EQ: | ||
28 | return ttl == info->ttl; | ||
29 | case IPT_TTL_NE: | ||
30 | return ttl != info->ttl; | ||
31 | case IPT_TTL_LT: | ||
32 | return ttl < info->ttl; | ||
33 | case IPT_TTL_GT: | ||
34 | return ttl > info->ttl; | ||
35 | default: | ||
36 | printk(KERN_WARNING "ipt_ttl: unknown mode %d\n", | ||
37 | info->mode); | ||
38 | return false; | ||
39 | } | ||
40 | |||
41 | return false; | ||
42 | } | ||
43 | |||
44 | static struct xt_match ttl_mt_reg __read_mostly = { | ||
45 | .name = "ttl", | ||
46 | .family = NFPROTO_IPV4, | ||
47 | .match = ttl_mt, | ||
48 | .matchsize = sizeof(struct ipt_ttl_info), | ||
49 | .me = THIS_MODULE, | ||
50 | }; | ||
51 | |||
52 | static int __init ttl_mt_init(void) | ||
53 | { | ||
54 | return xt_register_match(&ttl_mt_reg); | ||
55 | } | ||
56 | |||
57 | static void __exit ttl_mt_exit(void) | ||
58 | { | ||
59 | xt_unregister_match(&ttl_mt_reg); | ||
60 | } | ||
61 | |||
62 | module_init(ttl_mt_init); | ||
63 | module_exit(ttl_mt_exit); | ||
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 52cb6939d093..c30a969724f8 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c | |||
@@ -56,7 +56,6 @@ static struct | |||
56 | static struct xt_table packet_filter = { | 56 | static struct xt_table packet_filter = { |
57 | .name = "filter", | 57 | .name = "filter", |
58 | .valid_hooks = FILTER_VALID_HOOKS, | 58 | .valid_hooks = FILTER_VALID_HOOKS, |
59 | .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), | ||
60 | .me = THIS_MODULE, | 59 | .me = THIS_MODULE, |
61 | .af = AF_INET, | 60 | .af = AF_INET, |
62 | }; | 61 | }; |
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 3929d20b9e45..4087614d9519 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c | |||
@@ -67,7 +67,6 @@ static struct | |||
67 | static struct xt_table packet_mangler = { | 67 | static struct xt_table packet_mangler = { |
68 | .name = "mangle", | 68 | .name = "mangle", |
69 | .valid_hooks = MANGLE_VALID_HOOKS, | 69 | .valid_hooks = MANGLE_VALID_HOOKS, |
70 | .lock = __RW_LOCK_UNLOCKED(packet_mangler.lock), | ||
71 | .me = THIS_MODULE, | 70 | .me = THIS_MODULE, |
72 | .af = AF_INET, | 71 | .af = AF_INET, |
73 | }; | 72 | }; |
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 7f65d18333e3..e5356da1fb54 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c | |||
@@ -39,7 +39,6 @@ static struct | |||
39 | static struct xt_table packet_raw = { | 39 | static struct xt_table packet_raw = { |
40 | .name = "raw", | 40 | .name = "raw", |
41 | .valid_hooks = RAW_VALID_HOOKS, | 41 | .valid_hooks = RAW_VALID_HOOKS, |
42 | .lock = __RW_LOCK_UNLOCKED(packet_raw.lock), | ||
43 | .me = THIS_MODULE, | 42 | .me = THIS_MODULE, |
44 | .af = AF_INET, | 43 | .af = AF_INET, |
45 | }; | 44 | }; |
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index a52a35f4a584..29ab630f240a 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c | |||
@@ -60,7 +60,6 @@ static struct | |||
60 | static struct xt_table security_table = { | 60 | static struct xt_table security_table = { |
61 | .name = "security", | 61 | .name = "security", |
62 | .valid_hooks = SECURITY_VALID_HOOKS, | 62 | .valid_hooks = SECURITY_VALID_HOOKS, |
63 | .lock = __RW_LOCK_UNLOCKED(security_table.lock), | ||
64 | .me = THIS_MODULE, | 63 | .me = THIS_MODULE, |
65 | .af = AF_INET, | 64 | .af = AF_INET, |
66 | }; | 65 | }; |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 4beb04fac588..8b681f24e271 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -120,8 +120,10 @@ static unsigned int ipv4_confirm(unsigned int hooknum, | |||
120 | typeof(nf_nat_seq_adjust_hook) seq_adjust; | 120 | typeof(nf_nat_seq_adjust_hook) seq_adjust; |
121 | 121 | ||
122 | seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); | 122 | seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); |
123 | if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) | 123 | if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) { |
124 | NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); | ||
124 | return NF_DROP; | 125 | return NF_DROP; |
126 | } | ||
125 | } | 127 | } |
126 | out: | 128 | out: |
127 | /* We've seen it coming out the other side: confirm it */ | 129 | /* We've seen it coming out the other side: confirm it */ |
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index a7eb04719044..6348a793936e 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c | |||
@@ -61,7 +61,6 @@ static struct | |||
61 | static struct xt_table nat_table = { | 61 | static struct xt_table nat_table = { |
62 | .name = "nat", | 62 | .name = "nat", |
63 | .valid_hooks = NAT_VALID_HOOKS, | 63 | .valid_hooks = NAT_VALID_HOOKS, |
64 | .lock = __RW_LOCK_UNLOCKED(nat_table.lock), | ||
65 | .me = THIS_MODULE, | 64 | .me = THIS_MODULE, |
66 | .af = AF_INET, | 65 | .af = AF_INET, |
67 | }; | 66 | }; |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 53ea512c4608..625353a5fe18 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -95,13 +95,13 @@ config IP6_NF_MATCH_OPTS | |||
95 | To compile it as a module, choose M here. If unsure, say N. | 95 | To compile it as a module, choose M here. If unsure, say N. |
96 | 96 | ||
97 | config IP6_NF_MATCH_HL | 97 | config IP6_NF_MATCH_HL |
98 | tristate '"hl" match support' | 98 | tristate '"hl" hoplimit match support' |
99 | depends on NETFILTER_ADVANCED | 99 | depends on NETFILTER_ADVANCED |
100 | help | 100 | select NETFILTER_XT_MATCH_HL |
101 | HL matching allows you to match packets based on the hop | 101 | ---help--- |
102 | limit of the packet. | 102 | This is a backwards-compat option for the user's convenience |
103 | 103 | (e.g. when running oldconfig). It selects | |
104 | To compile it as a module, choose M here. If unsure, say N. | 104 | COFNIG_NETFILTER_XT_MATCH_HL. |
105 | 105 | ||
106 | config IP6_NF_MATCH_IPV6HEADER | 106 | config IP6_NF_MATCH_IPV6HEADER |
107 | tristate '"ipv6header" IPv6 Extension Headers Match' | 107 | tristate '"ipv6header" IPv6 Extension Headers Match' |
@@ -130,6 +130,15 @@ config IP6_NF_MATCH_RT | |||
130 | To compile it as a module, choose M here. If unsure, say N. | 130 | To compile it as a module, choose M here. If unsure, say N. |
131 | 131 | ||
132 | # The targets | 132 | # The targets |
133 | config IP6_NF_TARGET_HL | ||
134 | tristate '"HL" hoplimit target support' | ||
135 | depends on NETFILTER_ADVANCED | ||
136 | select NETFILTER_XT_TARGET_HL | ||
137 | ---help--- | ||
138 | This is a backwards-compat option for the user's convenience | ||
139 | (e.g. when running oldconfig). It selects | ||
140 | COFNIG_NETFILTER_XT_TARGET_HL. | ||
141 | |||
133 | config IP6_NF_TARGET_LOG | 142 | config IP6_NF_TARGET_LOG |
134 | tristate "LOG target support" | 143 | tristate "LOG target support" |
135 | default m if NETFILTER_ADVANCED=n | 144 | default m if NETFILTER_ADVANCED=n |
@@ -170,23 +179,6 @@ config IP6_NF_MANGLE | |||
170 | 179 | ||
171 | To compile it as a module, choose M here. If unsure, say N. | 180 | To compile it as a module, choose M here. If unsure, say N. |
172 | 181 | ||
173 | config IP6_NF_TARGET_HL | ||
174 | tristate 'HL (hoplimit) target support' | ||
175 | depends on IP6_NF_MANGLE | ||
176 | depends on NETFILTER_ADVANCED | ||
177 | help | ||
178 | This option adds a `HL' target, which enables the user to decrement | ||
179 | the hoplimit value of the IPv6 header or set it to a given (lower) | ||
180 | value. | ||
181 | |||
182 | While it is safe to decrement the hoplimit value, this option also | ||
183 | enables functionality to increment and set the hoplimit value of the | ||
184 | IPv6 header to arbitrary values. This is EXTREMELY DANGEROUS since | ||
185 | you can easily create immortal packets that loop forever on the | ||
186 | network. | ||
187 | |||
188 | To compile it as a module, choose M here. If unsure, say N. | ||
189 | |||
190 | config IP6_NF_RAW | 182 | config IP6_NF_RAW |
191 | tristate 'raw table support (required for TRACE)' | 183 | tristate 'raw table support (required for TRACE)' |
192 | depends on NETFILTER_ADVANCED | 184 | depends on NETFILTER_ADVANCED |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 3f17c948eefb..aafbba30c899 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -20,13 +20,11 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o | |||
20 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 20 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
21 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o | 21 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o |
22 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o | 22 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o |
23 | obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o | ||
24 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o | 23 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o |
25 | obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o | 24 | obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o |
26 | obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o | 25 | obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o |
27 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o | 26 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
28 | 27 | ||
29 | # targets | 28 | # targets |
30 | obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o | ||
31 | obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o | 29 | obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o |
32 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o | 30 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 5859c046cbc4..b693f841aeb4 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -643,6 +643,7 @@ static void __exit ip6_queue_fini(void) | |||
643 | 643 | ||
644 | MODULE_DESCRIPTION("IPv6 packet queue handler"); | 644 | MODULE_DESCRIPTION("IPv6 packet queue handler"); |
645 | MODULE_LICENSE("GPL"); | 645 | MODULE_LICENSE("GPL"); |
646 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_IP6_FW); | ||
646 | 647 | ||
647 | module_init(ip6_queue_init); | 648 | module_init(ip6_queue_init); |
648 | module_exit(ip6_queue_fini); | 649 | module_exit(ip6_queue_fini); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index a33485dc81cb..34af7bb8df5f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -89,6 +89,25 @@ ip6t_ext_hdr(u8 nexthdr) | |||
89 | (nexthdr == IPPROTO_DSTOPTS) ); | 89 | (nexthdr == IPPROTO_DSTOPTS) ); |
90 | } | 90 | } |
91 | 91 | ||
92 | static unsigned long ifname_compare(const char *_a, const char *_b, | ||
93 | const unsigned char *_mask) | ||
94 | { | ||
95 | const unsigned long *a = (const unsigned long *)_a; | ||
96 | const unsigned long *b = (const unsigned long *)_b; | ||
97 | const unsigned long *mask = (const unsigned long *)_mask; | ||
98 | unsigned long ret; | ||
99 | |||
100 | ret = (a[0] ^ b[0]) & mask[0]; | ||
101 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
102 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
103 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
104 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
105 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
106 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
107 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
92 | /* Returns whether matches rule or not. */ | 111 | /* Returns whether matches rule or not. */ |
93 | /* Performance critical - called for every packet */ | 112 | /* Performance critical - called for every packet */ |
94 | static inline bool | 113 | static inline bool |
@@ -99,7 +118,6 @@ ip6_packet_match(const struct sk_buff *skb, | |||
99 | unsigned int *protoff, | 118 | unsigned int *protoff, |
100 | int *fragoff, bool *hotdrop) | 119 | int *fragoff, bool *hotdrop) |
101 | { | 120 | { |
102 | size_t i; | ||
103 | unsigned long ret; | 121 | unsigned long ret; |
104 | const struct ipv6hdr *ipv6 = ipv6_hdr(skb); | 122 | const struct ipv6hdr *ipv6 = ipv6_hdr(skb); |
105 | 123 | ||
@@ -120,12 +138,7 @@ ip6_packet_match(const struct sk_buff *skb, | |||
120 | return false; | 138 | return false; |
121 | } | 139 | } |
122 | 140 | ||
123 | /* Look for ifname matches; this should unroll nicely. */ | 141 | ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask); |
124 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | ||
125 | ret |= (((const unsigned long *)indev)[i] | ||
126 | ^ ((const unsigned long *)ip6info->iniface)[i]) | ||
127 | & ((const unsigned long *)ip6info->iniface_mask)[i]; | ||
128 | } | ||
129 | 142 | ||
130 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { | 143 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { |
131 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 144 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -134,11 +147,7 @@ ip6_packet_match(const struct sk_buff *skb, | |||
134 | return false; | 147 | return false; |
135 | } | 148 | } |
136 | 149 | ||
137 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | 150 | ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask); |
138 | ret |= (((const unsigned long *)outdev)[i] | ||
139 | ^ ((const unsigned long *)ip6info->outiface)[i]) | ||
140 | & ((const unsigned long *)ip6info->outiface_mask)[i]; | ||
141 | } | ||
142 | 151 | ||
143 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { | 152 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { |
144 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 153 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
@@ -373,10 +382,12 @@ ip6t_do_table(struct sk_buff *skb, | |||
373 | mtpar.family = tgpar.family = NFPROTO_IPV6; | 382 | mtpar.family = tgpar.family = NFPROTO_IPV6; |
374 | tgpar.hooknum = hook; | 383 | tgpar.hooknum = hook; |
375 | 384 | ||
376 | read_lock_bh(&table->lock); | ||
377 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); | 385 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
378 | private = table->private; | 386 | |
379 | table_base = (void *)private->entries[smp_processor_id()]; | 387 | rcu_read_lock(); |
388 | private = rcu_dereference(table->private); | ||
389 | table_base = rcu_dereference(private->entries[smp_processor_id()]); | ||
390 | |||
380 | e = get_entry(table_base, private->hook_entry[hook]); | 391 | e = get_entry(table_base, private->hook_entry[hook]); |
381 | 392 | ||
382 | /* For return from builtin chain */ | 393 | /* For return from builtin chain */ |
@@ -474,7 +485,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
474 | #ifdef CONFIG_NETFILTER_DEBUG | 485 | #ifdef CONFIG_NETFILTER_DEBUG |
475 | ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; | 486 | ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; |
476 | #endif | 487 | #endif |
477 | read_unlock_bh(&table->lock); | 488 | rcu_read_unlock(); |
478 | 489 | ||
479 | #ifdef DEBUG_ALLOW_ALL | 490 | #ifdef DEBUG_ALLOW_ALL |
480 | return NF_ACCEPT; | 491 | return NF_ACCEPT; |
@@ -955,11 +966,64 @@ get_counters(const struct xt_table_info *t, | |||
955 | } | 966 | } |
956 | } | 967 | } |
957 | 968 | ||
969 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
970 | * and everything is OK. */ | ||
971 | static int | ||
972 | add_counter_to_entry(struct ip6t_entry *e, | ||
973 | const struct xt_counters addme[], | ||
974 | unsigned int *i) | ||
975 | { | ||
976 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
977 | |||
978 | (*i)++; | ||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | /* Take values from counters and add them back onto the current cpu */ | ||
983 | static void put_counters(struct xt_table_info *t, | ||
984 | const struct xt_counters counters[]) | ||
985 | { | ||
986 | unsigned int i, cpu; | ||
987 | |||
988 | local_bh_disable(); | ||
989 | cpu = smp_processor_id(); | ||
990 | i = 0; | ||
991 | IP6T_ENTRY_ITERATE(t->entries[cpu], | ||
992 | t->size, | ||
993 | add_counter_to_entry, | ||
994 | counters, | ||
995 | &i); | ||
996 | local_bh_enable(); | ||
997 | } | ||
998 | |||
999 | static inline int | ||
1000 | zero_entry_counter(struct ip6t_entry *e, void *arg) | ||
1001 | { | ||
1002 | e->counters.bcnt = 0; | ||
1003 | e->counters.pcnt = 0; | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | static void | ||
1008 | clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | ||
1009 | { | ||
1010 | unsigned int cpu; | ||
1011 | const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | ||
1012 | |||
1013 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | ||
1014 | for_each_possible_cpu(cpu) { | ||
1015 | memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | ||
1016 | IP6T_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | ||
1017 | zero_entry_counter, NULL); | ||
1018 | } | ||
1019 | } | ||
1020 | |||
958 | static struct xt_counters *alloc_counters(struct xt_table *table) | 1021 | static struct xt_counters *alloc_counters(struct xt_table *table) |
959 | { | 1022 | { |
960 | unsigned int countersize; | 1023 | unsigned int countersize; |
961 | struct xt_counters *counters; | 1024 | struct xt_counters *counters; |
962 | const struct xt_table_info *private = table->private; | 1025 | struct xt_table_info *private = table->private; |
1026 | struct xt_table_info *info; | ||
963 | 1027 | ||
964 | /* We need atomic snapshot of counters: rest doesn't change | 1028 | /* We need atomic snapshot of counters: rest doesn't change |
965 | (other than comefrom, which userspace doesn't care | 1029 | (other than comefrom, which userspace doesn't care |
@@ -968,14 +1032,28 @@ static struct xt_counters *alloc_counters(struct xt_table *table) | |||
968 | counters = vmalloc_node(countersize, numa_node_id()); | 1032 | counters = vmalloc_node(countersize, numa_node_id()); |
969 | 1033 | ||
970 | if (counters == NULL) | 1034 | if (counters == NULL) |
971 | return ERR_PTR(-ENOMEM); | 1035 | goto nomem; |
1036 | |||
1037 | info = xt_alloc_table_info(private->size); | ||
1038 | if (!info) | ||
1039 | goto free_counters; | ||
1040 | |||
1041 | clone_counters(info, private); | ||
972 | 1042 | ||
973 | /* First, sum counters... */ | 1043 | mutex_lock(&table->lock); |
974 | write_lock_bh(&table->lock); | 1044 | xt_table_entry_swap_rcu(private, info); |
975 | get_counters(private, counters); | 1045 | synchronize_net(); /* Wait until smoke has cleared */ |
976 | write_unlock_bh(&table->lock); | ||
977 | 1046 | ||
978 | return counters; | 1047 | get_counters(info, counters); |
1048 | put_counters(private, counters); | ||
1049 | mutex_unlock(&table->lock); | ||
1050 | |||
1051 | xt_free_table_info(info); | ||
1052 | |||
1053 | free_counters: | ||
1054 | vfree(counters); | ||
1055 | nomem: | ||
1056 | return ERR_PTR(-ENOMEM); | ||
979 | } | 1057 | } |
980 | 1058 | ||
981 | static int | 1059 | static int |
@@ -1342,28 +1420,6 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
1342 | return ret; | 1420 | return ret; |
1343 | } | 1421 | } |
1344 | 1422 | ||
1345 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1346 | * and everything is OK. */ | ||
1347 | static inline int | ||
1348 | add_counter_to_entry(struct ip6t_entry *e, | ||
1349 | const struct xt_counters addme[], | ||
1350 | unsigned int *i) | ||
1351 | { | ||
1352 | #if 0 | ||
1353 | duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n", | ||
1354 | *i, | ||
1355 | (long unsigned int)e->counters.pcnt, | ||
1356 | (long unsigned int)e->counters.bcnt, | ||
1357 | (long unsigned int)addme[*i].pcnt, | ||
1358 | (long unsigned int)addme[*i].bcnt); | ||
1359 | #endif | ||
1360 | |||
1361 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1362 | |||
1363 | (*i)++; | ||
1364 | return 0; | ||
1365 | } | ||
1366 | |||
1367 | static int | 1423 | static int |
1368 | do_add_counters(struct net *net, void __user *user, unsigned int len, | 1424 | do_add_counters(struct net *net, void __user *user, unsigned int len, |
1369 | int compat) | 1425 | int compat) |
@@ -1424,13 +1480,14 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
1424 | goto free; | 1480 | goto free; |
1425 | } | 1481 | } |
1426 | 1482 | ||
1427 | write_lock_bh(&t->lock); | 1483 | mutex_lock(&t->lock); |
1428 | private = t->private; | 1484 | private = t->private; |
1429 | if (private->number != num_counters) { | 1485 | if (private->number != num_counters) { |
1430 | ret = -EINVAL; | 1486 | ret = -EINVAL; |
1431 | goto unlock_up_free; | 1487 | goto unlock_up_free; |
1432 | } | 1488 | } |
1433 | 1489 | ||
1490 | preempt_disable(); | ||
1434 | i = 0; | 1491 | i = 0; |
1435 | /* Choose the copy that is on our node */ | 1492 | /* Choose the copy that is on our node */ |
1436 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1493 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
@@ -1439,8 +1496,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
1439 | add_counter_to_entry, | 1496 | add_counter_to_entry, |
1440 | paddc, | 1497 | paddc, |
1441 | &i); | 1498 | &i); |
1499 | preempt_enable(); | ||
1442 | unlock_up_free: | 1500 | unlock_up_free: |
1443 | write_unlock_bh(&t->lock); | 1501 | mutex_unlock(&t->lock); |
1444 | xt_table_unlock(t); | 1502 | xt_table_unlock(t); |
1445 | module_put(t->me); | 1503 | module_put(t->me); |
1446 | free: | 1504 | free: |
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c deleted file mode 100644 index 27b5adf670a2..000000000000 --- a/net/ipv6/netfilter/ip6t_HL.c +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | /* | ||
2 | * Hop Limit modification target for ip6tables | ||
3 | * Maciej Soltysiak <solt@dns.toxicfilms.tv> | ||
4 | * Based on HW's TTL module | ||
5 | * | ||
6 | * This software is distributed under the terms of GNU GPL | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/skbuff.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/ipv6.h> | ||
13 | |||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | #include <linux/netfilter_ipv6/ip6t_HL.h> | ||
16 | |||
17 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | ||
18 | MODULE_DESCRIPTION("Xtables: IPv6 Hop Limit field modification target"); | ||
19 | MODULE_LICENSE("GPL"); | ||
20 | |||
21 | static unsigned int | ||
22 | hl_tg6(struct sk_buff *skb, const struct xt_target_param *par) | ||
23 | { | ||
24 | struct ipv6hdr *ip6h; | ||
25 | const struct ip6t_HL_info *info = par->targinfo; | ||
26 | int new_hl; | ||
27 | |||
28 | if (!skb_make_writable(skb, skb->len)) | ||
29 | return NF_DROP; | ||
30 | |||
31 | ip6h = ipv6_hdr(skb); | ||
32 | |||
33 | switch (info->mode) { | ||
34 | case IP6T_HL_SET: | ||
35 | new_hl = info->hop_limit; | ||
36 | break; | ||
37 | case IP6T_HL_INC: | ||
38 | new_hl = ip6h->hop_limit + info->hop_limit; | ||
39 | if (new_hl > 255) | ||
40 | new_hl = 255; | ||
41 | break; | ||
42 | case IP6T_HL_DEC: | ||
43 | new_hl = ip6h->hop_limit - info->hop_limit; | ||
44 | if (new_hl < 0) | ||
45 | new_hl = 0; | ||
46 | break; | ||
47 | default: | ||
48 | new_hl = ip6h->hop_limit; | ||
49 | break; | ||
50 | } | ||
51 | |||
52 | ip6h->hop_limit = new_hl; | ||
53 | |||
54 | return XT_CONTINUE; | ||
55 | } | ||
56 | |||
57 | static bool hl_tg6_check(const struct xt_tgchk_param *par) | ||
58 | { | ||
59 | const struct ip6t_HL_info *info = par->targinfo; | ||
60 | |||
61 | if (info->mode > IP6T_HL_MAXMODE) { | ||
62 | printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", | ||
63 | info->mode); | ||
64 | return false; | ||
65 | } | ||
66 | if (info->mode != IP6T_HL_SET && info->hop_limit == 0) { | ||
67 | printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " | ||
68 | "make sense with value 0\n"); | ||
69 | return false; | ||
70 | } | ||
71 | return true; | ||
72 | } | ||
73 | |||
74 | static struct xt_target hl_tg6_reg __read_mostly = { | ||
75 | .name = "HL", | ||
76 | .family = NFPROTO_IPV6, | ||
77 | .target = hl_tg6, | ||
78 | .targetsize = sizeof(struct ip6t_HL_info), | ||
79 | .table = "mangle", | ||
80 | .checkentry = hl_tg6_check, | ||
81 | .me = THIS_MODULE | ||
82 | }; | ||
83 | |||
84 | static int __init hl_tg6_init(void) | ||
85 | { | ||
86 | return xt_register_target(&hl_tg6_reg); | ||
87 | } | ||
88 | |||
89 | static void __exit hl_tg6_exit(void) | ||
90 | { | ||
91 | xt_unregister_target(&hl_tg6_reg); | ||
92 | } | ||
93 | |||
94 | module_init(hl_tg6_init); | ||
95 | module_exit(hl_tg6_exit); | ||
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 37adf5abc51e..7018cac4fddc 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -477,7 +477,7 @@ static struct xt_target log_tg6_reg __read_mostly = { | |||
477 | .me = THIS_MODULE, | 477 | .me = THIS_MODULE, |
478 | }; | 478 | }; |
479 | 479 | ||
480 | static const struct nf_logger ip6t_logger = { | 480 | static struct nf_logger ip6t_logger __read_mostly = { |
481 | .name = "ip6t_LOG", | 481 | .name = "ip6t_LOG", |
482 | .logfn = &ip6t_log_packet, | 482 | .logfn = &ip6t_log_packet, |
483 | .me = THIS_MODULE, | 483 | .me = THIS_MODULE, |
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c deleted file mode 100644 index c964dca1132d..000000000000 --- a/net/ipv6/netfilter/ip6t_hl.c +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | /* Hop Limit matching module */ | ||
2 | |||
3 | /* (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv> | ||
4 | * Based on HW's ttl module | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ipv6.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | |||
15 | #include <linux/netfilter_ipv6/ip6t_hl.h> | ||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | |||
18 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | ||
19 | MODULE_DESCRIPTION("Xtables: IPv6 Hop Limit field match"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | |||
22 | static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | ||
23 | { | ||
24 | const struct ip6t_hl_info *info = par->matchinfo; | ||
25 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
26 | |||
27 | switch (info->mode) { | ||
28 | case IP6T_HL_EQ: | ||
29 | return ip6h->hop_limit == info->hop_limit; | ||
30 | break; | ||
31 | case IP6T_HL_NE: | ||
32 | return ip6h->hop_limit != info->hop_limit; | ||
33 | break; | ||
34 | case IP6T_HL_LT: | ||
35 | return ip6h->hop_limit < info->hop_limit; | ||
36 | break; | ||
37 | case IP6T_HL_GT: | ||
38 | return ip6h->hop_limit > info->hop_limit; | ||
39 | break; | ||
40 | default: | ||
41 | printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", | ||
42 | info->mode); | ||
43 | return false; | ||
44 | } | ||
45 | |||
46 | return false; | ||
47 | } | ||
48 | |||
49 | static struct xt_match hl_mt6_reg __read_mostly = { | ||
50 | .name = "hl", | ||
51 | .family = NFPROTO_IPV6, | ||
52 | .match = hl_mt6, | ||
53 | .matchsize = sizeof(struct ip6t_hl_info), | ||
54 | .me = THIS_MODULE, | ||
55 | }; | ||
56 | |||
57 | static int __init hl_mt6_init(void) | ||
58 | { | ||
59 | return xt_register_match(&hl_mt6_reg); | ||
60 | } | ||
61 | |||
62 | static void __exit hl_mt6_exit(void) | ||
63 | { | ||
64 | xt_unregister_match(&hl_mt6_reg); | ||
65 | } | ||
66 | |||
67 | module_init(hl_mt6_init); | ||
68 | module_exit(hl_mt6_exit); | ||
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 40d2e36d8fac..ef5a0a32bf8e 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -54,7 +54,6 @@ static struct | |||
54 | static struct xt_table packet_filter = { | 54 | static struct xt_table packet_filter = { |
55 | .name = "filter", | 55 | .name = "filter", |
56 | .valid_hooks = FILTER_VALID_HOOKS, | 56 | .valid_hooks = FILTER_VALID_HOOKS, |
57 | .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), | ||
58 | .me = THIS_MODULE, | 57 | .me = THIS_MODULE, |
59 | .af = AF_INET6, | 58 | .af = AF_INET6, |
60 | }; | 59 | }; |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index d0b31b259d4d..ab0d398a2ba7 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -60,7 +60,6 @@ static struct | |||
60 | static struct xt_table packet_mangler = { | 60 | static struct xt_table packet_mangler = { |
61 | .name = "mangle", | 61 | .name = "mangle", |
62 | .valid_hooks = MANGLE_VALID_HOOKS, | 62 | .valid_hooks = MANGLE_VALID_HOOKS, |
63 | .lock = __RW_LOCK_UNLOCKED(packet_mangler.lock), | ||
64 | .me = THIS_MODULE, | 63 | .me = THIS_MODULE, |
65 | .af = AF_INET6, | 64 | .af = AF_INET6, |
66 | }; | 65 | }; |
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 109fab6f831a..4b792b6ca321 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -38,7 +38,6 @@ static struct | |||
38 | static struct xt_table packet_raw = { | 38 | static struct xt_table packet_raw = { |
39 | .name = "raw", | 39 | .name = "raw", |
40 | .valid_hooks = RAW_VALID_HOOKS, | 40 | .valid_hooks = RAW_VALID_HOOKS, |
41 | .lock = __RW_LOCK_UNLOCKED(packet_raw.lock), | ||
42 | .me = THIS_MODULE, | 41 | .me = THIS_MODULE, |
43 | .af = AF_INET6, | 42 | .af = AF_INET6, |
44 | }; | 43 | }; |
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 20bc52f13e43..0ea37ff15d56 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c | |||
@@ -59,7 +59,6 @@ static struct | |||
59 | static struct xt_table security_table = { | 59 | static struct xt_table security_table = { |
60 | .name = "security", | 60 | .name = "security", |
61 | .valid_hooks = SECURITY_VALID_HOOKS, | 61 | .valid_hooks = SECURITY_VALID_HOOKS, |
62 | .lock = __RW_LOCK_UNLOCKED(security_table.lock), | ||
63 | .me = THIS_MODULE, | 62 | .me = THIS_MODULE, |
64 | .af = AF_INET6, | 63 | .af = AF_INET6, |
65 | }; | 64 | }; |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 727b9530448a..e6852f617217 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <net/netfilter/nf_conntrack_l4proto.h> | 26 | #include <net/netfilter/nf_conntrack_l4proto.h> |
27 | #include <net/netfilter/nf_conntrack_l3proto.h> | 27 | #include <net/netfilter/nf_conntrack_l3proto.h> |
28 | #include <net/netfilter/nf_conntrack_core.h> | 28 | #include <net/netfilter/nf_conntrack_core.h> |
29 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | ||
29 | 30 | ||
30 | static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | 31 | static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, |
31 | struct nf_conntrack_tuple *tuple) | 32 | struct nf_conntrack_tuple *tuple) |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 72dbb6d1a6b3..41b8a956e1be 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -126,6 +126,10 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
126 | pr_debug("icmpv6: can't create new conn with type %u\n", | 126 | pr_debug("icmpv6: can't create new conn with type %u\n", |
127 | type + 128); | 127 | type + 128); |
128 | nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); | 128 | nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); |
129 | if (LOG_INVALID(nf_ct_net(ct), IPPROTO_ICMPV6)) | ||
130 | nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, | ||
131 | "nf_ct_icmpv6: invalid new with type %d ", | ||
132 | type + 128); | ||
129 | return false; | 133 | return false; |
130 | } | 134 | } |
131 | atomic_set(&ct->proto.icmp.count, 0); | 135 | atomic_set(&ct->proto.icmp.count, 0); |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index c2bac9cd0caf..2562d05dbaf5 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -357,6 +357,45 @@ config NETFILTER_XT_TARGET_DSCP | |||
357 | 357 | ||
358 | To compile it as a module, choose M here. If unsure, say N. | 358 | To compile it as a module, choose M here. If unsure, say N. |
359 | 359 | ||
360 | config NETFILTER_XT_TARGET_HL | ||
361 | tristate '"HL" hoplimit target support' | ||
362 | depends on IP_NF_MANGLE || IP6_NF_MANGLE | ||
363 | depends on NETFILTER_ADVANCED | ||
364 | ---help--- | ||
365 | This option adds the "HL" (for IPv6) and "TTL" (for IPv4) | ||
366 | targets, which enable the user to change the | ||
367 | hoplimit/time-to-live value of the IP header. | ||
368 | |||
369 | While it is safe to decrement the hoplimit/TTL value, the | ||
370 | modules also allow to increment and set the hoplimit value of | ||
371 | the header to arbitrary values. This is EXTREMELY DANGEROUS | ||
372 | since you can easily create immortal packets that loop | ||
373 | forever on the network. | ||
374 | |||
375 | config NETFILTER_XT_TARGET_LED | ||
376 | tristate '"LED" target support' | ||
377 | depends on LEDS_CLASS | ||
378 | depends on NETFILTER_ADVANCED | ||
379 | help | ||
380 | This option adds a `LED' target, which allows you to blink LEDs in | ||
381 | response to particular packets passing through your machine. | ||
382 | |||
383 | This can be used to turn a spare LED into a network activity LED, | ||
384 | which only flashes in response to FTP transfers, for example. Or | ||
385 | you could have an LED which lights up for a minute or two every time | ||
386 | somebody connects to your machine via SSH. | ||
387 | |||
388 | You will need support for the "led" class to make this work. | ||
389 | |||
390 | To create an LED trigger for incoming SSH traffic: | ||
391 | iptables -A INPUT -p tcp --dport 22 -j LED --led-trigger-id ssh --led-delay 1000 | ||
392 | |||
393 | Then attach the new trigger to an LED on your system: | ||
394 | echo netfilter-ssh > /sys/class/leds/<ledname>/trigger | ||
395 | |||
396 | For more information on the LEDs available on your system, see | ||
397 | Documentation/leds-class.txt | ||
398 | |||
360 | config NETFILTER_XT_TARGET_MARK | 399 | config NETFILTER_XT_TARGET_MARK |
361 | tristate '"MARK" target support' | 400 | tristate '"MARK" target support' |
362 | default m if NETFILTER_ADVANCED=n | 401 | default m if NETFILTER_ADVANCED=n |
@@ -488,6 +527,22 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP | |||
488 | This option adds a "TCPOPTSTRIP" target, which allows you to strip | 527 | This option adds a "TCPOPTSTRIP" target, which allows you to strip |
489 | TCP options from TCP packets. | 528 | TCP options from TCP packets. |
490 | 529 | ||
530 | config NETFILTER_XT_MATCH_CLUSTER | ||
531 | tristate '"cluster" match support' | ||
532 | depends on NF_CONNTRACK | ||
533 | depends on NETFILTER_ADVANCED | ||
534 | ---help--- | ||
535 | This option allows you to build work-load-sharing clusters of | ||
536 | network servers/stateful firewalls without having a dedicated | ||
537 | load-balancing router/server/switch. Basically, this match returns | ||
538 | true when the packet must be handled by this cluster node. Thus, | ||
539 | all nodes see all packets and this match decides which node handles | ||
540 | what packets. The work-load sharing algorithm is based on source | ||
541 | address hashing. | ||
542 | |||
543 | If you say Y or M here, try `iptables -m cluster --help` for | ||
544 | more information. | ||
545 | |||
491 | config NETFILTER_XT_MATCH_COMMENT | 546 | config NETFILTER_XT_MATCH_COMMENT |
492 | tristate '"comment" match support' | 547 | tristate '"comment" match support' |
493 | depends on NETFILTER_ADVANCED | 548 | depends on NETFILTER_ADVANCED |
@@ -605,6 +660,14 @@ config NETFILTER_XT_MATCH_HELPER | |||
605 | 660 | ||
606 | To compile it as a module, choose M here. If unsure, say Y. | 661 | To compile it as a module, choose M here. If unsure, say Y. |
607 | 662 | ||
663 | config NETFILTER_XT_MATCH_HL | ||
664 | tristate '"hl" hoplimit/TTL match support' | ||
665 | depends on NETFILTER_ADVANCED | ||
666 | ---help--- | ||
667 | HL matching allows you to match packets based on the hoplimit | ||
668 | in the IPv6 header, or the time-to-live field in the IPv4 | ||
669 | header of the packet. | ||
670 | |||
608 | config NETFILTER_XT_MATCH_IPRANGE | 671 | config NETFILTER_XT_MATCH_IPRANGE |
609 | tristate '"iprange" address range match support' | 672 | tristate '"iprange" address range match support' |
610 | depends on NETFILTER_ADVANCED | 673 | depends on NETFILTER_ADVANCED |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index da3d909e053f..6282060fbda9 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -45,6 +45,8 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o | |||
45 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o | 45 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o |
46 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o | 46 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o |
47 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o | 47 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o |
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o | ||
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o | ||
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o | 50 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o |
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o | 51 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o |
50 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o | 52 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o |
@@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o | |||
57 | obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o | 59 | obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o |
58 | 60 | ||
59 | # matches | 61 | # matches |
62 | obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o | ||
60 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o | 63 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o |
61 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o | 64 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o |
62 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o | 65 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o |
@@ -67,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o | |||
67 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o | 70 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o |
68 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o | 71 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o |
69 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o | 72 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o |
73 | obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o | ||
70 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o | 74 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o |
71 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o | 75 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o |
72 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o | 76 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index a90ac83c5918..5bb34737501f 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -174,7 +174,6 @@ next_hook: | |||
174 | outdev, &elem, okfn, hook_thresh); | 174 | outdev, &elem, okfn, hook_thresh); |
175 | if (verdict == NF_ACCEPT || verdict == NF_STOP) { | 175 | if (verdict == NF_ACCEPT || verdict == NF_STOP) { |
176 | ret = 1; | 176 | ret = 1; |
177 | goto unlock; | ||
178 | } else if (verdict == NF_DROP) { | 177 | } else if (verdict == NF_DROP) { |
179 | kfree_skb(skb); | 178 | kfree_skb(skb); |
180 | ret = -EPERM; | 179 | ret = -EPERM; |
@@ -183,7 +182,6 @@ next_hook: | |||
183 | verdict >> NF_VERDICT_BITS)) | 182 | verdict >> NF_VERDICT_BITS)) |
184 | goto next_hook; | 183 | goto next_hook; |
185 | } | 184 | } |
186 | unlock: | ||
187 | rcu_read_unlock(); | 185 | rcu_read_unlock(); |
188 | return ret; | 186 | return ret; |
189 | } | 187 | } |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f4935e344b61..dfb447b584da 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_lock); | |||
54 | unsigned int nf_conntrack_htable_size __read_mostly; | 54 | unsigned int nf_conntrack_htable_size __read_mostly; |
55 | EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); | 55 | EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); |
56 | 56 | ||
57 | int nf_conntrack_max __read_mostly; | 57 | unsigned int nf_conntrack_max __read_mostly; |
58 | EXPORT_SYMBOL_GPL(nf_conntrack_max); | 58 | EXPORT_SYMBOL_GPL(nf_conntrack_max); |
59 | 59 | ||
60 | struct nf_conn nf_conntrack_untracked __read_mostly; | 60 | struct nf_conn nf_conntrack_untracked __read_mostly; |
@@ -472,7 +472,8 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, | |||
472 | struct nf_conn *ct; | 472 | struct nf_conn *ct; |
473 | 473 | ||
474 | if (unlikely(!nf_conntrack_hash_rnd_initted)) { | 474 | if (unlikely(!nf_conntrack_hash_rnd_initted)) { |
475 | get_random_bytes(&nf_conntrack_hash_rnd, 4); | 475 | get_random_bytes(&nf_conntrack_hash_rnd, |
476 | sizeof(nf_conntrack_hash_rnd)); | ||
476 | nf_conntrack_hash_rnd_initted = 1; | 477 | nf_conntrack_hash_rnd_initted = 1; |
477 | } | 478 | } |
478 | 479 | ||
@@ -516,16 +517,17 @@ EXPORT_SYMBOL_GPL(nf_conntrack_alloc); | |||
516 | static void nf_conntrack_free_rcu(struct rcu_head *head) | 517 | static void nf_conntrack_free_rcu(struct rcu_head *head) |
517 | { | 518 | { |
518 | struct nf_conn *ct = container_of(head, struct nf_conn, rcu); | 519 | struct nf_conn *ct = container_of(head, struct nf_conn, rcu); |
519 | struct net *net = nf_ct_net(ct); | ||
520 | 520 | ||
521 | nf_ct_ext_free(ct); | 521 | nf_ct_ext_free(ct); |
522 | kmem_cache_free(nf_conntrack_cachep, ct); | 522 | kmem_cache_free(nf_conntrack_cachep, ct); |
523 | atomic_dec(&net->ct.count); | ||
524 | } | 523 | } |
525 | 524 | ||
526 | void nf_conntrack_free(struct nf_conn *ct) | 525 | void nf_conntrack_free(struct nf_conn *ct) |
527 | { | 526 | { |
527 | struct net *net = nf_ct_net(ct); | ||
528 | |||
528 | nf_ct_ext_destroy(ct); | 529 | nf_ct_ext_destroy(ct); |
530 | atomic_dec(&net->ct.count); | ||
529 | call_rcu(&ct->rcu, nf_conntrack_free_rcu); | 531 | call_rcu(&ct->rcu, nf_conntrack_free_rcu); |
530 | } | 532 | } |
531 | EXPORT_SYMBOL_GPL(nf_conntrack_free); | 533 | EXPORT_SYMBOL_GPL(nf_conntrack_free); |
@@ -733,6 +735,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, | |||
733 | nf_conntrack_put(skb->nfct); | 735 | nf_conntrack_put(skb->nfct); |
734 | skb->nfct = NULL; | 736 | skb->nfct = NULL; |
735 | NF_CT_STAT_INC_ATOMIC(net, invalid); | 737 | NF_CT_STAT_INC_ATOMIC(net, invalid); |
738 | if (ret == -NF_DROP) | ||
739 | NF_CT_STAT_INC_ATOMIC(net, drop); | ||
736 | return -ret; | 740 | return -ret; |
737 | } | 741 | } |
738 | 742 | ||
@@ -1103,7 +1107,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) | |||
1103 | 1107 | ||
1104 | /* We have to rehahs for the new table anyway, so we also can | 1108 | /* We have to rehahs for the new table anyway, so we also can |
1105 | * use a newrandom seed */ | 1109 | * use a newrandom seed */ |
1106 | get_random_bytes(&rnd, 4); | 1110 | get_random_bytes(&rnd, sizeof(rnd)); |
1107 | 1111 | ||
1108 | /* Lookups in the old hash might happen in parallel, which means we | 1112 | /* Lookups in the old hash might happen in parallel, which means we |
1109 | * might get false negatives during connection lookup. New connections | 1113 | * might get false negatives during connection lookup. New connections |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 3a8a34a6d37c..357ba39d4c8d 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -72,7 +72,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple | |||
72 | unsigned int hash; | 72 | unsigned int hash; |
73 | 73 | ||
74 | if (unlikely(!nf_ct_expect_hash_rnd_initted)) { | 74 | if (unlikely(!nf_ct_expect_hash_rnd_initted)) { |
75 | get_random_bytes(&nf_ct_expect_hash_rnd, 4); | 75 | get_random_bytes(&nf_ct_expect_hash_rnd, |
76 | sizeof(nf_ct_expect_hash_rnd)); | ||
76 | nf_ct_expect_hash_rnd_initted = 1; | 77 | nf_ct_expect_hash_rnd_initted = 1; |
77 | } | 78 | } |
78 | 79 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index ed6d873ad384..7a16bd462f82 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -518,6 +518,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
518 | nla_put_failure: | 518 | nla_put_failure: |
519 | rcu_read_unlock(); | 519 | rcu_read_unlock(); |
520 | nlmsg_failure: | 520 | nlmsg_failure: |
521 | nfnetlink_set_err(0, group, -ENOBUFS); | ||
521 | kfree_skb(skb); | 522 | kfree_skb(skb); |
522 | return NOTIFY_DONE; | 523 | return NOTIFY_DONE; |
523 | } | 524 | } |
@@ -599,7 +600,8 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple) | |||
599 | 600 | ||
600 | nla_parse_nested(tb, CTA_IP_MAX, attr, NULL); | 601 | nla_parse_nested(tb, CTA_IP_MAX, attr, NULL); |
601 | 602 | ||
602 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | 603 | rcu_read_lock(); |
604 | l3proto = __nf_ct_l3proto_find(tuple->src.l3num); | ||
603 | 605 | ||
604 | if (likely(l3proto->nlattr_to_tuple)) { | 606 | if (likely(l3proto->nlattr_to_tuple)) { |
605 | ret = nla_validate_nested(attr, CTA_IP_MAX, | 607 | ret = nla_validate_nested(attr, CTA_IP_MAX, |
@@ -608,7 +610,7 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple) | |||
608 | ret = l3proto->nlattr_to_tuple(tb, tuple); | 610 | ret = l3proto->nlattr_to_tuple(tb, tuple); |
609 | } | 611 | } |
610 | 612 | ||
611 | nf_ct_l3proto_put(l3proto); | 613 | rcu_read_unlock(); |
612 | 614 | ||
613 | return ret; | 615 | return ret; |
614 | } | 616 | } |
@@ -633,7 +635,8 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, | |||
633 | return -EINVAL; | 635 | return -EINVAL; |
634 | tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]); | 636 | tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]); |
635 | 637 | ||
636 | l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); | 638 | rcu_read_lock(); |
639 | l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); | ||
637 | 640 | ||
638 | if (likely(l4proto->nlattr_to_tuple)) { | 641 | if (likely(l4proto->nlattr_to_tuple)) { |
639 | ret = nla_validate_nested(attr, CTA_PROTO_MAX, | 642 | ret = nla_validate_nested(attr, CTA_PROTO_MAX, |
@@ -642,7 +645,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, | |||
642 | ret = l4proto->nlattr_to_tuple(tb, tuple); | 645 | ret = l4proto->nlattr_to_tuple(tb, tuple); |
643 | } | 646 | } |
644 | 647 | ||
645 | nf_ct_l4proto_put(l4proto); | 648 | rcu_read_unlock(); |
646 | 649 | ||
647 | return ret; | 650 | return ret; |
648 | } | 651 | } |
@@ -989,10 +992,11 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) | |||
989 | 992 | ||
990 | nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL); | 993 | nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL); |
991 | 994 | ||
992 | l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct)); | 995 | rcu_read_lock(); |
996 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); | ||
993 | if (l4proto->from_nlattr) | 997 | if (l4proto->from_nlattr) |
994 | err = l4proto->from_nlattr(tb, ct); | 998 | err = l4proto->from_nlattr(tb, ct); |
995 | nf_ct_l4proto_put(l4proto); | 999 | rcu_read_unlock(); |
996 | 1000 | ||
997 | return err; | 1001 | return err; |
998 | } | 1002 | } |
@@ -1062,6 +1066,10 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) | |||
1062 | { | 1066 | { |
1063 | int err; | 1067 | int err; |
1064 | 1068 | ||
1069 | /* only allow NAT changes and master assignation for new conntracks */ | ||
1070 | if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST] || cda[CTA_TUPLE_MASTER]) | ||
1071 | return -EOPNOTSUPP; | ||
1072 | |||
1065 | if (cda[CTA_HELP]) { | 1073 | if (cda[CTA_HELP]) { |
1066 | err = ctnetlink_change_helper(ct, cda); | 1074 | err = ctnetlink_change_helper(ct, cda); |
1067 | if (err < 0) | 1075 | if (err < 0) |
@@ -1124,13 +1132,11 @@ ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report) | |||
1124 | report); | 1132 | report); |
1125 | } | 1133 | } |
1126 | 1134 | ||
1127 | static int | 1135 | static struct nf_conn * |
1128 | ctnetlink_create_conntrack(struct nlattr *cda[], | 1136 | ctnetlink_create_conntrack(struct nlattr *cda[], |
1129 | struct nf_conntrack_tuple *otuple, | 1137 | struct nf_conntrack_tuple *otuple, |
1130 | struct nf_conntrack_tuple *rtuple, | 1138 | struct nf_conntrack_tuple *rtuple, |
1131 | struct nf_conn *master_ct, | 1139 | u8 u3) |
1132 | u32 pid, | ||
1133 | int report) | ||
1134 | { | 1140 | { |
1135 | struct nf_conn *ct; | 1141 | struct nf_conn *ct; |
1136 | int err = -EINVAL; | 1142 | int err = -EINVAL; |
@@ -1138,10 +1144,10 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1138 | 1144 | ||
1139 | ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC); | 1145 | ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC); |
1140 | if (IS_ERR(ct)) | 1146 | if (IS_ERR(ct)) |
1141 | return -ENOMEM; | 1147 | return ERR_PTR(-ENOMEM); |
1142 | 1148 | ||
1143 | if (!cda[CTA_TIMEOUT]) | 1149 | if (!cda[CTA_TIMEOUT]) |
1144 | goto err; | 1150 | goto err1; |
1145 | ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); | 1151 | ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); |
1146 | 1152 | ||
1147 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; | 1153 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; |
@@ -1152,10 +1158,8 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1152 | char *helpname; | 1158 | char *helpname; |
1153 | 1159 | ||
1154 | err = ctnetlink_parse_help(cda[CTA_HELP], &helpname); | 1160 | err = ctnetlink_parse_help(cda[CTA_HELP], &helpname); |
1155 | if (err < 0) { | 1161 | if (err < 0) |
1156 | rcu_read_unlock(); | 1162 | goto err2; |
1157 | goto err; | ||
1158 | } | ||
1159 | 1163 | ||
1160 | helper = __nf_conntrack_helper_find_byname(helpname); | 1164 | helper = __nf_conntrack_helper_find_byname(helpname); |
1161 | if (helper == NULL) { | 1165 | if (helper == NULL) { |
@@ -1163,28 +1167,26 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1163 | #ifdef CONFIG_MODULES | 1167 | #ifdef CONFIG_MODULES |
1164 | if (request_module("nfct-helper-%s", helpname) < 0) { | 1168 | if (request_module("nfct-helper-%s", helpname) < 0) { |
1165 | err = -EOPNOTSUPP; | 1169 | err = -EOPNOTSUPP; |
1166 | goto err; | 1170 | goto err1; |
1167 | } | 1171 | } |
1168 | 1172 | ||
1169 | rcu_read_lock(); | 1173 | rcu_read_lock(); |
1170 | helper = __nf_conntrack_helper_find_byname(helpname); | 1174 | helper = __nf_conntrack_helper_find_byname(helpname); |
1171 | if (helper) { | 1175 | if (helper) { |
1172 | rcu_read_unlock(); | ||
1173 | err = -EAGAIN; | 1176 | err = -EAGAIN; |
1174 | goto err; | 1177 | goto err2; |
1175 | } | 1178 | } |
1176 | rcu_read_unlock(); | 1179 | rcu_read_unlock(); |
1177 | #endif | 1180 | #endif |
1178 | err = -EOPNOTSUPP; | 1181 | err = -EOPNOTSUPP; |
1179 | goto err; | 1182 | goto err1; |
1180 | } else { | 1183 | } else { |
1181 | struct nf_conn_help *help; | 1184 | struct nf_conn_help *help; |
1182 | 1185 | ||
1183 | help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); | 1186 | help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); |
1184 | if (help == NULL) { | 1187 | if (help == NULL) { |
1185 | rcu_read_unlock(); | ||
1186 | err = -ENOMEM; | 1188 | err = -ENOMEM; |
1187 | goto err; | 1189 | goto err2; |
1188 | } | 1190 | } |
1189 | 1191 | ||
1190 | /* not in hash table yet so not strictly necessary */ | 1192 | /* not in hash table yet so not strictly necessary */ |
@@ -1193,44 +1195,34 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1193 | } else { | 1195 | } else { |
1194 | /* try an implicit helper assignation */ | 1196 | /* try an implicit helper assignation */ |
1195 | err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC); | 1197 | err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC); |
1196 | if (err < 0) { | 1198 | if (err < 0) |
1197 | rcu_read_unlock(); | 1199 | goto err2; |
1198 | goto err; | ||
1199 | } | ||
1200 | } | 1200 | } |
1201 | 1201 | ||
1202 | if (cda[CTA_STATUS]) { | 1202 | if (cda[CTA_STATUS]) { |
1203 | err = ctnetlink_change_status(ct, cda); | 1203 | err = ctnetlink_change_status(ct, cda); |
1204 | if (err < 0) { | 1204 | if (err < 0) |
1205 | rcu_read_unlock(); | 1205 | goto err2; |
1206 | goto err; | ||
1207 | } | ||
1208 | } | 1206 | } |
1209 | 1207 | ||
1210 | if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { | 1208 | if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { |
1211 | err = ctnetlink_change_nat(ct, cda); | 1209 | err = ctnetlink_change_nat(ct, cda); |
1212 | if (err < 0) { | 1210 | if (err < 0) |
1213 | rcu_read_unlock(); | 1211 | goto err2; |
1214 | goto err; | ||
1215 | } | ||
1216 | } | 1212 | } |
1217 | 1213 | ||
1218 | #ifdef CONFIG_NF_NAT_NEEDED | 1214 | #ifdef CONFIG_NF_NAT_NEEDED |
1219 | if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { | 1215 | if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { |
1220 | err = ctnetlink_change_nat_seq_adj(ct, cda); | 1216 | err = ctnetlink_change_nat_seq_adj(ct, cda); |
1221 | if (err < 0) { | 1217 | if (err < 0) |
1222 | rcu_read_unlock(); | 1218 | goto err2; |
1223 | goto err; | ||
1224 | } | ||
1225 | } | 1219 | } |
1226 | #endif | 1220 | #endif |
1227 | 1221 | ||
1228 | if (cda[CTA_PROTOINFO]) { | 1222 | if (cda[CTA_PROTOINFO]) { |
1229 | err = ctnetlink_change_protoinfo(ct, cda); | 1223 | err = ctnetlink_change_protoinfo(ct, cda); |
1230 | if (err < 0) { | 1224 | if (err < 0) |
1231 | rcu_read_unlock(); | 1225 | goto err2; |
1232 | goto err; | ||
1233 | } | ||
1234 | } | 1226 | } |
1235 | 1227 | ||
1236 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); | 1228 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); |
@@ -1241,23 +1233,37 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1241 | #endif | 1233 | #endif |
1242 | 1234 | ||
1243 | /* setup master conntrack: this is a confirmed expectation */ | 1235 | /* setup master conntrack: this is a confirmed expectation */ |
1244 | if (master_ct) { | 1236 | if (cda[CTA_TUPLE_MASTER]) { |
1237 | struct nf_conntrack_tuple master; | ||
1238 | struct nf_conntrack_tuple_hash *master_h; | ||
1239 | struct nf_conn *master_ct; | ||
1240 | |||
1241 | err = ctnetlink_parse_tuple(cda, &master, CTA_TUPLE_MASTER, u3); | ||
1242 | if (err < 0) | ||
1243 | goto err2; | ||
1244 | |||
1245 | master_h = __nf_conntrack_find(&init_net, &master); | ||
1246 | if (master_h == NULL) { | ||
1247 | err = -ENOENT; | ||
1248 | goto err2; | ||
1249 | } | ||
1250 | master_ct = nf_ct_tuplehash_to_ctrack(master_h); | ||
1251 | nf_conntrack_get(&master_ct->ct_general); | ||
1245 | __set_bit(IPS_EXPECTED_BIT, &ct->status); | 1252 | __set_bit(IPS_EXPECTED_BIT, &ct->status); |
1246 | ct->master = master_ct; | 1253 | ct->master = master_ct; |
1247 | } | 1254 | } |
1248 | 1255 | ||
1249 | nf_conntrack_get(&ct->ct_general); | ||
1250 | add_timer(&ct->timeout); | 1256 | add_timer(&ct->timeout); |
1251 | nf_conntrack_hash_insert(ct); | 1257 | nf_conntrack_hash_insert(ct); |
1252 | rcu_read_unlock(); | 1258 | rcu_read_unlock(); |
1253 | ctnetlink_event_report(ct, pid, report); | ||
1254 | nf_ct_put(ct); | ||
1255 | 1259 | ||
1256 | return 0; | 1260 | return ct; |
1257 | 1261 | ||
1258 | err: | 1262 | err2: |
1263 | rcu_read_unlock(); | ||
1264 | err1: | ||
1259 | nf_conntrack_free(ct); | 1265 | nf_conntrack_free(ct); |
1260 | return err; | 1266 | return ERR_PTR(err); |
1261 | } | 1267 | } |
1262 | 1268 | ||
1263 | static int | 1269 | static int |
@@ -1289,38 +1295,25 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1289 | h = __nf_conntrack_find(&init_net, &rtuple); | 1295 | h = __nf_conntrack_find(&init_net, &rtuple); |
1290 | 1296 | ||
1291 | if (h == NULL) { | 1297 | if (h == NULL) { |
1292 | struct nf_conntrack_tuple master; | 1298 | err = -ENOENT; |
1293 | struct nf_conntrack_tuple_hash *master_h = NULL; | 1299 | if (nlh->nlmsg_flags & NLM_F_CREATE) { |
1294 | struct nf_conn *master_ct = NULL; | 1300 | struct nf_conn *ct; |
1295 | |||
1296 | if (cda[CTA_TUPLE_MASTER]) { | ||
1297 | err = ctnetlink_parse_tuple(cda, | ||
1298 | &master, | ||
1299 | CTA_TUPLE_MASTER, | ||
1300 | u3); | ||
1301 | if (err < 0) | ||
1302 | goto out_unlock; | ||
1303 | 1301 | ||
1304 | master_h = __nf_conntrack_find(&init_net, &master); | 1302 | ct = ctnetlink_create_conntrack(cda, &otuple, |
1305 | if (master_h == NULL) { | 1303 | &rtuple, u3); |
1306 | err = -ENOENT; | 1304 | if (IS_ERR(ct)) { |
1305 | err = PTR_ERR(ct); | ||
1307 | goto out_unlock; | 1306 | goto out_unlock; |
1308 | } | 1307 | } |
1309 | master_ct = nf_ct_tuplehash_to_ctrack(master_h); | 1308 | err = 0; |
1310 | nf_conntrack_get(&master_ct->ct_general); | 1309 | nf_conntrack_get(&ct->ct_general); |
1311 | } | 1310 | spin_unlock_bh(&nf_conntrack_lock); |
1312 | 1311 | ctnetlink_event_report(ct, | |
1313 | err = -ENOENT; | 1312 | NETLINK_CB(skb).pid, |
1314 | if (nlh->nlmsg_flags & NLM_F_CREATE) | 1313 | nlmsg_report(nlh)); |
1315 | err = ctnetlink_create_conntrack(cda, | 1314 | nf_ct_put(ct); |
1316 | &otuple, | 1315 | } else |
1317 | &rtuple, | 1316 | spin_unlock_bh(&nf_conntrack_lock); |
1318 | master_ct, | ||
1319 | NETLINK_CB(skb).pid, | ||
1320 | nlmsg_report(nlh)); | ||
1321 | spin_unlock_bh(&nf_conntrack_lock); | ||
1322 | if (err < 0 && master_ct) | ||
1323 | nf_ct_put(master_ct); | ||
1324 | 1317 | ||
1325 | return err; | 1318 | return err; |
1326 | } | 1319 | } |
@@ -1332,17 +1325,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1332 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { | 1325 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { |
1333 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); | 1326 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); |
1334 | 1327 | ||
1335 | /* we only allow nat config for new conntracks */ | ||
1336 | if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { | ||
1337 | err = -EOPNOTSUPP; | ||
1338 | goto out_unlock; | ||
1339 | } | ||
1340 | /* can't link an existing conntrack to a master */ | ||
1341 | if (cda[CTA_TUPLE_MASTER]) { | ||
1342 | err = -EOPNOTSUPP; | ||
1343 | goto out_unlock; | ||
1344 | } | ||
1345 | |||
1346 | err = ctnetlink_change_conntrack(ct, cda); | 1328 | err = ctnetlink_change_conntrack(ct, cda); |
1347 | if (err == 0) { | 1329 | if (err == 0) { |
1348 | nf_conntrack_get(&ct->ct_general); | 1330 | nf_conntrack_get(&ct->ct_general); |
@@ -1533,6 +1515,7 @@ static int ctnetlink_expect_event(struct notifier_block *this, | |||
1533 | nla_put_failure: | 1515 | nla_put_failure: |
1534 | rcu_read_unlock(); | 1516 | rcu_read_unlock(); |
1535 | nlmsg_failure: | 1517 | nlmsg_failure: |
1518 | nfnetlink_set_err(0, 0, -ENOBUFS); | ||
1536 | kfree_skb(skb); | 1519 | kfree_skb(skb); |
1537 | return NOTIFY_DONE; | 1520 | return NOTIFY_DONE; |
1538 | } | 1521 | } |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 592d73344d46..9a62b4efa0e1 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -74,27 +74,6 @@ EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); | |||
74 | 74 | ||
75 | /* this is guaranteed to always return a valid protocol helper, since | 75 | /* this is guaranteed to always return a valid protocol helper, since |
76 | * it falls back to generic_protocol */ | 76 | * it falls back to generic_protocol */ |
77 | struct nf_conntrack_l4proto * | ||
78 | nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto) | ||
79 | { | ||
80 | struct nf_conntrack_l4proto *p; | ||
81 | |||
82 | rcu_read_lock(); | ||
83 | p = __nf_ct_l4proto_find(l3proto, l4proto); | ||
84 | if (!try_module_get(p->me)) | ||
85 | p = &nf_conntrack_l4proto_generic; | ||
86 | rcu_read_unlock(); | ||
87 | |||
88 | return p; | ||
89 | } | ||
90 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); | ||
91 | |||
92 | void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) | ||
93 | { | ||
94 | module_put(p->me); | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); | ||
97 | |||
98 | struct nf_conntrack_l3proto * | 77 | struct nf_conntrack_l3proto * |
99 | nf_ct_l3proto_find_get(u_int16_t l3proto) | 78 | nf_ct_l3proto_find_get(u_int16_t l3proto) |
100 | { | 79 | { |
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 8fcf1762fabf..d3d5a7fd73ce 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
@@ -16,6 +16,9 @@ | |||
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/dccp.h> | 17 | #include <linux/dccp.h> |
18 | 18 | ||
19 | #include <net/net_namespace.h> | ||
20 | #include <net/netns/generic.h> | ||
21 | |||
19 | #include <linux/netfilter/nfnetlink_conntrack.h> | 22 | #include <linux/netfilter/nfnetlink_conntrack.h> |
20 | #include <net/netfilter/nf_conntrack.h> | 23 | #include <net/netfilter/nf_conntrack.h> |
21 | #include <net/netfilter/nf_conntrack_l4proto.h> | 24 | #include <net/netfilter/nf_conntrack_l4proto.h> |
@@ -23,8 +26,6 @@ | |||
23 | 26 | ||
24 | static DEFINE_RWLOCK(dccp_lock); | 27 | static DEFINE_RWLOCK(dccp_lock); |
25 | 28 | ||
26 | static int nf_ct_dccp_loose __read_mostly = 1; | ||
27 | |||
28 | /* Timeouts are based on values from RFC4340: | 29 | /* Timeouts are based on values from RFC4340: |
29 | * | 30 | * |
30 | * - REQUEST: | 31 | * - REQUEST: |
@@ -72,16 +73,6 @@ static int nf_ct_dccp_loose __read_mostly = 1; | |||
72 | 73 | ||
73 | #define DCCP_MSL (2 * 60 * HZ) | 74 | #define DCCP_MSL (2 * 60 * HZ) |
74 | 75 | ||
75 | static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = { | ||
76 | [CT_DCCP_REQUEST] = 2 * DCCP_MSL, | ||
77 | [CT_DCCP_RESPOND] = 4 * DCCP_MSL, | ||
78 | [CT_DCCP_PARTOPEN] = 4 * DCCP_MSL, | ||
79 | [CT_DCCP_OPEN] = 12 * 3600 * HZ, | ||
80 | [CT_DCCP_CLOSEREQ] = 64 * HZ, | ||
81 | [CT_DCCP_CLOSING] = 64 * HZ, | ||
82 | [CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL, | ||
83 | }; | ||
84 | |||
85 | static const char * const dccp_state_names[] = { | 76 | static const char * const dccp_state_names[] = { |
86 | [CT_DCCP_NONE] = "NONE", | 77 | [CT_DCCP_NONE] = "NONE", |
87 | [CT_DCCP_REQUEST] = "REQUEST", | 78 | [CT_DCCP_REQUEST] = "REQUEST", |
@@ -393,6 +384,22 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = | |||
393 | }, | 384 | }, |
394 | }; | 385 | }; |
395 | 386 | ||
387 | /* this module per-net specifics */ | ||
388 | static int dccp_net_id; | ||
389 | struct dccp_net { | ||
390 | int dccp_loose; | ||
391 | unsigned int dccp_timeout[CT_DCCP_MAX + 1]; | ||
392 | #ifdef CONFIG_SYSCTL | ||
393 | struct ctl_table_header *sysctl_header; | ||
394 | struct ctl_table *sysctl_table; | ||
395 | #endif | ||
396 | }; | ||
397 | |||
398 | static inline struct dccp_net *dccp_pernet(struct net *net) | ||
399 | { | ||
400 | return net_generic(net, dccp_net_id); | ||
401 | } | ||
402 | |||
396 | static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, | 403 | static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, |
397 | struct nf_conntrack_tuple *tuple) | 404 | struct nf_conntrack_tuple *tuple) |
398 | { | 405 | { |
@@ -419,6 +426,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
419 | unsigned int dataoff) | 426 | unsigned int dataoff) |
420 | { | 427 | { |
421 | struct net *net = nf_ct_net(ct); | 428 | struct net *net = nf_ct_net(ct); |
429 | struct dccp_net *dn; | ||
422 | struct dccp_hdr _dh, *dh; | 430 | struct dccp_hdr _dh, *dh; |
423 | const char *msg; | 431 | const char *msg; |
424 | u_int8_t state; | 432 | u_int8_t state; |
@@ -429,7 +437,8 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
429 | state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; | 437 | state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; |
430 | switch (state) { | 438 | switch (state) { |
431 | default: | 439 | default: |
432 | if (nf_ct_dccp_loose == 0) { | 440 | dn = dccp_pernet(net); |
441 | if (dn->dccp_loose == 0) { | ||
433 | msg = "nf_ct_dccp: not picking up existing connection "; | 442 | msg = "nf_ct_dccp: not picking up existing connection "; |
434 | goto out_invalid; | 443 | goto out_invalid; |
435 | } | 444 | } |
@@ -465,6 +474,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, | |||
465 | u_int8_t pf, unsigned int hooknum) | 474 | u_int8_t pf, unsigned int hooknum) |
466 | { | 475 | { |
467 | struct net *net = nf_ct_net(ct); | 476 | struct net *net = nf_ct_net(ct); |
477 | struct dccp_net *dn; | ||
468 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 478 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
469 | struct dccp_hdr _dh, *dh; | 479 | struct dccp_hdr _dh, *dh; |
470 | u_int8_t type, old_state, new_state; | 480 | u_int8_t type, old_state, new_state; |
@@ -542,7 +552,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, | |||
542 | ct->proto.dccp.last_pkt = type; | 552 | ct->proto.dccp.last_pkt = type; |
543 | ct->proto.dccp.state = new_state; | 553 | ct->proto.dccp.state = new_state; |
544 | write_unlock_bh(&dccp_lock); | 554 | write_unlock_bh(&dccp_lock); |
545 | nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]); | 555 | |
556 | dn = dccp_pernet(net); | ||
557 | nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]); | ||
546 | 558 | ||
547 | return NF_ACCEPT; | 559 | return NF_ACCEPT; |
548 | } | 560 | } |
@@ -660,13 +672,11 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) | |||
660 | #endif | 672 | #endif |
661 | 673 | ||
662 | #ifdef CONFIG_SYSCTL | 674 | #ifdef CONFIG_SYSCTL |
663 | static unsigned int dccp_sysctl_table_users; | 675 | /* template, data assigned later */ |
664 | static struct ctl_table_header *dccp_sysctl_header; | 676 | static struct ctl_table dccp_sysctl_table[] = { |
665 | static ctl_table dccp_sysctl_table[] = { | ||
666 | { | 677 | { |
667 | .ctl_name = CTL_UNNUMBERED, | 678 | .ctl_name = CTL_UNNUMBERED, |
668 | .procname = "nf_conntrack_dccp_timeout_request", | 679 | .procname = "nf_conntrack_dccp_timeout_request", |
669 | .data = &dccp_timeout[CT_DCCP_REQUEST], | ||
670 | .maxlen = sizeof(unsigned int), | 680 | .maxlen = sizeof(unsigned int), |
671 | .mode = 0644, | 681 | .mode = 0644, |
672 | .proc_handler = proc_dointvec_jiffies, | 682 | .proc_handler = proc_dointvec_jiffies, |
@@ -674,7 +684,6 @@ static ctl_table dccp_sysctl_table[] = { | |||
674 | { | 684 | { |
675 | .ctl_name = CTL_UNNUMBERED, | 685 | .ctl_name = CTL_UNNUMBERED, |
676 | .procname = "nf_conntrack_dccp_timeout_respond", | 686 | .procname = "nf_conntrack_dccp_timeout_respond", |
677 | .data = &dccp_timeout[CT_DCCP_RESPOND], | ||
678 | .maxlen = sizeof(unsigned int), | 687 | .maxlen = sizeof(unsigned int), |
679 | .mode = 0644, | 688 | .mode = 0644, |
680 | .proc_handler = proc_dointvec_jiffies, | 689 | .proc_handler = proc_dointvec_jiffies, |
@@ -682,7 +691,6 @@ static ctl_table dccp_sysctl_table[] = { | |||
682 | { | 691 | { |
683 | .ctl_name = CTL_UNNUMBERED, | 692 | .ctl_name = CTL_UNNUMBERED, |
684 | .procname = "nf_conntrack_dccp_timeout_partopen", | 693 | .procname = "nf_conntrack_dccp_timeout_partopen", |
685 | .data = &dccp_timeout[CT_DCCP_PARTOPEN], | ||
686 | .maxlen = sizeof(unsigned int), | 694 | .maxlen = sizeof(unsigned int), |
687 | .mode = 0644, | 695 | .mode = 0644, |
688 | .proc_handler = proc_dointvec_jiffies, | 696 | .proc_handler = proc_dointvec_jiffies, |
@@ -690,7 +698,6 @@ static ctl_table dccp_sysctl_table[] = { | |||
690 | { | 698 | { |
691 | .ctl_name = CTL_UNNUMBERED, | 699 | .ctl_name = CTL_UNNUMBERED, |
692 | .procname = "nf_conntrack_dccp_timeout_open", | 700 | .procname = "nf_conntrack_dccp_timeout_open", |
693 | .data = &dccp_timeout[CT_DCCP_OPEN], | ||
694 | .maxlen = sizeof(unsigned int), | 701 | .maxlen = sizeof(unsigned int), |
695 | .mode = 0644, | 702 | .mode = 0644, |
696 | .proc_handler = proc_dointvec_jiffies, | 703 | .proc_handler = proc_dointvec_jiffies, |
@@ -698,7 +705,6 @@ static ctl_table dccp_sysctl_table[] = { | |||
698 | { | 705 | { |
699 | .ctl_name = CTL_UNNUMBERED, | 706 | .ctl_name = CTL_UNNUMBERED, |
700 | .procname = "nf_conntrack_dccp_timeout_closereq", | 707 | .procname = "nf_conntrack_dccp_timeout_closereq", |
701 | .data = &dccp_timeout[CT_DCCP_CLOSEREQ], | ||
702 | .maxlen = sizeof(unsigned int), | 708 | .maxlen = sizeof(unsigned int), |
703 | .mode = 0644, | 709 | .mode = 0644, |
704 | .proc_handler = proc_dointvec_jiffies, | 710 | .proc_handler = proc_dointvec_jiffies, |
@@ -706,7 +712,6 @@ static ctl_table dccp_sysctl_table[] = { | |||
706 | { | 712 | { |
707 | .ctl_name = CTL_UNNUMBERED, | 713 | .ctl_name = CTL_UNNUMBERED, |
708 | .procname = "nf_conntrack_dccp_timeout_closing", | 714 | .procname = "nf_conntrack_dccp_timeout_closing", |
709 | .data = &dccp_timeout[CT_DCCP_CLOSING], | ||
710 | .maxlen = sizeof(unsigned int), | 715 | .maxlen = sizeof(unsigned int), |
711 | .mode = 0644, | 716 | .mode = 0644, |
712 | .proc_handler = proc_dointvec_jiffies, | 717 | .proc_handler = proc_dointvec_jiffies, |
@@ -714,7 +719,6 @@ static ctl_table dccp_sysctl_table[] = { | |||
714 | { | 719 | { |
715 | .ctl_name = CTL_UNNUMBERED, | 720 | .ctl_name = CTL_UNNUMBERED, |
716 | .procname = "nf_conntrack_dccp_timeout_timewait", | 721 | .procname = "nf_conntrack_dccp_timeout_timewait", |
717 | .data = &dccp_timeout[CT_DCCP_TIMEWAIT], | ||
718 | .maxlen = sizeof(unsigned int), | 722 | .maxlen = sizeof(unsigned int), |
719 | .mode = 0644, | 723 | .mode = 0644, |
720 | .proc_handler = proc_dointvec_jiffies, | 724 | .proc_handler = proc_dointvec_jiffies, |
@@ -722,8 +726,7 @@ static ctl_table dccp_sysctl_table[] = { | |||
722 | { | 726 | { |
723 | .ctl_name = CTL_UNNUMBERED, | 727 | .ctl_name = CTL_UNNUMBERED, |
724 | .procname = "nf_conntrack_dccp_loose", | 728 | .procname = "nf_conntrack_dccp_loose", |
725 | .data = &nf_ct_dccp_loose, | 729 | .maxlen = sizeof(int), |
726 | .maxlen = sizeof(nf_ct_dccp_loose), | ||
727 | .mode = 0644, | 730 | .mode = 0644, |
728 | .proc_handler = proc_dointvec, | 731 | .proc_handler = proc_dointvec, |
729 | }, | 732 | }, |
@@ -751,11 +754,6 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { | |||
751 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 754 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
752 | .nla_policy = nf_ct_port_nla_policy, | 755 | .nla_policy = nf_ct_port_nla_policy, |
753 | #endif | 756 | #endif |
754 | #ifdef CONFIG_SYSCTL | ||
755 | .ctl_table_users = &dccp_sysctl_table_users, | ||
756 | .ctl_table_header = &dccp_sysctl_header, | ||
757 | .ctl_table = dccp_sysctl_table, | ||
758 | #endif | ||
759 | }; | 757 | }; |
760 | 758 | ||
761 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | 759 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { |
@@ -776,34 +774,107 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
776 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 774 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
777 | .nla_policy = nf_ct_port_nla_policy, | 775 | .nla_policy = nf_ct_port_nla_policy, |
778 | #endif | 776 | #endif |
777 | }; | ||
778 | |||
779 | static __net_init int dccp_net_init(struct net *net) | ||
780 | { | ||
781 | struct dccp_net *dn; | ||
782 | int err; | ||
783 | |||
784 | dn = kmalloc(sizeof(*dn), GFP_KERNEL); | ||
785 | if (!dn) | ||
786 | return -ENOMEM; | ||
787 | |||
788 | /* default values */ | ||
789 | dn->dccp_loose = 1; | ||
790 | dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL; | ||
791 | dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL; | ||
792 | dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL; | ||
793 | dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ; | ||
794 | dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ; | ||
795 | dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; | ||
796 | dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; | ||
797 | |||
798 | err = net_assign_generic(net, dccp_net_id, dn); | ||
799 | if (err) | ||
800 | goto out; | ||
801 | |||
779 | #ifdef CONFIG_SYSCTL | 802 | #ifdef CONFIG_SYSCTL |
780 | .ctl_table_users = &dccp_sysctl_table_users, | 803 | err = -ENOMEM; |
781 | .ctl_table_header = &dccp_sysctl_header, | 804 | dn->sysctl_table = kmemdup(dccp_sysctl_table, |
782 | .ctl_table = dccp_sysctl_table, | 805 | sizeof(dccp_sysctl_table), GFP_KERNEL); |
806 | if (!dn->sysctl_table) | ||
807 | goto out; | ||
808 | |||
809 | dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST]; | ||
810 | dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND]; | ||
811 | dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN]; | ||
812 | dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN]; | ||
813 | dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ]; | ||
814 | dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING]; | ||
815 | dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT]; | ||
816 | dn->sysctl_table[7].data = &dn->dccp_loose; | ||
817 | |||
818 | dn->sysctl_header = register_net_sysctl_table(net, | ||
819 | nf_net_netfilter_sysctl_path, dn->sysctl_table); | ||
820 | if (!dn->sysctl_header) { | ||
821 | kfree(dn->sysctl_table); | ||
822 | goto out; | ||
823 | } | ||
783 | #endif | 824 | #endif |
825 | |||
826 | return 0; | ||
827 | |||
828 | out: | ||
829 | kfree(dn); | ||
830 | return err; | ||
831 | } | ||
832 | |||
833 | static __net_exit void dccp_net_exit(struct net *net) | ||
834 | { | ||
835 | struct dccp_net *dn = dccp_pernet(net); | ||
836 | #ifdef CONFIG_SYSCTL | ||
837 | unregister_net_sysctl_table(dn->sysctl_header); | ||
838 | kfree(dn->sysctl_table); | ||
839 | #endif | ||
840 | kfree(dn); | ||
841 | |||
842 | net_assign_generic(net, dccp_net_id, NULL); | ||
843 | } | ||
844 | |||
845 | static struct pernet_operations dccp_net_ops = { | ||
846 | .init = dccp_net_init, | ||
847 | .exit = dccp_net_exit, | ||
784 | }; | 848 | }; |
785 | 849 | ||
786 | static int __init nf_conntrack_proto_dccp_init(void) | 850 | static int __init nf_conntrack_proto_dccp_init(void) |
787 | { | 851 | { |
788 | int err; | 852 | int err; |
789 | 853 | ||
790 | err = nf_conntrack_l4proto_register(&dccp_proto4); | 854 | err = register_pernet_gen_subsys(&dccp_net_id, &dccp_net_ops); |
791 | if (err < 0) | 855 | if (err < 0) |
792 | goto err1; | 856 | goto err1; |
793 | 857 | ||
794 | err = nf_conntrack_l4proto_register(&dccp_proto6); | 858 | err = nf_conntrack_l4proto_register(&dccp_proto4); |
795 | if (err < 0) | 859 | if (err < 0) |
796 | goto err2; | 860 | goto err2; |
861 | |||
862 | err = nf_conntrack_l4proto_register(&dccp_proto6); | ||
863 | if (err < 0) | ||
864 | goto err3; | ||
797 | return 0; | 865 | return 0; |
798 | 866 | ||
799 | err2: | 867 | err3: |
800 | nf_conntrack_l4proto_unregister(&dccp_proto4); | 868 | nf_conntrack_l4proto_unregister(&dccp_proto4); |
869 | err2: | ||
870 | unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops); | ||
801 | err1: | 871 | err1: |
802 | return err; | 872 | return err; |
803 | } | 873 | } |
804 | 874 | ||
805 | static void __exit nf_conntrack_proto_dccp_fini(void) | 875 | static void __exit nf_conntrack_proto_dccp_fini(void) |
806 | { | 876 | { |
877 | unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops); | ||
807 | nf_conntrack_l4proto_unregister(&dccp_proto6); | 878 | nf_conntrack_l4proto_unregister(&dccp_proto6); |
808 | nf_conntrack_l4proto_unregister(&dccp_proto4); | 879 | nf_conntrack_l4proto_unregister(&dccp_proto4); |
809 | } | 880 | } |
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 4be80d7b8795..829374f426c4 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c | |||
@@ -92,7 +92,7 @@ static struct ctl_table generic_compat_sysctl_table[] = { | |||
92 | struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = | 92 | struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = |
93 | { | 93 | { |
94 | .l3proto = PF_UNSPEC, | 94 | .l3proto = PF_UNSPEC, |
95 | .l4proto = 0, | 95 | .l4proto = 255, |
96 | .name = "unknown", | 96 | .name = "unknown", |
97 | .pkt_to_tuple = generic_pkt_to_tuple, | 97 | .pkt_to_tuple = generic_pkt_to_tuple, |
98 | .invert_tuple = generic_invert_tuple, | 98 | .invert_tuple = generic_invert_tuple, |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index f3fd154d1ddd..e46f3b79adb3 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <net/netfilter/nf_conntrack_l4proto.h> | 25 | #include <net/netfilter/nf_conntrack_l4proto.h> |
26 | #include <net/netfilter/nf_conntrack_ecache.h> | 26 | #include <net/netfilter/nf_conntrack_ecache.h> |
27 | #include <net/netfilter/nf_log.h> | 27 | #include <net/netfilter/nf_log.h> |
28 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | ||
29 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | ||
28 | 30 | ||
29 | /* Protects ct->proto.tcp */ | 31 | /* Protects ct->proto.tcp */ |
30 | static DEFINE_RWLOCK(tcp_lock); | 32 | static DEFINE_RWLOCK(tcp_lock); |
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 2b8b1f579f93..d4021179e24e 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <net/netfilter/nf_conntrack_l4proto.h> | 22 | #include <net/netfilter/nf_conntrack_l4proto.h> |
23 | #include <net/netfilter/nf_conntrack_ecache.h> | 23 | #include <net/netfilter/nf_conntrack_ecache.h> |
24 | #include <net/netfilter/nf_log.h> | 24 | #include <net/netfilter/nf_log.h> |
25 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | ||
26 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | ||
25 | 27 | ||
26 | static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; | 28 | static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; |
27 | static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; | 29 | static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; |
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index fa8ae5d2659c..8bb998fe098b 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c | |||
@@ -14,58 +14,63 @@ | |||
14 | LOG target modules */ | 14 | LOG target modules */ |
15 | 15 | ||
16 | #define NF_LOG_PREFIXLEN 128 | 16 | #define NF_LOG_PREFIXLEN 128 |
17 | #define NFLOGGER_NAME_LEN 64 | ||
17 | 18 | ||
18 | static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly; | 19 | static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly; |
20 | static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly; | ||
19 | static DEFINE_MUTEX(nf_log_mutex); | 21 | static DEFINE_MUTEX(nf_log_mutex); |
20 | 22 | ||
21 | /* return EBUSY if somebody else is registered, EEXIST if the same logger | 23 | static struct nf_logger *__find_logger(int pf, const char *str_logger) |
22 | * is registred, 0 on success. */ | ||
23 | int nf_log_register(u_int8_t pf, const struct nf_logger *logger) | ||
24 | { | 24 | { |
25 | int ret; | 25 | struct nf_logger *t; |
26 | 26 | ||
27 | if (pf >= ARRAY_SIZE(nf_loggers)) | 27 | list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) { |
28 | return -EINVAL; | 28 | if (!strnicmp(str_logger, t->name, strlen(t->name))) |
29 | 29 | return t; | |
30 | /* Any setup of logging members must be done before | 30 | } |
31 | * substituting pointer. */ | ||
32 | ret = mutex_lock_interruptible(&nf_log_mutex); | ||
33 | if (ret < 0) | ||
34 | return ret; | ||
35 | |||
36 | if (!nf_loggers[pf]) | ||
37 | rcu_assign_pointer(nf_loggers[pf], logger); | ||
38 | else if (nf_loggers[pf] == logger) | ||
39 | ret = -EEXIST; | ||
40 | else | ||
41 | ret = -EBUSY; | ||
42 | 31 | ||
43 | mutex_unlock(&nf_log_mutex); | 32 | return NULL; |
44 | return ret; | ||
45 | } | 33 | } |
46 | EXPORT_SYMBOL(nf_log_register); | ||
47 | 34 | ||
48 | void nf_log_unregister_pf(u_int8_t pf) | 35 | /* return EEXIST if the same logger is registred, 0 on success. */ |
36 | int nf_log_register(u_int8_t pf, struct nf_logger *logger) | ||
49 | { | 37 | { |
38 | const struct nf_logger *llog; | ||
39 | |||
50 | if (pf >= ARRAY_SIZE(nf_loggers)) | 40 | if (pf >= ARRAY_SIZE(nf_loggers)) |
51 | return; | 41 | return -EINVAL; |
42 | |||
52 | mutex_lock(&nf_log_mutex); | 43 | mutex_lock(&nf_log_mutex); |
53 | rcu_assign_pointer(nf_loggers[pf], NULL); | 44 | |
45 | if (pf == NFPROTO_UNSPEC) { | ||
46 | int i; | ||
47 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) | ||
48 | list_add_tail(&(logger->list[i]), &(nf_loggers_l[i])); | ||
49 | } else { | ||
50 | /* register at end of list to honor first register win */ | ||
51 | list_add_tail(&logger->list[pf], &nf_loggers_l[pf]); | ||
52 | llog = rcu_dereference(nf_loggers[pf]); | ||
53 | if (llog == NULL) | ||
54 | rcu_assign_pointer(nf_loggers[pf], logger); | ||
55 | } | ||
56 | |||
54 | mutex_unlock(&nf_log_mutex); | 57 | mutex_unlock(&nf_log_mutex); |
55 | 58 | ||
56 | /* Give time to concurrent readers. */ | 59 | return 0; |
57 | synchronize_rcu(); | ||
58 | } | 60 | } |
59 | EXPORT_SYMBOL(nf_log_unregister_pf); | 61 | EXPORT_SYMBOL(nf_log_register); |
60 | 62 | ||
61 | void nf_log_unregister(const struct nf_logger *logger) | 63 | void nf_log_unregister(struct nf_logger *logger) |
62 | { | 64 | { |
65 | const struct nf_logger *c_logger; | ||
63 | int i; | 66 | int i; |
64 | 67 | ||
65 | mutex_lock(&nf_log_mutex); | 68 | mutex_lock(&nf_log_mutex); |
66 | for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) { | 69 | for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) { |
67 | if (nf_loggers[i] == logger) | 70 | c_logger = rcu_dereference(nf_loggers[i]); |
71 | if (c_logger == logger) | ||
68 | rcu_assign_pointer(nf_loggers[i], NULL); | 72 | rcu_assign_pointer(nf_loggers[i], NULL); |
73 | list_del(&logger->list[i]); | ||
69 | } | 74 | } |
70 | mutex_unlock(&nf_log_mutex); | 75 | mutex_unlock(&nf_log_mutex); |
71 | 76 | ||
@@ -73,6 +78,27 @@ void nf_log_unregister(const struct nf_logger *logger) | |||
73 | } | 78 | } |
74 | EXPORT_SYMBOL(nf_log_unregister); | 79 | EXPORT_SYMBOL(nf_log_unregister); |
75 | 80 | ||
81 | int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger) | ||
82 | { | ||
83 | mutex_lock(&nf_log_mutex); | ||
84 | if (__find_logger(pf, logger->name) == NULL) { | ||
85 | mutex_unlock(&nf_log_mutex); | ||
86 | return -ENOENT; | ||
87 | } | ||
88 | rcu_assign_pointer(nf_loggers[pf], logger); | ||
89 | mutex_unlock(&nf_log_mutex); | ||
90 | return 0; | ||
91 | } | ||
92 | EXPORT_SYMBOL(nf_log_bind_pf); | ||
93 | |||
94 | void nf_log_unbind_pf(u_int8_t pf) | ||
95 | { | ||
96 | mutex_lock(&nf_log_mutex); | ||
97 | rcu_assign_pointer(nf_loggers[pf], NULL); | ||
98 | mutex_unlock(&nf_log_mutex); | ||
99 | } | ||
100 | EXPORT_SYMBOL(nf_log_unbind_pf); | ||
101 | |||
76 | void nf_log_packet(u_int8_t pf, | 102 | void nf_log_packet(u_int8_t pf, |
77 | unsigned int hooknum, | 103 | unsigned int hooknum, |
78 | const struct sk_buff *skb, | 104 | const struct sk_buff *skb, |
@@ -129,13 +155,37 @@ static int seq_show(struct seq_file *s, void *v) | |||
129 | { | 155 | { |
130 | loff_t *pos = v; | 156 | loff_t *pos = v; |
131 | const struct nf_logger *logger; | 157 | const struct nf_logger *logger; |
158 | struct nf_logger *t; | ||
159 | int ret; | ||
132 | 160 | ||
133 | logger = rcu_dereference(nf_loggers[*pos]); | 161 | logger = rcu_dereference(nf_loggers[*pos]); |
134 | 162 | ||
135 | if (!logger) | 163 | if (!logger) |
136 | return seq_printf(s, "%2lld NONE\n", *pos); | 164 | ret = seq_printf(s, "%2lld NONE (", *pos); |
165 | else | ||
166 | ret = seq_printf(s, "%2lld %s (", *pos, logger->name); | ||
167 | |||
168 | if (ret < 0) | ||
169 | return ret; | ||
170 | |||
171 | mutex_lock(&nf_log_mutex); | ||
172 | list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) { | ||
173 | ret = seq_printf(s, "%s", t->name); | ||
174 | if (ret < 0) { | ||
175 | mutex_unlock(&nf_log_mutex); | ||
176 | return ret; | ||
177 | } | ||
178 | if (&t->list[*pos] != nf_loggers_l[*pos].prev) { | ||
179 | ret = seq_printf(s, ","); | ||
180 | if (ret < 0) { | ||
181 | mutex_unlock(&nf_log_mutex); | ||
182 | return ret; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | mutex_unlock(&nf_log_mutex); | ||
137 | 187 | ||
138 | return seq_printf(s, "%2lld %s\n", *pos, logger->name); | 188 | return seq_printf(s, ")\n"); |
139 | } | 189 | } |
140 | 190 | ||
141 | static const struct seq_operations nflog_seq_ops = { | 191 | static const struct seq_operations nflog_seq_ops = { |
@@ -158,15 +208,102 @@ static const struct file_operations nflog_file_ops = { | |||
158 | .release = seq_release, | 208 | .release = seq_release, |
159 | }; | 209 | }; |
160 | 210 | ||
211 | |||
161 | #endif /* PROC_FS */ | 212 | #endif /* PROC_FS */ |
162 | 213 | ||
214 | #ifdef CONFIG_SYSCTL | ||
215 | struct ctl_path nf_log_sysctl_path[] = { | ||
216 | { .procname = "net", .ctl_name = CTL_NET, }, | ||
217 | { .procname = "netfilter", .ctl_name = NET_NETFILTER, }, | ||
218 | { .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, }, | ||
219 | { } | ||
220 | }; | ||
221 | |||
222 | static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; | ||
223 | static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; | ||
224 | static struct ctl_table_header *nf_log_dir_header; | ||
225 | |||
226 | static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, | ||
227 | void *buffer, size_t *lenp, loff_t *ppos) | ||
228 | { | ||
229 | const struct nf_logger *logger; | ||
230 | int r = 0; | ||
231 | int tindex = (unsigned long)table->extra1; | ||
232 | |||
233 | if (write) { | ||
234 | if (!strcmp(buffer, "NONE")) { | ||
235 | nf_log_unbind_pf(tindex); | ||
236 | return 0; | ||
237 | } | ||
238 | mutex_lock(&nf_log_mutex); | ||
239 | logger = __find_logger(tindex, buffer); | ||
240 | if (logger == NULL) { | ||
241 | mutex_unlock(&nf_log_mutex); | ||
242 | return -ENOENT; | ||
243 | } | ||
244 | rcu_assign_pointer(nf_loggers[tindex], logger); | ||
245 | mutex_unlock(&nf_log_mutex); | ||
246 | } else { | ||
247 | rcu_read_lock(); | ||
248 | logger = rcu_dereference(nf_loggers[tindex]); | ||
249 | if (!logger) | ||
250 | table->data = "NONE"; | ||
251 | else | ||
252 | table->data = logger->name; | ||
253 | r = proc_dostring(table, write, filp, buffer, lenp, ppos); | ||
254 | rcu_read_unlock(); | ||
255 | } | ||
256 | |||
257 | return r; | ||
258 | } | ||
259 | |||
260 | static __init int netfilter_log_sysctl_init(void) | ||
261 | { | ||
262 | int i; | ||
263 | |||
264 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { | ||
265 | snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i); | ||
266 | nf_log_sysctl_table[i].ctl_name = CTL_UNNUMBERED; | ||
267 | nf_log_sysctl_table[i].procname = | ||
268 | nf_log_sysctl_fnames[i-NFPROTO_UNSPEC]; | ||
269 | nf_log_sysctl_table[i].data = NULL; | ||
270 | nf_log_sysctl_table[i].maxlen = | ||
271 | NFLOGGER_NAME_LEN * sizeof(char); | ||
272 | nf_log_sysctl_table[i].mode = 0644; | ||
273 | nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring; | ||
274 | nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i; | ||
275 | } | ||
276 | |||
277 | nf_log_dir_header = register_sysctl_paths(nf_log_sysctl_path, | ||
278 | nf_log_sysctl_table); | ||
279 | if (!nf_log_dir_header) | ||
280 | return -ENOMEM; | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | #else | ||
285 | static __init int netfilter_log_sysctl_init(void) | ||
286 | { | ||
287 | return 0; | ||
288 | } | ||
289 | #endif /* CONFIG_SYSCTL */ | ||
163 | 290 | ||
164 | int __init netfilter_log_init(void) | 291 | int __init netfilter_log_init(void) |
165 | { | 292 | { |
293 | int i, r; | ||
166 | #ifdef CONFIG_PROC_FS | 294 | #ifdef CONFIG_PROC_FS |
167 | if (!proc_create("nf_log", S_IRUGO, | 295 | if (!proc_create("nf_log", S_IRUGO, |
168 | proc_net_netfilter, &nflog_file_ops)) | 296 | proc_net_netfilter, &nflog_file_ops)) |
169 | return -1; | 297 | return -1; |
170 | #endif | 298 | #endif |
299 | |||
300 | /* Errors will trigger panic, unroll on error is unnecessary. */ | ||
301 | r = netfilter_log_sysctl_init(); | ||
302 | if (r < 0) | ||
303 | return r; | ||
304 | |||
305 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) | ||
306 | INIT_LIST_HEAD(&(nf_loggers_l[i])); | ||
307 | |||
171 | return 0; | 308 | return 0; |
172 | } | 309 | } |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 9c0ba17a1ddb..2785d66a7e38 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -113,6 +113,12 @@ int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) | |||
113 | } | 113 | } |
114 | EXPORT_SYMBOL_GPL(nfnetlink_send); | 114 | EXPORT_SYMBOL_GPL(nfnetlink_send); |
115 | 115 | ||
116 | void nfnetlink_set_err(u32 pid, u32 group, int error) | ||
117 | { | ||
118 | netlink_set_err(nfnl, pid, group, error); | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(nfnetlink_set_err); | ||
121 | |||
116 | int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) | 122 | int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) |
117 | { | 123 | { |
118 | return netlink_unicast(nfnl, skb, pid, flags); | 124 | return netlink_unicast(nfnl, skb, pid, flags); |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index c712e9fc6bba..fd326ac27ec8 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -693,7 +693,7 @@ nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, | |||
693 | return -ENOTSUPP; | 693 | return -ENOTSUPP; |
694 | } | 694 | } |
695 | 695 | ||
696 | static const struct nf_logger nfulnl_logger = { | 696 | static struct nf_logger nfulnl_logger __read_mostly = { |
697 | .name = "nfnetlink_log", | 697 | .name = "nfnetlink_log", |
698 | .logfn = &nfulnl_log_packet, | 698 | .logfn = &nfulnl_log_packet, |
699 | .me = THIS_MODULE, | 699 | .me = THIS_MODULE, |
@@ -725,9 +725,9 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
725 | /* Commands without queue context */ | 725 | /* Commands without queue context */ |
726 | switch (cmd->command) { | 726 | switch (cmd->command) { |
727 | case NFULNL_CFG_CMD_PF_BIND: | 727 | case NFULNL_CFG_CMD_PF_BIND: |
728 | return nf_log_register(pf, &nfulnl_logger); | 728 | return nf_log_bind_pf(pf, &nfulnl_logger); |
729 | case NFULNL_CFG_CMD_PF_UNBIND: | 729 | case NFULNL_CFG_CMD_PF_UNBIND: |
730 | nf_log_unregister_pf(pf); | 730 | nf_log_unbind_pf(pf); |
731 | return 0; | 731 | return 0; |
732 | } | 732 | } |
733 | } | 733 | } |
@@ -952,17 +952,25 @@ static int __init nfnetlink_log_init(void) | |||
952 | goto cleanup_netlink_notifier; | 952 | goto cleanup_netlink_notifier; |
953 | } | 953 | } |
954 | 954 | ||
955 | status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); | ||
956 | if (status < 0) { | ||
957 | printk(KERN_ERR "log: failed to register logger\n"); | ||
958 | goto cleanup_subsys; | ||
959 | } | ||
960 | |||
955 | #ifdef CONFIG_PROC_FS | 961 | #ifdef CONFIG_PROC_FS |
956 | if (!proc_create("nfnetlink_log", 0440, | 962 | if (!proc_create("nfnetlink_log", 0440, |
957 | proc_net_netfilter, &nful_file_ops)) | 963 | proc_net_netfilter, &nful_file_ops)) |
958 | goto cleanup_subsys; | 964 | goto cleanup_logger; |
959 | #endif | 965 | #endif |
960 | return status; | 966 | return status; |
961 | 967 | ||
962 | #ifdef CONFIG_PROC_FS | 968 | #ifdef CONFIG_PROC_FS |
969 | cleanup_logger: | ||
970 | nf_log_unregister(&nfulnl_logger); | ||
971 | #endif | ||
963 | cleanup_subsys: | 972 | cleanup_subsys: |
964 | nfnetlink_subsys_unregister(&nfulnl_subsys); | 973 | nfnetlink_subsys_unregister(&nfulnl_subsys); |
965 | #endif | ||
966 | cleanup_netlink_notifier: | 974 | cleanup_netlink_notifier: |
967 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); | 975 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); |
968 | return status; | 976 | return status; |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 5baccfa5a0de..509a95621f9f 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -625,6 +625,20 @@ void xt_free_table_info(struct xt_table_info *info) | |||
625 | } | 625 | } |
626 | EXPORT_SYMBOL(xt_free_table_info); | 626 | EXPORT_SYMBOL(xt_free_table_info); |
627 | 627 | ||
628 | void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo, | ||
629 | struct xt_table_info *newinfo) | ||
630 | { | ||
631 | unsigned int cpu; | ||
632 | |||
633 | for_each_possible_cpu(cpu) { | ||
634 | void *p = oldinfo->entries[cpu]; | ||
635 | rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]); | ||
636 | newinfo->entries[cpu] = p; | ||
637 | } | ||
638 | |||
639 | } | ||
640 | EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu); | ||
641 | |||
628 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ | 642 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ |
629 | struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, | 643 | struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, |
630 | const char *name) | 644 | const char *name) |
@@ -671,21 +685,22 @@ xt_replace_table(struct xt_table *table, | |||
671 | struct xt_table_info *oldinfo, *private; | 685 | struct xt_table_info *oldinfo, *private; |
672 | 686 | ||
673 | /* Do the substitution. */ | 687 | /* Do the substitution. */ |
674 | write_lock_bh(&table->lock); | 688 | mutex_lock(&table->lock); |
675 | private = table->private; | 689 | private = table->private; |
676 | /* Check inside lock: is the old number correct? */ | 690 | /* Check inside lock: is the old number correct? */ |
677 | if (num_counters != private->number) { | 691 | if (num_counters != private->number) { |
678 | duprintf("num_counters != table->private->number (%u/%u)\n", | 692 | duprintf("num_counters != table->private->number (%u/%u)\n", |
679 | num_counters, private->number); | 693 | num_counters, private->number); |
680 | write_unlock_bh(&table->lock); | 694 | mutex_unlock(&table->lock); |
681 | *error = -EAGAIN; | 695 | *error = -EAGAIN; |
682 | return NULL; | 696 | return NULL; |
683 | } | 697 | } |
684 | oldinfo = private; | 698 | oldinfo = private; |
685 | table->private = newinfo; | 699 | rcu_assign_pointer(table->private, newinfo); |
686 | newinfo->initial_entries = oldinfo->initial_entries; | 700 | newinfo->initial_entries = oldinfo->initial_entries; |
687 | write_unlock_bh(&table->lock); | 701 | mutex_unlock(&table->lock); |
688 | 702 | ||
703 | synchronize_net(); | ||
689 | return oldinfo; | 704 | return oldinfo; |
690 | } | 705 | } |
691 | EXPORT_SYMBOL_GPL(xt_replace_table); | 706 | EXPORT_SYMBOL_GPL(xt_replace_table); |
@@ -719,7 +734,8 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table, | |||
719 | 734 | ||
720 | /* Simplifies replace_table code. */ | 735 | /* Simplifies replace_table code. */ |
721 | table->private = bootstrap; | 736 | table->private = bootstrap; |
722 | rwlock_init(&table->lock); | 737 | mutex_init(&table->lock); |
738 | |||
723 | if (!xt_replace_table(table, 0, newinfo, &ret)) | 739 | if (!xt_replace_table(table, 0, newinfo, &ret)) |
724 | goto unlock; | 740 | goto unlock; |
725 | 741 | ||
diff --git a/net/netfilter/xt_HL.c b/net/netfilter/xt_HL.c new file mode 100644 index 000000000000..10e789e2d12a --- /dev/null +++ b/net/netfilter/xt_HL.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * TTL modification target for IP tables | ||
3 | * (C) 2000,2005 by Harald Welte <laforge@netfilter.org> | ||
4 | * | ||
5 | * Hop Limit modification target for ip6tables | ||
6 | * Maciej Soltysiak <solt@dns.toxicfilms.tv> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <linux/ipv6.h> | ||
17 | #include <net/checksum.h> | ||
18 | |||
19 | #include <linux/netfilter/x_tables.h> | ||
20 | #include <linux/netfilter_ipv4/ipt_TTL.h> | ||
21 | #include <linux/netfilter_ipv6/ip6t_HL.h> | ||
22 | |||
23 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
24 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | ||
25 | MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | static unsigned int | ||
29 | ttl_tg(struct sk_buff *skb, const struct xt_target_param *par) | ||
30 | { | ||
31 | struct iphdr *iph; | ||
32 | const struct ipt_TTL_info *info = par->targinfo; | ||
33 | int new_ttl; | ||
34 | |||
35 | if (!skb_make_writable(skb, skb->len)) | ||
36 | return NF_DROP; | ||
37 | |||
38 | iph = ip_hdr(skb); | ||
39 | |||
40 | switch (info->mode) { | ||
41 | case IPT_TTL_SET: | ||
42 | new_ttl = info->ttl; | ||
43 | break; | ||
44 | case IPT_TTL_INC: | ||
45 | new_ttl = iph->ttl + info->ttl; | ||
46 | if (new_ttl > 255) | ||
47 | new_ttl = 255; | ||
48 | break; | ||
49 | case IPT_TTL_DEC: | ||
50 | new_ttl = iph->ttl - info->ttl; | ||
51 | if (new_ttl < 0) | ||
52 | new_ttl = 0; | ||
53 | break; | ||
54 | default: | ||
55 | new_ttl = iph->ttl; | ||
56 | break; | ||
57 | } | ||
58 | |||
59 | if (new_ttl != iph->ttl) { | ||
60 | csum_replace2(&iph->check, htons(iph->ttl << 8), | ||
61 | htons(new_ttl << 8)); | ||
62 | iph->ttl = new_ttl; | ||
63 | } | ||
64 | |||
65 | return XT_CONTINUE; | ||
66 | } | ||
67 | |||
68 | static unsigned int | ||
69 | hl_tg6(struct sk_buff *skb, const struct xt_target_param *par) | ||
70 | { | ||
71 | struct ipv6hdr *ip6h; | ||
72 | const struct ip6t_HL_info *info = par->targinfo; | ||
73 | int new_hl; | ||
74 | |||
75 | if (!skb_make_writable(skb, skb->len)) | ||
76 | return NF_DROP; | ||
77 | |||
78 | ip6h = ipv6_hdr(skb); | ||
79 | |||
80 | switch (info->mode) { | ||
81 | case IP6T_HL_SET: | ||
82 | new_hl = info->hop_limit; | ||
83 | break; | ||
84 | case IP6T_HL_INC: | ||
85 | new_hl = ip6h->hop_limit + info->hop_limit; | ||
86 | if (new_hl > 255) | ||
87 | new_hl = 255; | ||
88 | break; | ||
89 | case IP6T_HL_DEC: | ||
90 | new_hl = ip6h->hop_limit - info->hop_limit; | ||
91 | if (new_hl < 0) | ||
92 | new_hl = 0; | ||
93 | break; | ||
94 | default: | ||
95 | new_hl = ip6h->hop_limit; | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | ip6h->hop_limit = new_hl; | ||
100 | |||
101 | return XT_CONTINUE; | ||
102 | } | ||
103 | |||
104 | static bool ttl_tg_check(const struct xt_tgchk_param *par) | ||
105 | { | ||
106 | const struct ipt_TTL_info *info = par->targinfo; | ||
107 | |||
108 | if (info->mode > IPT_TTL_MAXMODE) { | ||
109 | printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", | ||
110 | info->mode); | ||
111 | return false; | ||
112 | } | ||
113 | if (info->mode != IPT_TTL_SET && info->ttl == 0) | ||
114 | return false; | ||
115 | return true; | ||
116 | } | ||
117 | |||
118 | static bool hl_tg6_check(const struct xt_tgchk_param *par) | ||
119 | { | ||
120 | const struct ip6t_HL_info *info = par->targinfo; | ||
121 | |||
122 | if (info->mode > IP6T_HL_MAXMODE) { | ||
123 | printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", | ||
124 | info->mode); | ||
125 | return false; | ||
126 | } | ||
127 | if (info->mode != IP6T_HL_SET && info->hop_limit == 0) { | ||
128 | printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " | ||
129 | "make sense with value 0\n"); | ||
130 | return false; | ||
131 | } | ||
132 | return true; | ||
133 | } | ||
134 | |||
135 | static struct xt_target hl_tg_reg[] __read_mostly = { | ||
136 | { | ||
137 | .name = "TTL", | ||
138 | .revision = 0, | ||
139 | .family = NFPROTO_IPV4, | ||
140 | .target = ttl_tg, | ||
141 | .targetsize = sizeof(struct ipt_TTL_info), | ||
142 | .table = "mangle", | ||
143 | .checkentry = ttl_tg_check, | ||
144 | .me = THIS_MODULE, | ||
145 | }, | ||
146 | { | ||
147 | .name = "HL", | ||
148 | .revision = 0, | ||
149 | .family = NFPROTO_IPV6, | ||
150 | .target = hl_tg6, | ||
151 | .targetsize = sizeof(struct ip6t_HL_info), | ||
152 | .table = "mangle", | ||
153 | .checkentry = hl_tg6_check, | ||
154 | .me = THIS_MODULE, | ||
155 | }, | ||
156 | }; | ||
157 | |||
158 | static int __init hl_tg_init(void) | ||
159 | { | ||
160 | return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | ||
161 | } | ||
162 | |||
163 | static void __exit hl_tg_exit(void) | ||
164 | { | ||
165 | xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | ||
166 | } | ||
167 | |||
168 | module_init(hl_tg_init); | ||
169 | module_exit(hl_tg_exit); | ||
170 | MODULE_ALIAS("ipt_TTL"); | ||
171 | MODULE_ALIAS("ip6t_HL"); | ||
diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c new file mode 100644 index 000000000000..8ff7843bb921 --- /dev/null +++ b/net/netfilter/xt_LED.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * xt_LED.c - netfilter target to make LEDs blink upon packet matches | ||
3 | * | ||
4 | * Copyright (C) 2008 Adam Nielsen <a.nielsen@shikadi.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/skbuff.h> | ||
24 | #include <linux/netfilter/x_tables.h> | ||
25 | #include <linux/leds.h> | ||
26 | #include <linux/mutex.h> | ||
27 | |||
28 | #include <linux/netfilter/xt_LED.h> | ||
29 | |||
30 | MODULE_LICENSE("GPL"); | ||
31 | MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>"); | ||
32 | MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match"); | ||
33 | |||
34 | /* | ||
35 | * This is declared in here (the kernel module) only, to avoid having these | ||
36 | * dependencies in userspace code. This is what xt_led_info.internal_data | ||
37 | * points to. | ||
38 | */ | ||
39 | struct xt_led_info_internal { | ||
40 | struct led_trigger netfilter_led_trigger; | ||
41 | struct timer_list timer; | ||
42 | }; | ||
43 | |||
44 | static unsigned int | ||
45 | led_tg(struct sk_buff *skb, const struct xt_target_param *par) | ||
46 | { | ||
47 | const struct xt_led_info *ledinfo = par->targinfo; | ||
48 | struct xt_led_info_internal *ledinternal = ledinfo->internal_data; | ||
49 | |||
50 | /* | ||
51 | * If "always blink" is enabled, and there's still some time until the | ||
52 | * LED will switch off, briefly switch it off now. | ||
53 | */ | ||
54 | if ((ledinfo->delay > 0) && ledinfo->always_blink && | ||
55 | timer_pending(&ledinternal->timer)) | ||
56 | led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF); | ||
57 | |||
58 | led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); | ||
59 | |||
60 | /* If there's a positive delay, start/update the timer */ | ||
61 | if (ledinfo->delay > 0) { | ||
62 | mod_timer(&ledinternal->timer, | ||
63 | jiffies + msecs_to_jiffies(ledinfo->delay)); | ||
64 | |||
65 | /* Otherwise if there was no delay given, blink as fast as possible */ | ||
66 | } else if (ledinfo->delay == 0) { | ||
67 | led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); | ||
68 | } | ||
69 | |||
70 | /* else the delay is negative, which means switch on and stay on */ | ||
71 | |||
72 | return XT_CONTINUE; | ||
73 | } | ||
74 | |||
75 | static void led_timeout_callback(unsigned long data) | ||
76 | { | ||
77 | struct xt_led_info *ledinfo = (struct xt_led_info *)data; | ||
78 | struct xt_led_info_internal *ledinternal = ledinfo->internal_data; | ||
79 | |||
80 | led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); | ||
81 | } | ||
82 | |||
83 | static bool led_tg_check(const struct xt_tgchk_param *par) | ||
84 | { | ||
85 | struct xt_led_info *ledinfo = par->targinfo; | ||
86 | struct xt_led_info_internal *ledinternal; | ||
87 | int err; | ||
88 | |||
89 | if (ledinfo->id[0] == '\0') { | ||
90 | printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n"); | ||
91 | return false; | ||
92 | } | ||
93 | |||
94 | ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL); | ||
95 | if (!ledinternal) { | ||
96 | printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n"); | ||
97 | return false; | ||
98 | } | ||
99 | |||
100 | ledinternal->netfilter_led_trigger.name = ledinfo->id; | ||
101 | |||
102 | err = led_trigger_register(&ledinternal->netfilter_led_trigger); | ||
103 | if (err) { | ||
104 | printk(KERN_CRIT KBUILD_MODNAME | ||
105 | ": led_trigger_register() failed\n"); | ||
106 | if (err == -EEXIST) | ||
107 | printk(KERN_ERR KBUILD_MODNAME | ||
108 | ": Trigger name is already in use.\n"); | ||
109 | goto exit_alloc; | ||
110 | } | ||
111 | |||
112 | /* See if we need to set up a timer */ | ||
113 | if (ledinfo->delay > 0) | ||
114 | setup_timer(&ledinternal->timer, led_timeout_callback, | ||
115 | (unsigned long)ledinfo); | ||
116 | |||
117 | ledinfo->internal_data = ledinternal; | ||
118 | |||
119 | return true; | ||
120 | |||
121 | exit_alloc: | ||
122 | kfree(ledinternal); | ||
123 | |||
124 | return false; | ||
125 | } | ||
126 | |||
127 | static void led_tg_destroy(const struct xt_tgdtor_param *par) | ||
128 | { | ||
129 | const struct xt_led_info *ledinfo = par->targinfo; | ||
130 | struct xt_led_info_internal *ledinternal = ledinfo->internal_data; | ||
131 | |||
132 | if (ledinfo->delay > 0) | ||
133 | del_timer_sync(&ledinternal->timer); | ||
134 | |||
135 | led_trigger_unregister(&ledinternal->netfilter_led_trigger); | ||
136 | kfree(ledinternal); | ||
137 | } | ||
138 | |||
139 | static struct xt_target led_tg_reg __read_mostly = { | ||
140 | .name = "LED", | ||
141 | .revision = 0, | ||
142 | .family = NFPROTO_UNSPEC, | ||
143 | .target = led_tg, | ||
144 | .targetsize = XT_ALIGN(sizeof(struct xt_led_info)), | ||
145 | .checkentry = led_tg_check, | ||
146 | .destroy = led_tg_destroy, | ||
147 | .me = THIS_MODULE, | ||
148 | }; | ||
149 | |||
150 | static int __init led_tg_init(void) | ||
151 | { | ||
152 | return xt_register_target(&led_tg_reg); | ||
153 | } | ||
154 | |||
155 | static void __exit led_tg_exit(void) | ||
156 | { | ||
157 | xt_unregister_target(&led_tg_reg); | ||
158 | } | ||
159 | |||
160 | module_init(led_tg_init); | ||
161 | module_exit(led_tg_exit); | ||
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c new file mode 100644 index 000000000000..ad5bd890e4e8 --- /dev/null +++ b/net/netfilter/xt_cluster.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * (C) 2008-2009 Pablo Neira Ayuso <pablo@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/skbuff.h> | ||
10 | #include <linux/jhash.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <net/ipv6.h> | ||
13 | |||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | #include <net/netfilter/nf_conntrack.h> | ||
16 | #include <linux/netfilter/xt_cluster.h> | ||
17 | |||
18 | static inline u_int32_t nf_ct_orig_ipv4_src(const struct nf_conn *ct) | ||
19 | { | ||
20 | return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; | ||
21 | } | ||
22 | |||
23 | static inline const void *nf_ct_orig_ipv6_src(const struct nf_conn *ct) | ||
24 | { | ||
25 | return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6; | ||
26 | } | ||
27 | |||
28 | static inline u_int32_t | ||
29 | xt_cluster_hash_ipv4(u_int32_t ip, const struct xt_cluster_match_info *info) | ||
30 | { | ||
31 | return jhash_1word(ip, info->hash_seed); | ||
32 | } | ||
33 | |||
34 | static inline u_int32_t | ||
35 | xt_cluster_hash_ipv6(const void *ip, const struct xt_cluster_match_info *info) | ||
36 | { | ||
37 | return jhash2(ip, NF_CT_TUPLE_L3SIZE / sizeof(__u32), info->hash_seed); | ||
38 | } | ||
39 | |||
40 | static inline u_int32_t | ||
41 | xt_cluster_hash(const struct nf_conn *ct, | ||
42 | const struct xt_cluster_match_info *info) | ||
43 | { | ||
44 | u_int32_t hash = 0; | ||
45 | |||
46 | switch(nf_ct_l3num(ct)) { | ||
47 | case AF_INET: | ||
48 | hash = xt_cluster_hash_ipv4(nf_ct_orig_ipv4_src(ct), info); | ||
49 | break; | ||
50 | case AF_INET6: | ||
51 | hash = xt_cluster_hash_ipv6(nf_ct_orig_ipv6_src(ct), info); | ||
52 | break; | ||
53 | default: | ||
54 | WARN_ON(1); | ||
55 | break; | ||
56 | } | ||
57 | return (((u64)hash * info->total_nodes) >> 32); | ||
58 | } | ||
59 | |||
60 | static inline bool | ||
61 | xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family) | ||
62 | { | ||
63 | bool is_multicast = false; | ||
64 | |||
65 | switch(family) { | ||
66 | case NFPROTO_IPV4: | ||
67 | is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr); | ||
68 | break; | ||
69 | case NFPROTO_IPV6: | ||
70 | is_multicast = ipv6_addr_type(&ipv6_hdr(skb)->daddr) & | ||
71 | IPV6_ADDR_MULTICAST; | ||
72 | break; | ||
73 | default: | ||
74 | WARN_ON(1); | ||
75 | break; | ||
76 | } | ||
77 | return is_multicast; | ||
78 | } | ||
79 | |||
80 | static bool | ||
81 | xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par) | ||
82 | { | ||
83 | struct sk_buff *pskb = (struct sk_buff *)skb; | ||
84 | const struct xt_cluster_match_info *info = par->matchinfo; | ||
85 | const struct nf_conn *ct; | ||
86 | enum ip_conntrack_info ctinfo; | ||
87 | unsigned long hash; | ||
88 | |||
89 | /* This match assumes that all nodes see the same packets. This can be | ||
90 | * achieved if the switch that connects the cluster nodes support some | ||
91 | * sort of 'port mirroring'. However, if your switch does not support | ||
92 | * this, your cluster nodes can reply ARP request using a multicast MAC | ||
93 | * address. Thus, your switch will flood the same packets to the | ||
94 | * cluster nodes with the same multicast MAC address. Using a multicast | ||
95 | * link address is a RFC 1812 (section 3.3.2) violation, but this works | ||
96 | * fine in practise. | ||
97 | * | ||
98 | * Unfortunately, if you use the multicast MAC address, the link layer | ||
99 | * sets skbuff's pkt_type to PACKET_MULTICAST, which is not accepted | ||
100 | * by TCP and others for packets coming to this node. For that reason, | ||
101 | * this match mangles skbuff's pkt_type if it detects a packet | ||
102 | * addressed to a unicast address but using PACKET_MULTICAST. Yes, I | ||
103 | * know, matches should not alter packets, but we are doing this here | ||
104 | * because we would need to add a PKTTYPE target for this sole purpose. | ||
105 | */ | ||
106 | if (!xt_cluster_is_multicast_addr(skb, par->family) && | ||
107 | skb->pkt_type == PACKET_MULTICAST) { | ||
108 | pskb->pkt_type = PACKET_HOST; | ||
109 | } | ||
110 | |||
111 | ct = nf_ct_get(skb, &ctinfo); | ||
112 | if (ct == NULL) | ||
113 | return false; | ||
114 | |||
115 | if (ct == &nf_conntrack_untracked) | ||
116 | return false; | ||
117 | |||
118 | if (ct->master) | ||
119 | hash = xt_cluster_hash(ct->master, info); | ||
120 | else | ||
121 | hash = xt_cluster_hash(ct, info); | ||
122 | |||
123 | return !!((1 << hash) & info->node_mask) ^ | ||
124 | !!(info->flags & XT_CLUSTER_F_INV); | ||
125 | } | ||
126 | |||
127 | static bool xt_cluster_mt_checkentry(const struct xt_mtchk_param *par) | ||
128 | { | ||
129 | struct xt_cluster_match_info *info = par->matchinfo; | ||
130 | |||
131 | if (info->node_mask >= (1 << info->total_nodes)) { | ||
132 | printk(KERN_ERR "xt_cluster: this node mask cannot be " | ||
133 | "higher than the total number of nodes\n"); | ||
134 | return false; | ||
135 | } | ||
136 | return true; | ||
137 | } | ||
138 | |||
139 | static struct xt_match xt_cluster_match __read_mostly = { | ||
140 | .name = "cluster", | ||
141 | .family = NFPROTO_UNSPEC, | ||
142 | .match = xt_cluster_mt, | ||
143 | .checkentry = xt_cluster_mt_checkentry, | ||
144 | .matchsize = sizeof(struct xt_cluster_match_info), | ||
145 | .me = THIS_MODULE, | ||
146 | }; | ||
147 | |||
148 | static int __init xt_cluster_mt_init(void) | ||
149 | { | ||
150 | return xt_register_match(&xt_cluster_match); | ||
151 | } | ||
152 | |||
153 | static void __exit xt_cluster_mt_fini(void) | ||
154 | { | ||
155 | xt_unregister_match(&xt_cluster_match); | ||
156 | } | ||
157 | |||
158 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
159 | MODULE_LICENSE("GPL"); | ||
160 | MODULE_DESCRIPTION("Xtables: hash-based cluster match"); | ||
161 | MODULE_ALIAS("ipt_cluster"); | ||
162 | MODULE_ALIAS("ip6t_cluster"); | ||
163 | module_init(xt_cluster_mt_init); | ||
164 | module_exit(xt_cluster_mt_fini); | ||
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index f97fded024c4..a5b5369c30f9 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c | |||
@@ -149,7 +149,7 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht, | |||
149 | /* initialize hash with random val at the time we allocate | 149 | /* initialize hash with random val at the time we allocate |
150 | * the first hashtable entry */ | 150 | * the first hashtable entry */ |
151 | if (!ht->rnd_initialized) { | 151 | if (!ht->rnd_initialized) { |
152 | get_random_bytes(&ht->rnd, 4); | 152 | get_random_bytes(&ht->rnd, sizeof(ht->rnd)); |
153 | ht->rnd_initialized = 1; | 153 | ht->rnd_initialized = 1; |
154 | } | 154 | } |
155 | 155 | ||
@@ -565,8 +565,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, | |||
565 | static bool | 565 | static bool |
566 | hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) | 566 | hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) |
567 | { | 567 | { |
568 | const struct xt_hashlimit_info *r = | 568 | const struct xt_hashlimit_info *r = par->matchinfo; |
569 | ((const struct xt_hashlimit_info *)par->matchinfo)->u.master; | ||
570 | struct xt_hashlimit_htable *hinfo = r->hinfo; | 569 | struct xt_hashlimit_htable *hinfo = r->hinfo; |
571 | unsigned long now = jiffies; | 570 | unsigned long now = jiffies; |
572 | struct dsthash_ent *dh; | 571 | struct dsthash_ent *dh; |
@@ -702,8 +701,6 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) | |||
702 | } | 701 | } |
703 | mutex_unlock(&hlimit_mutex); | 702 | mutex_unlock(&hlimit_mutex); |
704 | 703 | ||
705 | /* Ugly hack: For SMP, we only want to use one set */ | ||
706 | r->u.master = r; | ||
707 | return true; | 704 | return true; |
708 | } | 705 | } |
709 | 706 | ||
diff --git a/net/netfilter/xt_hl.c b/net/netfilter/xt_hl.c new file mode 100644 index 000000000000..7726154c87b2 --- /dev/null +++ b/net/netfilter/xt_hl.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * IP tables module for matching the value of the TTL | ||
3 | * (C) 2000,2001 by Harald Welte <laforge@netfilter.org> | ||
4 | * | ||
5 | * Hop Limit matching module | ||
6 | * (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/ip.h> | ||
14 | #include <linux/ipv6.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | |||
18 | #include <linux/netfilter/x_tables.h> | ||
19 | #include <linux/netfilter_ipv4/ipt_ttl.h> | ||
20 | #include <linux/netfilter_ipv6/ip6t_hl.h> | ||
21 | |||
22 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | ||
23 | MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match"); | ||
24 | MODULE_LICENSE("GPL"); | ||
25 | MODULE_ALIAS("ipt_ttl"); | ||
26 | MODULE_ALIAS("ip6t_hl"); | ||
27 | |||
28 | static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par) | ||
29 | { | ||
30 | const struct ipt_ttl_info *info = par->matchinfo; | ||
31 | const u8 ttl = ip_hdr(skb)->ttl; | ||
32 | |||
33 | switch (info->mode) { | ||
34 | case IPT_TTL_EQ: | ||
35 | return ttl == info->ttl; | ||
36 | case IPT_TTL_NE: | ||
37 | return ttl != info->ttl; | ||
38 | case IPT_TTL_LT: | ||
39 | return ttl < info->ttl; | ||
40 | case IPT_TTL_GT: | ||
41 | return ttl > info->ttl; | ||
42 | default: | ||
43 | printk(KERN_WARNING "ipt_ttl: unknown mode %d\n", | ||
44 | info->mode); | ||
45 | return false; | ||
46 | } | ||
47 | |||
48 | return false; | ||
49 | } | ||
50 | |||
51 | static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | ||
52 | { | ||
53 | const struct ip6t_hl_info *info = par->matchinfo; | ||
54 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
55 | |||
56 | switch (info->mode) { | ||
57 | case IP6T_HL_EQ: | ||
58 | return ip6h->hop_limit == info->hop_limit; | ||
59 | break; | ||
60 | case IP6T_HL_NE: | ||
61 | return ip6h->hop_limit != info->hop_limit; | ||
62 | break; | ||
63 | case IP6T_HL_LT: | ||
64 | return ip6h->hop_limit < info->hop_limit; | ||
65 | break; | ||
66 | case IP6T_HL_GT: | ||
67 | return ip6h->hop_limit > info->hop_limit; | ||
68 | break; | ||
69 | default: | ||
70 | printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", | ||
71 | info->mode); | ||
72 | return false; | ||
73 | } | ||
74 | |||
75 | return false; | ||
76 | } | ||
77 | |||
78 | static struct xt_match hl_mt_reg[] __read_mostly = { | ||
79 | { | ||
80 | .name = "ttl", | ||
81 | .revision = 0, | ||
82 | .family = NFPROTO_IPV4, | ||
83 | .match = ttl_mt, | ||
84 | .matchsize = sizeof(struct ipt_ttl_info), | ||
85 | .me = THIS_MODULE, | ||
86 | }, | ||
87 | { | ||
88 | .name = "hl", | ||
89 | .revision = 0, | ||
90 | .family = NFPROTO_IPV6, | ||
91 | .match = hl_mt6, | ||
92 | .matchsize = sizeof(struct ip6t_hl_info), | ||
93 | .me = THIS_MODULE, | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | static int __init hl_mt_init(void) | ||
98 | { | ||
99 | return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); | ||
100 | } | ||
101 | |||
102 | static void __exit hl_mt_exit(void) | ||
103 | { | ||
104 | xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); | ||
105 | } | ||
106 | |||
107 | module_init(hl_mt_init); | ||
108 | module_exit(hl_mt_exit); | ||
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index c908d69a5595..2e8089ecd0af 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c | |||
@@ -14,6 +14,11 @@ | |||
14 | #include <linux/netfilter/x_tables.h> | 14 | #include <linux/netfilter/x_tables.h> |
15 | #include <linux/netfilter/xt_limit.h> | 15 | #include <linux/netfilter/xt_limit.h> |
16 | 16 | ||
17 | struct xt_limit_priv { | ||
18 | unsigned long prev; | ||
19 | uint32_t credit; | ||
20 | }; | ||
21 | |||
17 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
18 | MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); | 23 | MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); |
19 | MODULE_DESCRIPTION("Xtables: rate-limit match"); | 24 | MODULE_DESCRIPTION("Xtables: rate-limit match"); |
@@ -60,18 +65,18 @@ static DEFINE_SPINLOCK(limit_lock); | |||
60 | static bool | 65 | static bool |
61 | limit_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 66 | limit_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
62 | { | 67 | { |
63 | struct xt_rateinfo *r = | 68 | const struct xt_rateinfo *r = par->matchinfo; |
64 | ((const struct xt_rateinfo *)par->matchinfo)->master; | 69 | struct xt_limit_priv *priv = r->master; |
65 | unsigned long now = jiffies; | 70 | unsigned long now = jiffies; |
66 | 71 | ||
67 | spin_lock_bh(&limit_lock); | 72 | spin_lock_bh(&limit_lock); |
68 | r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY; | 73 | priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY; |
69 | if (r->credit > r->credit_cap) | 74 | if (priv->credit > r->credit_cap) |
70 | r->credit = r->credit_cap; | 75 | priv->credit = r->credit_cap; |
71 | 76 | ||
72 | if (r->credit >= r->cost) { | 77 | if (priv->credit >= r->cost) { |
73 | /* We're not limited. */ | 78 | /* We're not limited. */ |
74 | r->credit -= r->cost; | 79 | priv->credit -= r->cost; |
75 | spin_unlock_bh(&limit_lock); | 80 | spin_unlock_bh(&limit_lock); |
76 | return true; | 81 | return true; |
77 | } | 82 | } |
@@ -95,6 +100,7 @@ user2credits(u_int32_t user) | |||
95 | static bool limit_mt_check(const struct xt_mtchk_param *par) | 100 | static bool limit_mt_check(const struct xt_mtchk_param *par) |
96 | { | 101 | { |
97 | struct xt_rateinfo *r = par->matchinfo; | 102 | struct xt_rateinfo *r = par->matchinfo; |
103 | struct xt_limit_priv *priv; | ||
98 | 104 | ||
99 | /* Check for overflow. */ | 105 | /* Check for overflow. */ |
100 | if (r->burst == 0 | 106 | if (r->burst == 0 |
@@ -104,19 +110,30 @@ static bool limit_mt_check(const struct xt_mtchk_param *par) | |||
104 | return false; | 110 | return false; |
105 | } | 111 | } |
106 | 112 | ||
107 | /* For SMP, we only want to use one set of counters. */ | 113 | priv = kmalloc(sizeof(*priv), GFP_KERNEL); |
108 | r->master = r; | 114 | if (priv == NULL) |
115 | return -ENOMEM; | ||
116 | |||
117 | /* For SMP, we only want to use one set of state. */ | ||
118 | r->master = priv; | ||
109 | if (r->cost == 0) { | 119 | if (r->cost == 0) { |
110 | /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * | 120 | /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * |
111 | 128. */ | 121 | 128. */ |
112 | r->prev = jiffies; | 122 | priv->prev = jiffies; |
113 | r->credit = user2credits(r->avg * r->burst); /* Credits full. */ | 123 | priv->credit = user2credits(r->avg * r->burst); /* Credits full. */ |
114 | r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ | 124 | r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ |
115 | r->cost = user2credits(r->avg); | 125 | r->cost = user2credits(r->avg); |
116 | } | 126 | } |
117 | return true; | 127 | return true; |
118 | } | 128 | } |
119 | 129 | ||
130 | static void limit_mt_destroy(const struct xt_mtdtor_param *par) | ||
131 | { | ||
132 | const struct xt_rateinfo *info = par->matchinfo; | ||
133 | |||
134 | kfree(info->master); | ||
135 | } | ||
136 | |||
120 | #ifdef CONFIG_COMPAT | 137 | #ifdef CONFIG_COMPAT |
121 | struct compat_xt_rateinfo { | 138 | struct compat_xt_rateinfo { |
122 | u_int32_t avg; | 139 | u_int32_t avg; |
@@ -167,6 +184,7 @@ static struct xt_match limit_mt_reg __read_mostly = { | |||
167 | .family = NFPROTO_UNSPEC, | 184 | .family = NFPROTO_UNSPEC, |
168 | .match = limit_mt, | 185 | .match = limit_mt, |
169 | .checkentry = limit_mt_check, | 186 | .checkentry = limit_mt_check, |
187 | .destroy = limit_mt_destroy, | ||
170 | .matchsize = sizeof(struct xt_rateinfo), | 188 | .matchsize = sizeof(struct xt_rateinfo), |
171 | #ifdef CONFIG_COMPAT | 189 | #ifdef CONFIG_COMPAT |
172 | .compatsize = sizeof(struct compat_xt_rateinfo), | 190 | .compatsize = sizeof(struct compat_xt_rateinfo), |
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index 1bcdfc12cf59..44a234ef4439 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c | |||
@@ -20,13 +20,30 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match"); | |||
20 | MODULE_ALIAS("ipt_physdev"); | 20 | MODULE_ALIAS("ipt_physdev"); |
21 | MODULE_ALIAS("ip6t_physdev"); | 21 | MODULE_ALIAS("ip6t_physdev"); |
22 | 22 | ||
23 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | ||
24 | { | ||
25 | const unsigned long *a = (const unsigned long *)_a; | ||
26 | const unsigned long *b = (const unsigned long *)_b; | ||
27 | const unsigned long *mask = (const unsigned long *)_mask; | ||
28 | unsigned long ret; | ||
29 | |||
30 | ret = (a[0] ^ b[0]) & mask[0]; | ||
31 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
32 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
33 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
34 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
35 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
36 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
37 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
38 | return ret; | ||
39 | } | ||
40 | |||
23 | static bool | 41 | static bool |
24 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 42 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
25 | { | 43 | { |
26 | int i; | 44 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); |
27 | static const char nulldevname[IFNAMSIZ]; | ||
28 | const struct xt_physdev_info *info = par->matchinfo; | 45 | const struct xt_physdev_info *info = par->matchinfo; |
29 | bool ret; | 46 | unsigned long ret; |
30 | const char *indev, *outdev; | 47 | const char *indev, *outdev; |
31 | const struct nf_bridge_info *nf_bridge; | 48 | const struct nf_bridge_info *nf_bridge; |
32 | 49 | ||
@@ -68,11 +85,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |||
68 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) | 85 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) |
69 | goto match_outdev; | 86 | goto match_outdev; |
70 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; | 87 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; |
71 | for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) { | 88 | ret = ifname_compare(indev, info->physindev, info->in_mask); |
72 | ret |= (((const unsigned int *)indev)[i] | ||
73 | ^ ((const unsigned int *)info->physindev)[i]) | ||
74 | & ((const unsigned int *)info->in_mask)[i]; | ||
75 | } | ||
76 | 89 | ||
77 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) | 90 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) |
78 | return false; | 91 | return false; |
@@ -82,13 +95,9 @@ match_outdev: | |||
82 | return true; | 95 | return true; |
83 | outdev = nf_bridge->physoutdev ? | 96 | outdev = nf_bridge->physoutdev ? |
84 | nf_bridge->physoutdev->name : nulldevname; | 97 | nf_bridge->physoutdev->name : nulldevname; |
85 | for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) { | 98 | ret = ifname_compare(outdev, info->physoutdev, info->out_mask); |
86 | ret |= (((const unsigned int *)outdev)[i] | ||
87 | ^ ((const unsigned int *)info->physoutdev)[i]) | ||
88 | & ((const unsigned int *)info->out_mask)[i]; | ||
89 | } | ||
90 | 99 | ||
91 | return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT); | 100 | return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); |
92 | } | 101 | } |
93 | 102 | ||
94 | static bool physdev_mt_check(const struct xt_mtchk_param *par) | 103 | static bool physdev_mt_check(const struct xt_mtchk_param *par) |
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c index c84fce5e0f3e..01dd07b764ec 100644 --- a/net/netfilter/xt_quota.c +++ b/net/netfilter/xt_quota.c | |||
@@ -9,6 +9,10 @@ | |||
9 | #include <linux/netfilter/x_tables.h> | 9 | #include <linux/netfilter/x_tables.h> |
10 | #include <linux/netfilter/xt_quota.h> | 10 | #include <linux/netfilter/xt_quota.h> |
11 | 11 | ||
12 | struct xt_quota_priv { | ||
13 | uint64_t quota; | ||
14 | }; | ||
15 | |||
12 | MODULE_LICENSE("GPL"); | 16 | MODULE_LICENSE("GPL"); |
13 | MODULE_AUTHOR("Sam Johnston <samj@samj.net>"); | 17 | MODULE_AUTHOR("Sam Johnston <samj@samj.net>"); |
14 | MODULE_DESCRIPTION("Xtables: countdown quota match"); | 18 | MODULE_DESCRIPTION("Xtables: countdown quota match"); |
@@ -20,18 +24,20 @@ static DEFINE_SPINLOCK(quota_lock); | |||
20 | static bool | 24 | static bool |
21 | quota_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 25 | quota_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
22 | { | 26 | { |
23 | struct xt_quota_info *q = | 27 | struct xt_quota_info *q = (void *)par->matchinfo; |
24 | ((const struct xt_quota_info *)par->matchinfo)->master; | 28 | struct xt_quota_priv *priv = q->master; |
25 | bool ret = q->flags & XT_QUOTA_INVERT; | 29 | bool ret = q->flags & XT_QUOTA_INVERT; |
26 | 30 | ||
27 | spin_lock_bh("a_lock); | 31 | spin_lock_bh("a_lock); |
28 | if (q->quota >= skb->len) { | 32 | if (priv->quota >= skb->len) { |
29 | q->quota -= skb->len; | 33 | priv->quota -= skb->len; |
30 | ret = !ret; | 34 | ret = !ret; |
31 | } else { | 35 | } else { |
32 | /* we do not allow even small packets from now on */ | 36 | /* we do not allow even small packets from now on */ |
33 | q->quota = 0; | 37 | priv->quota = 0; |
34 | } | 38 | } |
39 | /* Copy quota back to matchinfo so that iptables can display it */ | ||
40 | q->quota = priv->quota; | ||
35 | spin_unlock_bh("a_lock); | 41 | spin_unlock_bh("a_lock); |
36 | 42 | ||
37 | return ret; | 43 | return ret; |
@@ -43,17 +49,28 @@ static bool quota_mt_check(const struct xt_mtchk_param *par) | |||
43 | 49 | ||
44 | if (q->flags & ~XT_QUOTA_MASK) | 50 | if (q->flags & ~XT_QUOTA_MASK) |
45 | return false; | 51 | return false; |
46 | /* For SMP, we only want to use one set of counters. */ | 52 | |
47 | q->master = q; | 53 | q->master = kmalloc(sizeof(*q->master), GFP_KERNEL); |
54 | if (q->master == NULL) | ||
55 | return -ENOMEM; | ||
56 | |||
48 | return true; | 57 | return true; |
49 | } | 58 | } |
50 | 59 | ||
60 | static void quota_mt_destroy(const struct xt_mtdtor_param *par) | ||
61 | { | ||
62 | const struct xt_quota_info *q = par->matchinfo; | ||
63 | |||
64 | kfree(q->master); | ||
65 | } | ||
66 | |||
51 | static struct xt_match quota_mt_reg __read_mostly = { | 67 | static struct xt_match quota_mt_reg __read_mostly = { |
52 | .name = "quota", | 68 | .name = "quota", |
53 | .revision = 0, | 69 | .revision = 0, |
54 | .family = NFPROTO_UNSPEC, | 70 | .family = NFPROTO_UNSPEC, |
55 | .match = quota_mt, | 71 | .match = quota_mt, |
56 | .checkentry = quota_mt_check, | 72 | .checkentry = quota_mt_check, |
73 | .destroy = quota_mt_destroy, | ||
57 | .matchsize = sizeof(struct xt_quota_info), | 74 | .matchsize = sizeof(struct xt_quota_info), |
58 | .me = THIS_MODULE, | 75 | .me = THIS_MODULE, |
59 | }; | 76 | }; |
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c index 0d75141139d5..d8c0f8f1a78e 100644 --- a/net/netfilter/xt_statistic.c +++ b/net/netfilter/xt_statistic.c | |||
@@ -16,6 +16,10 @@ | |||
16 | #include <linux/netfilter/xt_statistic.h> | 16 | #include <linux/netfilter/xt_statistic.h> |
17 | #include <linux/netfilter/x_tables.h> | 17 | #include <linux/netfilter/x_tables.h> |
18 | 18 | ||
19 | struct xt_statistic_priv { | ||
20 | uint32_t count; | ||
21 | }; | ||
22 | |||
19 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
20 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | 24 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); |
21 | MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)"); | 25 | MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)"); |
@@ -27,7 +31,7 @@ static DEFINE_SPINLOCK(nth_lock); | |||
27 | static bool | 31 | static bool |
28 | statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 32 | statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
29 | { | 33 | { |
30 | struct xt_statistic_info *info = (void *)par->matchinfo; | 34 | const struct xt_statistic_info *info = par->matchinfo; |
31 | bool ret = info->flags & XT_STATISTIC_INVERT; | 35 | bool ret = info->flags & XT_STATISTIC_INVERT; |
32 | 36 | ||
33 | switch (info->mode) { | 37 | switch (info->mode) { |
@@ -36,10 +40,9 @@ statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |||
36 | ret = !ret; | 40 | ret = !ret; |
37 | break; | 41 | break; |
38 | case XT_STATISTIC_MODE_NTH: | 42 | case XT_STATISTIC_MODE_NTH: |
39 | info = info->master; | ||
40 | spin_lock_bh(&nth_lock); | 43 | spin_lock_bh(&nth_lock); |
41 | if (info->u.nth.count++ == info->u.nth.every) { | 44 | if (info->master->count++ == info->u.nth.every) { |
42 | info->u.nth.count = 0; | 45 | info->master->count = 0; |
43 | ret = !ret; | 46 | ret = !ret; |
44 | } | 47 | } |
45 | spin_unlock_bh(&nth_lock); | 48 | spin_unlock_bh(&nth_lock); |
@@ -56,16 +59,31 @@ static bool statistic_mt_check(const struct xt_mtchk_param *par) | |||
56 | if (info->mode > XT_STATISTIC_MODE_MAX || | 59 | if (info->mode > XT_STATISTIC_MODE_MAX || |
57 | info->flags & ~XT_STATISTIC_MASK) | 60 | info->flags & ~XT_STATISTIC_MASK) |
58 | return false; | 61 | return false; |
59 | info->master = info; | 62 | |
63 | info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); | ||
64 | if (info->master == NULL) { | ||
65 | printk(KERN_ERR KBUILD_MODNAME ": Out of memory\n"); | ||
66 | return false; | ||
67 | } | ||
68 | info->master->count = info->u.nth.count; | ||
69 | |||
60 | return true; | 70 | return true; |
61 | } | 71 | } |
62 | 72 | ||
73 | static void statistic_mt_destroy(const struct xt_mtdtor_param *par) | ||
74 | { | ||
75 | const struct xt_statistic_info *info = par->matchinfo; | ||
76 | |||
77 | kfree(info->master); | ||
78 | } | ||
79 | |||
63 | static struct xt_match xt_statistic_mt_reg __read_mostly = { | 80 | static struct xt_match xt_statistic_mt_reg __read_mostly = { |
64 | .name = "statistic", | 81 | .name = "statistic", |
65 | .revision = 0, | 82 | .revision = 0, |
66 | .family = NFPROTO_UNSPEC, | 83 | .family = NFPROTO_UNSPEC, |
67 | .match = statistic_mt, | 84 | .match = statistic_mt, |
68 | .checkentry = statistic_mt_check, | 85 | .checkentry = statistic_mt_check, |
86 | .destroy = statistic_mt_destroy, | ||
69 | .matchsize = sizeof(struct xt_statistic_info), | 87 | .matchsize = sizeof(struct xt_statistic_info), |
70 | .me = THIS_MODULE, | 88 | .me = THIS_MODULE, |
71 | }; | 89 | }; |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a007dbb4c9f1..b73d4e61c5ac 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1117,6 +1117,7 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | |||
1117 | 1117 | ||
1118 | read_unlock(&nl_table_lock); | 1118 | read_unlock(&nl_table_lock); |
1119 | } | 1119 | } |
1120 | EXPORT_SYMBOL(netlink_set_err); | ||
1120 | 1121 | ||
1121 | /* must be called with netlink table grabbed */ | 1122 | /* must be called with netlink table grabbed */ |
1122 | static void netlink_update_socket_mc(struct netlink_sock *nlk, | 1123 | static void netlink_update_socket_mc(struct netlink_sock *nlk, |
diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 972201cd5fa7..0b15d7250c40 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c | |||
@@ -61,7 +61,7 @@ static struct ctl_table_root net_sysctl_root = { | |||
61 | static int net_ctl_ro_header_perms(struct ctl_table_root *root, | 61 | static int net_ctl_ro_header_perms(struct ctl_table_root *root, |
62 | struct nsproxy *namespaces, struct ctl_table *table) | 62 | struct nsproxy *namespaces, struct ctl_table *table) |
63 | { | 63 | { |
64 | if (namespaces->net_ns == &init_net) | 64 | if (net_eq(namespaces->net_ns, &init_net)) |
65 | return table->mode; | 65 | return table->mode; |
66 | else | 66 | else |
67 | return table->mode & ~0222; | 67 | return table->mode & ~0222; |