From 4a75ed32132d8e2292dd276f3ea7f4edec4f3d06 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 15 Sep 2016 17:28:00 +0200 Subject: src: add fib expression This adds the 'fib' expression which can be used to obtain the output interface from the route table based on either source or destination address of a packet. This can be used to e.g. add reverse path filtering: # drop if not coming from the same interface packet # arrived on # nft add rule x prerouting fib saddr . iif oif eq 0 drop # accept only if from eth0 # nft add rule x prerouting fib saddr . iif oif eq "eth0" accept # accept if from any valid interface # nft add rule x prerouting fib saddr oif accept Querying of address type is also supported. This can be used to e.g. only accept packets to addresses configured in the same interface: # fib daddr . iif type local Its also possible to use mark and verdict map, e.g.: # nft add rule x prerouting meta mark set 0xdead fib daddr . mark type vmap { blackhole : drop, prohibit : drop, unicast : accept } Signed-off-by: Florian Westphal --- src/Makefile.am | 1 + src/evaluate.c | 1 + src/fib.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++ src/netlink_delinearize.c | 19 ++++++ src/netlink_linearize.c | 16 ++++++ src/parser_bison.y | 50 ++++++++++++++++ src/scanner.l | 2 + 7 files changed, 233 insertions(+) create mode 100644 src/fib.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 9a151bd4..d021cb7f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,6 +36,7 @@ nft_SOURCES = main.c \ proto.c \ payload.c \ exthdr.c \ + fib.c \ hash.c \ meta.c \ rt.c \ diff --git a/src/evaluate.c b/src/evaluate.c index ab0dd9ef..a2e5dbb9 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1638,6 +1638,7 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr) return expr_evaluate_exthdr(ctx, expr); case EXPR_VERDICT: case EXPR_META: + case EXPR_FIB: return expr_evaluate_primary(ctx, expr); case EXPR_PAYLOAD: return expr_evaluate_payload(ctx, expr); diff --git a/src/fib.c b/src/fib.c new file mode 100644 index 00000000..346cce32 --- /dev/null +++ b/src/fib.c @@ -0,0 +1,144 @@ +/* + * FIB expression. + * + * Copyright (c) Red Hat GmbH. Author: Florian Westphal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const char *fib_result[NFT_FIB_RESULT_MAX + 1] = { + [NFT_FIB_RESULT_OIF] = "oif", + [NFT_FIB_RESULT_OIFNAME] = "oifname", + [NFT_FIB_RESULT_ADDRTYPE] = "type", +}; + +static const struct symbol_table addrtype_tbl = { + .symbols = { + SYMBOL("unspec", RTN_UNSPEC), + SYMBOL("unicast", RTN_UNICAST), + SYMBOL("local", RTN_LOCAL), + SYMBOL("broadcast", RTN_BROADCAST), + SYMBOL("anycast", RTN_ANYCAST), + SYMBOL("multicast", RTN_MULTICAST), + SYMBOL("blackhole", RTN_BLACKHOLE), + SYMBOL("unreachable", RTN_UNREACHABLE), + SYMBOL("prohibit", RTN_PROHIBIT), + SYMBOL_LIST_END + } +}; + +static const struct datatype fib_addr_type = { + .type = TYPE_FIB_ADDR, + .name = "fib_addrtype", + .desc = "fib address type", + .byteorder = BYTEORDER_HOST_ENDIAN, + .size = 4 * BITS_PER_BYTE, + .basetype = &integer_type, + .sym_tbl = &addrtype_tbl, +}; + +static const char *fib_result_str(enum nft_fib_result result) +{ + if (result <= NFT_FIB_RESULT_MAX) + return fib_result[result]; + + return "unknown"; +} + +static void __fib_expr_print_f(unsigned int *flags, unsigned int f, const char *s) +{ + if ((*flags & f) == 0) + return; + + printf("%s", s); + *flags &= ~f; + if (*flags) + printf(" . "); +} + +static void fib_expr_print(const struct expr *expr) +{ + unsigned int flags = expr->fib.flags; + + printf("fib "); + __fib_expr_print_f(&flags, NFTA_FIB_F_SADDR, "saddr"); + __fib_expr_print_f(&flags, NFTA_FIB_F_DADDR, "daddr"); + __fib_expr_print_f(&flags, NFTA_FIB_F_MARK, "mark"); + __fib_expr_print_f(&flags, NFTA_FIB_F_IIF, "iif"); + __fib_expr_print_f(&flags, NFTA_FIB_F_OIF, "oif"); + + if (flags) + printf("0x%x", flags); + + printf(" %s", fib_result_str(expr->fib.result)); +} + +static bool fib_expr_cmp(const struct expr *e1, const struct expr *e2) +{ + return e1->fib.result == e2->fib.result && + e1->fib.flags == e2->fib.flags; +} + +static void fib_expr_clone(struct expr *new, const struct expr *expr) +{ + new->fib.result = expr->fib.result; + new->fib.flags= expr->fib.flags; +} + +static const struct expr_ops fib_expr_ops = { + .type = EXPR_FIB, + .name = "fib", + .print = fib_expr_print, + .cmp = fib_expr_cmp, + .clone = fib_expr_clone, +}; + +struct expr *fib_expr_alloc(const struct location *loc, + unsigned int flags, unsigned int result) +{ + const struct datatype *type; + unsigned int len = 4 * BITS_PER_BYTE; + struct expr *expr; + + switch (result) { + case NFT_FIB_RESULT_OIF: + type = &ifindex_type; + break; + case NFT_FIB_RESULT_OIFNAME: + type = &string_type; + len = IFNAMSIZ * BITS_PER_BYTE; + break; + case NFT_FIB_RESULT_ADDRTYPE: + type = &fib_addr_type; + break; + default: + BUG("Unknown result %d\n", result); + } + + expr = expr_alloc(loc, &fib_expr_ops, type, + BYTEORDER_HOST_ENDIAN, len); + + expr->fib.result = result; + expr->fib.flags = flags; + + return expr; +} + +static void __init fib_init(void) +{ + datatype_register(&fib_addr_type); +} diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index dc9cc837..f0df8848 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -538,6 +538,23 @@ static void netlink_parse_hash(struct netlink_parse_ctx *ctx, netlink_set_register(ctx, dreg, expr); } +static void netlink_parse_fib(struct netlink_parse_ctx *ctx, + const struct location *loc, + const struct nftnl_expr *nle) +{ + enum nft_registers dreg; + struct expr *expr; + uint32_t flags, result; + + flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_FIB_FLAGS); + result = nftnl_expr_get_u32(nle, NFTNL_EXPR_FIB_RESULT); + + expr = fib_expr_alloc(loc, flags, result); + + dreg = netlink_parse_register(nle, NFTNL_EXPR_FIB_DREG); + netlink_set_register(ctx, dreg, expr); +} + static void netlink_parse_meta_expr(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) @@ -1120,6 +1137,7 @@ static const struct { { .name = "quota", .parse = netlink_parse_quota }, { .name = "numgen", .parse = netlink_parse_numgen }, { .name = "hash", .parse = netlink_parse_hash }, + { .name = "fib", .parse = netlink_parse_fib }, }; static int netlink_parse_expr(const struct nftnl_expr *nle, @@ -1743,6 +1761,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) case EXPR_RT: case EXPR_VERDICT: case EXPR_NUMGEN: + case EXPR_FIB: break; case EXPR_HASH: expr_postprocess(ctx, &expr->hash.expr); diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index a5d4502f..b5967d49 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -104,6 +104,20 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx, } } +static void netlink_gen_fib(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("fib"); + netlink_put_register(nle, NFTNL_EXPR_FIB_DREG, dreg); + nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_RESULT, expr->fib.result); + nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_FLAGS, expr->fib.flags); + + nftnl_rule_add_expr(ctx->nlr, nle); +} + static void netlink_gen_hash(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) @@ -663,6 +677,8 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx, return netlink_gen_numgen(ctx, expr, dreg); case EXPR_HASH: return netlink_gen_hash(ctx, expr, dreg); + case EXPR_FIB: + return netlink_gen_fib(ctx, expr, dreg); default: BUG("unknown expression type %s\n", expr->ops->name); } diff --git a/src/parser_bison.y b/src/parser_bison.y index dc02fd23..106df271 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -162,10 +162,13 @@ static void location_update(struct location *loc, struct location *rhs, int n) %token DASH "-" %token AT "@" %token VMAP "vmap" +%token LOOKUP "lookup" %token INCLUDE "include" %token DEFINE "define" +%token FIB "fib" + %token HOOK "hook" %token DEVICE "device" %token TABLE "table" @@ -601,6 +604,10 @@ static void location_update(struct location *loc, struct location *rhs, int n) %destructor { expr_free($$); } ct_expr %type ct_key ct_key_dir ct_key_counters +%type fib_expr +%destructor { expr_free($$); } fib_expr +%type fib_tuple fib_result fib_flag + %type export_format %type monitor_event %destructor { xfree($$); } monitor_event @@ -2006,9 +2013,52 @@ primary_expr : symbol_expr { $$ = $1; } | ct_expr { $$ = $1; } | numgen_expr { $$ = $1; } | hash_expr { $$ = $1; } + | fib_expr { $$ = $1; } | '(' basic_expr ')' { $$ = $2; } ; +fib_expr : FIB fib_tuple fib_result + { + if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) { + erec_queue(error(&@2, "fib: need either saddr or daddr"), state->msgs); + YYERROR; + } + + if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == + (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) { + erec_queue(error(&@2, "fib: saddr and daddr are mutually exclusive"), state->msgs); + YYERROR; + } + + if (($2 & (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) == + (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) { + erec_queue(error(&@2, "fib: iif and oif are mutually exclusive"), state->msgs); + YYERROR; + } + + $$ = fib_expr_alloc(&@$, $2, $3); + } + ; + +fib_result : OIF { $$ =NFT_FIB_RESULT_OIF; } + | OIFNAME { $$ =NFT_FIB_RESULT_OIFNAME; } + | TYPE { $$ =NFT_FIB_RESULT_ADDRTYPE; } + ; + +fib_flag : SADDR { $$ = NFTA_FIB_F_SADDR; } + | DADDR { $$ = NFTA_FIB_F_DADDR; } + | MARK { $$ = NFTA_FIB_F_MARK; } + | IIF { $$ = NFTA_FIB_F_IIF; } + | OIF { $$ = NFTA_FIB_F_OIF; } + ; + +fib_tuple : fib_flag DOT fib_tuple + { + $$ = $1 | $3; + } + | fib_flag + ; + shift_expr : primary_expr | shift_expr LSHIFT primary_expr { diff --git a/src/scanner.l b/src/scanner.l index c8352014..9cb8d778 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -465,6 +465,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "dup" { return DUP; } "fwd" { return FWD; } +"fib" { return FIB; } + "xml" { return XML; } "json" { return JSON; } -- cgit v1.2.3