]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
ebtables-nft: add broute table emulation
authorFlorian Westphal <fw@strlen.de>
Tue, 4 Apr 2023 09:45:44 +0000 (11:45 +0200)
committerPhil Sutter <phil@nwl.cc>
Tue, 4 Apr 2023 19:22:46 +0000 (21:22 +0200)
Use new 'meta broute set 1' to emulate -t broute.  If '-t broute' is given,
automatically translate -j DROP to 'meta broute set 1 accept' internally.

Reverse translation zaps the broute and pretends verdict was DROP.

Note that BROUTING is internally handled via PREROUTING, i.e. 'redirect'
and 'nat' targets are not available, they will need to be emulated via
nft expressions.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/ebtables-nft.8
iptables/nft-bridge.c
iptables/nft-shared.c
iptables/nft-shared.h
iptables/nft.c
iptables/nft.h
iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0

index d75aae240bc05223e0b49e3d76ccfafb90733646..0304b5088cd8c80cdc55dbc284d30914926c9bc7 100644 (file)
@@ -55,7 +55,7 @@ It is analogous to the
 application, but less complicated, due to the fact that the Ethernet protocol
 is much simpler than the IP protocol.
 .SS CHAINS
-There are two ebtables tables with built-in chains in the
+There are three ebtables tables with built-in chains in the
 Linux kernel. These tables are used to divide functionality into
 different sets of rules. Each set of rules is called a chain.
 Each chain is an ordered list of rules that can match Ethernet frames. If a
@@ -81,7 +81,10 @@ an 'extension' (see below) or a jump to a user-defined chain.
 .B ACCEPT
 means to let the frame through.
 .B DROP
-means the frame has to be dropped.
+means the frame has to be dropped. In the
+.BR BROUTING " chain however, the " ACCEPT " and " DROP " target have different"
+meanings (see the info provided for the
+.BR -t " option)."
 .B CONTINUE
 means the next rule has to be checked. This can be handy, f.e., to know how many
 frames pass a certain point in the chain, to log those frames or to apply multiple
@@ -93,17 +96,13 @@ For the extension targets please refer to the
 .B "TARGET EXTENSIONS"
 section of this man page.
 .SS TABLES
-As stated earlier, there are two ebtables tables in the Linux
-kernel.  The table names are
-.BR filter " and " nat .
-Of these two tables,
+As stated earlier, the table names are
+.BR filter ", " nat " and " broute .
+Of these tables,
 the filter table is the default table that the command operates on.
-If you are working with the filter table, then you can drop the '-t filter'
-argument to the ebtables command.  However, you will need to provide
-the -t argument for
-.B nat
-table.  Moreover, the -t argument must be the
-first argument on the ebtables command line, if used. 
+If you are working with a table other than filter, you will need to provide
+the -t argument.  Moreover, the -t argument must be the
+first argument on the ebtables command line, if used.
 .TP
 .B "-t, --table"
 .br
@@ -131,6 +130,23 @@ iptables world to ebtables it is easier to have the same names. Note that you
 can change the name
 .BR "" ( -E )
 if you don't like the default.
+.br
+.br
+.B broute
+is used to make a brouter, it has one built-in chain:
+.BR BROUTING .
+The targets
+.BR DROP " and " ACCEPT
+have a special meaning in the broute table (these names are used for
+compatibility reasons with ebtables-legacy).
+.B DROP
+actually means the frame has to be routed, while
+.B ACCEPT
+means the frame has to be bridged. The
+.B BROUTING
+chain is traversed very early.
+Normally those frames
+would be bridged, but you can decide otherwise here.
 .SH EBTABLES COMMAND LINE ARGUMENTS
 After the initial ebtables '-t table' command line argument, the remaining
 arguments can be divided into several groups.  These groups
@@ -1059,8 +1075,6 @@ arp message and the hardware address length in the arp header is 6 bytes.
 .BR "" "See " http://netfilter.org/mailinglists.html
 .SH BUGS
 The version of ebtables this man page ships with does not support the
-.B broute
-table. Also there is no support for
 .B string
 match. Further, support for atomic-options
 .RB ( --atomic-file ", " --atomic-init ", " --atomic-save ", " --atomic-commit )
index b9983b203f6d0601398e98c97f9bd02dcb7704c0..22860d6b91a6fa2e963483b22507903db875d55c 100644 (file)
@@ -95,8 +95,44 @@ static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r,
                add_cmp_ptr(r, op, iface, iface_len + 1, reg);
 }
 
+static int add_meta_broute(struct nftnl_rule *r)
+{
+       struct nftnl_expr *expr;
+
+       expr = nftnl_expr_alloc("immediate");
+       if (expr == NULL)
+               return -1;
+
+       nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
+       nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
+       nftnl_rule_add_expr(r, expr);
+
+       expr = nftnl_expr_alloc("meta");
+       if (expr == NULL)
+               return -1;
+       nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_BRI_BROUTE);
+       nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
+
+       nftnl_rule_add_expr(r, expr);
+       return 0;
+}
+
 static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
 {
+       const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
+
+       if (cs->target &&
+           table && strcmp(table, "broute") == 0) {
+               if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) {
+                       int ret = add_meta_broute(r);
+
+                       if (ret)
+                               return ret;
+
+                       cs->jumpto = "ACCEPT";
+               }
+       }
+
        return add_action(r, cs, false);
 }
 
index 1b22eb7afd305cf4daf401be3de8dcec0d0cdd2f..c19d78e469722146f08a7b003bff0b9aa7258e16 100644 (file)
@@ -511,8 +511,24 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
        *inv = (op == NFT_CMP_NEQ);
 }
 
-static void nft_meta_set_to_target(struct nft_xt_ctx *ctx,
-                                  struct nftnl_expr *e)
+static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx,
+                                     struct nft_xt_ctx_reg *sreg)
+{
+       if ((sreg->type != NFT_XT_REG_IMMEDIATE)) {
+               ctx->errmsg = "meta sreg is not an immediate";
+               return false;
+       }
+
+       if (sreg->immediate.data[0] == 0) {
+               ctx->errmsg = "meta sreg immediate is 0";
+               return false;
+       }
+
+       return true;
+}
+
+static void nft_parse_meta_set(struct nft_xt_ctx *ctx,
+                              struct nftnl_expr *e)
 {
        struct xtables_target *target;
        struct nft_xt_ctx_reg *sreg;
@@ -528,18 +544,17 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx,
 
        switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) {
        case NFT_META_NFTRACE:
-               if ((sreg->type != NFT_XT_REG_IMMEDIATE)) {
-                       ctx->errmsg = "meta nftrace but reg not immediate";
+               if (!nft_parse_meta_set_common(ctx, sreg))
                        return;
-               }
-
-               if (sreg->immediate.data[0] == 0) {
-                       ctx->errmsg = "trace is cleared";
-                       return;
-               }
 
                targname = "TRACE";
                break;
+       case NFT_META_BRI_BROUTE:
+               if (!nft_parse_meta_set_common(ctx, sreg))
+                       return;
+
+               ctx->cs->jumpto = "DROP";
+               return;
        default:
                ctx->errmsg = "meta sreg key not supported";
                return;
@@ -568,7 +583,7 @@ static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
         struct nft_xt_ctx_reg *reg;
 
        if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) {
-               nft_meta_set_to_target(ctx, e);
+               nft_parse_meta_set(ctx, e);
                return;
        }
 
@@ -1145,6 +1160,8 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
        /* Standard target? */
        switch(verdict) {
        case NF_ACCEPT:
+               if (cs->jumpto && strcmp(ctx->table, "broute") == 0)
+                       break;
                cs->jumpto = "ACCEPT";
                break;
        case NF_DROP:
index b8bc1a6ce2e9398ad39d00002d53e6869d41ffde..2c4c0d90cd077a803fc7ca41498757ad4cd6da73 100644 (file)
@@ -61,6 +61,9 @@ struct nft_xt_ctx_reg {
                struct {
                        uint32_t key;
                } meta_dreg;
+               struct {
+                       uint32_t key;
+               } meta_sreg;
        };
 
        struct {
index 5ef5335a24c1a6ebf5c9b0967e7905e817104962..1cb104e75ccc56636e64a7732d61662ef8d51b48 100644 (file)
@@ -643,6 +643,19 @@ static const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
                        },
                },
        },
+       [NFT_TABLE_BROUTE] = {
+               .name = "broute",
+               .type   = NFT_TABLE_BROUTE,
+               .chains = {
+                       {
+                               .name   = "BROUTING",
+                               .type   = "filter",
+                               .prio   = NF_BR_PRI_FIRST,
+                               .hook   = NF_BR_PRE_ROUTING,
+                       },
+               },
+       },
+
 };
 
 static int nft_table_builtin_add(struct nft_handle *h,
index 56005863ed4c44c605278d815773ec059666a142..1d18982dc8cf79ae240fb602e5af7249d2ba84e7 100644 (file)
@@ -14,8 +14,9 @@ enum nft_table_type {
        NFT_TABLE_RAW,
        NFT_TABLE_FILTER,
        NFT_TABLE_NAT,
+       NFT_TABLE_BROUTE,
 };
-#define NFT_TABLE_MAX  (NFT_TABLE_NAT + 1)
+#define NFT_TABLE_MAX  (NFT_TABLE_BROUTE + 1)
 
 struct builtin_chain {
        const char *name;
index 6f11bd12593dd5df7819da09502304818a62b59c..bae0de7db0c230cb0665b36b0129dea825521e69 100755 (executable)
@@ -15,13 +15,13 @@ get_entries_count() { # (chain)
 
 set -x
 
-for t in filter nat;do
+for t in filter nat broute; do
        $XT_MULTI ebtables -t $t -L || exit 1
        $XT_MULTI ebtables -t $t -X || exit 1
        $XT_MULTI ebtables -t $t -F || exit 1
 done
 
-for t in broute foobar ;do
+for t in foobar; do
        $XT_MULTI ebtables -t $t -L &&
        $XT_MULTI ebtables -t $t -X &&
        $XT_MULTI ebtables -t $t -F