netfilter: ipset: Consistent userspace testing with nomatch flag
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 16 Sep 2013 18:04:53 +0000 (20:04 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 16 Sep 2013 18:35:55 +0000 (20:35 +0200)
The "nomatch" commandline flag should invert the matching at testing,
similarly to the --return-nomatch flag of the "set" match of iptables.
Until now it worked with the elements with "nomatch" flag only. From
now on it works with elements without the flag too, i.e:

 # ipset n test hash:net
 # ipset a test 10.0.0.0/24 nomatch
 # ipset t test 10.0.0.1
 10.0.0.1 is NOT in set test.
 # ipset t test 10.0.0.1 nomatch
 10.0.0.1 is in set test.

 # ipset a test 192.168.0.0/24
 # ipset t test 192.168.0.1
 192.168.0.1 is in set test.
 # ipset t test 192.168.0.1 nomatch
 192.168.0.1 is NOT in set test.

 Before the patch the results were

 ...
 # ipset t test 192.168.0.1
 192.168.0.1 is in set test.
 # ipset t test 192.168.0.1 nomatch
 192.168.0.1 is in set test.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
include/linux/netfilter/ipset/ip_set.h
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipset/ip_set_hash_netport.c

index d80e2753847ce40d23e174e0b9fa623249bb4f28..9ac9fbde7b61a38795d631ab545b9bd3140fe6f6 100644 (file)
@@ -296,10 +296,12 @@ ip_set_eexist(int ret, u32 flags)
 
 /* Match elements marked with nomatch */
 static inline bool
-ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt)
+ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt, struct ip_set *set)
 {
        return adt == IPSET_TEST &&
-              ret == -ENOTEMPTY && ((flags >> 16) & IPSET_FLAG_NOMATCH);
+              (set->type->features & IPSET_TYPE_NOMATCH) &&
+              ((flags >> 16) & IPSET_FLAG_NOMATCH) &&
+              (ret > 0 || ret == -ENOTEMPTY);
 }
 
 /* Check the NLA_F_NET_BYTEORDER flag */
index f7713900798308557c134b00e9db3975e3697ecb..c8c303c3386fbca9aaf1c5e4aa94f5985da05bab 100644 (file)
@@ -1489,8 +1489,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
        if (ret == -EAGAIN)
                ret = 1;
 
-       return (ret < 0 && ret != -ENOTEMPTY) ? ret :
-               ret > 0 ? 0 : -IPSET_ERR_EXIST;
+       return ret > 0 ? 0 : -IPSET_ERR_EXIST;
 }
 
 /* Get headed data of a set */
index c6a525373be4e24bb4de1d056095c5edfe3919c2..f15f3e28b9c338c6e72d3aa949d9d241c0e7cabe 100644 (file)
@@ -260,7 +260,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                e.ip = htonl(ip);
                e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -544,7 +544,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
index da740ceb56aefc8db240d83d74daf68a631ec975..223e9f546d0fa3e414b7a53a839b56d6835093bb 100644 (file)
@@ -199,7 +199,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
                e.ip = htonl(ip & ip_set_hostmask(e.cidr));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret:
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -396,7 +396,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        ret = adtfn(set, &e, &ext, &ext, flags);
 
-       return ip_set_enomatch(ret, flags, adt) ? 1 :
+       return ip_set_enomatch(ret, flags, adt, set) ? -ret :
               ip_set_eexist(ret, flags) ? 0 : ret;
 }
 
index 84ae6f6ce624665f9d2cc27c07efe9033412f132..7d798d5d5cd30a66de3d6fade0b4110eeba583f7 100644 (file)
@@ -368,7 +368,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
                e.ip = htonl(ip & ip_set_hostmask(e.cidr));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -634,7 +634,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        ret = adtfn(set, &e, &ext, &ext, flags);
 
-       return ip_set_enomatch(ret, flags, adt) ? 1 :
+       return ip_set_enomatch(ret, flags, adt, set) ? -ret :
               ip_set_eexist(ret, flags) ? 0 : ret;
 }
 
index 9a0869853be565ca09a7e6c54c9cd205229dd3bf..09d6690bee6fd33891c4a00bbbb909f2bbf7731b 100644 (file)
@@ -244,7 +244,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
                e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -489,7 +489,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }