Re: How to port "-m multiport ! --sports 80,443" to nftables?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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, &regs->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(&regs->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.



[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux