diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack.h | 3 | ||||
-rw-r--r-- | include/net/netfilter/nf_nat.h | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 1 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 1 | ||||
-rw-r--r-- | net/netfilter/core.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_sctp.c | 8 | ||||
-rw-r--r-- | net/netfilter/nf_nat_core.c | 146 | ||||
-rw-r--r-- | net/netfilter/xt_hashlimit.c | 16 |
9 files changed, 88 insertions, 91 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index fdc9c64a1c94..8f3bd30511de 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
18 | #include <linux/compiler.h> | 18 | #include <linux/compiler.h> |
19 | #include <linux/atomic.h> | 19 | #include <linux/atomic.h> |
20 | #include <linux/rhashtable.h> | ||
21 | 20 | ||
22 | #include <linux/netfilter/nf_conntrack_tcp.h> | 21 | #include <linux/netfilter/nf_conntrack_tcp.h> |
23 | #include <linux/netfilter/nf_conntrack_dccp.h> | 22 | #include <linux/netfilter/nf_conntrack_dccp.h> |
@@ -77,7 +76,7 @@ struct nf_conn { | |||
77 | possible_net_t ct_net; | 76 | possible_net_t ct_net; |
78 | 77 | ||
79 | #if IS_ENABLED(CONFIG_NF_NAT) | 78 | #if IS_ENABLED(CONFIG_NF_NAT) |
80 | struct rhlist_head nat_bysource; | 79 | struct hlist_node nat_bysource; |
81 | #endif | 80 | #endif |
82 | /* all members below initialized via memset */ | 81 | /* all members below initialized via memset */ |
83 | u8 __nfct_init_offset[0]; | 82 | u8 __nfct_init_offset[0]; |
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index 05c82a1a4267..b71701302e61 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h | |||
@@ -1,6 +1,5 @@ | |||
1 | #ifndef _NF_NAT_H | 1 | #ifndef _NF_NAT_H |
2 | #define _NF_NAT_H | 2 | #define _NF_NAT_H |
3 | #include <linux/rhashtable.h> | ||
4 | #include <linux/netfilter_ipv4.h> | 3 | #include <linux/netfilter_ipv4.h> |
5 | #include <linux/netfilter/nf_nat.h> | 4 | #include <linux/netfilter/nf_nat.h> |
6 | #include <net/netfilter/nf_conntrack_tuple.h> | 5 | #include <net/netfilter/nf_conntrack_tuple.h> |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index e04457198f93..9e2770fd00be 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -629,6 +629,7 @@ static void get_counters(const struct xt_table_info *t, | |||
629 | 629 | ||
630 | ADD_COUNTER(counters[i], bcnt, pcnt); | 630 | ADD_COUNTER(counters[i], bcnt, pcnt); |
631 | ++i; | 631 | ++i; |
632 | cond_resched(); | ||
632 | } | 633 | } |
633 | } | 634 | } |
634 | } | 635 | } |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 576cba2b57e9..39286e543ee6 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -776,6 +776,7 @@ get_counters(const struct xt_table_info *t, | |||
776 | 776 | ||
777 | ADD_COUNTER(counters[i], bcnt, pcnt); | 777 | ADD_COUNTER(counters[i], bcnt, pcnt); |
778 | ++i; /* macro does multi eval of i */ | 778 | ++i; /* macro does multi eval of i */ |
779 | cond_resched(); | ||
779 | } | 780 | } |
780 | } | 781 | } |
781 | } | 782 | } |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 54b1e75eded1..01bd3ee5ebc6 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -795,6 +795,7 @@ get_counters(const struct xt_table_info *t, | |||
795 | 795 | ||
796 | ADD_COUNTER(counters[i], bcnt, pcnt); | 796 | ADD_COUNTER(counters[i], bcnt, pcnt); |
797 | ++i; | 797 | ++i; |
798 | cond_resched(); | ||
798 | } | 799 | } |
799 | } | 800 | } |
800 | } | 801 | } |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 04fe25abc5f6..52cd2901a097 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -215,7 +215,7 @@ static void *__nf_hook_entries_try_shrink(struct nf_hook_entries __rcu **pp) | |||
215 | if (skip == hook_entries) | 215 | if (skip == hook_entries) |
216 | goto out_assign; | 216 | goto out_assign; |
217 | 217 | ||
218 | if (WARN_ON(skip == 0)) | 218 | if (skip == 0) |
219 | return NULL; | 219 | return NULL; |
220 | 220 | ||
221 | hook_entries -= skip; | 221 | hook_entries -= skip; |
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index e1efa446b305..57c8ee66491e 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c | |||
@@ -24,9 +24,13 @@ sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb, | |||
24 | if (sh) { | 24 | if (sh) { |
25 | sch = skb_header_pointer(skb, iph->len + sizeof(_sctph), | 25 | sch = skb_header_pointer(skb, iph->len + sizeof(_sctph), |
26 | sizeof(_schunkh), &_schunkh); | 26 | sizeof(_schunkh), &_schunkh); |
27 | if (sch && (sch->type == SCTP_CID_INIT || | 27 | if (sch) { |
28 | sysctl_sloppy_sctp(ipvs))) | 28 | if (sch->type == SCTP_CID_ABORT || |
29 | !(sysctl_sloppy_sctp(ipvs) || | ||
30 | sch->type == SCTP_CID_INIT)) | ||
31 | return 1; | ||
29 | ports = &sh->source; | 32 | ports = &sh->source; |
33 | } | ||
30 | } | 34 | } |
31 | } else { | 35 | } else { |
32 | ports = skb_header_pointer( | 36 | ports = skb_header_pointer( |
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 40573aa6c133..f393a7086025 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
@@ -30,19 +30,17 @@ | |||
30 | #include <net/netfilter/nf_conntrack_zones.h> | 30 | #include <net/netfilter/nf_conntrack_zones.h> |
31 | #include <linux/netfilter/nf_nat.h> | 31 | #include <linux/netfilter/nf_nat.h> |
32 | 32 | ||
33 | static spinlock_t nf_nat_locks[CONNTRACK_LOCKS]; | ||
34 | |||
33 | static DEFINE_MUTEX(nf_nat_proto_mutex); | 35 | static DEFINE_MUTEX(nf_nat_proto_mutex); |
34 | static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO] | 36 | static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO] |
35 | __read_mostly; | 37 | __read_mostly; |
36 | static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO] | 38 | static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO] |
37 | __read_mostly; | 39 | __read_mostly; |
38 | 40 | ||
39 | struct nf_nat_conn_key { | 41 | static struct hlist_head *nf_nat_bysource __read_mostly; |
40 | const struct net *net; | 42 | static unsigned int nf_nat_htable_size __read_mostly; |
41 | const struct nf_conntrack_tuple *tuple; | 43 | static unsigned int nf_nat_hash_rnd __read_mostly; |
42 | const struct nf_conntrack_zone *zone; | ||
43 | }; | ||
44 | |||
45 | static struct rhltable nf_nat_bysource_table; | ||
46 | 44 | ||
47 | inline const struct nf_nat_l3proto * | 45 | inline const struct nf_nat_l3proto * |
48 | __nf_nat_l3proto_find(u8 family) | 46 | __nf_nat_l3proto_find(u8 family) |
@@ -118,17 +116,19 @@ int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family) | |||
118 | EXPORT_SYMBOL(nf_xfrm_me_harder); | 116 | EXPORT_SYMBOL(nf_xfrm_me_harder); |
119 | #endif /* CONFIG_XFRM */ | 117 | #endif /* CONFIG_XFRM */ |
120 | 118 | ||
121 | static u32 nf_nat_bysource_hash(const void *data, u32 len, u32 seed) | 119 | /* We keep an extra hash for each conntrack, for fast searching. */ |
120 | static unsigned int | ||
121 | hash_by_src(const struct net *n, const struct nf_conntrack_tuple *tuple) | ||
122 | { | 122 | { |
123 | const struct nf_conntrack_tuple *t; | 123 | unsigned int hash; |
124 | const struct nf_conn *ct = data; | 124 | |
125 | get_random_once(&nf_nat_hash_rnd, sizeof(nf_nat_hash_rnd)); | ||
125 | 126 | ||
126 | t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
127 | /* Original src, to ensure we map it consistently if poss. */ | 127 | /* Original src, to ensure we map it consistently if poss. */ |
128 | hash = jhash2((u32 *)&tuple->src, sizeof(tuple->src) / sizeof(u32), | ||
129 | tuple->dst.protonum ^ nf_nat_hash_rnd ^ net_hash_mix(n)); | ||
128 | 130 | ||
129 | seed ^= net_hash_mix(nf_ct_net(ct)); | 131 | return reciprocal_scale(hash, nf_nat_htable_size); |
130 | return jhash2((const u32 *)&t->src, sizeof(t->src) / sizeof(u32), | ||
131 | t->dst.protonum ^ seed); | ||
132 | } | 132 | } |
133 | 133 | ||
134 | /* Is this tuple already taken? (not by us) */ | 134 | /* Is this tuple already taken? (not by us) */ |
@@ -184,28 +184,6 @@ same_src(const struct nf_conn *ct, | |||
184 | t->src.u.all == tuple->src.u.all); | 184 | t->src.u.all == tuple->src.u.all); |
185 | } | 185 | } |
186 | 186 | ||
187 | static int nf_nat_bysource_cmp(struct rhashtable_compare_arg *arg, | ||
188 | const void *obj) | ||
189 | { | ||
190 | const struct nf_nat_conn_key *key = arg->key; | ||
191 | const struct nf_conn *ct = obj; | ||
192 | |||
193 | if (!same_src(ct, key->tuple) || | ||
194 | !net_eq(nf_ct_net(ct), key->net) || | ||
195 | !nf_ct_zone_equal(ct, key->zone, IP_CT_DIR_ORIGINAL)) | ||
196 | return 1; | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static struct rhashtable_params nf_nat_bysource_params = { | ||
202 | .head_offset = offsetof(struct nf_conn, nat_bysource), | ||
203 | .obj_hashfn = nf_nat_bysource_hash, | ||
204 | .obj_cmpfn = nf_nat_bysource_cmp, | ||
205 | .nelem_hint = 256, | ||
206 | .min_size = 1024, | ||
207 | }; | ||
208 | |||
209 | /* Only called for SRC manip */ | 187 | /* Only called for SRC manip */ |
210 | static int | 188 | static int |
211 | find_appropriate_src(struct net *net, | 189 | find_appropriate_src(struct net *net, |
@@ -216,26 +194,22 @@ find_appropriate_src(struct net *net, | |||
216 | struct nf_conntrack_tuple *result, | 194 | struct nf_conntrack_tuple *result, |
217 | const struct nf_nat_range *range) | 195 | const struct nf_nat_range *range) |
218 | { | 196 | { |
197 | unsigned int h = hash_by_src(net, tuple); | ||
219 | const struct nf_conn *ct; | 198 | const struct nf_conn *ct; |
220 | struct nf_nat_conn_key key = { | ||
221 | .net = net, | ||
222 | .tuple = tuple, | ||
223 | .zone = zone | ||
224 | }; | ||
225 | struct rhlist_head *hl, *h; | ||
226 | |||
227 | hl = rhltable_lookup(&nf_nat_bysource_table, &key, | ||
228 | nf_nat_bysource_params); | ||
229 | |||
230 | rhl_for_each_entry_rcu(ct, h, hl, nat_bysource) { | ||
231 | nf_ct_invert_tuplepr(result, | ||
232 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
233 | result->dst = tuple->dst; | ||
234 | 199 | ||
235 | if (in_range(l3proto, l4proto, result, range)) | 200 | hlist_for_each_entry_rcu(ct, &nf_nat_bysource[h], nat_bysource) { |
236 | return 1; | 201 | if (same_src(ct, tuple) && |
202 | net_eq(net, nf_ct_net(ct)) && | ||
203 | nf_ct_zone_equal(ct, zone, IP_CT_DIR_ORIGINAL)) { | ||
204 | /* Copy source part from reply tuple. */ | ||
205 | nf_ct_invert_tuplepr(result, | ||
206 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
207 | result->dst = tuple->dst; | ||
208 | |||
209 | if (in_range(l3proto, l4proto, result, range)) | ||
210 | return 1; | ||
211 | } | ||
237 | } | 212 | } |
238 | |||
239 | return 0; | 213 | return 0; |
240 | } | 214 | } |
241 | 215 | ||
@@ -408,6 +382,7 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
408 | const struct nf_nat_range *range, | 382 | const struct nf_nat_range *range, |
409 | enum nf_nat_manip_type maniptype) | 383 | enum nf_nat_manip_type maniptype) |
410 | { | 384 | { |
385 | struct net *net = nf_ct_net(ct); | ||
411 | struct nf_conntrack_tuple curr_tuple, new_tuple; | 386 | struct nf_conntrack_tuple curr_tuple, new_tuple; |
412 | 387 | ||
413 | /* Can't setup nat info for confirmed ct. */ | 388 | /* Can't setup nat info for confirmed ct. */ |
@@ -416,7 +391,9 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
416 | 391 | ||
417 | WARN_ON(maniptype != NF_NAT_MANIP_SRC && | 392 | WARN_ON(maniptype != NF_NAT_MANIP_SRC && |
418 | maniptype != NF_NAT_MANIP_DST); | 393 | maniptype != NF_NAT_MANIP_DST); |
419 | BUG_ON(nf_nat_initialized(ct, maniptype)); | 394 | |
395 | if (WARN_ON(nf_nat_initialized(ct, maniptype))) | ||
396 | return NF_DROP; | ||
420 | 397 | ||
421 | /* What we've got will look like inverse of reply. Normally | 398 | /* What we've got will look like inverse of reply. Normally |
422 | * this is what is in the conntrack, except for prior | 399 | * this is what is in the conntrack, except for prior |
@@ -447,19 +424,16 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
447 | } | 424 | } |
448 | 425 | ||
449 | if (maniptype == NF_NAT_MANIP_SRC) { | 426 | if (maniptype == NF_NAT_MANIP_SRC) { |
450 | struct nf_nat_conn_key key = { | 427 | unsigned int srchash; |
451 | .net = nf_ct_net(ct), | 428 | spinlock_t *lock; |
452 | .tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 429 | |
453 | .zone = nf_ct_zone(ct), | 430 | srchash = hash_by_src(net, |
454 | }; | 431 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
455 | int err; | 432 | lock = &nf_nat_locks[srchash % ARRAY_SIZE(nf_nat_locks)]; |
456 | 433 | spin_lock_bh(lock); | |
457 | err = rhltable_insert_key(&nf_nat_bysource_table, | 434 | hlist_add_head_rcu(&ct->nat_bysource, |
458 | &key, | 435 | &nf_nat_bysource[srchash]); |
459 | &ct->nat_bysource, | 436 | spin_unlock_bh(lock); |
460 | nf_nat_bysource_params); | ||
461 | if (err) | ||
462 | return NF_DROP; | ||
463 | } | 437 | } |
464 | 438 | ||
465 | /* It's done. */ | 439 | /* It's done. */ |
@@ -553,6 +527,16 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data) | |||
553 | return i->status & IPS_NAT_MASK ? 1 : 0; | 527 | return i->status & IPS_NAT_MASK ? 1 : 0; |
554 | } | 528 | } |
555 | 529 | ||
530 | static void __nf_nat_cleanup_conntrack(struct nf_conn *ct) | ||
531 | { | ||
532 | unsigned int h; | ||
533 | |||
534 | h = hash_by_src(nf_ct_net(ct), &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
535 | spin_lock_bh(&nf_nat_locks[h % ARRAY_SIZE(nf_nat_locks)]); | ||
536 | hlist_del_rcu(&ct->nat_bysource); | ||
537 | spin_unlock_bh(&nf_nat_locks[h % ARRAY_SIZE(nf_nat_locks)]); | ||
538 | } | ||
539 | |||
556 | static int nf_nat_proto_clean(struct nf_conn *ct, void *data) | 540 | static int nf_nat_proto_clean(struct nf_conn *ct, void *data) |
557 | { | 541 | { |
558 | if (nf_nat_proto_remove(ct, data)) | 542 | if (nf_nat_proto_remove(ct, data)) |
@@ -568,8 +552,7 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data) | |||
568 | * will delete entry from already-freed table. | 552 | * will delete entry from already-freed table. |
569 | */ | 553 | */ |
570 | clear_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); | 554 | clear_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); |
571 | rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource, | 555 | __nf_nat_cleanup_conntrack(ct); |
572 | nf_nat_bysource_params); | ||
573 | 556 | ||
574 | /* don't delete conntrack. Although that would make things a lot | 557 | /* don't delete conntrack. Although that would make things a lot |
575 | * simpler, we'd end up flushing all conntracks on nat rmmod. | 558 | * simpler, we'd end up flushing all conntracks on nat rmmod. |
@@ -698,8 +681,7 @@ EXPORT_SYMBOL_GPL(nf_nat_l3proto_unregister); | |||
698 | static void nf_nat_cleanup_conntrack(struct nf_conn *ct) | 681 | static void nf_nat_cleanup_conntrack(struct nf_conn *ct) |
699 | { | 682 | { |
700 | if (ct->status & IPS_SRC_NAT_DONE) | 683 | if (ct->status & IPS_SRC_NAT_DONE) |
701 | rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource, | 684 | __nf_nat_cleanup_conntrack(ct); |
702 | nf_nat_bysource_params); | ||
703 | } | 685 | } |
704 | 686 | ||
705 | static struct nf_ct_ext_type nat_extend __read_mostly = { | 687 | static struct nf_ct_ext_type nat_extend __read_mostly = { |
@@ -821,19 +803,27 @@ static struct nf_ct_helper_expectfn follow_master_nat = { | |||
821 | 803 | ||
822 | static int __init nf_nat_init(void) | 804 | static int __init nf_nat_init(void) |
823 | { | 805 | { |
824 | int ret; | 806 | int ret, i; |
825 | 807 | ||
826 | ret = rhltable_init(&nf_nat_bysource_table, &nf_nat_bysource_params); | 808 | /* Leave them the same for the moment. */ |
827 | if (ret) | 809 | nf_nat_htable_size = nf_conntrack_htable_size; |
828 | return ret; | 810 | if (nf_nat_htable_size < ARRAY_SIZE(nf_nat_locks)) |
811 | nf_nat_htable_size = ARRAY_SIZE(nf_nat_locks); | ||
812 | |||
813 | nf_nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, 0); | ||
814 | if (!nf_nat_bysource) | ||
815 | return -ENOMEM; | ||
829 | 816 | ||
830 | ret = nf_ct_extend_register(&nat_extend); | 817 | ret = nf_ct_extend_register(&nat_extend); |
831 | if (ret < 0) { | 818 | if (ret < 0) { |
832 | rhltable_destroy(&nf_nat_bysource_table); | 819 | nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size); |
833 | printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); | 820 | printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); |
834 | return ret; | 821 | return ret; |
835 | } | 822 | } |
836 | 823 | ||
824 | for (i = 0; i < ARRAY_SIZE(nf_nat_locks); i++) | ||
825 | spin_lock_init(&nf_nat_locks[i]); | ||
826 | |||
837 | nf_ct_helper_expectfn_register(&follow_master_nat); | 827 | nf_ct_helper_expectfn_register(&follow_master_nat); |
838 | 828 | ||
839 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); | 829 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); |
@@ -863,8 +853,8 @@ static void __exit nf_nat_cleanup(void) | |||
863 | 853 | ||
864 | for (i = 0; i < NFPROTO_NUMPROTO; i++) | 854 | for (i = 0; i < NFPROTO_NUMPROTO; i++) |
865 | kfree(nf_nat_l4protos[i]); | 855 | kfree(nf_nat_l4protos[i]); |
866 | 856 | synchronize_net(); | |
867 | rhltable_destroy(&nf_nat_bysource_table); | 857 | nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size); |
868 | } | 858 | } |
869 | 859 | ||
870 | MODULE_LICENSE("GPL"); | 860 | MODULE_LICENSE("GPL"); |
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 10d48234f5f4..5da8746f7b88 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/netfilter_ipv6/ip6_tables.h> | 35 | #include <linux/netfilter_ipv6/ip6_tables.h> |
36 | #include <linux/netfilter/xt_hashlimit.h> | 36 | #include <linux/netfilter/xt_hashlimit.h> |
37 | #include <linux/mutex.h> | 37 | #include <linux/mutex.h> |
38 | #include <linux/kernel.h> | ||
38 | 39 | ||
39 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
40 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | 41 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
@@ -279,7 +280,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg, | |||
279 | size = cfg->size; | 280 | size = cfg->size; |
280 | } else { | 281 | } else { |
281 | size = (totalram_pages << PAGE_SHIFT) / 16384 / | 282 | size = (totalram_pages << PAGE_SHIFT) / 16384 / |
282 | sizeof(struct list_head); | 283 | sizeof(struct hlist_head); |
283 | if (totalram_pages > 1024 * 1024 * 1024 / PAGE_SIZE) | 284 | if (totalram_pages > 1024 * 1024 * 1024 / PAGE_SIZE) |
284 | size = 8192; | 285 | size = 8192; |
285 | if (size < 16) | 286 | if (size < 16) |
@@ -287,7 +288,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg, | |||
287 | } | 288 | } |
288 | /* FIXME: don't use vmalloc() here or anywhere else -HW */ | 289 | /* FIXME: don't use vmalloc() here or anywhere else -HW */ |
289 | hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + | 290 | hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + |
290 | sizeof(struct list_head) * size); | 291 | sizeof(struct hlist_head) * size); |
291 | if (hinfo == NULL) | 292 | if (hinfo == NULL) |
292 | return -ENOMEM; | 293 | return -ENOMEM; |
293 | *out_hinfo = hinfo; | 294 | *out_hinfo = hinfo; |
@@ -527,12 +528,12 @@ static u64 user2rate(u64 user) | |||
527 | } | 528 | } |
528 | } | 529 | } |
529 | 530 | ||
530 | static u64 user2rate_bytes(u64 user) | 531 | static u64 user2rate_bytes(u32 user) |
531 | { | 532 | { |
532 | u64 r; | 533 | u64 r; |
533 | 534 | ||
534 | r = user ? 0xFFFFFFFFULL / user : 0xFFFFFFFFULL; | 535 | r = user ? U32_MAX / user : U32_MAX; |
535 | r = (r - 1) << 4; | 536 | r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT; |
536 | return r; | 537 | return r; |
537 | } | 538 | } |
538 | 539 | ||
@@ -588,7 +589,8 @@ static void rateinfo_init(struct dsthash_ent *dh, | |||
588 | dh->rateinfo.prev_window = 0; | 589 | dh->rateinfo.prev_window = 0; |
589 | dh->rateinfo.current_rate = 0; | 590 | dh->rateinfo.current_rate = 0; |
590 | if (hinfo->cfg.mode & XT_HASHLIMIT_BYTES) { | 591 | if (hinfo->cfg.mode & XT_HASHLIMIT_BYTES) { |
591 | dh->rateinfo.rate = user2rate_bytes(hinfo->cfg.avg); | 592 | dh->rateinfo.rate = |
593 | user2rate_bytes((u32)hinfo->cfg.avg); | ||
592 | if (hinfo->cfg.burst) | 594 | if (hinfo->cfg.burst) |
593 | dh->rateinfo.burst = | 595 | dh->rateinfo.burst = |
594 | hinfo->cfg.burst * dh->rateinfo.rate; | 596 | hinfo->cfg.burst * dh->rateinfo.rate; |
@@ -870,7 +872,7 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par, | |||
870 | 872 | ||
871 | /* Check for overflow. */ | 873 | /* Check for overflow. */ |
872 | if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) { | 874 | if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) { |
873 | if (cfg->avg == 0) { | 875 | if (cfg->avg == 0 || cfg->avg > U32_MAX) { |
874 | pr_info("hashlimit invalid rate\n"); | 876 | pr_info("hashlimit invalid rate\n"); |
875 | return -ERANGE; | 877 | return -ERANGE; |
876 | } | 878 | } |