diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2012-09-21 16:02:36 -0400 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2012-09-22 16:44:34 -0400 |
commit | 3e0304a583d72c747caa8afac76b8d514aa293f5 (patch) | |
tree | 134fd8cc48ed72be16a7ca2f90b169de103bec2e | |
parent | 3ace95c0ac125a042cfb682d0a9bbdbf1e5a2c65 (diff) |
netfilter: ipset: Support to match elements marked with "nomatch"
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 ...
...
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
-rw-r--r-- | include/linux/netfilter/ipset/ip_set.h | 4 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportnet.c | 11 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_net.c | 10 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netiface.c | 11 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netport.c | 10 | ||||
-rw-r--r-- | net/netfilter/xt_set.c | 22 |
7 files changed, 54 insertions, 20 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 0c1e97b3acfb..528697b3c152 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h | |||
@@ -190,6 +190,7 @@ enum ip_set_dim { | |||
190 | * If changed, new revision of iptables match/target is required. | 190 | * If changed, new revision of iptables match/target is required. |
191 | */ | 191 | */ |
192 | IPSET_DIM_MAX = 6, | 192 | IPSET_DIM_MAX = 6, |
193 | IPSET_BIT_RETURN_NOMATCH = 7, | ||
193 | }; | 194 | }; |
194 | 195 | ||
195 | /* Option flags for kernel operations */ | 196 | /* Option flags for kernel operations */ |
@@ -198,6 +199,7 @@ enum ip_set_kopt { | |||
198 | IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), | 199 | IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), |
199 | IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), | 200 | IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), |
200 | IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), | 201 | IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), |
202 | IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH), | ||
201 | }; | 203 | }; |
202 | 204 | ||
203 | #ifdef __KERNEL__ | 205 | #ifdef __KERNEL__ |
@@ -229,6 +231,8 @@ enum ip_set_feature { | |||
229 | IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), | 231 | IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), |
230 | IPSET_TYPE_IFACE_FLAG = 5, | 232 | IPSET_TYPE_IFACE_FLAG = 5, |
231 | IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG), | 233 | IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG), |
234 | IPSET_TYPE_NOMATCH_FLAG = 6, | ||
235 | IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG), | ||
232 | /* Strictly speaking not a feature, but a flag for dumping: | 236 | /* Strictly speaking not a feature, but a flag for dumping: |
233 | * this settype must be dumped last */ | 237 | * this settype must be dumped last */ |
234 | IPSET_DUMP_LAST_FLAG = 7, | 238 | IPSET_DUMP_LAST_FLAG = 7, |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 72e9bf0ef90d..778465f217fa 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -370,6 +370,12 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, | |||
370 | set->variant->kadt(set, skb, par, IPSET_ADD, opt); | 370 | set->variant->kadt(set, skb, par, IPSET_ADD, opt); |
371 | write_unlock_bh(&set->lock); | 371 | write_unlock_bh(&set->lock); |
372 | ret = 1; | 372 | ret = 1; |
373 | } else { | ||
374 | /* --return-nomatch: invert matched element */ | ||
375 | if ((opt->flags & IPSET_RETURN_NOMATCH) && | ||
376 | (set->type->features & IPSET_TYPE_NOMATCH) && | ||
377 | (ret > 0 || ret == -ENOTEMPTY)) | ||
378 | ret = -ret; | ||
373 | } | 379 | } |
374 | 380 | ||
375 | /* Convert error codes to nomatch */ | 381 | /* Convert error codes to nomatch */ |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 8ee916875a23..cb71f9a774e7 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
@@ -104,10 +104,10 @@ hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags) | |||
104 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | 104 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline bool | 107 | static inline int |
108 | hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem) | 108 | hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem) |
109 | { | 109 | { |
110 | return !elem->nomatch; | 110 | return elem->nomatch ? -ENOTEMPTY : 1; |
111 | } | 111 | } |
112 | 112 | ||
113 | static inline void | 113 | static inline void |
@@ -411,10 +411,10 @@ hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags) | |||
411 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | 411 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); |
412 | } | 412 | } |
413 | 413 | ||
414 | static inline bool | 414 | static inline int |
415 | hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem) | 415 | hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem) |
416 | { | 416 | { |
417 | return !elem->nomatch; | 417 | return elem->nomatch ? -ENOTEMPTY : 1; |
418 | } | 418 | } |
419 | 419 | ||
420 | static inline void | 420 | static inline void |
@@ -697,7 +697,8 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
697 | static struct ip_set_type hash_ipportnet_type __read_mostly = { | 697 | static struct ip_set_type hash_ipportnet_type __read_mostly = { |
698 | .name = "hash:ip,port,net", | 698 | .name = "hash:ip,port,net", |
699 | .protocol = IPSET_PROTOCOL, | 699 | .protocol = IPSET_PROTOCOL, |
700 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, | 700 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 | |
701 | IPSET_TYPE_NOMATCH, | ||
701 | .dimension = IPSET_DIM_THREE, | 702 | .dimension = IPSET_DIM_THREE, |
702 | .family = NFPROTO_UNSPEC, | 703 | .family = NFPROTO_UNSPEC, |
703 | .revision_min = REVISION_MIN, | 704 | .revision_min = REVISION_MIN, |
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 014ff7272f7b..29e94b981f3f 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
@@ -90,10 +90,10 @@ hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags) | |||
90 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | 90 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; |
91 | } | 91 | } |
92 | 92 | ||
93 | static inline bool | 93 | static inline int |
94 | hash_net4_data_match(const struct hash_net4_elem *elem) | 94 | hash_net4_data_match(const struct hash_net4_elem *elem) |
95 | { | 95 | { |
96 | return !elem->nomatch; | 96 | return elem->nomatch ? -ENOTEMPTY : 1; |
97 | } | 97 | } |
98 | 98 | ||
99 | static inline void | 99 | static inline void |
@@ -311,10 +311,10 @@ hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags) | |||
311 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | 311 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; |
312 | } | 312 | } |
313 | 313 | ||
314 | static inline bool | 314 | static inline int |
315 | hash_net6_data_match(const struct hash_net6_elem *elem) | 315 | hash_net6_data_match(const struct hash_net6_elem *elem) |
316 | { | 316 | { |
317 | return !elem->nomatch; | 317 | return elem->nomatch ? -ENOTEMPTY : 1; |
318 | } | 318 | } |
319 | 319 | ||
320 | static inline void | 320 | static inline void |
@@ -536,7 +536,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
536 | static struct ip_set_type hash_net_type __read_mostly = { | 536 | static struct ip_set_type hash_net_type __read_mostly = { |
537 | .name = "hash:net", | 537 | .name = "hash:net", |
538 | .protocol = IPSET_PROTOCOL, | 538 | .protocol = IPSET_PROTOCOL, |
539 | .features = IPSET_TYPE_IP, | 539 | .features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH, |
540 | .dimension = IPSET_DIM_ONE, | 540 | .dimension = IPSET_DIM_ONE, |
541 | .family = NFPROTO_UNSPEC, | 541 | .family = NFPROTO_UNSPEC, |
542 | .revision_min = REVISION_MIN, | 542 | .revision_min = REVISION_MIN, |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index a5c8491d265e..b9a63381e349 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
@@ -201,10 +201,10 @@ hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags) | |||
201 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | 201 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; |
202 | } | 202 | } |
203 | 203 | ||
204 | static inline bool | 204 | static inline int |
205 | hash_netiface4_data_match(const struct hash_netiface4_elem *elem) | 205 | hash_netiface4_data_match(const struct hash_netiface4_elem *elem) |
206 | { | 206 | { |
207 | return !elem->nomatch; | 207 | return elem->nomatch ? -ENOTEMPTY : 1; |
208 | } | 208 | } |
209 | 209 | ||
210 | static inline void | 210 | static inline void |
@@ -497,10 +497,10 @@ hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags) | |||
497 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | 497 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; |
498 | } | 498 | } |
499 | 499 | ||
500 | static inline bool | 500 | static inline int |
501 | hash_netiface6_data_match(const struct hash_netiface6_elem *elem) | 501 | hash_netiface6_data_match(const struct hash_netiface6_elem *elem) |
502 | { | 502 | { |
503 | return !elem->nomatch; | 503 | return elem->nomatch ? -ENOTEMPTY : 1; |
504 | } | 504 | } |
505 | 505 | ||
506 | static inline void | 506 | static inline void |
@@ -774,7 +774,8 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
774 | static struct ip_set_type hash_netiface_type __read_mostly = { | 774 | static struct ip_set_type hash_netiface_type __read_mostly = { |
775 | .name = "hash:net,iface", | 775 | .name = "hash:net,iface", |
776 | .protocol = IPSET_PROTOCOL, | 776 | .protocol = IPSET_PROTOCOL, |
777 | .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE, | 777 | .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE | |
778 | IPSET_TYPE_NOMATCH, | ||
778 | .dimension = IPSET_DIM_TWO, | 779 | .dimension = IPSET_DIM_TWO, |
779 | .family = NFPROTO_UNSPEC, | 780 | .family = NFPROTO_UNSPEC, |
780 | .revision_min = REVISION_MIN, | 781 | .revision_min = REVISION_MIN, |
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 7ca357a62b1c..7ef700de596c 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
@@ -104,10 +104,10 @@ hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags) | |||
104 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | 104 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline bool | 107 | static inline int |
108 | hash_netport4_data_match(const struct hash_netport4_elem *elem) | 108 | hash_netport4_data_match(const struct hash_netport4_elem *elem) |
109 | { | 109 | { |
110 | return !elem->nomatch; | 110 | return elem->nomatch ? -ENOTEMPTY : 1; |
111 | } | 111 | } |
112 | 112 | ||
113 | static inline void | 113 | static inline void |
@@ -375,10 +375,10 @@ hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags) | |||
375 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | 375 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); |
376 | } | 376 | } |
377 | 377 | ||
378 | static inline bool | 378 | static inline int |
379 | hash_netport6_data_match(const struct hash_netport6_elem *elem) | 379 | hash_netport6_data_match(const struct hash_netport6_elem *elem) |
380 | { | 380 | { |
381 | return !elem->nomatch; | 381 | return elem->nomatch ? -ENOTEMPTY : 1; |
382 | } | 382 | } |
383 | 383 | ||
384 | static inline void | 384 | static inline void |
@@ -650,7 +650,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
650 | static struct ip_set_type hash_netport_type __read_mostly = { | 650 | static struct ip_set_type hash_netport_type __read_mostly = { |
651 | .name = "hash:net,port", | 651 | .name = "hash:net,port", |
652 | .protocol = IPSET_PROTOCOL, | 652 | .protocol = IPSET_PROTOCOL, |
653 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, | 653 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH, |
654 | .dimension = IPSET_DIM_TWO, | 654 | .dimension = IPSET_DIM_TWO, |
655 | .family = NFPROTO_UNSPEC, | 655 | .family = NFPROTO_UNSPEC, |
656 | .revision_min = REVISION_MIN, | 656 | .revision_min = REVISION_MIN, |
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index c6f7db720d84..865a9e54f3ad 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c | |||
@@ -356,6 +356,27 @@ static struct xt_match set_matches[] __read_mostly = { | |||
356 | .destroy = set_match_v1_destroy, | 356 | .destroy = set_match_v1_destroy, |
357 | .me = THIS_MODULE | 357 | .me = THIS_MODULE |
358 | }, | 358 | }, |
359 | /* --return-nomatch flag support */ | ||
360 | { | ||
361 | .name = "set", | ||
362 | .family = NFPROTO_IPV4, | ||
363 | .revision = 2, | ||
364 | .match = set_match_v1, | ||
365 | .matchsize = sizeof(struct xt_set_info_match_v1), | ||
366 | .checkentry = set_match_v1_checkentry, | ||
367 | .destroy = set_match_v1_destroy, | ||
368 | .me = THIS_MODULE | ||
369 | }, | ||
370 | { | ||
371 | .name = "set", | ||
372 | .family = NFPROTO_IPV6, | ||
373 | .revision = 2, | ||
374 | .match = set_match_v1, | ||
375 | .matchsize = sizeof(struct xt_set_info_match_v1), | ||
376 | .checkentry = set_match_v1_checkentry, | ||
377 | .destroy = set_match_v1_destroy, | ||
378 | .me = THIS_MODULE | ||
379 | }, | ||
359 | }; | 380 | }; |
360 | 381 | ||
361 | static struct xt_target set_targets[] __read_mostly = { | 382 | static struct xt_target set_targets[] __read_mostly = { |
@@ -389,6 +410,7 @@ static struct xt_target set_targets[] __read_mostly = { | |||
389 | .destroy = set_target_v1_destroy, | 410 | .destroy = set_target_v1_destroy, |
390 | .me = THIS_MODULE | 411 | .me = THIS_MODULE |
391 | }, | 412 | }, |
413 | /* --timeout and --exist flags support */ | ||
392 | { | 414 | { |
393 | .name = "SET", | 415 | .name = "SET", |
394 | .revision = 2, | 416 | .revision = 2, |