Mikhail Morfikov <mmorfikov@xxxxxxxxx> wrote: > I have the following iptables rule that I want to convert to a nftables rule: > > $ipt -A peerblock -p tcp -m multiport ! --dports 80,443 -m set --match-set some_set dst -j DROP > > This rule won't block the 80 and 443 ports no matter what kind > of IP addresses are in the set. All other packets that are > destined to the IPs from the set (no matter what port) will be > dropped. > > I thought I would create a similar rule in nftables, but > according to the "quick reference" page, I have only the > following options: > > tcp dport 22 > tcp dport != 33-45 > tcp dport { 33-55 } > tcp dport {telnet, http, https } > tcp dport vmap { 22 : accept, 23 : drop } > tcp dport vmap { 25:accept, 28:drop } > > There's no != 80,443 or != 80, != 443 or { !80, !433 } There is tcp dport != { 80, 443 } should work just fine and match when dport is not in the anonymous set. Check out iptables-translate tool, it can help if you are familiar with iptables. > add rule ip raw-set peerblock ip daddr @some_set tcp dport vmap { 80:accept, 443:accept } counter drop > > Which in mind would be: allow 80 and 443, and block the rest. > But that actually doesn't work, I mean it doesn't block the rest. > > Also, does "counter" work with vmap because I see "0" all the time? Right, it doesn't work because in case no result is found 'lookup expression' sets 'break' in the verdict register. Pablo/others, I would propose following change, which i think is backwards compatible: +++ b/net/netfilter/nft_lookup.c @@ -37,15 +37,19 @@ void nft_lookup_eval(const struct nft_expr *expr, found = set->ops->lookup(nft_net(pkt), set, ®s->data[priv->sreg], &ext) ^ priv->invert; - if (!found) { - regs->verdict.code = NFT_BREAK; - return; - } - if (set->flags & NFT_SET_MAP) + if (set->flags & NFT_SET_MAP) { + if (!found) { + if (priv->dreg != NFT_REG_VERDICT) + regs->verdict.code = NFT_BREAK; + return; + } + nft_data_copy(®s->data[priv->dreg], nft_set_ext_data(ext), set->dlen); - + } else if (!found) { + regs->verdict.code = NFT_BREAK; + } } This makes following rule work: tcp dport vmap { 80:accept, 443:accept } counter drop (if 80/443, we leave via nft_data_copy, so evaluation of ruleset terminates with verdict, if no result, we do not set NFT_BREAK anymore, so we continue to evaluate remaining expressions (counter, drop). With jumps to user defined chains this scheme should work as well, as we would continue after the rule if we had a match. If the set doesn't contain verdicts (but e.g. nfmarks), then priv->dreg can't be NFT_REG_VERDICT. If you agree, I will make a formal submission.