diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2011-06-16 12:52:41 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-06-16 12:52:41 -0400 |
commit | d0d9e0a5a8db05b2179c2ffb25d1c2850cce3c8e (patch) | |
tree | 16be0164e378226c7603838ded9bcf3fd4041692 /net/netfilter | |
parent | f1e00b39797944bf25addaf543839feeb25fbdc5 (diff) |
netfilter: ipset: support range for IPv4 at adding/deleting elements for hash:*net* types
The range internally is converted to the network(s) equal to the range.
Example:
# ipset new test hash:net
# ipset add test 10.2.0.0-10.2.1.12
# ipset list test
Name: test
Type: hash:net
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16888
References: 0
Members:
10.2.1.12
10.2.1.0/29
10.2.0.0/24
10.2.1.8/30
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportnet.c | 69 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_net.c | 51 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netport.c | 69 | ||||
-rw-r--r-- | net/netfilter/ipset/pfxlen.c | 21 |
4 files changed, 156 insertions, 54 deletions
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 0b54fdea9794..ef068b03ec1a 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
@@ -146,6 +146,7 @@ hash_ipportnet4_data_next(struct ip_set_hash *h, | |||
146 | { | 146 | { |
147 | h->next.ip = ntohl(d->ip); | 147 | h->next.ip = ntohl(d->ip); |
148 | h->next.port = ntohs(d->port); | 148 | h->next.port = ntohs(d->port); |
149 | h->next.ip2 = ntohl(d->ip2); | ||
149 | } | 150 | } |
150 | 151 | ||
151 | static int | 152 | static int |
@@ -181,6 +182,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
181 | ipset_adtfn adtfn = set->variant->adt[adt]; | 182 | ipset_adtfn adtfn = set->variant->adt[adt]; |
182 | struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; | 183 | struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; |
183 | u32 ip, ip_to, p = 0, port, port_to; | 184 | u32 ip, ip_to, p = 0, port, port_to; |
185 | u32 ip2_from = 0, ip2_to, ip2_last, ip2; | ||
184 | u32 timeout = h->timeout; | 186 | u32 timeout = h->timeout; |
185 | bool with_ports = false; | 187 | bool with_ports = false; |
186 | int ret; | 188 | int ret; |
@@ -194,21 +196,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
194 | if (tb[IPSET_ATTR_LINENO]) | 196 | if (tb[IPSET_ATTR_LINENO]) |
195 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | 197 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); |
196 | 198 | ||
197 | ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip); | 199 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); |
198 | if (ret) | 200 | if (ret) |
199 | return ret; | 201 | return ret; |
200 | 202 | ||
201 | ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2); | 203 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from); |
202 | if (ret) | 204 | if (ret) |
203 | return ret; | 205 | return ret; |
204 | 206 | ||
205 | if (tb[IPSET_ATTR_CIDR2]) | 207 | if (tb[IPSET_ATTR_CIDR2]) { |
206 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); | 208 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); |
207 | 209 | if (!data.cidr) | |
208 | if (!data.cidr) | 210 | return -IPSET_ERR_INVALID_CIDR; |
209 | return -IPSET_ERR_INVALID_CIDR; | 211 | } |
210 | |||
211 | data.ip2 &= ip_set_netmask(data.cidr); | ||
212 | 212 | ||
213 | if (tb[IPSET_ATTR_PORT]) | 213 | if (tb[IPSET_ATTR_PORT]) |
214 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); | 214 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); |
@@ -233,14 +233,16 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
233 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 233 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
234 | } | 234 | } |
235 | 235 | ||
236 | with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; | ||
236 | if (adt == IPSET_TEST || | 237 | if (adt == IPSET_TEST || |
237 | !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || | 238 | !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports || |
238 | tb[IPSET_ATTR_PORT_TO])) { | 239 | tb[IPSET_ATTR_IP2_TO])) { |
240 | data.ip = htonl(ip); | ||
241 | data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr)); | ||
239 | ret = adtfn(set, &data, timeout, flags); | 242 | ret = adtfn(set, &data, timeout, flags); |
240 | return ip_set_eexist(ret, flags) ? 0 : ret; | 243 | return ip_set_eexist(ret, flags) ? 0 : ret; |
241 | } | 244 | } |
242 | 245 | ||
243 | ip = ntohl(data.ip); | ||
244 | if (tb[IPSET_ATTR_IP_TO]) { | 246 | if (tb[IPSET_ATTR_IP_TO]) { |
245 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); | 247 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); |
246 | if (ret) | 248 | if (ret) |
@@ -254,29 +256,48 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
254 | return -IPSET_ERR_INVALID_CIDR; | 256 | return -IPSET_ERR_INVALID_CIDR; |
255 | ip &= ip_set_hostmask(cidr); | 257 | ip &= ip_set_hostmask(cidr); |
256 | ip_to = ip | ~ip_set_hostmask(cidr); | 258 | ip_to = ip | ~ip_set_hostmask(cidr); |
257 | } else | 259 | } |
258 | ip_to = ip; | ||
259 | 260 | ||
260 | port_to = port = ntohs(data.port); | 261 | port_to = port = ntohs(data.port); |
261 | if (with_ports && tb[IPSET_ATTR_PORT_TO]) { | 262 | if (tb[IPSET_ATTR_PORT_TO]) { |
262 | port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); | 263 | port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); |
263 | if (port > port_to) | 264 | if (port > port_to) |
264 | swap(port, port_to); | 265 | swap(port, port_to); |
265 | } | 266 | } |
267 | if (tb[IPSET_ATTR_IP2_TO]) { | ||
268 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); | ||
269 | if (ret) | ||
270 | return ret; | ||
271 | if (ip2_from > ip2_to) | ||
272 | swap(ip2_from, ip2_to); | ||
273 | if (ip2_from + UINT_MAX == ip2_to) | ||
274 | return -IPSET_ERR_HASH_RANGE; | ||
275 | } else { | ||
276 | ip2_from &= ip_set_hostmask(data.cidr); | ||
277 | ip2_to = ip2_from | ~ip_set_hostmask(data.cidr); | ||
278 | } | ||
266 | 279 | ||
267 | if (retried) | 280 | if (retried) |
268 | ip = h->next.ip; | 281 | ip = h->next.ip; |
269 | for (; !before(ip_to, ip); ip++) { | 282 | for (; !before(ip_to, ip); ip++) { |
283 | data.ip = htonl(ip); | ||
270 | p = retried && ip == h->next.ip ? h->next.port : port; | 284 | p = retried && ip == h->next.ip ? h->next.port : port; |
271 | for (; p <= port_to; p++) { | 285 | for (; p <= port_to; p++) { |
272 | data.ip = htonl(ip); | ||
273 | data.port = htons(p); | 286 | data.port = htons(p); |
274 | ret = adtfn(set, &data, timeout, flags); | 287 | ip2 = retried && ip == h->next.ip && p == h->next.port |
275 | 288 | ? h->next.ip2 : ip2_from; | |
276 | if (ret && !ip_set_eexist(ret, flags)) | 289 | while (!after(ip2, ip2_to)) { |
277 | return ret; | 290 | data.ip2 = htonl(ip2); |
278 | else | 291 | ip2_last = ip_set_range_to_cidr(ip2, ip2_to, |
279 | ret = 0; | 292 | &data.cidr); |
293 | ret = adtfn(set, &data, timeout, flags); | ||
294 | |||
295 | if (ret && !ip_set_eexist(ret, flags)) | ||
296 | return ret; | ||
297 | else | ||
298 | ret = 0; | ||
299 | ip2 = ip2_last + 1; | ||
300 | } | ||
280 | } | 301 | } |
281 | } | 302 | } |
282 | return ret; | 303 | return ret; |
@@ -451,6 +472,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
451 | tb[IPSET_ATTR_IP_TO] || | 472 | tb[IPSET_ATTR_IP_TO] || |
452 | tb[IPSET_ATTR_CIDR])) | 473 | tb[IPSET_ATTR_CIDR])) |
453 | return -IPSET_ERR_PROTOCOL; | 474 | return -IPSET_ERR_PROTOCOL; |
475 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | ||
476 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | ||
454 | 477 | ||
455 | if (tb[IPSET_ATTR_LINENO]) | 478 | if (tb[IPSET_ATTR_LINENO]) |
456 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | 479 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); |
@@ -596,7 +619,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { | |||
596 | .dimension = IPSET_DIM_THREE, | 619 | .dimension = IPSET_DIM_THREE, |
597 | .family = AF_UNSPEC, | 620 | .family = AF_UNSPEC, |
598 | .revision_min = 0, | 621 | .revision_min = 0, |
599 | .revision_max = 1, /* SCTP and UDPLITE support added */ | 622 | /* 1 SCTP and UDPLITE support added */ |
623 | .revision_max = 2, /* Range as input support for IPv4 added */ | ||
600 | .create = hash_ipportnet_create, | 624 | .create = hash_ipportnet_create, |
601 | .create_policy = { | 625 | .create_policy = { |
602 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 626 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
@@ -609,6 +633,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { | |||
609 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | 633 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
610 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | 634 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, |
611 | [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, | 635 | [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, |
636 | [IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED }, | ||
612 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, | 637 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, |
613 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, | 638 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, |
614 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | 639 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, |
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 360cf5b3ddf6..8d3c3efbbf17 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
@@ -129,6 +129,7 @@ static inline void | |||
129 | hash_net4_data_next(struct ip_set_hash *h, | 129 | hash_net4_data_next(struct ip_set_hash *h, |
130 | const struct hash_net4_elem *d) | 130 | const struct hash_net4_elem *d) |
131 | { | 131 | { |
132 | h->next.ip = ntohl(d->ip); | ||
132 | } | 133 | } |
133 | 134 | ||
134 | static int | 135 | static int |
@@ -158,6 +159,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
158 | ipset_adtfn adtfn = set->variant->adt[adt]; | 159 | ipset_adtfn adtfn = set->variant->adt[adt]; |
159 | struct hash_net4_elem data = { .cidr = HOST_MASK }; | 160 | struct hash_net4_elem data = { .cidr = HOST_MASK }; |
160 | u32 timeout = h->timeout; | 161 | u32 timeout = h->timeout; |
162 | u32 ip = 0, ip_to, last; | ||
161 | int ret; | 163 | int ret; |
162 | 164 | ||
163 | if (unlikely(!tb[IPSET_ATTR_IP] || | 165 | if (unlikely(!tb[IPSET_ATTR_IP] || |
@@ -167,27 +169,51 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
167 | if (tb[IPSET_ATTR_LINENO]) | 169 | if (tb[IPSET_ATTR_LINENO]) |
168 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | 170 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); |
169 | 171 | ||
170 | ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip); | 172 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); |
171 | if (ret) | 173 | if (ret) |
172 | return ret; | 174 | return ret; |
173 | 175 | ||
174 | if (tb[IPSET_ATTR_CIDR]) | 176 | if (tb[IPSET_ATTR_CIDR]) { |
175 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 177 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
176 | 178 | if (!data.cidr) | |
177 | if (!data.cidr) | 179 | return -IPSET_ERR_INVALID_CIDR; |
178 | return -IPSET_ERR_INVALID_CIDR; | 180 | } |
179 | |||
180 | data.ip &= ip_set_netmask(data.cidr); | ||
181 | 181 | ||
182 | if (tb[IPSET_ATTR_TIMEOUT]) { | 182 | if (tb[IPSET_ATTR_TIMEOUT]) { |
183 | if (!with_timeout(h->timeout)) | 183 | if (!with_timeout(h->timeout)) |
184 | return -IPSET_ERR_TIMEOUT; | 184 | return -IPSET_ERR_TIMEOUT; |
185 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 185 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
186 | } | 186 | } |
187 | |||
188 | if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { | ||
189 | data.ip = htonl(ip & ip_set_hostmask(data.cidr)); | ||
190 | ret = adtfn(set, &data, timeout, flags); | ||
191 | return ip_set_eexist(ret, flags) ? 0 : ret; | ||
192 | } | ||
187 | 193 | ||
188 | ret = adtfn(set, &data, timeout, flags); | 194 | ip_to = ip; |
189 | 195 | if (tb[IPSET_ATTR_IP_TO]) { | |
190 | return ip_set_eexist(ret, flags) ? 0 : ret; | 196 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); |
197 | if (ret) | ||
198 | return ret; | ||
199 | if (ip_to < ip) | ||
200 | swap(ip, ip_to); | ||
201 | if (ip + UINT_MAX == ip_to) | ||
202 | return -IPSET_ERR_HASH_RANGE; | ||
203 | } | ||
204 | if (retried) | ||
205 | ip = h->next.ip; | ||
206 | while (!after(ip, ip_to)) { | ||
207 | data.ip = htonl(ip); | ||
208 | last = ip_set_range_to_cidr(ip, ip_to, &data.cidr); | ||
209 | ret = adtfn(set, &data, timeout, flags); | ||
210 | if (ret && !ip_set_eexist(ret, flags)) | ||
211 | return ret; | ||
212 | else | ||
213 | ret = 0; | ||
214 | ip = last + 1; | ||
215 | } | ||
216 | return ret; | ||
191 | } | 217 | } |
192 | 218 | ||
193 | static bool | 219 | static bool |
@@ -334,6 +360,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
334 | if (unlikely(!tb[IPSET_ATTR_IP] || | 360 | if (unlikely(!tb[IPSET_ATTR_IP] || |
335 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | 361 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) |
336 | return -IPSET_ERR_PROTOCOL; | 362 | return -IPSET_ERR_PROTOCOL; |
363 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | ||
364 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | ||
337 | 365 | ||
338 | if (tb[IPSET_ATTR_LINENO]) | 366 | if (tb[IPSET_ATTR_LINENO]) |
339 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | 367 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); |
@@ -438,7 +466,7 @@ static struct ip_set_type hash_net_type __read_mostly = { | |||
438 | .dimension = IPSET_DIM_ONE, | 466 | .dimension = IPSET_DIM_ONE, |
439 | .family = AF_UNSPEC, | 467 | .family = AF_UNSPEC, |
440 | .revision_min = 0, | 468 | .revision_min = 0, |
441 | .revision_max = 0, | 469 | .revision_max = 1, /* Range as input support for IPv4 added */ |
442 | .create = hash_net_create, | 470 | .create = hash_net_create, |
443 | .create_policy = { | 471 | .create_policy = { |
444 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 472 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
@@ -449,6 +477,7 @@ static struct ip_set_type hash_net_type __read_mostly = { | |||
449 | }, | 477 | }, |
450 | .adt_policy = { | 478 | .adt_policy = { |
451 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | 479 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
480 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | ||
452 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | 481 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, |
453 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | 482 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
454 | }, | 483 | }, |
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 09f807fa24ac..300103096879 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
@@ -141,6 +141,7 @@ static inline void | |||
141 | hash_netport4_data_next(struct ip_set_hash *h, | 141 | hash_netport4_data_next(struct ip_set_hash *h, |
142 | const struct hash_netport4_elem *d) | 142 | const struct hash_netport4_elem *d) |
143 | { | 143 | { |
144 | h->next.ip = ntohl(d->ip); | ||
144 | h->next.port = ntohs(d->port); | 145 | h->next.port = ntohs(d->port); |
145 | } | 146 | } |
146 | 147 | ||
@@ -175,7 +176,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
175 | const struct ip_set_hash *h = set->data; | 176 | const struct ip_set_hash *h = set->data; |
176 | ipset_adtfn adtfn = set->variant->adt[adt]; | 177 | ipset_adtfn adtfn = set->variant->adt[adt]; |
177 | struct hash_netport4_elem data = { .cidr = HOST_MASK }; | 178 | struct hash_netport4_elem data = { .cidr = HOST_MASK }; |
178 | u32 port, port_to; | 179 | u32 port, port_to, p = 0, ip = 0, ip_to, last; |
179 | u32 timeout = h->timeout; | 180 | u32 timeout = h->timeout; |
180 | bool with_ports = false; | 181 | bool with_ports = false; |
181 | int ret; | 182 | int ret; |
@@ -189,15 +190,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
189 | if (tb[IPSET_ATTR_LINENO]) | 190 | if (tb[IPSET_ATTR_LINENO]) |
190 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | 191 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); |
191 | 192 | ||
192 | ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip); | 193 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); |
193 | if (ret) | 194 | if (ret) |
194 | return ret; | 195 | return ret; |
195 | 196 | ||
196 | if (tb[IPSET_ATTR_CIDR]) | 197 | if (tb[IPSET_ATTR_CIDR]) { |
197 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 198 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
198 | if (!data.cidr) | 199 | if (!data.cidr) |
199 | return -IPSET_ERR_INVALID_CIDR; | 200 | return -IPSET_ERR_INVALID_CIDR; |
200 | data.ip &= ip_set_netmask(data.cidr); | 201 | } |
201 | 202 | ||
202 | if (tb[IPSET_ATTR_PORT]) | 203 | if (tb[IPSET_ATTR_PORT]) |
203 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); | 204 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); |
@@ -222,26 +223,48 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
222 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 223 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
223 | } | 224 | } |
224 | 225 | ||
225 | if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { | 226 | with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; |
227 | if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) { | ||
228 | data.ip = htonl(ip & ip_set_hostmask(data.cidr)); | ||
226 | ret = adtfn(set, &data, timeout, flags); | 229 | ret = adtfn(set, &data, timeout, flags); |
227 | return ip_set_eexist(ret, flags) ? 0 : ret; | 230 | return ip_set_eexist(ret, flags) ? 0 : ret; |
228 | } | 231 | } |
229 | 232 | ||
230 | port = ntohs(data.port); | 233 | port = port_to = ntohs(data.port); |
231 | port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); | 234 | if (tb[IPSET_ATTR_PORT_TO]) { |
232 | if (port > port_to) | 235 | port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); |
233 | swap(port, port_to); | 236 | if (port_to < port) |
237 | swap(port, port_to); | ||
238 | } | ||
239 | if (tb[IPSET_ATTR_IP_TO]) { | ||
240 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); | ||
241 | if (ret) | ||
242 | return ret; | ||
243 | if (ip_to < ip) | ||
244 | swap(ip, ip_to); | ||
245 | if (ip + UINT_MAX == ip_to) | ||
246 | return -IPSET_ERR_HASH_RANGE; | ||
247 | } else { | ||
248 | ip &= ip_set_hostmask(data.cidr); | ||
249 | ip_to = ip | ~ip_set_hostmask(data.cidr); | ||
250 | } | ||
234 | 251 | ||
235 | if (retried) | 252 | if (retried) |
236 | port = h->next.port; | 253 | ip = h->next.ip; |
237 | for (; port <= port_to; port++) { | 254 | while (!after(ip, ip_to)) { |
238 | data.port = htons(port); | 255 | data.ip = htonl(ip); |
239 | ret = adtfn(set, &data, timeout, flags); | 256 | last = ip_set_range_to_cidr(ip, ip_to, &data.cidr); |
240 | 257 | p = retried && ip == h->next.ip ? h->next.port : port; | |
241 | if (ret && !ip_set_eexist(ret, flags)) | 258 | for (; p <= port_to; p++) { |
242 | return ret; | 259 | data.port = htons(p); |
243 | else | 260 | ret = adtfn(set, &data, timeout, flags); |
244 | ret = 0; | 261 | |
262 | if (ret && !ip_set_eexist(ret, flags)) | ||
263 | return ret; | ||
264 | else | ||
265 | ret = 0; | ||
266 | } | ||
267 | ip = last + 1; | ||
245 | } | 268 | } |
246 | return ret; | 269 | return ret; |
247 | } | 270 | } |
@@ -407,6 +430,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
407 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 430 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
408 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | 431 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) |
409 | return -IPSET_ERR_PROTOCOL; | 432 | return -IPSET_ERR_PROTOCOL; |
433 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | ||
434 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | ||
410 | 435 | ||
411 | if (tb[IPSET_ATTR_LINENO]) | 436 | if (tb[IPSET_ATTR_LINENO]) |
412 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | 437 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); |
@@ -545,7 +570,8 @@ static struct ip_set_type hash_netport_type __read_mostly = { | |||
545 | .dimension = IPSET_DIM_TWO, | 570 | .dimension = IPSET_DIM_TWO, |
546 | .family = AF_UNSPEC, | 571 | .family = AF_UNSPEC, |
547 | .revision_min = 0, | 572 | .revision_min = 0, |
548 | .revision_max = 1, /* SCTP and UDPLITE support added */ | 573 | /* 1 SCTP and UDPLITE support added */ |
574 | .revision_max = 2, /* Range as input support for IPv4 added */ | ||
549 | .create = hash_netport_create, | 575 | .create = hash_netport_create, |
550 | .create_policy = { | 576 | .create_policy = { |
551 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 577 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
@@ -557,6 +583,7 @@ static struct ip_set_type hash_netport_type __read_mostly = { | |||
557 | }, | 583 | }, |
558 | .adt_policy = { | 584 | .adt_policy = { |
559 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | 585 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
586 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | ||
560 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, | 587 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, |
561 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, | 588 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, |
562 | [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, | 589 | [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, |
diff --git a/net/netfilter/ipset/pfxlen.c b/net/netfilter/ipset/pfxlen.c index 23f8c8162214..b57a85673de7 100644 --- a/net/netfilter/ipset/pfxlen.c +++ b/net/netfilter/ipset/pfxlen.c | |||
@@ -289,3 +289,24 @@ const union nf_inet_addr ip_set_hostmask_map[] = { | |||
289 | E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF), | 289 | E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF), |
290 | }; | 290 | }; |
291 | EXPORT_SYMBOL_GPL(ip_set_hostmask_map); | 291 | EXPORT_SYMBOL_GPL(ip_set_hostmask_map); |
292 | |||
293 | /* Find the largest network which matches the range from left, in host order. */ | ||
294 | u32 | ||
295 | ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr) | ||
296 | { | ||
297 | u32 last; | ||
298 | u8 i; | ||
299 | |||
300 | for (i = 1; i < 32; i++) { | ||
301 | if ((from & ip_set_hostmask(i)) != from) | ||
302 | continue; | ||
303 | last = from | ~ip_set_hostmask(i); | ||
304 | if (!after(last, to)) { | ||
305 | *cidr = i; | ||
306 | return last; | ||
307 | } | ||
308 | } | ||
309 | *cidr = 32; | ||
310 | return from; | ||
311 | } | ||
312 | EXPORT_SYMBOL_GPL(ip_set_range_to_cidr); | ||