diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2011-06-16 12:49:17 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-06-16 12:49:17 -0400 |
commit | 3d14b171f004f75c2d1e82e10545966f94132705 (patch) | |
tree | 149f8ac4663f9824c636ccf059664e5e61a920fe | |
parent | c1e2e04388b2539960453689b8e721709f71dc9c (diff) |
netfilter: ipset: fix adding ranges to hash types
When ranges are added to hash types, the elements may trigger rehashing
the set. However, the last successfully added element was not kept track
so the adding started again with the first element after the rehashing.
Bug reported by Mr Dash Four.
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | include/linux/netfilter/ipset/ip_set.h | 2 | ||||
-rw-r--r-- | include/linux/netfilter/ipset/ip_set_ahash.h | 22 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ip.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ipmac.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_port.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 11 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ip.c | 17 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipport.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportip.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportnet.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_net.c | 16 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netport.c | 22 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_list_set.c | 2 |
13 files changed, 157 insertions, 34 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index e677c4d8f00e..710ba0070298 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h | |||
@@ -244,7 +244,7 @@ struct ip_set_type_variant { | |||
244 | * zero for no match/success to add/delete | 244 | * zero for no match/success to add/delete |
245 | * positive for matching element */ | 245 | * positive for matching element */ |
246 | int (*uadt)(struct ip_set *set, struct nlattr *tb[], | 246 | int (*uadt)(struct ip_set *set, struct nlattr *tb[], |
247 | enum ipset_adt adt, u32 *lineno, u32 flags); | 247 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); |
248 | 248 | ||
249 | /* Low level add/del/test functions */ | 249 | /* Low level add/del/test functions */ |
250 | ipset_adtfn adt[IPSET_ADT_MAX]; | 250 | ipset_adtfn adt[IPSET_ADT_MAX]; |
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h index 6c0219348b43..8709bd950c8b 100644 --- a/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/include/linux/netfilter/ipset/ip_set_ahash.h | |||
@@ -5,6 +5,11 @@ | |||
5 | #include <linux/jhash.h> | 5 | #include <linux/jhash.h> |
6 | #include <linux/netfilter/ipset/ip_set_timeout.h> | 6 | #include <linux/netfilter/ipset/ip_set_timeout.h> |
7 | 7 | ||
8 | #define CONCAT(a, b, c) a##b##c | ||
9 | #define TOKEN(a, b, c) CONCAT(a, b, c) | ||
10 | |||
11 | #define type_pf_next TOKEN(TYPE, PF, _elem) | ||
12 | |||
8 | /* Hashing which uses arrays to resolve clashing. The hash table is resized | 13 | /* Hashing which uses arrays to resolve clashing. The hash table is resized |
9 | * (doubled) when searching becomes too long. | 14 | * (doubled) when searching becomes too long. |
10 | * Internally jhash is used with the assumption that the size of the | 15 | * Internally jhash is used with the assumption that the size of the |
@@ -54,6 +59,7 @@ struct ip_set_hash { | |||
54 | u32 initval; /* random jhash init value */ | 59 | u32 initval; /* random jhash init value */ |
55 | u32 timeout; /* timeout value, if enabled */ | 60 | u32 timeout; /* timeout value, if enabled */ |
56 | struct timer_list gc; /* garbage collection when timeout enabled */ | 61 | struct timer_list gc; /* garbage collection when timeout enabled */ |
62 | struct type_pf_next next; /* temporary storage for uadd */ | ||
57 | #ifdef IP_SET_HASH_WITH_NETMASK | 63 | #ifdef IP_SET_HASH_WITH_NETMASK |
58 | u8 netmask; /* netmask value for subnets to store */ | 64 | u8 netmask; /* netmask value for subnets to store */ |
59 | #endif | 65 | #endif |
@@ -217,6 +223,7 @@ ip_set_hash_destroy(struct ip_set *set) | |||
217 | #define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask) | 223 | #define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask) |
218 | #define type_pf_data_list TOKEN(TYPE, PF, _data_list) | 224 | #define type_pf_data_list TOKEN(TYPE, PF, _data_list) |
219 | #define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) | 225 | #define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) |
226 | #define type_pf_data_next TOKEN(TYPE, PF, _data_next) | ||
220 | 227 | ||
221 | #define type_pf_elem TOKEN(TYPE, PF, _elem) | 228 | #define type_pf_elem TOKEN(TYPE, PF, _elem) |
222 | #define type_pf_telem TOKEN(TYPE, PF, _telem) | 229 | #define type_pf_telem TOKEN(TYPE, PF, _telem) |
@@ -346,6 +353,9 @@ retry: | |||
346 | return 0; | 353 | return 0; |
347 | } | 354 | } |
348 | 355 | ||
356 | static inline void | ||
357 | type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d); | ||
358 | |||
349 | /* Add an element to a hash and update the internal counters when succeeded, | 359 | /* Add an element to a hash and update the internal counters when succeeded, |
350 | * otherwise report the proper error code. */ | 360 | * otherwise report the proper error code. */ |
351 | static int | 361 | static int |
@@ -372,8 +382,11 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
372 | } | 382 | } |
373 | 383 | ||
374 | ret = type_pf_elem_add(n, value); | 384 | ret = type_pf_elem_add(n, value); |
375 | if (ret != 0) | 385 | if (ret != 0) { |
386 | if (ret == -EAGAIN) | ||
387 | type_pf_data_next(h, d); | ||
376 | goto out; | 388 | goto out; |
389 | } | ||
377 | 390 | ||
378 | #ifdef IP_SET_HASH_WITH_NETS | 391 | #ifdef IP_SET_HASH_WITH_NETS |
379 | add_cidr(h, d->cidr, HOST_MASK); | 392 | add_cidr(h, d->cidr, HOST_MASK); |
@@ -589,7 +602,7 @@ type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, | |||
589 | enum ipset_adt adt, const struct ip_set_adt_opt *opt); | 602 | enum ipset_adt adt, const struct ip_set_adt_opt *opt); |
590 | static int | 603 | static int |
591 | type_pf_uadt(struct ip_set *set, struct nlattr *tb[], | 604 | type_pf_uadt(struct ip_set *set, struct nlattr *tb[], |
592 | enum ipset_adt adt, u32 *lineno, u32 flags); | 605 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); |
593 | 606 | ||
594 | static const struct ip_set_type_variant type_pf_variant = { | 607 | static const struct ip_set_type_variant type_pf_variant = { |
595 | .kadt = type_pf_kadt, | 608 | .kadt = type_pf_kadt, |
@@ -821,8 +834,11 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
821 | goto out; | 834 | goto out; |
822 | } | 835 | } |
823 | ret = type_pf_elem_tadd(n, d, timeout); | 836 | ret = type_pf_elem_tadd(n, d, timeout); |
824 | if (ret != 0) | 837 | if (ret != 0) { |
838 | if (ret == -EEXIST) | ||
839 | type_pf_data_next(h, d); | ||
825 | goto out; | 840 | goto out; |
841 | } | ||
826 | 842 | ||
827 | #ifdef IP_SET_HASH_WITH_NETS | 843 | #ifdef IP_SET_HASH_WITH_NETS |
828 | add_cidr(h, d->cidr, HOST_MASK); | 844 | add_cidr(h, d->cidr, HOST_MASK); |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index 75990b37ca37..3a71c8e41557 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c | |||
@@ -236,7 +236,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
236 | 236 | ||
237 | static int | 237 | static int |
238 | bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], | 238 | bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], |
239 | enum ipset_adt adt, u32 *lineno, u32 flags) | 239 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
240 | { | 240 | { |
241 | struct bitmap_ip *map = set->data; | 241 | struct bitmap_ip *map = set->data; |
242 | ipset_adtfn adtfn = set->variant->adt[adt]; | 242 | ipset_adtfn adtfn = set->variant->adt[adt]; |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index cbe77f36650b..fdd5f79d93f3 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c | |||
@@ -365,7 +365,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
365 | 365 | ||
366 | static int | 366 | static int |
367 | bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], | 367 | bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], |
368 | enum ipset_adt adt, u32 *lineno, u32 flags) | 368 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
369 | { | 369 | { |
370 | const struct bitmap_ipmac *map = set->data; | 370 | const struct bitmap_ipmac *map = set->data; |
371 | ipset_adtfn adtfn = set->variant->adt[adt]; | 371 | ipset_adtfn adtfn = set->variant->adt[adt]; |
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 0b0ae19d0290..a6a5b3558ddc 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c | |||
@@ -231,7 +231,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
231 | 231 | ||
232 | static int | 232 | static int |
233 | bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], | 233 | bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], |
234 | enum ipset_adt adt, u32 *lineno, u32 flags) | 234 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
235 | { | 235 | { |
236 | struct bitmap_port *map = set->data; | 236 | struct bitmap_port *map = set->data; |
237 | ipset_adtfn adtfn = set->variant->adt[adt]; | 237 | ipset_adtfn adtfn = set->variant->adt[adt]; |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 8446c7d81898..528a9b3933ab 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -1158,17 +1158,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, | |||
1158 | struct nlattr *tb[], enum ipset_adt adt, | 1158 | struct nlattr *tb[], enum ipset_adt adt, |
1159 | u32 flags, bool use_lineno) | 1159 | u32 flags, bool use_lineno) |
1160 | { | 1160 | { |
1161 | int ret, retried = 0; | 1161 | int ret; |
1162 | u32 lineno = 0; | 1162 | u32 lineno = 0; |
1163 | bool eexist = flags & IPSET_FLAG_EXIST; | 1163 | bool eexist = flags & IPSET_FLAG_EXIST, retried = false; |
1164 | 1164 | ||
1165 | do { | 1165 | do { |
1166 | write_lock_bh(&set->lock); | 1166 | write_lock_bh(&set->lock); |
1167 | ret = set->variant->uadt(set, tb, adt, &lineno, flags); | 1167 | ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried); |
1168 | write_unlock_bh(&set->lock); | 1168 | write_unlock_bh(&set->lock); |
1169 | retried = true; | ||
1169 | } while (ret == -EAGAIN && | 1170 | } while (ret == -EAGAIN && |
1170 | set->variant->resize && | 1171 | set->variant->resize && |
1171 | (ret = set->variant->resize(set, retried++)) == 0); | 1172 | (ret = set->variant->resize(set, retried)) == 0); |
1172 | 1173 | ||
1173 | if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) | 1174 | if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) |
1174 | return 0; | 1175 | return 0; |
@@ -1341,7 +1342,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, | |||
1341 | return -IPSET_ERR_PROTOCOL; | 1342 | return -IPSET_ERR_PROTOCOL; |
1342 | 1343 | ||
1343 | read_lock_bh(&set->lock); | 1344 | read_lock_bh(&set->lock); |
1344 | ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0); | 1345 | ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0); |
1345 | read_unlock_bh(&set->lock); | 1346 | read_unlock_bh(&set->lock); |
1346 | /* Userspace can't trigger element to be re-added */ | 1347 | /* Userspace can't trigger element to be re-added */ |
1347 | if (ret == -EAGAIN) | 1348 | if (ret == -EAGAIN) |
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index 65a445477f64..c99e861ce031 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c | |||
@@ -108,6 +108,12 @@ nla_put_failure: | |||
108 | #define HOST_MASK 32 | 108 | #define HOST_MASK 32 |
109 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 109 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
110 | 110 | ||
111 | static inline void | ||
112 | hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d) | ||
113 | { | ||
114 | h->next.ip = ntohl(d->ip); | ||
115 | } | ||
116 | |||
111 | static int | 117 | static int |
112 | hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, | 118 | hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, |
113 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 119 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -126,7 +132,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
126 | 132 | ||
127 | static int | 133 | static int |
128 | hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], | 134 | hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], |
129 | enum ipset_adt adt, u32 *lineno, u32 flags) | 135 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
130 | { | 136 | { |
131 | const struct ip_set_hash *h = set->data; | 137 | const struct ip_set_hash *h = set->data; |
132 | ipset_adtfn adtfn = set->variant->adt[adt]; | 138 | ipset_adtfn adtfn = set->variant->adt[adt]; |
@@ -178,6 +184,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
178 | 184 | ||
179 | hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); | 185 | hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); |
180 | 186 | ||
187 | if (retried) | ||
188 | ip = h->next.ip; | ||
181 | for (; !before(ip_to, ip); ip += hosts) { | 189 | for (; !before(ip_to, ip); ip += hosts) { |
182 | nip = htonl(ip); | 190 | nip = htonl(ip); |
183 | if (nip == 0) | 191 | if (nip == 0) |
@@ -281,6 +289,11 @@ nla_put_failure: | |||
281 | #define HOST_MASK 128 | 289 | #define HOST_MASK 128 |
282 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 290 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
283 | 291 | ||
292 | static inline void | ||
293 | hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d) | ||
294 | { | ||
295 | } | ||
296 | |||
284 | static int | 297 | static int |
285 | hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, | 298 | hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, |
286 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 299 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -305,7 +318,7 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { | |||
305 | 318 | ||
306 | static int | 319 | static int |
307 | hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], | 320 | hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], |
308 | enum ipset_adt adt, u32 *lineno, u32 flags) | 321 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
309 | { | 322 | { |
310 | const struct ip_set_hash *h = set->data; | 323 | const struct ip_set_hash *h = set->data; |
311 | ipset_adtfn adtfn = set->variant->adt[adt]; | 324 | ipset_adtfn adtfn = set->variant->adt[adt]; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 9f179bb4f13e..aa91b2c73be3 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c | |||
@@ -124,6 +124,14 @@ nla_put_failure: | |||
124 | #define HOST_MASK 32 | 124 | #define HOST_MASK 32 |
125 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 125 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
126 | 126 | ||
127 | static inline void | ||
128 | hash_ipport4_data_next(struct ip_set_hash *h, | ||
129 | const struct hash_ipport4_elem *d) | ||
130 | { | ||
131 | h->next.ip = ntohl(d->ip); | ||
132 | h->next.port = ntohs(d->port); | ||
133 | } | ||
134 | |||
127 | static int | 135 | static int |
128 | hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, | 136 | hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, |
129 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 137 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -143,12 +151,12 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
143 | 151 | ||
144 | static int | 152 | static int |
145 | hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], | 153 | hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], |
146 | enum ipset_adt adt, u32 *lineno, u32 flags) | 154 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
147 | { | 155 | { |
148 | const struct ip_set_hash *h = set->data; | 156 | const struct ip_set_hash *h = set->data; |
149 | ipset_adtfn adtfn = set->variant->adt[adt]; | 157 | ipset_adtfn adtfn = set->variant->adt[adt]; |
150 | struct hash_ipport4_elem data = { }; | 158 | struct hash_ipport4_elem data = { }; |
151 | u32 ip, ip_to, p, port, port_to; | 159 | u32 ip, ip_to, p = 0, port, port_to; |
152 | u32 timeout = h->timeout; | 160 | u32 timeout = h->timeout; |
153 | bool with_ports = false; | 161 | bool with_ports = false; |
154 | int ret; | 162 | int ret; |
@@ -220,8 +228,11 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
220 | swap(port, port_to); | 228 | swap(port, port_to); |
221 | } | 229 | } |
222 | 230 | ||
223 | for (; !before(ip_to, ip); ip++) | 231 | if (retried) |
224 | for (p = port; p <= port_to; p++) { | 232 | ip = h->next.ip; |
233 | for (; !before(ip_to, ip); ip++) { | ||
234 | p = retried && ip == h->next.ip ? h->next.port : port; | ||
235 | for (; p <= port_to; p++) { | ||
225 | data.ip = htonl(ip); | 236 | data.ip = htonl(ip); |
226 | data.port = htons(p); | 237 | data.port = htons(p); |
227 | ret = adtfn(set, &data, timeout, flags); | 238 | ret = adtfn(set, &data, timeout, flags); |
@@ -231,6 +242,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
231 | else | 242 | else |
232 | ret = 0; | 243 | ret = 0; |
233 | } | 244 | } |
245 | } | ||
234 | return ret; | 246 | return ret; |
235 | } | 247 | } |
236 | 248 | ||
@@ -328,6 +340,13 @@ nla_put_failure: | |||
328 | #define HOST_MASK 128 | 340 | #define HOST_MASK 128 |
329 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 341 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
330 | 342 | ||
343 | static inline void | ||
344 | hash_ipport6_data_next(struct ip_set_hash *h, | ||
345 | const struct hash_ipport6_elem *d) | ||
346 | { | ||
347 | h->next.port = ntohs(d->port); | ||
348 | } | ||
349 | |||
331 | static int | 350 | static int |
332 | hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, | 351 | hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, |
333 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 352 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -347,7 +366,7 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
347 | 366 | ||
348 | static int | 367 | static int |
349 | hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], | 368 | hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], |
350 | enum ipset_adt adt, u32 *lineno, u32 flags) | 369 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
351 | { | 370 | { |
352 | const struct ip_set_hash *h = set->data; | 371 | const struct ip_set_hash *h = set->data; |
353 | ipset_adtfn adtfn = set->variant->adt[adt]; | 372 | ipset_adtfn adtfn = set->variant->adt[adt]; |
@@ -405,6 +424,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
405 | if (port > port_to) | 424 | if (port > port_to) |
406 | swap(port, port_to); | 425 | swap(port, port_to); |
407 | 426 | ||
427 | if (retried) | ||
428 | port = h->next.port; | ||
408 | for (; port <= port_to; port++) { | 429 | for (; port <= port_to; port++) { |
409 | data.port = htons(port); | 430 | data.port = htons(port); |
410 | ret = adtfn(set, &data, timeout, flags); | 431 | ret = adtfn(set, &data, timeout, flags); |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 7cfa52b34981..b88e74e0bf06 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c | |||
@@ -127,6 +127,14 @@ nla_put_failure: | |||
127 | #define HOST_MASK 32 | 127 | #define HOST_MASK 32 |
128 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 128 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
129 | 129 | ||
130 | static inline void | ||
131 | hash_ipportip4_data_next(struct ip_set_hash *h, | ||
132 | const struct hash_ipportip4_elem *d) | ||
133 | { | ||
134 | h->next.ip = ntohl(d->ip); | ||
135 | h->next.port = ntohs(d->port); | ||
136 | } | ||
137 | |||
130 | static int | 138 | static int |
131 | hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, | 139 | hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, |
132 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 140 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -147,12 +155,12 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
147 | 155 | ||
148 | static int | 156 | static int |
149 | hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], | 157 | hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], |
150 | enum ipset_adt adt, u32 *lineno, u32 flags) | 158 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
151 | { | 159 | { |
152 | const struct ip_set_hash *h = set->data; | 160 | const struct ip_set_hash *h = set->data; |
153 | ipset_adtfn adtfn = set->variant->adt[adt]; | 161 | ipset_adtfn adtfn = set->variant->adt[adt]; |
154 | struct hash_ipportip4_elem data = { }; | 162 | struct hash_ipportip4_elem data = { }; |
155 | u32 ip, ip_to, p, port, port_to; | 163 | u32 ip, ip_to, p = 0, port, port_to; |
156 | u32 timeout = h->timeout; | 164 | u32 timeout = h->timeout; |
157 | bool with_ports = false; | 165 | bool with_ports = false; |
158 | int ret; | 166 | int ret; |
@@ -228,8 +236,11 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
228 | swap(port, port_to); | 236 | swap(port, port_to); |
229 | } | 237 | } |
230 | 238 | ||
231 | for (; !before(ip_to, ip); ip++) | 239 | if (retried) |
232 | for (p = port; p <= port_to; p++) { | 240 | ip = h->next.ip; |
241 | for (; !before(ip_to, ip); ip++) { | ||
242 | p = retried && ip == h->next.ip ? h->next.port : port; | ||
243 | for (; p <= port_to; p++) { | ||
233 | data.ip = htonl(ip); | 244 | data.ip = htonl(ip); |
234 | data.port = htons(p); | 245 | data.port = htons(p); |
235 | ret = adtfn(set, &data, timeout, flags); | 246 | ret = adtfn(set, &data, timeout, flags); |
@@ -239,6 +250,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
239 | else | 250 | else |
240 | ret = 0; | 251 | ret = 0; |
241 | } | 252 | } |
253 | } | ||
242 | return ret; | 254 | return ret; |
243 | } | 255 | } |
244 | 256 | ||
@@ -341,6 +353,13 @@ nla_put_failure: | |||
341 | #define HOST_MASK 128 | 353 | #define HOST_MASK 128 |
342 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 354 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
343 | 355 | ||
356 | static inline void | ||
357 | hash_ipportip6_data_next(struct ip_set_hash *h, | ||
358 | const struct hash_ipportip6_elem *d) | ||
359 | { | ||
360 | h->next.port = ntohs(d->port); | ||
361 | } | ||
362 | |||
344 | static int | 363 | static int |
345 | hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, | 364 | hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, |
346 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 365 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -361,7 +380,7 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
361 | 380 | ||
362 | static int | 381 | static int |
363 | hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], | 382 | hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], |
364 | enum ipset_adt adt, u32 *lineno, u32 flags) | 383 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
365 | { | 384 | { |
366 | const struct ip_set_hash *h = set->data; | 385 | const struct ip_set_hash *h = set->data; |
367 | ipset_adtfn adtfn = set->variant->adt[adt]; | 386 | ipset_adtfn adtfn = set->variant->adt[adt]; |
@@ -423,6 +442,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
423 | if (port > port_to) | 442 | if (port > port_to) |
424 | swap(port, port_to); | 443 | swap(port, port_to); |
425 | 444 | ||
445 | if (retried) | ||
446 | port = h->next.port; | ||
426 | for (; port <= port_to; port++) { | 447 | for (; port <= port_to; port++) { |
427 | data.port = htons(port); | 448 | data.port = htons(port); |
428 | ret = adtfn(set, &data, timeout, flags); | 449 | ret = adtfn(set, &data, timeout, flags); |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 104042aba92b..605ef3bf94ef 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
@@ -140,6 +140,14 @@ nla_put_failure: | |||
140 | #define HOST_MASK 32 | 140 | #define HOST_MASK 32 |
141 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 141 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
142 | 142 | ||
143 | static inline void | ||
144 | hash_ipportnet4_data_next(struct ip_set_hash *h, | ||
145 | const struct hash_ipportnet4_elem *d) | ||
146 | { | ||
147 | h->next.ip = ntohl(d->ip); | ||
148 | h->next.port = ntohs(d->port); | ||
149 | } | ||
150 | |||
143 | static int | 151 | static int |
144 | hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | 152 | hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, |
145 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 153 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -167,12 +175,12 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
167 | 175 | ||
168 | static int | 176 | static int |
169 | hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | 177 | hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], |
170 | enum ipset_adt adt, u32 *lineno, u32 flags) | 178 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
171 | { | 179 | { |
172 | const struct ip_set_hash *h = set->data; | 180 | const struct ip_set_hash *h = set->data; |
173 | ipset_adtfn adtfn = set->variant->adt[adt]; | 181 | ipset_adtfn adtfn = set->variant->adt[adt]; |
174 | struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; | 182 | struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; |
175 | u32 ip, ip_to, p, port, port_to; | 183 | u32 ip, ip_to, p = 0, port, port_to; |
176 | u32 timeout = h->timeout; | 184 | u32 timeout = h->timeout; |
177 | bool with_ports = false; | 185 | bool with_ports = false; |
178 | int ret; | 186 | int ret; |
@@ -256,8 +264,11 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
256 | swap(port, port_to); | 264 | swap(port, port_to); |
257 | } | 265 | } |
258 | 266 | ||
259 | for (; !before(ip_to, ip); ip++) | 267 | if (retried) |
260 | for (p = port; p <= port_to; p++) { | 268 | ip = h->next.ip; |
269 | for (; !before(ip_to, ip); ip++) { | ||
270 | p = retried && ip == h->next.ip ? h->next.port : port; | ||
271 | for (; p <= port_to; p++) { | ||
261 | data.ip = htonl(ip); | 272 | data.ip = htonl(ip); |
262 | data.port = htons(p); | 273 | data.port = htons(p); |
263 | ret = adtfn(set, &data, timeout, flags); | 274 | ret = adtfn(set, &data, timeout, flags); |
@@ -267,6 +278,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
267 | else | 278 | else |
268 | ret = 0; | 279 | ret = 0; |
269 | } | 280 | } |
281 | } | ||
270 | return ret; | 282 | return ret; |
271 | } | 283 | } |
272 | 284 | ||
@@ -388,6 +400,13 @@ nla_put_failure: | |||
388 | #define HOST_MASK 128 | 400 | #define HOST_MASK 128 |
389 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 401 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
390 | 402 | ||
403 | static inline void | ||
404 | hash_ipportnet6_data_next(struct ip_set_hash *h, | ||
405 | const struct hash_ipportnet6_elem *d) | ||
406 | { | ||
407 | h->next.port = ntohs(d->port); | ||
408 | } | ||
409 | |||
391 | static int | 410 | static int |
392 | hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | 411 | hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, |
393 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 412 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -415,7 +434,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
415 | 434 | ||
416 | static int | 435 | static int |
417 | hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | 436 | hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], |
418 | enum ipset_adt adt, u32 *lineno, u32 flags) | 437 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
419 | { | 438 | { |
420 | const struct ip_set_hash *h = set->data; | 439 | const struct ip_set_hash *h = set->data; |
421 | ipset_adtfn adtfn = set->variant->adt[adt]; | 440 | ipset_adtfn adtfn = set->variant->adt[adt]; |
@@ -485,6 +504,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
485 | if (port > port_to) | 504 | if (port > port_to) |
486 | swap(port, port_to); | 505 | swap(port, port_to); |
487 | 506 | ||
507 | if (retried) | ||
508 | port = h->next.port; | ||
488 | for (; port <= port_to; port++) { | 509 | for (; port <= port_to; port++) { |
489 | data.port = htons(port); | 510 | data.port = htons(port); |
490 | ret = adtfn(set, &data, timeout, flags); | 511 | ret = adtfn(set, &data, timeout, flags); |
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 0024053e409a..e6f8bc5771ca 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
@@ -125,6 +125,12 @@ nla_put_failure: | |||
125 | #define HOST_MASK 32 | 125 | #define HOST_MASK 32 |
126 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 126 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
127 | 127 | ||
128 | static inline void | ||
129 | hash_net4_data_next(struct ip_set_hash *h, | ||
130 | const struct hash_net4_elem *d) | ||
131 | { | ||
132 | } | ||
133 | |||
128 | static int | 134 | static int |
129 | hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, | 135 | hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, |
130 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 136 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -146,7 +152,7 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
146 | 152 | ||
147 | static int | 153 | static int |
148 | hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | 154 | hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], |
149 | enum ipset_adt adt, u32 *lineno, u32 flags) | 155 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
150 | { | 156 | { |
151 | const struct ip_set_hash *h = set->data; | 157 | const struct ip_set_hash *h = set->data; |
152 | ipset_adtfn adtfn = set->variant->adt[adt]; | 158 | ipset_adtfn adtfn = set->variant->adt[adt]; |
@@ -290,6 +296,12 @@ nla_put_failure: | |||
290 | #define HOST_MASK 128 | 296 | #define HOST_MASK 128 |
291 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 297 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
292 | 298 | ||
299 | static inline void | ||
300 | hash_net6_data_next(struct ip_set_hash *h, | ||
301 | const struct hash_net6_elem *d) | ||
302 | { | ||
303 | } | ||
304 | |||
293 | static int | 305 | static int |
294 | hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, | 306 | hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, |
295 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 307 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -311,7 +323,7 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
311 | 323 | ||
312 | static int | 324 | static int |
313 | hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | 325 | hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], |
314 | enum ipset_adt adt, u32 *lineno, u32 flags) | 326 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
315 | { | 327 | { |
316 | const struct ip_set_hash *h = set->data; | 328 | const struct ip_set_hash *h = set->data; |
317 | ipset_adtfn adtfn = set->variant->adt[adt]; | 329 | ipset_adtfn adtfn = set->variant->adt[adt]; |
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 7a2327b3407d..037b829178dc 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
@@ -137,6 +137,13 @@ nla_put_failure: | |||
137 | #define HOST_MASK 32 | 137 | #define HOST_MASK 32 |
138 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 138 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
139 | 139 | ||
140 | static inline void | ||
141 | hash_netport4_data_next(struct ip_set_hash *h, | ||
142 | const struct hash_netport4_elem *d) | ||
143 | { | ||
144 | h->next.port = ntohs(d->port); | ||
145 | } | ||
146 | |||
140 | static int | 147 | static int |
141 | hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, | 148 | hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, |
142 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 149 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -163,7 +170,7 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
163 | 170 | ||
164 | static int | 171 | static int |
165 | hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | 172 | hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], |
166 | enum ipset_adt adt, u32 *lineno, u32 flags) | 173 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
167 | { | 174 | { |
168 | const struct ip_set_hash *h = set->data; | 175 | const struct ip_set_hash *h = set->data; |
169 | ipset_adtfn adtfn = set->variant->adt[adt]; | 176 | ipset_adtfn adtfn = set->variant->adt[adt]; |
@@ -225,6 +232,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
225 | if (port > port_to) | 232 | if (port > port_to) |
226 | swap(port, port_to); | 233 | swap(port, port_to); |
227 | 234 | ||
235 | if (retried) | ||
236 | port = h->next.port; | ||
228 | for (; port <= port_to; port++) { | 237 | for (; port <= port_to; port++) { |
229 | data.port = htons(port); | 238 | data.port = htons(port); |
230 | ret = adtfn(set, &data, timeout, flags); | 239 | ret = adtfn(set, &data, timeout, flags); |
@@ -350,6 +359,13 @@ nla_put_failure: | |||
350 | #define HOST_MASK 128 | 359 | #define HOST_MASK 128 |
351 | #include <linux/netfilter/ipset/ip_set_ahash.h> | 360 | #include <linux/netfilter/ipset/ip_set_ahash.h> |
352 | 361 | ||
362 | static inline void | ||
363 | hash_netport6_data_next(struct ip_set_hash *h, | ||
364 | const struct hash_netport6_elem *d) | ||
365 | { | ||
366 | h->next.port = ntohs(d->port); | ||
367 | } | ||
368 | |||
353 | static int | 369 | static int |
354 | hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, | 370 | hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, |
355 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) | 371 | enum ipset_adt adt, const struct ip_set_adt_opt *opt) |
@@ -376,7 +392,7 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
376 | 392 | ||
377 | static int | 393 | static int |
378 | hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | 394 | hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], |
379 | enum ipset_adt adt, u32 *lineno, u32 flags) | 395 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
380 | { | 396 | { |
381 | const struct ip_set_hash *h = set->data; | 397 | const struct ip_set_hash *h = set->data; |
382 | ipset_adtfn adtfn = set->variant->adt[adt]; | 398 | ipset_adtfn adtfn = set->variant->adt[adt]; |
@@ -438,6 +454,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
438 | if (port > port_to) | 454 | if (port > port_to) |
439 | swap(port, port_to); | 455 | swap(port, port_to); |
440 | 456 | ||
457 | if (retried) | ||
458 | port = h->next.port; | ||
441 | for (; port <= port_to; port++) { | 459 | for (; port <= port_to; port++) { |
442 | data.port = htons(port); | 460 | data.port = htons(port); |
443 | ret = adtfn(set, &data, timeout, flags); | 461 | ret = adtfn(set, &data, timeout, flags); |
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index f05e9eb863dc..74f0dcc30d98 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c | |||
@@ -218,7 +218,7 @@ cleanup_entries(struct list_set *map) | |||
218 | 218 | ||
219 | static int | 219 | static int |
220 | list_set_uadt(struct ip_set *set, struct nlattr *tb[], | 220 | list_set_uadt(struct ip_set *set, struct nlattr *tb[], |
221 | enum ipset_adt adt, u32 *lineno, u32 flags) | 221 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
222 | { | 222 | { |
223 | struct list_set *map = set->data; | 223 | struct list_set *map = set->data; |
224 | bool with_timeout = with_timeout(map->timeout); | 224 | bool with_timeout = with_timeout(map->timeout); |