Signed-off-by: Fernando Fernandez Mancera <ffmancera@xxxxxxxxxx> --- include/linux/netfilter/nf_SYNPROXY.h | 23 ++++++++++++ include/linux/netfilter/nf_tables.h | 16 +++++++++ include/statement.h | 11 ++++++ src/evaluate.c | 16 +++++++++ src/netlink_delinearize.c | 17 +++++++++ src/netlink_linearize.c | 17 +++++++++ src/parser_bison.y | 48 +++++++++++++++++++++++++ src/scanner.l | 6 ++++ src/statement.c | 50 +++++++++++++++++++++++++++ 9 files changed, 204 insertions(+) create mode 100644 include/linux/netfilter/nf_SYNPROXY.h diff --git a/include/linux/netfilter/nf_SYNPROXY.h b/include/linux/netfilter/nf_SYNPROXY.h new file mode 100644 index 0000000..0e7c391 --- /dev/null +++ b/include/linux/netfilter/nf_SYNPROXY.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _NF_SYNPROXY_H +#define _NF_SYNPROXY_H + +#include <linux/types.h> + +#define NF_SYNPROXY_OPT_MSS 0x01 +#define NF_SYNPROXY_OPT_WSCALE 0x02 +#define NF_SYNPROXY_OPT_SACK_PERM 0x04 +#define NF_SYNPROXY_OPT_TIMESTAMP 0x08 +#define NF_SYNPROXY_OPT_ECN 0x10 +#define NF_SYNPROXY_FLAGMASK (NF_SYNPROXY_OPT_MSS | \ + NF_SYNPROXY_OPT_WSCALE | \ + NF_SYNPROXY_OPT_SACK_PERM | \ + NF_SYNPROXY_OPT_TIMESTAMP) + +struct nf_synproxy_info { + __u8 options; + __u8 wscale; + __u16 mss; +}; + +#endif /* _NF_SYNPROXY_H */ diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 7bdb234..d9ccf3f 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -1529,6 +1529,22 @@ enum nft_osf_attributes { }; #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1) +/** + * enum nft_synproxy_attributes - nftables synproxy expression + * netlink attributes + * + * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16) + * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8) + * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32) + */ +enum nft_synproxy_attributes { + NFTA_SYNPROXY_MSS, + NFTA_SYNPROXY_WSCALE, + NFTA_SYNPROXY_FLAGS, + __NFTA_SYNPROXY_MAX, +}; +#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1) + /** * enum nft_device_attributes - nf_tables device netlink attributes * diff --git a/include/statement.h b/include/statement.h index 91d6e0e..f789ced 100644 --- a/include/statement.h +++ b/include/statement.h @@ -203,6 +203,14 @@ struct map_stmt { extern struct stmt *map_stmt_alloc(const struct location *loc); +struct synproxy_stmt { + uint16_t mss; + uint8_t wscale; + uint32_t flags; +}; + +extern struct stmt *synproxy_stmt_alloc(const struct location *loc); + struct meter_stmt { struct expr *set; struct expr *key; @@ -270,6 +278,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc); * @STMT_FLOW_OFFLOAD: flow offload statement * @STMT_CONNLIMIT: connection limit statement * @STMT_MAP: map statement + * @STMT_SYNPROXY: synproxy statement */ enum stmt_types { STMT_INVALID, @@ -297,6 +306,7 @@ enum stmt_types { STMT_FLOW_OFFLOAD, STMT_CONNLIMIT, STMT_MAP, + STMT_SYNPROXY, }; /** @@ -361,6 +371,7 @@ struct stmt { struct objref_stmt objref; struct flow_stmt flow; struct map_stmt map; + struct synproxy_stmt synproxy; }; }; diff --git a/src/evaluate.c b/src/evaluate.c index 39101b4..04692b8 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -17,6 +17,7 @@ #include <linux/netfilter.h> #include <linux/netfilter_arp.h> #include <linux/netfilter/nf_tables.h> +#include <linux/netfilter/nf_SYNPROXY.h> #include <linux/netfilter_ipv4.h> #include <netinet/ip_icmp.h> #include <netinet/icmp6.h> @@ -2704,6 +2705,19 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt) return 0; } +static int stmt_evaluate_synproxy(struct eval_ctx *ctx, struct stmt *stmt) +{ + printf("Values of the synproxy expr: %u %u\n", stmt->synproxy.mss, stmt->synproxy.wscale); + if (stmt->synproxy.flags != 0 && + !(stmt->synproxy.flags & (NF_SYNPROXY_OPT_MSS | + NF_SYNPROXY_OPT_WSCALE | + NF_SYNPROXY_OPT_TIMESTAMP | + NF_SYNPROXY_OPT_SACK_PERM))) + return stmt_error(ctx, stmt, "This flags are not supported for SYNPROXY"); + + return 0; +} + static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt) { int err; @@ -3048,6 +3062,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt) return stmt_evaluate_objref(ctx, stmt); case STMT_MAP: return stmt_evaluate_map(ctx, stmt); + case STMT_SYNPROXY: + return stmt_evaluate_synproxy(ctx, stmt); default: BUG("unknown statement type %s\n", stmt->ops->name); } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 0270e1f..2785325 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -1010,6 +1010,22 @@ out_err: xfree(stmt); } +static void netlink_parse_synproxy(struct netlink_parse_ctx *ctx, + const struct location *loc, + const struct nftnl_expr *nle) +{ + struct stmt *stmt; + + stmt = synproxy_stmt_alloc(loc); + stmt->synproxy.mss = nftnl_expr_get_u16(nle, NFTNL_EXPR_SYNPROXY_MSS); + stmt->synproxy.wscale = nftnl_expr_get_u8(nle, + NFTNL_EXPR_SYNPROXY_WSCALE); + stmt->synproxy.flags = nftnl_expr_get_u32(nle, + NFTNL_EXPR_SYNPROXY_FLAGS); + + ctx->stmt = stmt; +} + static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) @@ -1476,6 +1492,7 @@ static const struct { { .name = "tcpopt", .parse = netlink_parse_exthdr }, { .name = "flow_offload", .parse = netlink_parse_flow_offload }, { .name = "xfrm", .parse = netlink_parse_xfrm }, + { .name = "synproxy", .parse = netlink_parse_synproxy }, }; static int netlink_parse_expr(const struct nftnl_expr *nle, diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 2c6aa64..498326d 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -1141,6 +1141,21 @@ static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx, nftnl_rule_add_expr(ctx->nlr, nle); } +static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx, + const struct stmt *stmt) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("synproxy"); + nftnl_expr_set_u16(nle, NFTNL_EXPR_SYNPROXY_MSS, stmt->synproxy.mss); + nftnl_expr_set_u8(nle, NFTNL_EXPR_SYNPROXY_WSCALE, + stmt->synproxy.wscale); + nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS, + stmt->synproxy.flags); + + nftnl_rule_add_expr(ctx->nlr, nle); +} + static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { @@ -1382,6 +1397,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx, return netlink_gen_nat_stmt(ctx, stmt); case STMT_TPROXY: return netlink_gen_tproxy_stmt(ctx, stmt); + case STMT_SYNPROXY: + return netlink_gen_synproxy_stmt(ctx, stmt); case STMT_DUP: return netlink_gen_dup_stmt(ctx, stmt); case STMT_QUEUE: diff --git a/src/parser_bison.y b/src/parser_bison.y index 97a48f3..61e0888 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -23,6 +23,7 @@ #include <linux/netfilter/nf_nat.h> #include <linux/netfilter/nf_log.h> #include <linux/netfilter/nfnetlink_osf.h> +#include <linux/netfilter/nf_SYNPROXY.h> #include <linux/xfrm.h> #include <netinet/ip_icmp.h> #include <netinet/icmp6.h> @@ -200,6 +201,12 @@ int nft_lex(void *, void *, void *); %token OSF "osf" +%token SYNPROXY "synproxy" +%token MSS "mss" +%token WSCALE "wscale" +%token TIMESTAMP "timestamp" +%token SACKPERM "sack-perm" + %token HOOK "hook" %token DEVICE "device" %token DEVICES "devices" @@ -601,6 +608,9 @@ int nft_lex(void *, void *, void *); %type <val> nf_nat_flags nf_nat_flag offset_opt %type <stmt> tproxy_stmt %destructor { stmt_free($$); } tproxy_stmt +%type <stmt> synproxy_stmt synproxy_stmt_alloc +%destructor { stmt_free($$); } synproxy_stmt synproxy_stmt_alloc + %type <stmt> queue_stmt queue_stmt_alloc %destructor { stmt_free($$); } queue_stmt queue_stmt_alloc @@ -2245,6 +2255,7 @@ stmt : verdict_stmt | fwd_stmt | set_stmt | map_stmt + | synproxy_stmt ; verdict_stmt : verdict_expr @@ -2675,6 +2686,43 @@ tproxy_stmt : TPROXY TO stmt_expr } ; +synproxy_stmt : synproxy_stmt_alloc + | synproxy_stmt_alloc synproxy_args + ; + +synproxy_stmt_alloc : SYNPROXY + { + $$ = synproxy_stmt_alloc(&@$); + } + ; + +synproxy_args : synproxy_arg + { + $<stmt>$ = $<stmt>0; + } + | synproxy_args synproxy_arg + ; + +synproxy_arg : MSS NUM + { + $<stmt>0->synproxy.mss = $2; + $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_MSS; + } + | WSCALE NUM + { + $<stmt>0->synproxy.wscale = $2; + $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE; + } + | TIMESTAMP + { + $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP; + } + | SACKPERM + { + $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM; + } + ; + primary_stmt_expr : symbol_expr { $$ = $1; } | integer_expr { $$ = $1; } | boolean_expr { $$ = $1; } diff --git a/src/scanner.l b/src/scanner.l index d1f6e87..e990cc6 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -543,6 +543,12 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "osf" { return OSF; } +"synproxy" { return SYNPROXY; } +"mss" { return MSS; } +"wscale" { return WSCALE; } +"timestamp" { return TIMESTAMP; } +"sack-perm" { return SACKPERM; } + "notrack" { return NOTRACK; } "options" { return OPTIONS; } diff --git a/src/statement.c b/src/statement.c index a9e8b3a..3489e3e 100644 --- a/src/statement.c +++ b/src/statement.c @@ -29,6 +29,7 @@ #include <netinet/in.h> #include <linux/netfilter/nf_nat.h> #include <linux/netfilter/nf_log.h> +#include <linux/netfilter/nf_SYNPROXY.h> struct stmt *stmt_alloc(const struct location *loc, const struct stmt_ops *ops) @@ -877,3 +878,52 @@ struct stmt *xt_stmt_alloc(const struct location *loc) { return stmt_alloc(loc, &xt_stmt_ops); } + +static const char *synproxy_sack_to_str(const uint32_t flags) +{ + if (flags & NF_SYNPROXY_OPT_SACK_PERM) + return " sack-perm"; + + return ""; +} + +static const char *synproxy_timestamp_to_str(const uint32_t flags) +{ + if (flags & NF_SYNPROXY_OPT_TIMESTAMP) + return " timestamp"; + + return ""; +} + +static void synproxy_stmt_print(const struct stmt *stmt, + struct output_ctx *octx) +{ + uint32_t flags = stmt->synproxy.flags; + const char *ts_str = synproxy_timestamp_to_str(flags); + const char *sack_str = synproxy_sack_to_str(flags); + + if (flags & (NF_SYNPROXY_OPT_MSS | NF_SYNPROXY_OPT_WSCALE)) + nft_print(octx, "synproxy mss %u wscale %u%s%s", + stmt->synproxy.mss, stmt->synproxy.wscale, + ts_str, sack_str); + else if (flags & NF_SYNPROXY_OPT_MSS) + nft_print(octx, "synproxy mss %u%s%s", stmt->synproxy.mss, + ts_str, sack_str); + else if (flags & NF_SYNPROXY_OPT_WSCALE) + nft_print(octx, "synproxy wscale %u%s%s", stmt->synproxy.wscale, + ts_str, sack_str); + else + nft_print(octx, "synproxy%s%s", ts_str, sack_str); + +} + +static const struct stmt_ops synproxy_stmt_ops = { + .type = STMT_SYNPROXY, + .name = "synproxy", + .print = synproxy_stmt_print, +}; + +struct stmt *synproxy_stmt_alloc(const struct location *loc) +{ + return stmt_alloc(loc, &synproxy_stmt_ops); +} -- 2.20.1