summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2012-09-21 21:03:24 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2012-09-21 21:03:24 +0200
commit3a3794573386d0cb2930a9daad5615036c06f4e2 (patch)
tree52dc8066bff6301af9910a47f8e235336f77e8a8
parent3578220cf27c3e7017dd8af6b17c08218cf632d0 (diff)
Support to match elements marked with "nomatch" in hash:*net* sets
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 ... ...
-rw-r--r--include/libipset/linux_ip_set.h2
-rw-r--r--kernel/include/linux/netfilter/ipset/ip_set.h4
-rw-r--r--kernel/net/netfilter/ipset/ip_set_core.c6
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c11
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_net.c10
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_netiface.c11
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_netport.c10
-rw-r--r--kernel/net/netfilter/xt_set.c22
-rwxr-xr-xtests/iptables.sh29
-rw-r--r--tests/match_flags.t49
-rwxr-xr-xtests/runtest.sh2
11 files changed, 135 insertions, 21 deletions
diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h
index 008da06..d3267a4 100644
--- a/include/libipset/linux_ip_set.h
+++ b/include/libipset/linux_ip_set.h
@@ -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 */
diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h
index e6bfe3b..81d9213 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set.h
+++ b/kernel/include/linux/netfilter/ipset/ip_set.h
@@ -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,
diff --git a/kernel/net/netfilter/ipset/ip_set_core.c b/kernel/net/netfilter/ipset/ip_set_core.c
index 57dc1bd..535e635 100644
--- a/kernel/net/netfilter/ipset/ip_set_core.c
+++ b/kernel/net/netfilter/ipset/ip_set_core.c
@@ -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 */
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 8ee9168..cb71f9a 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -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,
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_net.c b/kernel/net/netfilter/ipset/ip_set_hash_net.c
index 014ff72..29e94b9 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_net.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_net.c
@@ -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,
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
index a5c8491..b9a6338 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -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,
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netport.c b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
index 7ca357a..7ef700d 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
@@ -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,
diff --git a/kernel/net/netfilter/xt_set.c b/kernel/net/netfilter/xt_set.c
index c6f7db7..865a9e5 100644
--- a/kernel/net/netfilter/xt_set.c
+++ b/kernel/net/netfilter/xt_set.c
@@ -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,
diff --git a/tests/iptables.sh b/tests/iptables.sh
index 9b1c90c..63b0b92 100755
--- a/tests/iptables.sh
+++ b/tests/iptables.sh
@@ -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
index 0000000..8cede10
--- /dev/null
+++ b/tests/match_flags.t
@@ -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
diff --git a/tests/runtest.sh b/tests/runtest.sh
index ff5c492..ad2ac42 100755
--- a/tests/runtest.sh
+++ b/tests/runtest.sh
@@ -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