]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink_delinearize: restore binop syntax when listing ruleset for flags
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 18 Mar 2024 12:10:55 +0000 (13:10 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 23 Jan 2025 00:35:35 +0000 (01:35 +0100)
commit b11b6c68e61ea294eb4c313705ccfe3e7b0eda87 upstream.

c3d57114f119 ("parser_bison: add shortcut syntax for matching flags
without binary operations") provides a similar syntax to iptables using
a prefix representation for flag matching.

Restore original representation using binop when listing the ruleset.
The parser still accepts the prefix notation for backward compatibility.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/netlink_delinearize.c
tests/py/inet/tcp.t
tests/py/inet/tcp.t.json
tests/py/inet/tcp.t.json.output
tests/py/inet/tcp.t.payload
tests/shell/testcases/nft-f/dumps/sample-ruleset.nft [new file with mode: 0644]
tests/shell/testcases/packetpath/tcp_options

index 273669a3bb3bb65e6f3f5cfa9ff0536104feac83..1726101bf211a5ec09f3e6bf1910019714ec0b41 100644 (file)
@@ -2365,56 +2365,29 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
 
        if (binop->op == OP_AND && (expr->op == OP_NEQ || expr->op == OP_EQ) &&
            right->dtype->basetype &&
-           right->dtype->basetype->type == TYPE_BITMASK) {
-               switch (right->etype) {
-               case EXPR_VALUE:
-                       if (!mpz_cmp_ui(right->value, 0)) {
-                               /* Flag comparison: data & flags != 0
-                                *
-                                * Split the flags into a list of flag values and convert the
-                                * op to OP_EQ.
-                                */
-                               expr_free(right);
-
-                               expr->left  = expr_get(binop->left);
-                               expr->right = binop_tree_to_list(NULL, binop->right);
-                               switch (expr->op) {
-                               case OP_NEQ:
-                                       expr->op = OP_IMPLICIT;
-                                       break;
-                               case OP_EQ:
-                                       expr->op = OP_NEG;
-                                       break;
-                               default:
-                                       BUG("unknown operation type %d\n", expr->op);
-                               }
-                               expr_free(binop);
-                       } else if (binop->right->etype == EXPR_VALUE &&
-                                  right->etype == EXPR_VALUE &&
-                                  !mpz_cmp(right->value, binop->right->value)) {
-                               /* Skip flag / flag representation for:
-                                * data & flag == flag
-                                * data & flag != flag
-                                */
-                               ;
-                       } else {
-                               *exprp = flagcmp_expr_alloc(&expr->location, expr->op,
-                                                           expr_get(binop->left),
-                                                           binop_tree_to_list(NULL, binop->right),
-                                                           expr_get(right));
-                               expr_free(expr);
-                       }
+           right->dtype->basetype->type == TYPE_BITMASK &&
+           right->etype == EXPR_VALUE &&
+           !mpz_cmp_ui(right->value, 0)) {
+               /* Flag comparison: data & flags != 0
+                *
+                * Split the flags into a list of flag values and convert the
+                * op to OP_EQ.
+                */
+               expr_free(right);
+
+               expr->left  = expr_get(binop->left);
+               expr->right = binop_tree_to_list(NULL, binop->right);
+               switch (expr->op) {
+               case OP_NEQ:
+                       expr->op = OP_IMPLICIT;
                        break;
-               case EXPR_BINOP:
-                       *exprp = flagcmp_expr_alloc(&expr->location, expr->op,
-                                                   expr_get(binop->left),
-                                                   binop_tree_to_list(NULL, binop->right),
-                                                   binop_tree_to_list(NULL, right));
-                       expr_free(expr);
+               case OP_EQ:
+                       expr->op = OP_NEG;
                        break;
                default:
-                       break;
+                       BUG("unknown operation type %d\n", expr->op);
                }
+               expr_free(binop);
        } else if (binop->left->dtype->flags & DTYPE_F_PREFIX &&
                   binop->op == OP_AND && expr->right->etype == EXPR_VALUE &&
                   expr_mask_is_prefix(binop->right)) {
index f51ebd36b503f0a2d37b47b4b79a4bc02859a332..f4bdac177e1a5c0aa7bc77fa0a0afb9178510078 100644 (file)
@@ -68,8 +68,8 @@ tcp flags != { fin, urg, ecn, cwr} drop;ok
 tcp flags cwr;ok
 tcp flags != cwr;ok
 tcp flags == syn;ok
-tcp flags fin,syn / fin,syn;ok
-tcp flags != syn / fin,syn;ok
+tcp flags fin,syn / fin,syn;ok;tcp flags & (fin | syn) == fin | syn
+tcp flags != syn / fin,syn;ok;tcp flags & (fin | syn) != syn
 tcp flags & syn != 0;ok;tcp flags syn
 tcp flags & syn == 0;ok;tcp flags ! syn
 tcp flags & (syn | ack) != 0;ok;tcp flags syn,ack
@@ -77,12 +77,12 @@ tcp flags & (syn | ack) == 0;ok;tcp flags ! syn,ack
 # it should be possible to transform this to: tcp flags syn
 tcp flags & syn == syn;ok
 tcp flags & syn != syn;ok
-tcp flags & (fin | syn | rst | ack) syn;ok;tcp flags syn / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) == syn;ok;tcp flags syn / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) != syn;ok;tcp flags != syn / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) == (syn | ack);ok;tcp flags syn,ack / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) != (syn | ack);ok;tcp flags != syn,ack / fin,syn,rst,ack
-tcp flags & (syn | ack) == (syn | ack);ok;tcp flags syn,ack / syn,ack
+tcp flags & (fin | syn | rst | ack) syn;ok;tcp flags & (fin | syn | rst | ack) == syn
+tcp flags & (fin | syn | rst | ack) == syn;ok
+tcp flags & (fin | syn | rst | ack) != syn;ok
+tcp flags & (fin | syn | rst | ack) == syn | ack;ok
+tcp flags & (fin | syn | rst | ack) != syn | ack;ok
+tcp flags & (syn | ack) == syn | ack;ok
 tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr;ok;tcp flags == 0xff
 tcp flags { syn, syn | ack };ok
 tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack };ok
