== Multiple set matches with Linux's iptables 'ipset' extension Recently, [[Luke Atchew https://twitter.com/ayotayo]] approached me on Twitter to ask if I had any ideas for solving an ipset challenge. Suppose that you have a set of origin hosts, a set of destination servers, and you want to allow traffic from the origin hosts to the destination servers while blocking all other traffic. As Luke noted, most ipset examples, [[including mine IptablesIpsetNotes]], are about blocking access to or from a set of hosts; they don't have a matrix setup like Luke's. One obvious option is a complex multi-rule setup, where you have a series of rules that try to block and accept more and more of the traffic that you want; for example, you can start out by blocking all traffic to '_! -match-set Destinations dst_'. This gets complex if you have other rules involved, though. Another option is one of ipset's more complicated set types, such as _hash:net,net_, but then you get into hassles populating and maintaining the set (since it's basically the cross product of your allowed source and destination hosts). As Luke Atchew discovered while working on this, all of this complexity is unnecessary because ~~you can match against multiple ipset sets in the same iptables rule~~. It is perfectly legitimate to write rules like: .pn prewrap on > iptables -A FORWARD -m set --match-set Locals src -m set --match-set Remotes dst -j ACCEPT > iptables -A FORWARD -m set ! --match-set Locals src -m set --match-set Remotes dst -j DROP (These rules use different keys, here the source and destination IPs, but it's probably legitimate to have several _--match-set_'s that reuse the same key. You might need a source IP to be in an 'allowed' set and not in a 'temporarily blocked' set, for example.) An important note here is that you absolutely have to use two '_-m set_' arguments, one before each _--match-set_. If you leave the second one out you will get the somewhat obscure error message '_iptables v1.4.21: --match-set can be specified only once_', which may mislead you into believing that this isn't supported at all. This is a really easy mistake to make because it sure smells like the second _-m set_ is surplus; after all, you already told _iptables_ you wanted to use the ipset extension here. (I assume that the second '_-m set_' is causing the parser to start setting up a new internal ipset matching operation instead of accumulating more options for the first one.)