Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: ipset: netnet,netportnet: Fix value range support for IPv4

Ranges of values are broken with hash:net,net and hash:net,port,net.

hash:net,net
============

# ipset create test-nn hash:net,net
# ipset add test-nn 10.0.10.1-10.0.10.127,10.0.0.0/8

# ipset list test-nn
Name: test-nn
Type: hash:net,net
Revision: 0
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16960
References: 0
Members:
10.0.10.1,10.0.0.0/8

# ipset test test-nn 10.0.10.65,10.0.0.1
10.0.10.65,10.0.0.1 is NOT in set test-nn.
# ipset test test-nn 10.0.10.1,10.0.0.1
10.0.10.1,10.0.0.1 is in set test-nn.

hash:net,port,net
=================

# ipset create test-npn hash:net,port,net
# ipset add test-npn 10.0.10.1-10.0.10.127,tcp:80,10.0.0.0/8
# ipset list test-npn
Name: test-npn
Type: hash:net,port,net
Revision: 0
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 17344
References: 0
Members:
10.0.10.8/29,tcp:80,10.0.0.0
10.0.10.16/28,tcp:80,10.0.0.0
10.0.10.2/31,tcp:80,10.0.0.0
10.0.10.64/26,tcp:80,10.0.0.0
10.0.10.32/27,tcp:80,10.0.0.0
10.0.10.4/30,tcp:80,10.0.0.0
10.0.10.1,tcp:80,10.0.0.0
# ipset list test-npn
# ipset test test-npn 10.0.10.126,tcp:80,10.0.0.2
10.0.10.126,tcp:80,10.0.0.2 is NOT in set test-npn.
# ipset test test-npn 10.0.10.126,tcp:80,10.0.0.0
10.0.10.126,tcp:80,10.0.0.0 is in set test-npn.

# ipset create test-npn hash:net,port,net
# ipset add test-npn 10.0.10.0/24,tcp:80-81,10.0.0.0/8
# ipset list test-npn
Name: test-npn
Type: hash:net,port,net
Revision: 0
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 17024
References: 0
Members:
10.0.10.0,tcp:80,10.0.0.0
10.0.10.0,tcp:81,10.0.0.0
# ipset test test-npn 10.0.10.126,tcp:80,10.0.0.0
10.0.10.126,tcp:80,10.0.0.0 is NOT in set test-npn.
# ipset test test-npn 10.0.10.0,tcp:80,10.0.0.0
10.0.10.0,tcp:80,10.0.0.0 is in set test-npn.

Correctly setup from..to variables where no IPSET_ATTR_IP_TO{,2}
attribute is given, so in range processing loop we construct proper
cidr value. Check whenever we have no ranges and can short cut in
hash:net,net properly. Use unlikely() where appropriate, to comply
with other modules.

Signed-off-by: Sergey Popovich <popovich_sergei@mail.ru>
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

authored by

Sergey Popovich and committed by
Jozsef Kadlecsik
6e41ee68 ecc245c2

+11 -8
+7 -6
net/netfilter/ipset/ip_set_hash_netnet.c
··· 203 203 flags |= (IPSET_FLAG_NOMATCH << 16); 204 204 } 205 205 206 - if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] && 206 + if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] || 207 207 tb[IPSET_ATTR_IP2_TO])) { 208 208 e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); 209 209 e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); ··· 219 219 return ret; 220 220 if (ip_to < ip) 221 221 swap(ip, ip_to); 222 - if (ip + UINT_MAX == ip_to) 222 + if (unlikely(ip + UINT_MAX == ip_to)) 223 223 return -IPSET_ERR_HASH_RANGE; 224 - } 224 + } else 225 + ip_set_mask_from_to(ip, ip_to, e.cidr[0]); 225 226 226 227 ip2_to = ip2_from; 227 228 if (tb[IPSET_ATTR_IP2_TO]) { ··· 231 230 return ret; 232 231 if (ip2_to < ip2_from) 233 232 swap(ip2_from, ip2_to); 234 - if (ip2_from + UINT_MAX == ip2_to) 233 + if (unlikely(ip2_from + UINT_MAX == ip2_to)) 235 234 return -IPSET_ERR_HASH_RANGE; 236 - 237 - } 235 + } else 236 + ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); 238 237 239 238 if (retried) 240 239 ip = ntohl(h->next.ip[0]);
+4 -2
net/netfilter/ipset/ip_set_hash_netportnet.c
··· 257 257 swap(ip, ip_to); 258 258 if (unlikely(ip + UINT_MAX == ip_to)) 259 259 return -IPSET_ERR_HASH_RANGE; 260 - } 260 + } else 261 + ip_set_mask_from_to(ip, ip_to, e.cidr[0]); 261 262 262 263 port_to = port = ntohs(e.port); 263 264 if (tb[IPSET_ATTR_PORT_TO]) { ··· 276 275 swap(ip2_from, ip2_to); 277 276 if (unlikely(ip2_from + UINT_MAX == ip2_to)) 278 277 return -IPSET_ERR_HASH_RANGE; 279 - } 278 + } else 279 + ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); 280 280 281 281 if (retried) 282 282 ip = ntohl(h->next.ip[0]);