index 8439c2b5931dd70f0a84f02b892141b6e332d0d1..d3a846cf9a4006f81e0d598bfc7cd9c091f6c428 100644 (file)
     }
 ]
 
-# tcp flags & (fin | syn | rst | ack) == (syn | ack)
+# tcp flags & (fin | syn | rst | ack) == syn | ack
 [
     {
         "match": {
     }
 ]
 
-# tcp flags & (fin | syn | rst | ack) != (syn | ack)
+# tcp flags & (syn | ack) == syn | ack
 [
     {
         "match": {
                         }
                     },
                     [
-                        "fin",
                         "syn",
-                        "rst",
                         "ack"
                     ]
                 ]
             },
-            "op": "!=",
+            "op": "==",
             "right": [
                 "syn",
                 "ack"
     }
 ]
 
-# tcp flags & (syn | ack) == (syn | ack)
+# tcp flags & (fin | syn | rst | ack) != syn | ack
 [
     {
         "match": {
                             "protocol": "tcp"
                         }
                     },
-                    [
-                        "syn",
-                        "ack"
-                    ]
+                    {
+                        "|": [
+                            {
+                                "|": [
+                                    {
+                                        "|": [
+                                            "fin",
+                                            "syn"
+                                        ]
+                                    },
+                                    "rst"
+                                ]
+                            },
+                            "ack"
+                        ]
+                    }
                 ]
             },
-            "op": "==",
-            "right": [
-                "syn",
-                "ack"
-            ]
+            "op": "!=",
+            "right": {
+                "|": [
+                    "syn",
+                    "ack"
+                ]
+            }
         }
     }
 ]
index c471e8d8dcef5f5a4cc57f7b038bb0d4f93b38fc..e186e127fd6711c4caf43b65b8fa760e21179c6e 100644 (file)
         }
     }
 ]
