]> granicus.if.org Git - ipset/commitdiff
Support to match elements marked with "nomatch" in hash:*net* sets
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 21 Sep 2012 19:03:24 +0000 (21:03 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 21 Sep 2012 19:03:24 +0000 (21:03 +0200)
Exceptions can now be matched and we can branch according to the
possible cases:

a. match in the set if the element is not flagged as "nomatch"
b. match in the set if the element is flagged with "nomatch"
c. no match

i.e.

iptables ... -m set --match-set ... -j ...
iptables ... -m set --match-set ... --nomatch-entries -j ...
...

include/libipset/linux_ip_set.h
kernel/include/linux/netfilter/ipset/ip_set.h
kernel/net/netfilter/ipset/ip_set_core.c
kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
kernel/net/netfilter/ipset/ip_set_hash_net.c
kernel/net/netfilter/ipset/ip_set_hash_netiface.c
kernel/net/netfilter/ipset/ip_set_hash_netport.c
kernel/net/netfilter/xt_set.c
tests/iptables.sh
tests/match_flags.t [new file with mode: 0644]
tests/runtest.sh

index 008da06a590eea076a10644e0fcf0a307bf613d4..d3267a47f6f8d77dee2869ee8bc7774bca911c04 100644 (file)
@@ -190,6 +190,7 @@ enum ip_set_dim {
         * If changed, new revision of iptables match/target is required.
         */
        IPSET_DIM_MAX = 6,
+       IPSET_BIT_RETURN_NOMATCH = 7,
 };
 
 /* Option flags for kernel operations */
@@ -198,6 +199,7 @@ enum ip_set_kopt {
        IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
        IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
        IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
+       IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
 };
 
 #endif /* __IP_SET_H */
index e6bfe3bf1c2e6488e9f383c1a39541cdd6e61588..81d9213df48e5f4d4b383227ea0fc0731797da31 100644 (file)
@@ -190,6 +190,7 @@ enum ip_set_dim {
         * If changed, new revision of iptables match/target is required.
         */
        IPSET_DIM_MAX = 6,
+       IPSET_BIT_RETURN_NOMATCH = 7,
 };
 
 /* Option flags for kernel operations */
@@ -198,6 +199,7 @@ enum ip_set_kopt {
        IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
        IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
        IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
+       IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
 };
 
 #ifdef __KERNEL__
@@ -229,6 +231,8 @@ enum ip_set_feature {
        IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
        IPSET_TYPE_IFACE_FLAG = 5,
        IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
+       IPSET_TYPE_NOMATCH_FLAG = 6,
+       IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG),
        /* Strictly speaking not a feature, but a flag for dumping:
         * this settype must be dumped last */
        IPSET_DUMP_LAST_FLAG = 7,
index 57dc1bd4c6cec24a067e8558c3c78005242cdb3b..535e635407a8a28ae974c9c560df0439c32d750b 100644 (file)
@@ -378,6 +378,12 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
                set->variant->kadt(set, skb, par, IPSET_ADD, opt);
                write_unlock_bh(&set->lock);
                ret = 1;
+       } else {
+               /* --return-nomatch: invert matched element */
+               if ((opt->flags & IPSET_RETURN_NOMATCH) &&
+                   (set->type->features & IPSET_TYPE_NOMATCH) &&
+                   (ret > 0 || ret == -ENOTEMPTY))
+                       ret = -ret;
        }
 
        /* Convert error codes to nomatch */
index 8ee916875a238edde0b457208b7c93eee8ac0bb4..cb71f9a774e7d50d67998aaaadc199a563f43f40 100644 (file)
@@ -104,10 +104,10 @@ hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
-static inline bool
+static inline int
 hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -411,10 +411,10 @@ hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
-static inline bool
+static inline int
 hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -697,7 +697,8 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 static struct ip_set_type hash_ipportnet_type __read_mostly = {
        .name           = "hash:ip,port,net",
        .protocol       = IPSET_PROTOCOL,
-       .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 |
+                         IPSET_TYPE_NOMATCH,
        .dimension      = IPSET_DIM_THREE,
        .family         = NFPROTO_UNSPEC,
        .revision_min   = REVISION_MIN,
index 014ff7272f7b58f027a7d02bb9ab0d9199b3628a..29e94b981f3f3fe4853a9683a1cbecdfc9d7ec42 100644 (file)
@@ -90,10 +90,10 @@ hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags)
        dst->nomatch = flags & IPSET_FLAG_NOMATCH;
 }
 
