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

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>

+54 -20
+4
include/linux/netfilter/ipset/ip_set.h
··· 190 190 * If changed, new revision of iptables match/target is required. 191 191 */ 192 192 IPSET_DIM_MAX = 6, 193 + IPSET_BIT_RETURN_NOMATCH = 7, 193 194 }; 194 195 195 196 /* Option flags for kernel operations */ ··· 199 198 IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), 200 199 IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), 201 200 IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), 201 + IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH), 202 202 }; 203 203 204 204 #ifdef __KERNEL__ ··· 231 229 IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), 232 230 IPSET_TYPE_IFACE_FLAG = 5, 233 231 IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG), 232 + IPSET_TYPE_NOMATCH_FLAG = 6, 233 + IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG), 234 234 /* Strictly speaking not a feature, but a flag for dumping: 235 235 * this settype must be dumped last */ 236 236 IPSET_DUMP_LAST_FLAG = 7,
+6
net/netfilter/ipset/ip_set_core.c
··· 370 370 set->variant->kadt(set, skb, par, IPSET_ADD, opt); 371 371 write_unlock_bh(&set->lock); 372 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 381 /* Convert error codes to nomatch */
+6 -5
net/netfilter/ipset/ip_set_hash_ipportnet.c
··· 104 104 dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); 105 105 } 106 106 107 - static inline bool 107 + static inline int 108 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 113 static inline void ··· 411 411 dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); 412 412 } 413 413 414 - static inline bool 414 + static inline int 415 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 420 static inline void ··· 697 697 static struct ip_set_type hash_ipportnet_type __read_mostly = { 698 698 .name = "hash:ip,port,net", 699 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 702 .dimension = IPSET_DIM_THREE, 702 703 .family = NFPROTO_UNSPEC, 703 704 .revision_min = REVISION_MIN,
+5 -5
net/netfilter/ipset/ip_set_hash_net.c
··· 90 90 dst->nomatch = flags & IPSET_FLAG_NOMATCH; 91 91 } 92 92 93 - static inline bool 93 + static inline int 94 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 99 static inline void ··· 311 311 dst->nomatch = flags & IPSET_FLAG_NOMATCH; 312 312 } 313 313 314 - static inline bool 314 + static inline int 315 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 320 static inline void ··· 536 536 static struct ip_set_type hash_net_type __read_mostly = { 537 537 .name = "hash:net", 538 538 .protocol = IPSET_PROTOCOL, 539 - .features = IPSET_TYPE_IP, 539 + .features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH, 540 540 .dimension = IPSET_DIM_ONE, 541 541 .family = NFPROTO_UNSPEC, 542 542 .revision_min = REVISION_MIN,
+6 -5
net/netfilter/ipset/ip_set_hash_netiface.c
··· 201 201 dst->nomatch = flags & IPSET_FLAG_NOMATCH; 202 202 } 203 203 204 - static inline bool 204 + static inline int 205 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 210 static inline void ··· 497 497 dst->nomatch = flags & IPSET_FLAG_NOMATCH; 498 498 } 499 499 500 - static inline bool 500 + static inline int 501 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 506 static inline void ··· 774 774 static struct ip_set_type hash_netiface_type __read_mostly = { 775 775 .name = "hash:net,iface", 776 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 779 .dimension = IPSET_DIM_TWO, 779 780 .family = NFPROTO_UNSPEC, 780 781 .revision_min = REVISION_MIN,
+5 -5
net/netfilter/ipset/ip_set_hash_netport.c
··· 104 104 dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); 105 105 } 106 106 107 - static inline bool 107 + static inline int 108 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 113 static inline void ··· 375 375 dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); 376 376 } 377 377 378 - static inline bool 378 + static inline int 379 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 384 static inline void ··· 650 650 static struct ip_set_type hash_netport_type __read_mostly = { 651 651 .name = "hash:net,port", 652 652 .protocol = IPSET_PROTOCOL, 653 - .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, 653 + .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH, 654 654 .dimension = IPSET_DIM_TWO, 655 655 .family = NFPROTO_UNSPEC, 656 656 .revision_min = REVISION_MIN,
+22
net/netfilter/xt_set.c
··· 356 356 .destroy = set_match_v1_destroy, 357 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 382 static struct xt_target set_targets[] __read_mostly = { ··· 410 389 .destroy = set_target_v1_destroy, 411 390 .me = THIS_MODULE 412 391 }, 392 + /* --timeout and --exist flags support */ 413 393 { 414 394 .name = "SET", 415 395 .revision = 2,