+
+# tcp flags fin,syn / fin,syn
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            "fin",
+                            "syn"
+                        ]
+                    }
+                ]
+            },
+            "op": "==",
+            "right": {
+                "|": [
+                    "fin",
+                    "syn"
+                ]
+            }
+        }
+    }
+]
+
+# tcp flags != syn / fin,syn
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            "fin",
+                            "syn"
+                        ]
+                    }
+                ]
+            },
+            "op": "!=",
+            "right": "syn"
+        }
+    }
+]
+
+# tcp flags & (fin | syn | rst | ack) syn
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            {
+                                "|": [
+                                    {
+                                        "|": [
+                                            "fin",
+                                            "syn"
+                                        ]
+                                    },
+                                    "rst"
+                                ]
+                            },
+                            "ack"
+                        ]
+                    }
+                ]
+            },
+            "op": "==",
+            "right": "syn"
+        }
+    }
+]
+
+# tcp flags & (fin | syn | rst | ack) == syn
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            {
+                                "|": [
+                                    {
+                                        "|": [
+                                            "fin",
+                                            "syn"
+                                        ]
+                                    },
+                                    "rst"
+                                ]
+                            },
+                            "ack"
+                        ]
+                    }
+                ]
+            },
+            "op": "==",
+            "right": "syn"
+        }
+    }
+]
+
+# tcp flags & (fin | syn | rst | ack) != syn
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            {
+                                "|": [
+                                    {
+                                        "|": [
+                                            "fin",
+                                            "syn"
+                                        ]
+                                    },
+                                    "rst"
+                                ]
+                            },
+                            "ack"
+                        ]
+                    }
+                ]
+            },
+            "op": "!=",
+            "right": "syn"
+        }
+    }
+]
+
+# tcp flags & (fin | syn | rst | ack) == syn | ack
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            {
+                                "|": [
+                                    {
+                                        "|": [
+                                            "fin",
+                                            "syn"
+                                        ]
+                                    },
+                                    "rst"
+                                ]
+                            },
+                            "ack"
+                        ]
+                    }
+                ]
+            },
+            "op": "==",
+            "right": {
+                "|": [
+                    "syn",
+                    "ack"
+                ]
+            }
+        }
+    }
+]
+
+# tcp flags & (fin | syn | rst | ack) != syn | ack
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            {
+                                "|": [
+                                    {
+                                        "|": [
+                                            "fin",
+                                            "syn"
+                                        ]
+                                    },
+                                    "rst"
+                                ]
+                            },
+                            "ack"
+                        ]
+                    }
+                ]
+            },
+            "op": "!=",
+            "right": {
+                "|": [
+                    "syn",
+                    "ack"
+                ]
+            }
+        }
+    }
+]
+
+# tcp flags & (syn | ack) == syn | ack
+[
+    {
+        "match": {
+            "left": {
+                "&": [
+                    {
+                        "payload": {
+                            "field": "flags",
+                            "protocol": "tcp"
+                        }
+                    },
+                    {
+                        "|": [
+                            "syn",
+                            "ack"
+                        ]
+                    }
+                ]
+            },
+            "op": "==",
+            "right": {
+                "|": [
+                    "syn",
+                    "ack"
+                ]
+            }
+        }
+    }
+]
+
index 1cfe500bff1ae5f3fd6223f6d2bd0f2556f2d5e1..bc6bb989ae1afc0c8bb27fe94568139e7222bb6a 100644 (file)
@@ -442,7 +442,7 @@ inet test-inet input
   [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
   [ cmp neq reg 1 0x00000002 ]
 
-# tcp flags & (fin | syn | rst | ack) == (syn | ack)
+# tcp flags & (fin | syn | rst | ack) == syn | ack
 inet test-inet input
   [ meta load l4proto => reg 1 ]
   [ cmp eq reg 1 0x00000006 ]
@@ -450,7 +450,7 @@ inet test-inet input
   [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
   [ cmp eq reg 1 0x00000012 ]
 
-# tcp flags & (fin | syn | rst | ack) != (syn | ack)
+# tcp flags & (fin | syn | rst | ack) != syn | ack
 inet test-inet input
   [ meta load l4proto => reg 1 ]
   [ cmp eq reg 1 0x00000006 ]
@@ -458,7 +458,7 @@ inet test-inet input
   [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
   [ cmp neq reg 1 0x00000012 ]
 
-# tcp flags & (syn | ack) == (syn | ack)
+# tcp flags & (syn | ack) == syn | ack
 inet test-inet input
   [ meta load l4proto => reg 1 ]
   [ cmp eq reg 1 0x00000006 ]
diff --git a/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft b/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft
new file mode 100644 (file)
index 0000000..1a9f4e7
--- /dev/null
@@ -0,0 +1,239 @@
+table inet filter {
+       map if_input {
+               type ifname : verdict
+               elements = { "eth0" : jump public_input,
+                            "eth1" : jump home_input,
+                            "eth2.10" : jump home_input,
+                            "eth2.20" : jump home_input }
+       }
+
+       map if_forward {
+               type ifname : verdict
+               elements = { "eth0" : jump public_forward,
+                            "eth1" : jump trusted_forward,
+                            "eth2.10" : jump voip_forward,
+                            "eth2.20" : jump guest_forward }
+       }
+
+       map if_output {
+               type ifname : verdict
+               elements = { "eth0" : jump public_output,
+                            "eth1" : jump home_output,
+                            "eth2.10" : jump home_output,
+                            "eth2.20" : jump home_output }
+       }
+
+       set ipv4_blacklist {
+               type ipv4_addr
+               flags interval
+               auto-merge
+       }
+
+       set ipv6_blacklist {
+               type ipv6_addr
+               flags interval
+               auto-merge
+       }
+
+       set limit_src_ip {
+               type ipv4_addr
+               size 1024
+               flags dynamic,timeout
+       }
+
+       set limit_src_ip6 {
+               type ipv6_addr
+               size 1024
+               flags dynamic,timeout
+       }
+
+       chain PREROUTING_RAW {
+               type filter hook prerouting priority raw; policy accept;
+               meta l4proto != { icmp, tcp, udp, ipv6-icmp } counter packets 0 bytes 0 drop
+               tcp flags syn jump {
+                       tcp option maxseg size 1-500 counter packets 0 bytes 0 drop
+                       tcp sport 0 counter packets 0 bytes 0 drop
+               }
+               rt type 0 counter packets 0 bytes 0 drop
+       }
+
+       chain PREROUTING_MANGLE {
+               type filter hook prerouting priority mangle; policy accept;
+               ct state vmap { invalid : jump ct_invalid_pre, related : jump rpfilter, new : jump ct_new_pre, untracked : jump ct_untracked_pre }
+       }
+
+       chain ct_invalid_pre {
+               counter packets 0 bytes 0 drop
+       }
+
+       chain ct_untracked_pre {
+               icmpv6 type { mld-listener-query, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } return
+               counter packets 0 bytes 0 drop
+       }
+
+       chain ct_new_pre {
+               jump rpfilter
+               tcp flags & (fin | syn | rst | ack) != syn counter packets 0 bytes 0 drop
+               iifname "eth0" meta nfproto vmap { ipv4 : jump blacklist_input_ipv4, ipv6 : jump blacklist_input_ipv6 }
+       }
+
+       chain rpfilter {
+               ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp sport 68 udp dport 67 return
+               ip6 saddr :: ip6 daddr . icmpv6 type { ff02::1:ff00:0/104 . nd-neighbor-solicit, ff02::16 . mld2-listener-report } return
+               fib saddr . iif oif 0 counter packets 0 bytes 0 drop
+       }
+
+       chain blacklist_input_ipv4 {
+               ip saddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 } counter packets 0 bytes 0 drop
+               ip saddr @ipv4_blacklist counter packets 0 bytes 0 drop
+       }
+
+       chain blacklist_input_ipv6 {
+               icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 return
+               udp sport 547 ip6 saddr fe80::/64 return
+               ip6 saddr { ::/3, 2001::/32, 2001:2::/48, 2001:3::/32, 2001:10::-2001:2f:ffff:ffff:ffff:ffff:ffff:ffff, 2001:db8::/32, 2002::/16, 3000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } counter packets 0 bytes 0 drop
+               ip6 saddr @ipv6_blacklist counter packets 0 bytes 0 drop
+       }
+
+       chain INPUT {
+               type filter hook input priority filter; policy drop;
+               iif "lo" accept
+               ct state established,related accept
+               iifname vmap @if_input
+               log prefix "NFT REJECT IN " flags ip options flags ether limit rate 5/second burst 10 packets reject
+       }
+
+       chain public_input {
+               icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 ip6 hoplimit 255 accept
+               udp sport 547 udp dport 546 ip6 saddr fe80::/64 accept
+               fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop
+               counter packets 0 bytes 0 drop
+       }
+
+       chain home_input {
+               icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+               icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+               udp sport 68 udp dport 67 accept
+               udp sport 546 udp dport 547 iifname { "eth1", "eth2.10", "eth2.20" } accept
+               fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop
+               icmp type echo-request accept
+               icmpv6 type echo-request accept
+               tcp dport 22 iifname "eth1" accept
+               meta l4proto { tcp, udp } th dport 53 jump {
+                       ip6 saddr != { fd00::/8, fe80::/64 } counter packets 0 bytes 0 reject with icmpv6 port-unreachable
+                       accept
+               }
+               udp dport 123 accept
+               tcp dport 8443 accept
+       }
+
+       chain FORWARD_MANGLE {
+               type filter hook forward priority mangle; policy accept;
+               oifname "eth0" jump {
+                       ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+                       tcp flags & (syn | rst) == syn tcp option maxseg size set rt mtu
+               }
+       }
+
+       chain blacklist_output_ipv4 {
+               ip daddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 } goto log_blacklist
+               ip daddr @ipv4_blacklist goto log_blacklist
+       }
+
+       chain blacklist_output_ipv6 {
+               icmpv6 type . ip6 daddr { nd-router-solicit . ff02::2, nd-neighbor-solicit . ff02::1:ff00:0/104, nd-neighbor-advert . fe80::/64, nd-neighbor-advert . ff02::1, nd-neighbor-advert . ff02::1:ff00:0/104, mld2-listener-report . ff02::16 } return
+               udp dport 547 ip6 daddr ff02::1:2 return
+               ip6 daddr { ::/3, 2001::/32, 2001:2::/48, 2001:3::/32, 2001:10::-2001:2f:ffff:ffff:ffff:ffff:ffff:ffff, 2001:db8::/32, 2002::/16, 3000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } goto log_blacklist
+               ip6 daddr @ipv6_blacklist goto log_blacklist
+       }
+
+       chain log_blacklist {
+               log prefix "NFT BLACKLIST " flags ip options flags ether limit rate 5/minute burst 10 packets drop
+               counter packets 0 bytes 0 drop
+       }
+
+       chain FORWARD {
+               type filter hook forward priority filter; policy drop;
+               ct state established,related accept
+               fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop
+               iifname vmap @if_forward
+               log prefix "NFT REJECT FWD " flags ip options flags ether limit rate 5/second burst 10 packets reject
+       }
+
+       chain public_forward {
+               udp dport { 5060, 7078-7097 } oifname "eth2.10" jump {
+                       ip6 saddr { 2001:db8::1-2001:db8::2 } accept
+                       meta nfproto ipv6 log prefix "NFT DROP SIP " flags ip options flags ether limit rate 5/second burst 10 packets drop
+               }
+               counter packets 0 bytes 0 drop
+       }
+
+       chain trusted_forward {
+               oifname "eth0" accept
+               icmp type echo-request accept
+               icmpv6 type echo-request accept
+               ip daddr { 192.168.3.30, 192.168.4.40 } tcp dport vmap { 22 : accept, 80 : drop, 443 : accept }
+               ip daddr 192.168.2.20 jump {
+                       tcp dport { 80, 443, 515, 631, 9100 } accept
+                       udp dport 161 accept
+               }
+       }
+
+       chain voip_forward {
+               icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } oifname "eth0" accept
+               ip6 daddr { 2001:db8::1-2001:db8::2 } jump {
+                       udp dport { 3478, 5060 } accept
+                       udp sport 7078-7097 accept
+                       tcp dport 5061 accept
+               }
+               tcp dport 587 ip daddr 10.0.0.1 accept
+               tcp dport 80 oifname "eth0" counter packets 0 bytes 0 reject
+       }
+
+       chain guest_forward {
+               oifname "eth0" accept
+       }
+
+       chain OUTPUT {
+               type filter hook output priority filter; policy drop;
+               oif "lo" accept
+               ct state vmap { invalid : jump ct_invalid_out, established : accept, related : accept, untracked : jump ct_untracked_out }
+               oifname vmap @if_output
+               log prefix "NFT REJECT OUT " flags ip options flags ether limit rate 5/second burst 10 packets reject
+       }
+
+       chain ct_invalid_out {
+               counter packets 0 bytes 0 drop
+       }
+
+       chain ct_untracked_out {
+               icmpv6 type { mld-listener-query, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } return
+               counter packets 0 bytes 0 drop
+       }
+
+       chain public_output {
+               ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+               icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept
+               icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+               icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+               icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+               udp dport 547 ip6 saddr fe80::/64 ip6 daddr ff02::1:2 accept
+               udp dport { 53, 123 } accept
+               tcp dport { 443, 587, 853 } accept
+       }
+
+       chain home_output {
+               icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept
+               icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+               icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+               icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+               udp sport 547 udp dport 546 ip6 saddr fe80::/64 oifname { "eth1", "eth2.10", "eth2.20" } accept
+               udp sport 67 udp dport 68 ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } accept
+               tcp dport 22 ip daddr 192.168.1.10 accept
+       }
+
+       chain POSTROUTING_SRCNAT {
+               type nat hook postrouting priority srcnat; policy accept;
+               ip saddr { 192.168.1.0-192.168.4.255 } oifname "eth0" masquerade
+       }
+}
index 1c9ee5329b267baa48d8b3d18e436e0097e6ebb6..88552226ee3ad6d749f7fec4c28a32e41843af7a 100755 (executable)
@@ -15,14 +15,14 @@ table inet t {
        chain c {
                type filter hook output priority 0;
                tcp dport != 22345 accept
-               tcp flags syn / fin,syn,rst,ack tcp option 254  length ge 4 counter name nomatchc drop
-               tcp flags syn / fin,syn,rst,ack tcp option fastopen length ge 2 reset tcp option fastopen counter name nomatchc
-               tcp flags syn / fin,syn,rst,ack tcp option sack-perm missing counter name nomatchc
-               tcp flags syn / fin,syn,rst,ack tcp option sack-perm exists counter name sackpermc
-               tcp flags syn / fin,syn,rst,ack tcp option maxseg size gt 1400 counter name maxsegc
-               tcp flags syn / fin,syn,rst,ack tcp option nop missing counter name nomatchc
-               tcp flags syn / fin,syn,rst,ack tcp option nop exists counter name nopc
-               tcp flags syn / fin,syn,rst,ack drop
+               tcp flags & (fin | syn | rst | ack ) == syn tcp option 254  length ge 4 counter name nomatchc drop
+               tcp flags & (fin | syn | rst | ack ) == syn tcp option fastopen length ge 2 reset tcp option fastopen counter name nomatchc
+               tcp flags & (fin | syn | rst | ack ) == syn tcp option sack-perm missing counter name nomatchc
+               tcp flags & (fin | syn | rst | ack) == syn tcp option sack-perm exists counter name sackpermc
+               tcp flags & (fin | syn | rst | ack) == syn tcp option maxseg size gt 1400 counter name maxsegc
+               tcp flags & (fin | syn | rst | ack) == syn tcp option nop missing counter name nomatchc
+               tcp flags & (fin | syn | rst | ack) == syn tcp option nop exists counter name nopc
+               tcp flags & (fin | syn | rst | ack) == syn drop
        }
 }
 EOF