From 58c89e8768711a959fdc6e953df3ea2254ff93c1 Mon Sep 17 00:00:00 2001 From: Syrone Wong Date: Sat, 9 Apr 2022 00:38:51 +0800 Subject: [PATCH] nftables: add fullcone expression support Signed-off-by: Syrone Wong --- include/linux/netfilter/nf_tables.h | 16 ++++++++++ include/statement.h | 1 + src/netlink_delinearize.c | 48 +++++++++++++++++++++++++++++ src/netlink_linearize.c | 7 +++++ src/parser_bison.y | 28 +++++++++++++++-- src/scanner.l | 1 + src/statement.c | 1 + 7 files changed, 100 insertions(+), 2 deletions(-) diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 75df968..beab9d8 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -1409,6 +1409,22 @@ enum nft_masq_attributes { }; #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +/** + * enum nft_fullcone_attributes - nf_tables fullcone expression attributes + * + * @NFTA_FULLCONE_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_FULLCONE_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_FULLCONE_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) + */ +enum nft_fullcone_attributes { + NFTA_FULLCONE_UNSPEC, + NFTA_FULLCONE_FLAGS, + NFTA_FULLCONE_REG_PROTO_MIN, + NFTA_FULLCONE_REG_PROTO_MAX, + __NFTA_FULLCONE_MAX +}; +#define NFTA_FULLCONE_MAX (__NFTA_FULLCONE_MAX - 1) + /** * enum nft_redir_attributes - nf_tables redirect expression netlink attributes * diff --git a/include/statement.h b/include/statement.h index 2a2d300..cbd48dd 100644 --- a/include/statement.h +++ b/include/statement.h @@ -122,6 +122,7 @@ enum nft_nat_etypes { __NFT_NAT_SNAT = NFT_NAT_SNAT, __NFT_NAT_DNAT = NFT_NAT_DNAT, NFT_NAT_MASQ, + NFT_NAT_FULLCONE, NFT_NAT_REDIR, }; diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 068c3bb..8513113 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -1369,6 +1369,53 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, stmt_free(stmt); } +static void netlink_parse_fullcone(struct netlink_parse_ctx *ctx, + const struct location *loc, + const struct nftnl_expr *nle) +{ + enum nft_registers reg1, reg2; + struct expr *proto; + struct stmt *stmt; + uint32_t flags = 0; + + if (nftnl_expr_is_set(nle, NFTNL_EXPR_FULLCONE_FLAGS)) + flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_FULLCONE_FLAGS); + + stmt = nat_stmt_alloc(loc, NFT_NAT_FULLCONE); + stmt->nat.flags = flags; + + reg1 = netlink_parse_register(nle, NFTNL_EXPR_FULLCONE_REG_PROTO_MIN); + if (reg1) { + proto = netlink_get_register(ctx, loc, reg1); + if (proto == NULL) { + netlink_error(ctx, loc, + "fullcone statement has no proto expression"); + goto out_err; + } + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + stmt->nat.proto = proto; + } + + reg2 = netlink_parse_register(nle, NFTNL_EXPR_FULLCONE_REG_PROTO_MAX); + if (reg2 && reg2 != reg1) { + proto = netlink_get_register(ctx, loc, reg2); + if (proto == NULL) { + netlink_error(ctx, loc, + "fullcone statement has no proto expression"); + goto out_err; + } + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + if (stmt->nat.proto != NULL) + proto = range_expr_alloc(loc, stmt->nat.proto, proto); + stmt->nat.proto = proto; + } + + ctx->stmt = stmt; + return; +out_err: + stmt_free(stmt); +} + static void netlink_parse_redir(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) @@ -1787,6 +1834,7 @@ static const struct expr_handler netlink_parsers[] = { { .name = "tproxy", .parse = netlink_parse_tproxy }, { .name = "notrack", .parse = netlink_parse_notrack }, { .name = "masq", .parse = netlink_parse_masq }, + { .name = "fullcone", .parse = netlink_parse_fullcone }, { .name = "redir", .parse = netlink_parse_redir }, { .name = "dup", .parse = netlink_parse_dup }, { .name = "queue", .parse = netlink_parse_queue }, diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index c8bbcb7..505eafa 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -1140,6 +1140,13 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN; nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX; break; + case NFT_NAT_FULLCONE: + nle = alloc_nft_expr("fullcone"); + + nftnl_flag_attr = NFTNL_EXPR_FULLCONE_FLAGS; + nftnl_reg_pmin = NFTNL_EXPR_FULLCONE_REG_PROTO_MIN; + nftnl_reg_pmax = NFTNL_EXPR_FULLCONE_REG_PROTO_MAX; + break; case NFT_NAT_REDIR: nle = alloc_nft_expr("redir"); diff --git a/src/parser_bison.y b/src/parser_bison.y index ca5c488..ec9fc9b 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -571,6 +571,7 @@ int nft_lex(void *, void *, void *); %token SNAT "snat" %token DNAT "dnat" %token MASQUERADE "masquerade" +%token FULLCONE "fullcone" %token REDIRECT "redirect" %token RANDOM "random" %token FULLY_RANDOM "fully-random" @@ -703,8 +704,8 @@ int nft_lex(void *, void *, void *); %type limit_burst_pkts limit_burst_bytes limit_mode limit_bytes time_unit quota_mode %type reject_stmt reject_stmt_alloc %destructor { stmt_free($$); } reject_stmt reject_stmt_alloc -%type nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc -%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc +%type nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc fullcone_stmt fullcone_stmt_alloc redir_stmt redir_stmt_alloc +%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc fullcone_stmt fullcone_stmt_alloc redir_stmt redir_stmt_alloc %type nf_nat_flags nf_nat_flag offset_opt %type tproxy_stmt %destructor { stmt_free($$); } tproxy_stmt @@ -2853,6 +2854,7 @@ stmt : verdict_stmt | queue_stmt | ct_stmt | masq_stmt close_scope_nat + | fullcone_stmt close_scope_nat | redir_stmt close_scope_nat | dup_stmt close_scope_dup | fwd_stmt close_scope_fwd @@ -3753,6 +3755,28 @@ masq_stmt_args : TO COLON stmt_expr } ; +fullcone_stmt : fullcone_stmt_alloc fullcone_stmt_args + | fullcone_stmt_alloc + ; + +fullcone_stmt_alloc : FULLCONE { $$ = nat_stmt_alloc(&@$, NFT_NAT_FULLCONE); } + ; + +fullcone_stmt_args : TO COLON stmt_expr + { + $0->nat.proto = $3; + } + | TO COLON stmt_expr nf_nat_flags + { + $0->nat.proto = $3; + $0->nat.flags = $4; + } + | nf_nat_flags + { + $0->nat.flags = $1; + } + ; + redir_stmt : redir_stmt_alloc redir_stmt_arg | redir_stmt_alloc ; diff --git a/src/scanner.l b/src/scanner.l index 2154281..c389860 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -453,6 +453,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "snat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; } "dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; } "masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; } +"fullcone" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return FULLCONE; } "redirect" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return REDIRECT; } "random" { return RANDOM; } { diff --git a/src/statement.c b/src/statement.c index 30caf9c..f4866c2 100644 --- a/src/statement.c +++ b/src/statement.c @@ -650,6 +650,7 @@ const char *nat_etype2str(enum nft_nat_etypes type) [NFT_NAT_SNAT] = "snat", [NFT_NAT_DNAT] = "dnat", [NFT_NAT_MASQ] = "masquerade", + [NFT_NAT_FULLCONE] = "fullcone", [NFT_NAT_REDIR] = "redirect", };