aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-06-16 12:52:41 -0400
committerPatrick McHardy <kaber@trash.net>2011-06-16 12:52:41 -0400
commitd0d9e0a5a8db05b2179c2ffb25d1c2850cce3c8e (patch)
tree16be0164e378226c7603838ded9bcf3fd4041692 /net/netfilter
parentf1e00b39797944bf25addaf543839feeb25fbdc5 (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.c69
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c51
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c69
-rw-r--r--net/netfilter/ipset/pfxlen.c21
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
151static int 152static 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
129hash_net4_data_next(struct ip_set_hash *h, 129hash_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
134static int 135static 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
193static bool 219static 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
141hash_netport4_data_next(struct ip_set_hash *h, 141hash_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};
291EXPORT_SYMBOL_GPL(ip_set_hostmask_map); 291EXPORT_SYMBOL_GPL(ip_set_hostmask_map);
292
293/* Find the largest network which matches the range from left, in host order. */
294u32
295ip_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}
312EXPORT_SYMBOL_GPL(ip_set_range_to_cidr);