-static inline bool
+static inline int
 hash_net4_data_match(const struct hash_net4_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -311,10 +311,10 @@ hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags)
        dst->nomatch = flags & IPSET_FLAG_NOMATCH;
 }
 
-static inline bool
+static inline int
 hash_net6_data_match(const struct hash_net6_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -536,7 +536,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 static struct ip_set_type hash_net_type __read_mostly = {
        .name           = "hash:net",
        .protocol       = IPSET_PROTOCOL,
-       .features       = IPSET_TYPE_IP,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
        .dimension      = IPSET_DIM_ONE,
        .family         = NFPROTO_UNSPEC,
        .revision_min   = REVISION_MIN,
index a5c8491d265e6b92fd3ec868291b015741f08a95..b9a63381e34998e08ab5271f7d82cca9058a76d8 100644 (file)
@@ -201,10 +201,10 @@ hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags)
        dst->nomatch = flags & IPSET_FLAG_NOMATCH;
 }
 
-static inline bool
+static inline int
 hash_netiface4_data_match(const struct hash_netiface4_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -497,10 +497,10 @@ hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags)
        dst->nomatch = flags & IPSET_FLAG_NOMATCH;
 }
 
-static inline bool
+static inline int
 hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -774,7 +774,8 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 static struct ip_set_type hash_netiface_type __read_mostly = {
        .name           = "hash:net,iface",
        .protocol       = IPSET_PROTOCOL,
-       .features       = IPSET_TYPE_IP | IPSET_TYPE_IFACE,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_IFACE |
+                         IPSET_TYPE_NOMATCH,
        .dimension      = IPSET_DIM_TWO,
        .family         = NFPROTO_UNSPEC,
        .revision_min   = REVISION_MIN,
index 7ca357a62b1c650e2745ae8b5713bf38708b1b7f..7ef700de596c54d09f8873a4498da207bfd5a828 100644 (file)
@@ -104,10 +104,10 @@ hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
-static inline bool
+static inline int
 hash_netport4_data_match(const struct hash_netport4_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -375,10 +375,10 @@ hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
-static inline bool
+static inline int
 hash_netport6_data_match(const struct hash_netport6_elem *elem)
 {
-       return !elem->nomatch;
+       return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
 static inline void
@@ -650,7 +650,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 static struct ip_set_type hash_netport_type __read_mostly = {
        .name           = "hash:net,port",
        .protocol       = IPSET_PROTOCOL,
-       .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH,
        .dimension      = IPSET_DIM_TWO,
        .family         = NFPROTO_UNSPEC,
        .revision_min   = REVISION_MIN,
index c6f7db720d84f4650e975a952054c04d15868fc3..865a9e54f3ad85477e8b3d5dc481f1ea444fe978 100644 (file)
@@ -356,6 +356,27 @@ static struct xt_match set_matches[] __read_mostly = {
                .destroy        = set_match_v1_destroy,
                .me             = THIS_MODULE
        },
+       /* --return-nomatch flag support */
+       {
+               .name           = "set",
+               .family         = NFPROTO_IPV4,
+               .revision       = 2,
+               .match          = set_match_v1,
+               .matchsize      = sizeof(struct xt_set_info_match_v1),
+               .checkentry     = set_match_v1_checkentry,
+               .destroy        = set_match_v1_destroy,
+               .me             = THIS_MODULE
+       },
+       {
+               .name           = "set",
+               .family         = NFPROTO_IPV6,
+               .revision       = 2,
+               .match          = set_match_v1,
+               .matchsize      = sizeof(struct xt_set_info_match_v1),
+               .checkentry     = set_match_v1_checkentry,
+               .destroy        = set_match_v1_destroy,
+               .me             = THIS_MODULE
+       },
 };
 
 static struct xt_target set_targets[] __read_mostly = {
@@ -389,6 +410,7 @@ static struct xt_target set_targets[] __read_mostly = {
                .destroy        = set_target_v1_destroy,
                .me             = THIS_MODULE
        },
+       /* --timeout and --exist flags support */
        {
                .name           = "SET",
                .revision       = 2,
index 9b1c90c1d182dea6554b322eb4157776c2ec018f..63b0b920a8bb91463ad9bff9efcc7d8c4d80a217 100755 (executable)
@@ -59,6 +59,35 @@ start)
                      -j LOG --log-prefix "in set list: "
        $cmd -A OUTPUT -d $NET -j DROP
        cat /dev/null > .foo.err
+       cat /dev/null > /var/log/kern.log
+       ;;
+start_flags)
+       ../src/ipset n test hash:net $family 2>/dev/null
+       ../src/ipset a test 10.0.0.0/16 2>/dev/null
+       ../src/ipset a test 10.0.0.0/24 nomatch 2>/dev/null
+       ../src/ipset a test 10.0.0.1 2>/dev/null
+       $cmd -A INPUT ! -s 10.0.0.0/16 -j ACCEPT
+       $cmd -A INPUT -m set --match-set test src \
+                     -j LOG --log-prefix "in set test: "
+       $cmd -A INPUT -m set --match-set test src --return-nomatch \
+                     -j LOG --log-prefix "in set test-nomatch: "
+       $cmd -A INPUT -s 10.0.0.0/16 -j DROP
+       cat /dev/null > .foo.err
+       cat /dev/null > /var/log/kern.log
+       ;;
+start_flags_reversed)
+       ../src/ipset n test hash:net $family 2>/dev/null
+       ../src/ipset a test 10.0.0.0/16 2>/dev/null
+       ../src/ipset a test 10.0.0.0/24 nomatch 2>/dev/null
+       ../src/ipset a test 10.0.0.1 2>/dev/null
+       $cmd -A INPUT ! -s 10.0.0.0/16 -j ACCEPT
+       $cmd -A INPUT -m set --match-set test src --return-nomatch \
+                     -j LOG --log-prefix "in set test-nomatch: "
+       $cmd -A INPUT -m set --match-set test src \
+                     -j LOG --log-prefix "in set test: "
+       $cmd -A INPUT -s 10.0.0.0/16 -j DROP
+       cat /dev/null > .foo.err
+       cat /dev/null > /var/log/kern.log
        ;;
 del)
        $cmd -F INPUT
diff --git a/tests/match_flags.t b/tests/match_flags.t
new file mode 100644 (file)
index 0000000..8cede10
--- /dev/null
@@ -0,0 +1,49 @@
+# Create sets and inet rules which call set match
+0 ./iptables.sh inet start_flags
+# Send probe packet from 10.0.0.0,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.0.0 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched with --return-nomatch
+0 ./check_klog.sh 10.0.0.0 tcp 1025 test-nomatch
+# Send probe packet from 10.0.0.1,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.0.1 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched
+0 ./check_klog.sh 10.0.0.1 tcp 1025 test
+# Send probe packet from 10.0.0.2,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.2 -is 10.0.0.2 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched with --return-nomatch
+0 ./check_klog.sh 10.0.0.2 tcp 1025 test-nomatch
+# Send probe packet from 10.0.0.255,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.0.255 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched with --return-nomatch
+0 ./check_klog.sh 10.0.0.255 tcp 1025 test-nomatch
+# Send probe packet from 10.0.1.0,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.1.0 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched
+0 ./check_klog.sh 10.0.1.0 tcp 1025 test
+# Destroy sets and rules
+0 ./iptables.sh inet stop
+# Create sets and inet rules which call set match, reversed rule order
+0 ./iptables.sh inet start_flags_reversed
+# Send probe packet from 10.0.0.0,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.0.0 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched with --return-nomatch
+0 ./check_klog.sh 10.0.0.0 tcp 1025 test-nomatch
+# Send probe packet from 10.0.0.1,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.0.1 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched
+0 ./check_klog.sh 10.0.0.1 tcp 1025 test
+# Send probe packet from 10.0.0.2,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.2 -is 10.0.0.2 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched with --return-nomatch
+0 ./check_klog.sh 10.0.0.2 tcp 1025 test-nomatch
+# Send probe packet from 10.0.0.255,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.0.255 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched with --return-nomatch
+0 ./check_klog.sh 10.0.0.255 tcp 1025 test-nomatch
+# Send probe packet from 10.0.1.0,tcp:1025
+0 sendip -p ipv4 -id 127.0.0.1 -is 10.0.1.0 -p tcp -td 80 -ts 1025 127.0.0.1
+# Check that test set matched
+0 ./check_klog.sh 10.0.1.0 tcp 1025 test
+# Destroy sets and rules
+0 ./iptables.sh inet stop
+# eof
index ff5c492852cb40ffa8146613e4c43ebea8fe54a1..ad2ac4221404b1d85e07589ad40bbb161be10b6a 100755 (executable)
@@ -22,7 +22,7 @@ add_tests() {
        # inet|inet6 network
        if [ $1 = "inet" ]; then
                cmd=iptables-save
-               add=match_target
+               add="match_target match_flags"
        else
                cmd=ip6tables-save
                add=match_target6