diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..73189d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/nftables-0.8.tar.bz2 diff --git a/.nftables.metadata b/.nftables.metadata new file mode 100644 index 0000000..769c19f --- /dev/null +++ b/.nftables.metadata @@ -0,0 +1 @@ +651c462e1eaa07303978208b7a29050bb4a6f441 SOURCES/nftables-0.8.tar.bz2 diff --git a/SOURCES/0001-src-fix-protocol-context-update-on-big-endian-system.patch b/SOURCES/0001-src-fix-protocol-context-update-on-big-endian-system.patch new file mode 100644 index 0000000..409ca4d --- /dev/null +++ b/SOURCES/0001-src-fix-protocol-context-update-on-big-endian-system.patch @@ -0,0 +1,208 @@ +From ae89c5b2865f77ac5e3f8e6c74c9b07296a1acdf Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 14 Dec 2017 14:17:27 +0100 +Subject: [PATCH] src: fix protocol context update on big-endian systems + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523016 +Upstream Status: nftables commit a2c55e04d5a11 + +commit a2c55e04d5a1187914cba2c02810db94de499ace +Author: Phil Sutter +Date: Sat Dec 9 16:52:29 2017 +0100 + + src: fix protocol context update on big-endian systems + + There is an obscure bug on big-endian systems when trying to list a rule + containing the expression 'ct helper tftp' which triggers the assert() + call in mpz_get_type(). + + Florian identified the cause: ct_expr_pctx_update() is called for the + relational expression which calls mpz_get_uint32() to get RHS value + (assuming it is a protocol number). On big-endian systems, the + misinterpreted value exceeds UINT_MAX. + + Expressions' pctx_update() callback should only be called for protocol + matches, so ct_meta_common_postprocess() lacked a check for 'left->flags + & EXPR_F_PROTOCOL' like the one already present in + payload_expr_pctx_update(). + + In order to fix this in a clean way, this patch introduces a wrapper + relational_expr_pctx_update() to be used instead of directly calling + LHS's pctx_update() callback which unifies the necessary checks (and + adds one more assert): + + - assert(expr->ops->type == EXPR_RELATIONAL) + -> This is new, just to ensure the wrapper is called properly. + - assert(expr->op == OP_EQ) + -> This was moved from {ct,meta,payload}_expr_pctx_update(). + - left->ops->pctx_update != NULL + -> This was taken from expr_evaluate_relational(), a necessary + requirement for the introduced wrapper to function at all. + - (left->flags & EXPR_F_PROTOCOL) != 0 + -> The crucial missing check which led to the problem. + + Suggested-by: Florian Westphal + Signed-off-by: Phil Sutter + Signed-off-by: Florian Westphal +--- + include/expression.h | 3 +++ + src/ct.c | 2 -- + src/evaluate.c | 6 ++---- + src/expression.c | 13 +++++++++++++ + src/meta.c | 2 -- + src/netlink.c | 2 +- + src/netlink_delinearize.c | 4 ++-- + src/payload.c | 7 +------ + 8 files changed, 22 insertions(+), 17 deletions(-) + +diff --git a/include/expression.h b/include/expression.h +index 215cbc9..915ce0b 100644 +--- a/include/expression.h ++++ b/include/expression.h +@@ -369,6 +369,9 @@ extern struct expr *binop_expr_alloc(const struct location *loc, enum ops op, + extern struct expr *relational_expr_alloc(const struct location *loc, enum ops op, + struct expr *left, struct expr *right); + ++extern void relational_expr_pctx_update(struct proto_ctx *ctx, ++ const struct expr *expr); ++ + extern struct expr *verdict_expr_alloc(const struct location *loc, + int verdict, const char *chain); + +diff --git a/src/ct.c b/src/ct.c +index 58b873e..8ab32e9 100644 +--- a/src/ct.c ++++ b/src/ct.c +@@ -327,8 +327,6 @@ static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr) + const struct proto_desc *base = NULL, *desc; + uint32_t nhproto; + +- assert(expr->op == OP_EQ); +- + nhproto = mpz_get_uint32(right->value); + + base = ctx->protocol[left->ct.base].desc; +diff --git a/src/evaluate.c b/src/evaluate.c +index 618e188..f16bb33 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -743,7 +743,7 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct) + constant_data_ptr(ct->ct.nfproto, left->len)); + dep = relational_expr_alloc(&ct->location, OP_EQ, left, right); + +- left->ops->pctx_update(&ctx->pctx, dep); ++ relational_expr_pctx_update(&ctx->pctx, dep); + + nstmt = expr_stmt_alloc(&dep->location, dep); + +@@ -1632,9 +1632,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) + * Update protocol context for payload and meta iiftype + * equality expressions. + */ +- if (left->flags & EXPR_F_PROTOCOL && +- left->ops->pctx_update) +- left->ops->pctx_update(&ctx->pctx, rel); ++ relational_expr_pctx_update(&ctx->pctx, rel); + + if (left->ops->type == EXPR_CONCAT) + return 0; +diff --git a/src/expression.c b/src/expression.c +index fc1097a..f8b560c 100644 +--- a/src/expression.c ++++ b/src/expression.c +@@ -600,6 +600,19 @@ struct expr *relational_expr_alloc(const struct location *loc, enum ops op, + return expr; + } + ++void relational_expr_pctx_update(struct proto_ctx *ctx, ++ const struct expr *expr) ++{ ++ const struct expr *left = expr->left; ++ ++ assert(expr->ops->type == EXPR_RELATIONAL); ++ assert(expr->op == OP_EQ); ++ ++ if (left->ops->pctx_update && ++ (left->flags & EXPR_F_PROTOCOL)) ++ left->ops->pctx_update(ctx, expr); ++} ++ + static void range_expr_print(const struct expr *expr, struct output_ctx *octx) + { + octx->numeric += NUMERIC_ALL + 1; +diff --git a/src/meta.c b/src/meta.c +index 56b9e29..3c31174 100644 +--- a/src/meta.c ++++ b/src/meta.c +@@ -482,8 +482,6 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx, + const struct proto_desc *desc; + uint8_t protonum; + +- assert(expr->op == OP_EQ); +- + switch (left->meta.key) { + case NFT_META_IIFTYPE: + if (h->base < PROTO_BASE_NETWORK_HDR && +diff --git a/src/netlink.c b/src/netlink.c +index d5d410a..5d6f5ce 100644 +--- a/src/netlink.c ++++ b/src/netlink.c +@@ -2729,7 +2729,7 @@ restart: + list_add_tail(&stmt->list, &unordered); + + desc = ctx->protocol[base].desc; +- lhs->ops->pctx_update(ctx, rel); ++ relational_expr_pctx_update(ctx, rel); + } + + expr_free(rhs); +diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c +index 4432887..11fd330 100644 +--- a/src/netlink_delinearize.c ++++ b/src/netlink_delinearize.c +@@ -1329,7 +1329,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, + nexpr = relational_expr_alloc(&expr->location, expr->op, + left, tmp); + if (expr->op == OP_EQ) +- left->ops->pctx_update(&ctx->pctx, nexpr); ++ relational_expr_pctx_update(&ctx->pctx, nexpr); + + nstmt = expr_stmt_alloc(&ctx->stmt->location, nexpr); + list_add_tail(&nstmt->list, &ctx->stmt->list); +@@ -1397,7 +1397,7 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx, + if (expr->right->ops->type == EXPR_RANGE) + break; + +- expr->left->ops->pctx_update(&ctx->pctx, expr); ++ relational_expr_pctx_update(&ctx->pctx, expr); + + if (ctx->pdctx.pbase == PROTO_BASE_INVALID && + left->flags & EXPR_F_PROTOCOL) { +diff --git a/src/payload.c b/src/payload.c +index aa8a95a..60090ac 100644 +--- a/src/payload.c ++++ b/src/payload.c +@@ -84,11 +84,6 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx, + const struct proto_desc *base, *desc; + unsigned int proto = 0; + +- if (!(left->flags & EXPR_F_PROTOCOL)) +- return; +- +- assert(expr->op == OP_EQ); +- + /* Export the data in the correct byte order */ + assert(right->len / BITS_PER_BYTE <= sizeof(proto)); + mpz_export_data(constant_data_ptr(proto, right->len), right->value, +@@ -240,7 +235,7 @@ static int payload_add_dependency(struct eval_ctx *ctx, + return expr_error(ctx->msgs, expr, + "dependency statement is invalid"); + } +- left->ops->pctx_update(&ctx->pctx, dep); ++ relational_expr_pctx_update(&ctx->pctx, dep); + *res = stmt; + return 0; + } +-- +1.8.3.1 + diff --git a/SOURCES/0002-netlink_linearize-exthdr-op-must-be-u32.patch b/SOURCES/0002-netlink_linearize-exthdr-op-must-be-u32.patch new file mode 100644 index 0000000..72caf4c --- /dev/null +++ b/SOURCES/0002-netlink_linearize-exthdr-op-must-be-u32.patch @@ -0,0 +1,48 @@ +From d0d83585f7f6a74ac02338a37c6860cd2f26b33b Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 14 Dec 2017 14:18:17 +0100 +Subject: [PATCH] netlink_linearize: exthdr op must be u32 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1524246 +Upstream Status: nftables commit 80f5d7fd66895 + +commit 80f5d7fd66895c651c9d1e35b2353f3020ffb538 +Author: Florian Westphal +Date: Mon Dec 11 10:06:55 2017 +0100 + + netlink_linearize: exthdr op must be u32 + + libnftnl casts this to u32. Broke exthdr expressions on bigendian. + + Reported-by: Li Shuang + Signed-off-by: Florian Westphal + Acked-by: Pablo Neira Ayuso +--- + src/netlink_linearize.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c +index fb2d250..a268dcc 100644 +--- a/src/netlink_linearize.c ++++ b/src/netlink_linearize.c +@@ -178,7 +178,7 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx, + nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE); + nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN, + div_round_up(expr->len, BITS_PER_BYTE)); +- nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op); ++ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op); + nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_FLAGS, expr->exthdr.flags); + nftnl_rule_add_expr(ctx->nlr, nle); + } +@@ -839,7 +839,7 @@ static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx, + nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE); + nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN, + div_round_up(expr->len, BITS_PER_BYTE)); +- nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op); ++ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op); + nftnl_rule_add_expr(ctx->nlr, nle); + } + +-- +1.8.3.1 + diff --git a/SOURCES/0003-src-avoid-errouneous-assert-with-map-concat.patch b/SOURCES/0003-src-avoid-errouneous-assert-with-map-concat.patch new file mode 100644 index 0000000..a088894 --- /dev/null +++ b/SOURCES/0003-src-avoid-errouneous-assert-with-map-concat.patch @@ -0,0 +1,63 @@ +From ed405d0eafc7b1f71013cf42f9ed550d64ec56c5 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 6 Jun 2018 10:44:43 +0200 +Subject: [PATCH] src: avoid errouneous assert with map+concat + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1540917 +Upstream Status: nftables commit 483e5ea7167e1 + +commit 483e5ea7167e1537accf4cb083b88a8beea8f834 +Author: Florian Westphal +Date: Tue Mar 27 09:29:54 2018 +0200 + + src: avoid errouneous assert with map+concat + + Phil reported following assert: + + add rule ip6 f o mark set ip6 saddr . ip6 daddr . tcp dport \ + map { dead::beef . f00::. 22 : 1 } + nft: netlink_linearize.c:655: netlink_gen_expr: Assertion `dreg < ctx->reg_low' failed. + + This happens because "mark set" will allocate one register (the dreg), + but netlink_gen_concat_expr will populate a lot more register space if + the concat expression strings a lot of expressions together. + + As the assert is useful pseudo-reserve the register space as per + concat->len and undo after generating the expressions. + + Reported-by: Phil Sutter + Signed-off-by: Florian Westphal +--- + src/netlink_linearize.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c +index a268dcc..e9a4515 100644 +--- a/src/netlink_linearize.c ++++ b/src/netlink_linearize.c +@@ -243,6 +243,7 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx, + { + struct nftnl_expr *nle; + enum nft_registers sreg; ++ int regspace = 0; + + assert(expr->mappings->ops->type == EXPR_SET_REF); + +@@ -251,7 +252,14 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx, + else + sreg = dreg; + ++ /* suppress assert in netlink_gen_expr */ ++ if (expr->map->ops->type == EXPR_CONCAT) { ++ regspace = netlink_register_space(expr->map->len); ++ ctx->reg_low += regspace; ++ } ++ + netlink_gen_expr(ctx, expr->map, sreg); ++ ctx->reg_low -= regspace; + + nle = alloc_nft_expr("lookup"); + netlink_put_register(nle, NFTNL_EXPR_LOOKUP_SREG, sreg); +-- +1.8.3.1 + diff --git a/SOURCES/0004-Review-switch-statements-for-unmarked-fall-through-c.patch b/SOURCES/0004-Review-switch-statements-for-unmarked-fall-through-c.patch new file mode 100644 index 0000000..7efb3ef --- /dev/null +++ b/SOURCES/0004-Review-switch-statements-for-unmarked-fall-through-c.patch @@ -0,0 +1,121 @@ +From 8a8b80fafcbf3843e1736daff707b7cb5b64f31f Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:00 +0200 +Subject: [PATCH] Review switch statements for unmarked fall through cases + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit 7f31d3191622b + +commit 7f31d3191622b650521014e311ace96aa7c5522c +Author: Phil Sutter +Date: Wed Feb 28 16:06:16 2018 +0100 + + Review switch statements for unmarked fall through cases + + While revisiting all of them, clear a few oddities as well: + + - There's no point in marking empty fall through cases: They are easy to + spot and a common concept when using switch(). + + - Fix indenting of break statement in one occasion. + + - Drop needless braces around one case which doesn't declare variables. + + Signed-off-by: Phil Sutter + Signed-off-by: Florian Westphal +--- + src/ct.c | 2 +- + src/evaluate.c | 1 + + src/hash.c | 2 +- + src/netlink_delinearize.c | 1 + + src/rule.c | 5 +++-- + 5 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/src/ct.c b/src/ct.c +index 8ab32e9..1e06013 100644 +--- a/src/ct.c ++++ b/src/ct.c +@@ -289,7 +289,7 @@ static void ct_print(enum nft_ct_keys key, int8_t dir, uint8_t nfproto, + } + + switch (key) { +- case NFT_CT_SRC: /* fallthrough */ ++ case NFT_CT_SRC: + case NFT_CT_DST: + desc = proto_find_upper(&proto_inet, nfproto); + if (desc) +diff --git a/src/evaluate.c b/src/evaluate.c +index f16bb33..25a7376 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -2705,6 +2705,7 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt) + + map->mappings->set->flags |= + map->mappings->set->init->set_flags; ++ /* fall through */ + case EXPR_SYMBOL: + if (expr_evaluate(ctx, &map->mappings) < 0) + return -1; +diff --git a/src/hash.c b/src/hash.c +index 9cd3c8c..3355cad 100644 +--- a/src/hash.c ++++ b/src/hash.c +@@ -20,7 +20,7 @@ static void hash_expr_print(const struct expr *expr, struct output_ctx *octx) + switch (expr->hash.type) { + case NFT_HASH_SYM: + nft_print(octx, "symhash"); +- break; ++ break; + case NFT_HASH_JENKINS: + default: + nft_print(octx, "jhash "); +diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c +index 11fd330..61cba52 100644 +--- a/src/netlink_delinearize.c ++++ b/src/netlink_delinearize.c +@@ -1411,6 +1411,7 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx, + case OP_NEQ: + if (right->ops->type != EXPR_SET && right->ops->type != EXPR_SET_REF) + break; ++ /* fall through */ + case OP_LOOKUP: + expr_set_type(right, left->dtype, left->byteorder); + break; +diff --git a/src/rule.c b/src/rule.c +index d744cf6..e7ccb2b 100644 +--- a/src/rule.c ++++ b/src/rule.c +@@ -1297,7 +1297,7 @@ static void obj_print_data(const struct obj *obj, + } + } + break; +- case NFT_OBJECT_CT_HELPER: { ++ case NFT_OBJECT_CT_HELPER: + nft_print(octx, "ct helper %s {\n", obj->handle.obj); + nft_print(octx, "\t\ttype \"%s\" protocol ", + obj->ct_helper.name); +@@ -1305,7 +1305,6 @@ static void obj_print_data(const struct obj *obj, + nft_print(octx, "\t\tl3proto %s", + family2str(obj->ct_helper.l3proto)); + break; +- } + case NFT_OBJECT_LIMIT: { + bool inv = obj->limit.flags & NFT_LIMIT_F_INV; + const char *data_unit; +@@ -1617,11 +1616,13 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd) + switch (cmd->obj) { + case CMD_OBJ_COUNTERS: + dump = true; ++ /* fall through */ + case CMD_OBJ_COUNTER: + type = NFT_OBJECT_COUNTER; + break; + case CMD_OBJ_QUOTAS: + dump = true; ++ /* fall through */ + case CMD_OBJ_QUOTA: + type = NFT_OBJECT_QUOTA; + break; +-- +1.8.3.1 + diff --git a/SOURCES/0005-monitor-Make-trace-events-respect-output_fp.patch b/SOURCES/0005-monitor-Make-trace-events-respect-output_fp.patch new file mode 100644 index 0000000..8768802 --- /dev/null +++ b/SOURCES/0005-monitor-Make-trace-events-respect-output_fp.patch @@ -0,0 +1,128 @@ +From 696fd8bbb2c654a1d16849fef0f0ae362739def4 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:00 +0200 +Subject: [PATCH] monitor: Make trace events respect output_fp + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit 657472843e7a7 + +commit 657472843e7a7a4bc7f756356e6636b1f197b745 +Author: Phil Sutter +Date: Wed Feb 28 16:04:27 2018 +0100 + + monitor: Make trace events respect output_fp + + Seems like this was incompletely converted, part of the output went to + output_fp already. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/netlink.c | 38 +++++++++++++++++++++----------------- + 1 file changed, 21 insertions(+), 17 deletions(-) + +diff --git a/src/netlink.c b/src/netlink.c +index 5d6f5ce..d839ded 100644 +--- a/src/netlink.c ++++ b/src/netlink.c +@@ -2587,14 +2587,18 @@ static void netlink_events_cache_update(struct netlink_mon_handler *monh, + } + } + +-static void trace_print_hdr(const struct nftnl_trace *nlt) ++static void trace_print_hdr(const struct nftnl_trace *nlt, ++ struct output_ctx *octx) + { +- printf("trace id %08x ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID)); +- printf("%s ", family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY))); ++ nft_print(octx, "trace id %08x %s ", ++ nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID), ++ family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY))); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE)) +- printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE)); ++ nft_print(octx, "%s ", ++ nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE)); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN)) +- printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN)); ++ nft_print(octx, "%s ", ++ nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN)); + } + + static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr, +@@ -2611,7 +2615,7 @@ static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr, + rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs); + + expr_print(rel, octx); +- printf(" "); ++ nft_print(octx, " "); + expr_free(rel); + } + +@@ -2661,12 +2665,12 @@ static void trace_print_rule(const struct nftnl_trace *nlt, + if (!rule) + return; + +- trace_print_hdr(nlt); +- printf("rule "); ++ trace_print_hdr(nlt, octx); ++ nft_print(octx, "rule "); + rule_print(rule, octx); +- printf(" ("); ++ nft_print(octx, " ("); + trace_print_verdict(nlt, octx); +- printf(")\n"); ++ nft_print(octx, ")\n"); + } + + static void trace_gen_stmts(struct list_head *stmts, +@@ -2775,9 +2779,9 @@ static void trace_print_packet(const struct nftnl_trace *nlt, + uint32_t nfproto; + struct stmt *stmt, *next; + +- trace_print_hdr(nlt); ++ trace_print_hdr(nlt, octx); + +- printf("packet: "); ++ nft_print(octx, "packet: "); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF)) + trace_print_expr(nlt, NFTNL_TRACE_IIF, + meta_expr_alloc(&netlink_location, +@@ -2813,10 +2817,10 @@ static void trace_print_packet(const struct nftnl_trace *nlt, + + list_for_each_entry_safe(stmt, next, &stmts, list) { + stmt_print(stmt, octx); +- printf(" "); ++ nft_print(octx, " "); + stmt_free(stmt); + } +- printf("\n"); ++ nft_print(octx, "\n"); + } + + static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, +@@ -2844,11 +2848,11 @@ static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, + break; + case NFT_TRACETYPE_POLICY: + case NFT_TRACETYPE_RETURN: +- trace_print_hdr(nlt); ++ trace_print_hdr(nlt, monh->ctx->octx); + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT)) { + trace_print_verdict(nlt, monh->ctx->octx); +- printf(" "); ++ nft_mon_print(monh, " "); + } + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK)) +@@ -2856,7 +2860,7 @@ static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, + meta_expr_alloc(&netlink_location, + NFT_META_MARK), + monh->ctx->octx); +- printf("\n"); ++ nft_mon_print(monh, "\n"); + break; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0006-monitor-Make-JSON-XML-output-respect-output_fp.patch b/SOURCES/0006-monitor-Make-JSON-XML-output-respect-output_fp.patch new file mode 100644 index 0000000..dc961d6 --- /dev/null +++ b/SOURCES/0006-monitor-Make-JSON-XML-output-respect-output_fp.patch @@ -0,0 +1,120 @@ +From fa5ccccd164b7285c4d105265ece4ea7ccdd996a Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:00 +0200 +Subject: [PATCH] monitor: Make JSON/XML output respect output_fp + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit 59034b47590d7 + +commit 59034b47590d7cd19ba2fda24bf4426c355f95bc +Author: Phil Sutter +Date: Wed Feb 28 16:04:28 2018 +0100 + + monitor: Make JSON/XML output respect output_fp + + Make sure events callbacks print to output_ctx-defined stream for any + type of output format. + + Since all of them use nft_print() as last call (if anything is printed + at all), the final call to fflush() in netlink_events_cb() can be + dropped. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/netlink.c | 37 ++++++++++++++++++------------------- + 1 file changed, 18 insertions(+), 19 deletions(-) + +diff --git a/src/netlink.c b/src/netlink.c +index d839ded..ca0e207 100644 +--- a/src/netlink.c ++++ b/src/netlink.c +@@ -2015,9 +2015,9 @@ static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type, + break; + case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: +- nftnl_table_fprintf(stdout, nlt, monh->format, +- netlink_msg2nftnl_of(type)); +- fprintf(stdout, "\n"); ++ nftnl_table_fprintf(monh->ctx->octx->output_fp, nlt, ++ monh->format, netlink_msg2nftnl_of(type)); ++ nft_mon_print(monh, "\n"); + break; + } + +@@ -2057,9 +2057,9 @@ static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type, + break; + case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: +- nftnl_chain_fprintf(stdout, nlc, monh->format, +- netlink_msg2nftnl_of(type)); +- fprintf(stdout, "\n"); ++ nftnl_chain_fprintf(monh->ctx->octx->output_fp, nlc, ++ monh->format, netlink_msg2nftnl_of(type)); ++ nft_mon_print(monh, "\n"); + break; + } + +@@ -2104,9 +2104,9 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type, + break; + case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: +- nftnl_set_fprintf(stdout, nls, monh->format, +- netlink_msg2nftnl_of(type)); +- fprintf(stdout, "\n"); ++ nftnl_set_fprintf(monh->ctx->octx->output_fp, nls, ++ monh->format, netlink_msg2nftnl_of(type)); ++ nft_mon_print(monh, "\n"); + break; + } + out: +@@ -2253,9 +2253,9 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, + break; + case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: +- nftnl_set_fprintf(stdout, nls, monh->format, +- netlink_msg2nftnl_of(type)); +- fprintf(stdout, "\n"); ++ nftnl_set_fprintf(monh->ctx->octx->output_fp, nls, ++ monh->format, netlink_msg2nftnl_of(type)); ++ nft_mon_print(monh, "\n"); + break; + } + out: +@@ -2298,9 +2298,9 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type, + break; + case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: +- nftnl_obj_fprintf(stdout, nlo, monh->format, +- netlink_msg2nftnl_of(type)); +- fprintf(stdout, "\n"); ++ nftnl_obj_fprintf(monh->ctx->octx->output_fp, nlo, ++ monh->format, netlink_msg2nftnl_of(type)); ++ nft_mon_print(monh, "\n"); + break; + } + +@@ -2354,9 +2354,9 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type, + break; + case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: +- nftnl_rule_fprintf(stdout, nlr, monh->format, +- netlink_msg2nftnl_of(type)); +- fprintf(stdout, "\n"); ++ nftnl_rule_fprintf(monh->ctx->octx->output_fp, nlr, ++ monh->format, netlink_msg2nftnl_of(type)); ++ nft_mon_print(monh, "\n"); + break; + } + +@@ -2985,7 +2985,6 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data) + ret = netlink_events_newgen_cb(nlh, type, monh); + break; + } +- fflush(stdout); + + return ret; + } +-- +1.8.3.1 + diff --git a/SOURCES/0007-cli-Drop-pointless-check-in-cli_append_multiline.patch b/SOURCES/0007-cli-Drop-pointless-check-in-cli_append_multiline.patch new file mode 100644 index 0000000..37cfcee --- /dev/null +++ b/SOURCES/0007-cli-Drop-pointless-check-in-cli_append_multiline.patch @@ -0,0 +1,69 @@ +From a5e89843a77c234f1f858737b676161ff8ee0227 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:00 +0200 +Subject: [PATCH] cli: Drop pointless check in cli_append_multiline() + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit f51ed1db70abd +Conflicts: Context change due to missing commit + 4c15b4008c249 ("cli: Use nft_run_cmd_from_buffer()") + +commit f51ed1db70abdbb909e81bc670ffdfa05f421257 +Author: Phil Sutter +Date: Thu Mar 1 15:00:27 2018 +0100 + + cli: Drop pointless check in cli_append_multiline() + + The function is called from cli_complete after it has checked for line + to be != NULL. The other part of the conditional, namely multiline being + NULL, is perfectly valid (if the last read line didn't end with + backslash. Hence drop the conditional completely. + + Since variable eof is not used anywhere outside of the dropped + conditional, get rid of it completely. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/cli.c | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/src/cli.c b/src/cli.c +index cadc3af..53427a0 100644 +--- a/src/cli.c ++++ b/src/cli.c +@@ -46,21 +46,13 @@ static struct mnl_socket *cli_nf_sock; + static void *scanner; + static char histfile[PATH_MAX]; + static char *multiline; +-static bool eof; + + static char *cli_append_multiline(char *line) + { ++ size_t len = strlen(line); + bool complete = false; +- size_t len; + char *s; + +- if (line == NULL && multiline == NULL) { +- eof = true; +- return NULL; +- } +- +- len = strlen(line); +- + if (len == 0) + return NULL; + +@@ -174,7 +166,7 @@ int cli_init(struct nft_ctx *nft, struct mnl_socket *nf_sock, + state = _state; + scanner = scanner_init(state); + +- while (!eof) ++ while (true) + rl_callback_read_char(); + return 0; + } +-- +1.8.3.1 + diff --git a/SOURCES/0008-erec-Avoid-passing-negative-offset-to-fseek.patch b/SOURCES/0008-erec-Avoid-passing-negative-offset-to-fseek.patch new file mode 100644 index 0000000..e6f747e --- /dev/null +++ b/SOURCES/0008-erec-Avoid-passing-negative-offset-to-fseek.patch @@ -0,0 +1,56 @@ +From 76bfabfffc6d10f3b55c896dc7afc24fa3a71fc9 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:47 +0200 +Subject: [PATCH] erec: Avoid passing negative offset to fseek() + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit 3570b6bc8b4f1 + +commit 3570b6bc8b4f136d07121b28cd79b6356e8e969b +Author: Phil Sutter +Date: Thu Mar 1 15:00:28 2018 +0100 + + erec: Avoid passing negative offset to fseek() + + If the initial call to ftell() fails, variable orig_offset is set to -1. + Avoid passing this to fseek() later on. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/erec.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/erec.c b/src/erec.c +index 80806ff..8de249d 100644 +--- a/src/erec.c ++++ b/src/erec.c +@@ -121,7 +121,7 @@ void erec_print(struct output_ctx *octx, const struct error_record *erec, + char buf[1024] = {}; + char *pbuf = NULL; + unsigned int i, end; +- int l, ret; ++ int l; + off_t orig_offset = 0; + FILE *f = octx->output_fp; + +@@ -136,12 +136,12 @@ void erec_print(struct output_ctx *octx, const struct error_record *erec, + break; + case INDESC_FILE: + orig_offset = ftell(indesc->fp); +- fseek(indesc->fp, loc->line_offset, SEEK_SET); +- ret = fread(buf, 1, sizeof(buf) - 1, indesc->fp); +- if (ret > 0) ++ if (orig_offset >= 0 && ++ !fseek(indesc->fp, loc->line_offset, SEEK_SET) && ++ fread(buf, 1, sizeof(buf) - 1, indesc->fp) > 0 && ++ !fseek(indesc->fp, orig_offset, SEEK_SET)) + *strchrnul(buf, '\n') = '\0'; + line = buf; +- fseek(indesc->fp, orig_offset, SEEK_SET); + break; + case INDESC_INTERNAL: + case INDESC_NETLINK: +-- +1.8.3.1 + diff --git a/SOURCES/0009-evaluate-Fix-memleak-in-stmt_reject_gen_dependency.patch b/SOURCES/0009-evaluate-Fix-memleak-in-stmt_reject_gen_dependency.patch new file mode 100644 index 0000000..27225a4 --- /dev/null +++ b/SOURCES/0009-evaluate-Fix-memleak-in-stmt_reject_gen_dependency.patch @@ -0,0 +1,60 @@ +From 56d8528fdd3c3f7db138622d94d2a6bac6b46e4e Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:47 +0200 +Subject: [PATCH] evaluate: Fix memleak in stmt_reject_gen_dependency() + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit edcf3adcf4c4c + +commit edcf3adcf4c4cf58cb0b965b984a512b12181a58 +Author: Phil Sutter +Date: Thu Mar 1 15:00:29 2018 +0100 + + evaluate: Fix memleak in stmt_reject_gen_dependency() + + The allocated payload expression is not used after returning from that + function, so it needs to be freed again. + + Simple test case: + + | nft add rule inet t c reject with tcp reset + + Valgrind reports definitely lost 144 bytes. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/evaluate.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/evaluate.c b/src/evaluate.c +index 25a7376..8552e4a 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -2136,8 +2136,10 @@ static int stmt_reject_gen_dependency(struct eval_ctx *ctx, struct stmt *stmt, + if (ret <= 0) + return ret; + +- if (payload_gen_dependency(ctx, payload, &nstmt) < 0) +- return -1; ++ if (payload_gen_dependency(ctx, payload, &nstmt) < 0) { ++ ret = -1; ++ goto out; ++ } + + /* + * Unlike payload deps this adds the dependency at the beginning, i.e. +@@ -2148,7 +2150,9 @@ static int stmt_reject_gen_dependency(struct eval_ctx *ctx, struct stmt *stmt, + * Otherwise we'd log things that won't be rejected. + */ + list_add(&nstmt->list, &ctx->rule->stmts); +- return 0; ++out: ++ xfree(payload); ++ return ret; + } + + static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx, +-- +1.8.3.1 + diff --git a/SOURCES/0010-hash-Fix-potential-null-pointer-dereference-in-hash_.patch b/SOURCES/0010-hash-Fix-potential-null-pointer-dereference-in-hash_.patch new file mode 100644 index 0000000..c94449d --- /dev/null +++ b/SOURCES/0010-hash-Fix-potential-null-pointer-dereference-in-hash_.patch @@ -0,0 +1,49 @@ +From 76a8ca39b3f95b898cd92546fb87ccaa2d1922c7 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:47 +0200 +Subject: [PATCH] hash: Fix potential null-pointer dereference in + hash_expr_cmp() + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit 5043a1e4847c0 + +commit 5043a1e4847c0149dabaf0b529a14a43b957e5e4 +Author: Phil Sutter +Date: Thu Mar 1 15:00:30 2018 +0100 + + hash: Fix potential null-pointer dereference in hash_expr_cmp() + + The first part of the conditional: + + | (e1->hash.expr || expr_cmp(e1->hash.expr, e2->hash.expr)) + + will call expr_cmp() in case e1->hash.expr is NULL, causing null-pointer + dereference. This is probably a typo, the intention when introducing + this was to avoid the call to expr_cmp() for symmetric hash expressions + which don't use expr->hash.expr. Inverting the existence check should + fix this. + + Fixes: 3a86406729782 ("src: hash: support of symmetric hash") + Cc: Laura Garcia Liebana + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/hash.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/hash.c b/src/hash.c +index 3355cad..e699963 100644 +--- a/src/hash.c ++++ b/src/hash.c +@@ -36,7 +36,7 @@ static void hash_expr_print(const struct expr *expr, struct output_ctx *octx) + + static bool hash_expr_cmp(const struct expr *e1, const struct expr *e2) + { +- return (e1->hash.expr || ++ return (!e1->hash.expr || + expr_cmp(e1->hash.expr, e2->hash.expr)) && + e1->hash.mod == e2->hash.mod && + e1->hash.seed_set == e2->hash.seed_set && +-- +1.8.3.1 + diff --git a/SOURCES/0011-netlink-Complain-if-setting-O_NONBLOCK-fails.patch b/SOURCES/0011-netlink-Complain-if-setting-O_NONBLOCK-fails.patch new file mode 100644 index 0000000..077a5ea --- /dev/null +++ b/SOURCES/0011-netlink-Complain-if-setting-O_NONBLOCK-fails.patch @@ -0,0 +1,41 @@ +From 094f7dd2dce0c449313f1f1ea69dc849fc89b62a Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:47 +0200 +Subject: [PATCH] netlink: Complain if setting O_NONBLOCK fails + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit 4342fcbd40534 + +commit 4342fcbd40534158107ebe6a10e5f7886b3e8ced +Author: Phil Sutter +Date: Thu Mar 1 15:00:31 2018 +0100 + + netlink: Complain if setting O_NONBLOCK fails + + Assuming that code is not aware that reads from netlink socket may + block, treat inability to set O_NONBLOCK flag as fatal initialization + error aborting program execution. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/netlink.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/netlink.c b/src/netlink.c +index ca0e207..ebfad18 100644 +--- a/src/netlink.c ++++ b/src/netlink.c +@@ -58,7 +58,8 @@ struct mnl_socket *netlink_open_sock(void) + if (nf_sock == NULL) + netlink_init_error(); + +- fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK); ++ if (fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK)) ++ netlink_init_error(); + + return nf_sock; + } +-- +1.8.3.1 + diff --git a/SOURCES/0012-netlink_delinearize-Fix-resource-leaks.patch b/SOURCES/0012-netlink_delinearize-Fix-resource-leaks.patch new file mode 100644 index 0000000..02b1cc8 --- /dev/null +++ b/SOURCES/0012-netlink_delinearize-Fix-resource-leaks.patch @@ -0,0 +1,351 @@ +From 5e9e2dc7e972f6bbbc0156ad97b4ee9d11fcb837 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:22:47 +0200 +Subject: [PATCH] netlink_delinearize: Fix resource leaks + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157 +Upstream Status: nftables commit 671851617c8d8 + +commit 671851617c8d8c1dfe9822eee8dcc7b827fff850 +Author: Phil Sutter +Date: Thu Mar 1 15:00:32 2018 +0100 + + netlink_delinearize: Fix resource leaks + + Most of the cases are basically the same: Error path fails to free the + previously allocated statement or expression. A few cases received + special treatment though: + + - In netlink_parse_payload_stmt(), the leak is easily avoided by code + reordering. + + - In netlink_parse_exthdr(), there's no point in introducing a goto + label since there is but a single affected error check. + + - In netlink_parse_hash() non-error path leaked as well if sreg + contained a concatenated expression. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/netlink_delinearize.c | 144 +++++++++++++++++++++++++++++----------------- + 1 file changed, 92 insertions(+), 52 deletions(-) + +diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c +index 61cba52..e25160a 100644 +--- a/src/netlink_delinearize.c ++++ b/src/netlink_delinearize.c +@@ -470,15 +470,15 @@ static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx, + offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET) * BITS_PER_BYTE; + len = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_LEN) * BITS_PER_BYTE; + +- expr = payload_expr_alloc(loc, NULL, 0); +- payload_init_raw(expr, base, offset, len); +- + sreg = netlink_parse_register(nle, NFTNL_EXPR_PAYLOAD_SREG); + val = netlink_get_register(ctx, loc, sreg); + if (val == NULL) + return netlink_error(ctx, loc, + "payload statement has no expression"); + ++ expr = payload_expr_alloc(loc, NULL, 0); ++ payload_init_raw(expr, base, offset, len); ++ + stmt = payload_stmt_alloc(loc, expr, val); + + list_add_tail(&stmt->list, &ctx->rule->stmts); +@@ -523,9 +523,11 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx, + + sreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_SREG); + val = netlink_get_register(ctx, loc, sreg); +- if (val == NULL) ++ if (val == NULL) { ++ xfree(expr); + return netlink_error(ctx, loc, + "exthdr statement has no expression"); ++ } + + expr_set_type(val, expr->dtype, expr->byteorder); + +@@ -556,22 +558,27 @@ static void netlink_parse_hash(struct netlink_parse_ctx *ctx, + sreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_SREG); + hexpr = netlink_get_register(ctx, loc, sreg); + +- if (hexpr == NULL) +- return ++ if (hexpr == NULL) { + netlink_error(ctx, loc, + "hash statement has no expression"); ++ goto out_err; ++ } + len = nftnl_expr_get_u32(nle, + NFTNL_EXPR_HASH_LEN) * BITS_PER_BYTE; + if (hexpr->len < len) { ++ xfree(hexpr); + hexpr = netlink_parse_concat_expr(ctx, loc, sreg, len); + if (hexpr == NULL) +- return; ++ goto out_err; + } + expr->hash.expr = hexpr; + } + + dreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_DREG); + netlink_set_register(ctx, dreg, expr); ++ return; ++out_err: ++ xfree(expr); + } + + static void netlink_parse_fib(struct netlink_parse_ctx *ctx, +@@ -853,10 +860,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, + reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN); + if (reg1) { + addr = netlink_get_register(ctx, loc, reg1); +- if (addr == NULL) +- return netlink_error(ctx, loc, +- "NAT statement has no address " +- "expression"); ++ if (addr == NULL) { ++ netlink_error(ctx, loc, ++ "NAT statement has no address expression"); ++ goto out_err; ++ } + + if (family == AF_INET) + expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN); +@@ -869,10 +877,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, + reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX); + if (reg2 && reg2 != reg1) { + addr = netlink_get_register(ctx, loc, reg2); +- if (addr == NULL) +- return netlink_error(ctx, loc, +- "NAT statement has no address " +- "expression"); ++ if (addr == NULL) { ++ netlink_error(ctx, loc, ++ "NAT statement has no address expression"); ++ goto out_err; ++ } + + if (family == AF_INET) + expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN); +@@ -887,10 +896,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, + reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN); + if (reg1) { + proto = netlink_get_register(ctx, loc, reg1); +- if (proto == NULL) +- return netlink_error(ctx, loc, +- "NAT statement has no proto " +- "expression"); ++ if (proto == NULL) { ++ netlink_error(ctx, loc, ++ "NAT statement has no proto expression"); ++ goto out_err; ++ } + + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + stmt->nat.proto = proto; +@@ -899,10 +909,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, + reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MAX); + if (reg2 && reg2 != reg1) { + proto = netlink_get_register(ctx, loc, reg2); +- if (proto == NULL) +- return netlink_error(ctx, loc, +- "NAT statement has no proto " +- "expression"); ++ if (proto == NULL) { ++ netlink_error(ctx, loc, ++ "NAT statement has no proto expression"); ++ goto out_err; ++ } + + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + if (stmt->nat.proto != NULL) +@@ -911,6 +922,9 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, + } + + ctx->stmt = stmt; ++ return; ++out_err: ++ xfree(stmt); + } + + static void netlink_parse_masq(struct netlink_parse_ctx *ctx, +@@ -931,10 +945,11 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, + reg1 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MIN); + if (reg1) { + proto = netlink_get_register(ctx, loc, reg1); +- if (proto == NULL) +- return netlink_error(ctx, loc, +- "MASQUERADE statement" +- "has no proto expression"); ++ if (proto == NULL) { ++ netlink_error(ctx, loc, ++ "MASQUERADE statement has no proto expression"); ++ goto out_err; ++ } + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + stmt->masq.proto = proto; + } +@@ -942,10 +957,11 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, + reg2 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MAX); + if (reg2 && reg2 != reg1) { + proto = netlink_get_register(ctx, loc, reg2); +- if (proto == NULL) +- return netlink_error(ctx, loc, +- "MASQUERADE statement" +- "has no proto expression"); ++ if (proto == NULL) { ++ netlink_error(ctx, loc, ++ "MASQUERADE statement has no proto expression"); ++ goto out_err; ++ } + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + if (stmt->masq.proto != NULL) + proto = range_expr_alloc(loc, stmt->masq.proto, proto); +@@ -953,6 +969,9 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, + } + + ctx->stmt = stmt; ++ return; ++out_err: ++ xfree(stmt); + } + + static void netlink_parse_redir(struct netlink_parse_ctx *ctx, +@@ -974,10 +993,11 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx, + reg1 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MIN); + if (reg1) { + proto = netlink_get_register(ctx, loc, reg1); +- if (proto == NULL) +- return netlink_error(ctx, loc, +- "redirect statement has no proto " +- "expression"); ++ if (proto == NULL) { ++ netlink_error(ctx, loc, ++ "redirect statement has no proto expression"); ++ goto out_err; ++ } + + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + stmt->redir.proto = proto; +@@ -986,10 +1006,11 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx, + reg2 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MAX); + if (reg2 && reg2 != reg1) { + proto = netlink_get_register(ctx, loc, reg2); +- if (proto == NULL) +- return netlink_error(ctx, loc, +- "redirect statement has no proto " +- "expression"); ++ if (proto == NULL) { ++ netlink_error(ctx, loc, ++ "redirect statement has no proto expression"); ++ goto out_err; ++ } + + expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); + if (stmt->redir.proto != NULL) +@@ -999,6 +1020,9 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx, + } + + ctx->stmt = stmt; ++ return; ++out_err: ++ xfree(stmt); + } + + static void netlink_parse_dup(struct netlink_parse_ctx *ctx, +@@ -1014,9 +1038,11 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx, + reg1 = netlink_parse_register(nle, NFTNL_EXPR_DUP_SREG_ADDR); + if (reg1) { + addr = netlink_get_register(ctx, loc, reg1); +- if (addr == NULL) +- return netlink_error(ctx, loc, +- "DUP statement has no destination expression"); ++ if (addr == NULL) { ++ netlink_error(ctx, loc, ++ "DUP statement has no destination expression"); ++ goto out_err; ++ } + + switch (ctx->table->handle.family) { + case NFPROTO_IPV4: +@@ -1033,9 +1059,11 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx, + reg2 = netlink_parse_register(nle, NFTNL_EXPR_DUP_SREG_DEV); + if (reg2) { + dev = netlink_get_register(ctx, loc, reg2); +- if (dev == NULL) +- return netlink_error(ctx, loc, +- "DUP statement has no output expression"); ++ if (dev == NULL) { ++ netlink_error(ctx, loc, ++ "DUP statement has no output expression"); ++ goto out_err; ++ } + + expr_set_type(dev, &ifindex_type, BYTEORDER_HOST_ENDIAN); + if (stmt->dup.to == NULL) +@@ -1045,6 +1073,9 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx, + } + + ctx->stmt = stmt; ++ return; ++out_err: ++ xfree(stmt); + } + + static void netlink_parse_fwd(struct netlink_parse_ctx *ctx, +@@ -1060,15 +1091,20 @@ static void netlink_parse_fwd(struct netlink_parse_ctx *ctx, + reg1 = netlink_parse_register(nle, NFTNL_EXPR_FWD_SREG_DEV); + if (reg1) { + dev = netlink_get_register(ctx, loc, reg1); +- if (dev == NULL) +- return netlink_error(ctx, loc, +- "fwd statement has no output expression"); ++ if (dev == NULL) { ++ netlink_error(ctx, loc, ++ "fwd statement has no output expression"); ++ goto out_err; ++ } + + expr_set_type(dev, &ifindex_type, BYTEORDER_HOST_ENDIAN); + stmt->fwd.to = dev; + } + + ctx->stmt = stmt; ++ return; ++out_err: ++ xfree(stmt); + } + + static void netlink_parse_queue(struct netlink_parse_ctx *ctx, +@@ -1135,10 +1171,11 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx, + dnle = nftnl_expr_get(nle, NFTNL_EXPR_DYNSET_EXPR, NULL); + if (dnle != NULL) { + if (netlink_parse_expr(dnle, ctx) < 0) +- return; +- if (ctx->stmt == NULL) +- return netlink_error(ctx, loc, +- "Could not parse dynset stmt"); ++ goto out_err; ++ if (ctx->stmt == NULL) { ++ netlink_error(ctx, loc, "Could not parse dynset stmt"); ++ goto out_err; ++ } + dstmt = ctx->stmt; + } + +@@ -1155,6 +1192,9 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx, + } + + ctx->stmt = stmt; ++ return; ++out_err: ++ xfree(expr); + } + + static void netlink_parse_objref(struct netlink_parse_ctx *ctx, +-- +1.8.3.1 + diff --git a/SOURCES/0013-nft.8-Fix-reject-statement-documentation.patch b/SOURCES/0013-nft.8-Fix-reject-statement-documentation.patch new file mode 100644 index 0000000..d33971f --- /dev/null +++ b/SOURCES/0013-nft.8-Fix-reject-statement-documentation.patch @@ -0,0 +1,60 @@ +From c2e843f9386bfa01bfbdd2742ce89f6c474ac0ee Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:23:54 +0200 +Subject: [PATCH] nft.8: Fix reject statement documentation + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1571938 +Upstream Status: nftables commit 9b3036bb9f00d + +commit 9b3036bb9f00d6e244ed92e0e782c5617ae40b84 +Author: Phil Sutter +Date: Wed Jun 6 10:56:26 2018 +0200 + + nft.8: Fix reject statement documentation + + First of all, 'with icmp6' is invalid, expected is 'with icmpv6'. In + addition to that, parameter 'type' expects an icmp*_code type, not + icmp*_type. The respective table column was already correct, but in + synopsis it was wrong. + + Signed-off-by: Phil Sutter + Signed-off-by: Florian Westphal +--- + doc/nft.xml | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/doc/nft.xml b/doc/nft.xml +index c7e12c9..3da5fda 100644 +--- a/doc/nft.xml ++++ b/doc/nft.xml +@@ -4472,14 +4472,14 @@ ip6 filter output log flags all + with + + icmp +- icmp6 ++ icmpv6 + icmpx + + type + +- icmp_type +- icmp6_type +- icmpx_type ++ icmp_code ++ icmpv6_code ++ icmpx_code + + + +@@ -4516,7 +4516,7 @@ ip6 filter output log flags all + icmp_code + + +- icmp6 ++ icmpv6 + ip6 + icmpv6_code + +-- +1.8.3.1 + diff --git a/SOURCES/0014-doc-reword-insert-position-this-expects-rule-handle-.patch b/SOURCES/0014-doc-reword-insert-position-this-expects-rule-handle-.patch new file mode 100644 index 0000000..ed9eb84 --- /dev/null +++ b/SOURCES/0014-doc-reword-insert-position-this-expects-rule-handle-.patch @@ -0,0 +1,56 @@ +From 9abe6ef333d4d1f7c83e10ee73bca70f64b9fdba Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:36:59 +0200 +Subject: [PATCH] doc: reword insert position, this expects rule handle to + insert, not a relative postition + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1571968 +Upstream Status: nftables commit 45172efadbede +Conflicts: Context change due to missing commit f9cb9580b924f + ("doc: nft.8 aim for consistent synopses throughout") + +commit 45172efadbedee2b2dedc1e771046cca7edb0111 +Author: Florian Westphal +Date: Tue Apr 24 16:54:52 2018 +0200 + + doc: reword insert position, this expects rule handle to insert, not a relative postition + + Signed-off-by: Florian Westphal +--- + doc/nft.xml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/doc/nft.xml b/doc/nft.xml +index 3da5fda..45a392f 100644 +--- a/doc/nft.xml ++++ b/doc/nft.xml +@@ -835,7 +835,7 @@ filter input iif $int_ifs accept + family + table + chain +- position position ++ position handle + statement + + +@@ -868,7 +868,7 @@ filter input iif $int_ifs accept + + Add a new rule described by the list of statements. The rule is appended to the + given chain unless a position is specified, in which case the rule is appended to +- the rule given by the position. ++ the rule given by the handle. + + + +@@ -877,7 +877,7 @@ filter input iif $int_ifs accept + + + Similar to the add command, but the rule is prepended to the +- beginning of the chain or before the rule at the given position. ++ beginning of the chain or before the rule with the given handle. + + + +-- +1.8.3.1 + diff --git a/SOURCES/0015-Deprecate-add-insert-rule-position-argument.patch b/SOURCES/0015-Deprecate-add-insert-rule-position-argument.patch new file mode 100644 index 0000000..83f6343 --- /dev/null +++ b/SOURCES/0015-Deprecate-add-insert-rule-position-argument.patch @@ -0,0 +1,92 @@ +From 197711f42a7580918c99536ff891eef7dd040c6b Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:37:57 +0200 +Subject: [PATCH] Deprecate add/insert rule 'position' argument + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1571968 +Upstream Status: nftables commit effb881c9cef2 +Conflicts: Context change due to missing commit f9cb9580b924f + ("doc: nft.8 aim for consistent synopses throughout") + +commit effb881c9cef28aca47adeec5014e0457507539e +Author: Phil Sutter +Date: Wed May 9 16:03:40 2018 +0200 + + Deprecate add/insert rule 'position' argument + + Instead, use 'handle' keyword for the same effect since that is more + consistent with respect to replace/delete commands. The old keyword is + still supported for backwards compatibility and also listed in man page + along with a hint that it shouldn't be used anymore. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + doc/nft.xml | 17 +++++++++++++---- + src/parser_bison.y | 8 ++++++++ + 2 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/doc/nft.xml b/doc/nft.xml +index 45a392f..e6cfb78 100644 +--- a/doc/nft.xml ++++ b/doc/nft.xml +@@ -835,7 +835,13 @@ filter input iif $int_ifs accept + family + table + chain +- position handle ++ ++ ++ handle ++ position ++ ++ handle ++ + statement + + +@@ -867,8 +873,10 @@ filter input iif $int_ifs accept + + + Add a new rule described by the list of statements. The rule is appended to the +- given chain unless a position is specified, in which case the rule is appended to +- the rule given by the handle. ++ given chain unless a handle is specified, in which case the ++ rule is appended to the rule given by the handle. ++ The alternative name position is deprecated and should not be ++ used anymore. + + + +@@ -877,7 +885,8 @@ filter input iif $int_ifs accept + + + Similar to the add command, but the rule is prepended to the +- beginning of the chain or before the rule with the given handle. ++ beginning of the chain or before the rule with the given ++ handle. + + + +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 7016f5b..f9878ba 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -1708,6 +1708,14 @@ rule_position : chain_spec + handle_merge(&$1, &$2); + $$ = $1; + } ++ | chain_spec handle_spec ++ { ++ $2.position.location = $2.handle.location; ++ $2.position.id = $2.handle.id; ++ $2.handle.id = 0; ++ handle_merge(&$1, &$2); ++ $$ = $1; ++ } + ; + + ruleid_spec : chain_spec handle_spec +-- +1.8.3.1 + diff --git a/SOURCES/0016-evaluate-explicitly-deny-concatenated-types-in-inter.patch b/SOURCES/0016-evaluate-explicitly-deny-concatenated-types-in-inter.patch new file mode 100644 index 0000000..891358c --- /dev/null +++ b/SOURCES/0016-evaluate-explicitly-deny-concatenated-types-in-inter.patch @@ -0,0 +1,54 @@ +From d8f1860f72840104bff3742f477c572b57a9c3c1 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 20 Jun 2018 09:38:55 +0200 +Subject: [PATCH] evaluate: explicitly deny concatenated types in interval sets + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1576426 +Upstream Status: nftables commit 9a3d80172a61e + +commit 9a3d80172a61e89c2862bcf41cb58313c236b308 +Author: Phil Sutter +Date: Wed Jun 6 13:21:49 2018 +0200 + + evaluate: explicitly deny concatenated types in interval sets + + Previously, this triggered a program abort: + + | # nft add table ip t + | # nft add set ip t my_set '{ type ipv4_addr . inet_service ; flags interval ; }' + | # nft add element ip t my_set '{10.0.0.1 . tcp }' + | BUG: invalid range expression type concat + | nft: expression.c:1085: range_expr_value_low: Assertion `0' failed. + + With this patch in place, the 'add set' command above gives an error + message: + + | # nft add set ip t my_set3 '{ type ipv4_addr . inet_service ; flags interval ; }' + | Error: concatenated types not supported in interval sets + | add set ip t my_set3 { type ipv4_addr . inet_service ; flags interval ; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Signed-off-by: Phil Sutter + Signed-off-by: Florian Westphal +--- + src/evaluate.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/evaluate.c b/src/evaluate.c +index 8552e4a..ab1347f 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -2865,6 +2865,10 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set) + "specified in %s definition", + set->key->dtype->name, type); + } ++ if (set->flags & NFT_SET_INTERVAL && ++ set->key->ops->type == EXPR_CONCAT) ++ return set_error(ctx, set, "concatenated types not supported in interval sets"); ++ + if (set->flags & NFT_SET_MAP) { + if (set->datatype == NULL) + return set_error(ctx, set, "map definition does not " +-- +1.8.3.1 + diff --git a/SOURCES/0017-src-bail-out-when-exporting-ruleset-with-unsupported.patch b/SOURCES/0017-src-bail-out-when-exporting-ruleset-with-unsupported.patch new file mode 100644 index 0000000..916d287 --- /dev/null +++ b/SOURCES/0017-src-bail-out-when-exporting-ruleset-with-unsupported.patch @@ -0,0 +1,92 @@ +From 032a1808c1abb70004703f57c2d1625a099beca3 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 15 Mar 2019 12:59:19 +0100 +Subject: [PATCH] src: bail out when exporting ruleset with unsupported output + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1646336 +Upstream Status: nftables commit a340aa6ca6cd0 +Conflicts: +* Dropped changes to import command which doesn't exist in RHEL7. +* Changes to parser_bison.y applied manually. Major conflicts due to + missing commit 2fa54d8a49352 ("src: Add import command for low level + json"). +* Adjusted to missing commit 2fa54d8a49352 ("src: Add import command for + low level json"). + +commit a340aa6ca6cd08ae173fbb95cd3e65807264df07 +Author: Pablo Neira Ayuso +Date: Thu Feb 15 17:22:16 2018 +0100 + + src: bail out when exporting ruleset with unsupported output + + Display error message and propagate error to shell when running command + with unsupported output: + + # nft export ruleset json + Error: this output type is not supported + export ruleset json + ^^^^^^^^^^^^^^^^^^^^ + # echo $? + 1 + + When displaying the output in json using the low-level VM + representation, it shows: + + # nft export ruleset vm json + ... low-level VM json output + # echo $? + 0 + + While at it, do the same with obsoleted XML output. + + Fixes: https://bugzilla.netfilter.org/show_bug.cgi?id=1224 + Signed-off-by: Pablo Neira Ayuso +--- + include/nftables.h | 2 ++ + src/evaluate.c | 3 +++ + src/parser_bison.y | 4 ++-- + 3 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/include/nftables.h b/include/nftables.h +index 01d72a8..0abbcaf 100644 +--- a/include/nftables.h ++++ b/include/nftables.h +@@ -154,4 +154,6 @@ int nft_print(struct output_ctx *octx, const char *fmt, ...) + int nft_gmp_print(struct output_ctx *octx, const char *fmt, ...) + __attribute__((format(printf, 2, 0))); + ++#define __NFT_OUTPUT_NOTSUPP UINT_MAX ++ + #endif /* NFTABLES_NFTABLES_H */ +diff --git a/src/evaluate.c b/src/evaluate.c +index ab1347f..c8a98f1 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -3426,6 +3426,9 @@ static int cmd_evaluate_monitor(struct eval_ctx *ctx, struct cmd *cmd) + + static int cmd_evaluate_export(struct eval_ctx *ctx, struct cmd *cmd) + { ++ if (cmd->export->format == __NFT_OUTPUT_NOTSUPP) ++ return cmd_error(ctx, "this output type is not supported"); ++ + return cache_update(ctx->nf_sock, ctx->cache, cmd->op, ctx->msgs, + ctx->debug_mask & DEBUG_NETLINK, ctx->octx); + } +diff --git a/src/parser_bison.y b/src/parser_bison.y +index f9878ba..e87669e 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -1204,8 +1204,8 @@ monitor_format : /* empty */ { $$ = NFTNL_OUTPUT_DEFAULT; } + | export_format + ; + +-export_format : XML { $$ = NFTNL_OUTPUT_XML; } +- | JSON { $$ = NFTNL_OUTPUT_JSON; } ++export_format : XML { $$ = __NFT_OUTPUT_NOTSUPP; } ++ | JSON { $$ = __NFT_OUTPUT_NOTSUPP; } + ; + + describe_cmd : primary_expr +-- +1.8.3.1 + diff --git a/SOURCES/0018-monitor-Drop-fake-XML-support.patch b/SOURCES/0018-monitor-Drop-fake-XML-support.patch new file mode 100644 index 0000000..13385b2 --- /dev/null +++ b/SOURCES/0018-monitor-Drop-fake-XML-support.patch @@ -0,0 +1,80 @@ +From 1dbcbe1ae24756b7b7a7fe8a02626f58604ca2fd Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 15 Mar 2019 13:08:03 +0100 +Subject: [PATCH] monitor: Drop fake XML support + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1646336 +Upstream Status: nftables commit 2194a76ed46a2 +Conflicts: Adjusted changes to missing commit fbcb888b311a9 + ("src: move monitor code to src/monitor.c"). + +commit 2194a76ed46a2f097c5ca5955e44544418866cc2 +Author: Phil Sutter +Date: Thu Oct 11 17:48:57 2018 +0200 + + monitor: Drop fake XML support + + Since libnftnl doesn't support XML formatting, pretending to do so in + nft monitor is pointless. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + src/netlink.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/netlink.c b/src/netlink.c +index ebfad18..09d483d 100644 +--- a/src/netlink.c ++++ b/src/netlink.c +@@ -2014,7 +2014,6 @@ static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type, + nft_mon_print(monh, "%s %s\n", family2str(family), + nftnl_table_get_str(nlt, NFTNL_TABLE_NAME)); + break; +- case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: + nftnl_table_fprintf(monh->ctx->octx->output_fp, nlt, + monh->format, netlink_msg2nftnl_of(type)); +@@ -2056,7 +2055,6 @@ static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type, + break; + } + break; +- case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: + nftnl_chain_fprintf(monh->ctx->octx->output_fp, nlc, + monh->format, netlink_msg2nftnl_of(type)); +@@ -2103,7 +2101,6 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type, + break; + } + break; +- case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: + nftnl_set_fprintf(monh->ctx->octx->output_fp, nls, + monh->format, netlink_msg2nftnl_of(type)); +@@ -2252,7 +2249,6 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, + + set_free(dummyset); + break; +- case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: + nftnl_set_fprintf(monh->ctx->octx->output_fp, nls, + monh->format, netlink_msg2nftnl_of(type)); +@@ -2297,7 +2293,6 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type, + break; + } + break; +- case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: + nftnl_obj_fprintf(monh->ctx->octx->output_fp, nlo, + monh->format, netlink_msg2nftnl_of(type)); +@@ -2353,7 +2348,6 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type, + break; + } + break; +- case NFTNL_OUTPUT_XML: + case NFTNL_OUTPUT_JSON: + nftnl_rule_fprintf(monh->ctx->octx->output_fp, nlr, + monh->format, netlink_msg2nftnl_of(type)); +-- +1.8.3.1 + diff --git a/SOURCES/0019-src-Reject-export-vm-json-command.patch b/SOURCES/0019-src-Reject-export-vm-json-command.patch new file mode 100644 index 0000000..9ed20ea --- /dev/null +++ b/SOURCES/0019-src-Reject-export-vm-json-command.patch @@ -0,0 +1,117 @@ +From 213bb692b8907c2d458298ff2569c96ed71fb925 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 15 Mar 2019 13:08:45 +0100 +Subject: [PATCH] src: Reject 'export vm json' command + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1646336 +Upstream Status: nftables commit 8d51f169e0e83 +Conflicts: +* Adjusted changes to missing commit a84f9329d2f6c + ("src: use location to display error messages"). +* Error message changed to not suggest 'nft -j' which doesn't exist in + RHEL7. +* Man page changes applied manually, upstream converted to asciidoc in + between. +* Include netlink.h from src/evaluate.c to make NFTNL_OUTPUT_JSON + known. Upstream added this in unrelated commit 1524134b0bc01 + ("src: osf: load pf.os from expr_evaluate_osf()"). + +commit 8d51f169e0e832a41d2ed278be903c08bd4fa473 +Author: Phil Sutter +Date: Mon Dec 17 16:29:56 2018 +0100 + + src: Reject 'export vm json' command + + Since libnftnl recently dropped JSON output support, this form of JSON + export is not available anymore. Point at 'nft -j list ruleset' command + for a replacement in error message. + + Since 'export' command is not useable anymore, remove it from + documentation. Instead point out that 'list ruleset' command serves well + for dumping and later restoring. + + To not cause pointless inconvenience for users wishing to store their + ruleset in JSON format, make JSON parser fallback to CMD_ADD if no + recognized command property was found. This allows to feed the output of + 'nft -j list ruleset' into 'nft -f' without any modification. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + doc/nft.xml | 23 +++-------------------- + src/evaluate.c | 4 ++++ + 2 files changed, 7 insertions(+), 20 deletions(-) + +diff --git a/doc/nft.xml b/doc/nft.xml +index e6cfb78..a4a4c3f 100644 +--- a/doc/nft.xml ++++ b/doc/nft.xml +@@ -514,11 +514,6 @@ filter input iif $int_ifs accept + ruleset + family + +- +- export +- ruleset +- format +- + + + +@@ -548,17 +543,6 @@ filter input iif $int_ifs accept + + + +- +- +- +- +- Print the ruleset in machine readable format. The +- mandatory format parameter +- may be either xml or +- json. +- +- +- + + + +@@ -568,10 +552,9 @@ filter input iif $int_ifs accept + + + +- Note that contrary to what one might assume, the output generated +- by export is not parseable by +- nft -f. Instead, the output of +- list command serves well for that purpose. ++ By design, list ruleset command output may be used as ++ input to nft -f. Effectively, this is the nft-equivalent ++ of iptables-save and iptables-restore. + + + +diff --git a/src/evaluate.c b/src/evaluate.c +index c8a98f1..b6c70b8 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -24,6 +24,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -3428,6 +3429,9 @@ static int cmd_evaluate_export(struct eval_ctx *ctx, struct cmd *cmd) + { + if (cmd->export->format == __NFT_OUTPUT_NOTSUPP) + return cmd_error(ctx, "this output type is not supported"); ++ else if (cmd->export->format == NFTNL_OUTPUT_JSON) ++ return cmd_error(ctx, ++ "JSON export is not supported"); + + return cache_update(ctx->nf_sock, ctx->cache, cmd->op, ctx->msgs, + ctx->debug_mask & DEBUG_NETLINK, ctx->octx); +-- +1.8.3.1 + diff --git a/SOURCES/0020-include-fix-build-failure.patch b/SOURCES/0020-include-fix-build-failure.patch new file mode 100644 index 0000000..c250f81 --- /dev/null +++ b/SOURCES/0020-include-fix-build-failure.patch @@ -0,0 +1,37 @@ +From f663f587d6e0ceb0674575db7c8538cf672ae160 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 15 Mar 2019 14:35:12 +0100 +Subject: [PATCH] include: fix build failure + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1646336 +Upstream Status: nftables commit cea0712fe7759 + +commit cea0712fe7759fc1153cd0fd1c882486d036647d +Author: Florian Westphal +Date: Sat Feb 17 23:21:14 2018 +0100 + + include: fix build failure + + on older machine of mine: + ../include/nftables.h:130:30: error: 'UINT_MAX' undeclared (first use in this function) + + Signed-off-by: Florian Westphal +--- + include/nftables.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/nftables.h b/include/nftables.h +index 0abbcaf..2c18c48 100644 +--- a/include/nftables.h ++++ b/include/nftables.h +@@ -3,6 +3,7 @@ + + #include + #include ++#include + #include + + enum numeric_level { +-- +1.8.3.1 + diff --git a/SOURCES/0021-nft.8-Update-meta-pkt_type-value-description.patch b/SOURCES/0021-nft.8-Update-meta-pkt_type-value-description.patch new file mode 100644 index 0000000..6f02302 --- /dev/null +++ b/SOURCES/0021-nft.8-Update-meta-pkt_type-value-description.patch @@ -0,0 +1,51 @@ +From c5911dc74ad3d2858962e3384753c49cc3ad5ebe Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 4 Apr 2019 12:32:26 +0200 +Subject: [PATCH] nft.8: Update meta pkt_type value description + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1628694 +Upstream Status: nftables commit d75e9184bb51a +Conflicts: Changes applied manually to doc/nft.xml, upstream switched to + using asciidoc. + +commit d75e9184bb51a1311ac950b13384f329836d597e +Author: Phil Sutter +Date: Fri Sep 14 11:00:14 2018 +0200 + + nft.8: Update meta pkt_type value description + + Commit 8a7f6de536408 ("meta: fix pkttype name and add 'other' symbol") + deprecated pkt_type value 'unicast' (for it being misleading) and + introduced 'host' and 'other' but it did not update documentation + accordingly. Fix this by replacing 'unicast' with 'host' in + documentation and adding 'other'. + + While being at it, make sure these literal values are recognized as + such: Put them in all lower-case (as required by the parser) and in bold + font (to stand out a bit more). + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + doc/nft.xml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/doc/nft.xml b/doc/nft.xml +index a4a4c3f..12b6cea 100644 +--- a/doc/nft.xml ++++ b/doc/nft.xml +@@ -2734,8 +2734,9 @@ filter output icmpv6 type { echo-request, echo-reply } + + pkt_type + +- Packet type: Unicast (addressed to local host), +- Broadcast (to all), Multicast (to group). ++ Packet type: host (addressed to local host), ++ broadcast (to all), multicast (to group), ++ other (addressed to another host). + + + +-- +1.8.3.1 + diff --git a/SOURCES/0022-doc-Add-minimal-description-of-v-map-statements.patch b/SOURCES/0022-doc-Add-minimal-description-of-v-map-statements.patch new file mode 100644 index 0000000..392f1e9 --- /dev/null +++ b/SOURCES/0022-doc-Add-minimal-description-of-v-map-statements.patch @@ -0,0 +1,104 @@ +From 3344672e56bad6468981d1bf683c312b18957671 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 4 Apr 2019 13:02:55 +0200 +Subject: [PATCH] doc: Add minimal description of (v)map statements + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1628974 +Upstream Status: nftables commit 3b29acc8f2994 +Conflicts: Changes applied manually to doc/nft.xml, upstream switched to + using asciidoc. + +commit 3b29acc8f29944c5cf34259f2e2b5b40b4d0ccdd +Author: Phil Sutter +Date: Tue Apr 2 15:36:42 2019 +0200 + + doc: Add minimal description of (v)map statements + + Although quite useful, these were missing in man page. Content loosely + based on wiki documentation. + + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso +--- + doc/nft.xml | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 65 insertions(+) + +diff --git a/doc/nft.xml b/doc/nft.xml +index 12b6cea..5ab363f 100644 +--- a/doc/nft.xml ++++ b/doc/nft.xml +@@ -5012,6 +5012,71 @@ add rule nat prerouting tcp dport 22 redirect to :2222 + + + ++ ++ Map statement ++ ++ The map statement is used to lookup data based on some specific input key. ++ ++ ++ ++ expression ++ map { ++ key ++ : ++ value ++ ++ , ++ key ++ : ++ value ++ ++ } ++ ++ ++ ++ using the map statement ++ ++# select DNAT target based on TCP dport: ++# connections to port 80 are redirected to 192.168.1.100, ++# connections to port 8888 are redirected to 192.168.1.101 ++nft add rule ip nat prerouting dnat tcp dport map { 80 : 192.168.1.100, 8888 : 192.168.1.101 } ++ ++# source address based SNAT: ++# packets from net 192.168.1.0/24 will appear as originating from 10.0.0.1, ++# packets from net 192.168.2.0/24 will appear as originating from 10.0.0.2 ++nft add rule ip nat postrouting snat to ip saddr map { 192.168.1.0/24 : 10.0.0.1, 192.168.2.0/24 : 10.0.0.2 } ++ ++ ++ ++ ++ Vmap statement ++ ++ The verdict map (vmap) statement works analogous to the map statement, but contains verdicts as values. ++ ++ ++ ++ expression ++ vmap { ++ key ++ : ++ value ++ ++ , ++ key ++ : ++ value ++ ++ } ++ ++ ++ ++ using the vmap statement ++ ++# jump to different chains depending on layer 4 protocol type: ++nft add rule ip filter input ip protocol vmap { tcp : jump tcp-chain, udp : jump udp-chain , icmp : jump icmp-chain } ++ ++ ++ + + + +-- +1.8.3.1 + diff --git a/SOURCES/nft.8 b/SOURCES/nft.8 new file mode 100644 index 0000000..971784c --- /dev/null +++ b/SOURCES/nft.8 @@ -0,0 +1,4768 @@ +'\" t -*- coding: us-ascii -*- +.if \n(.g .ds T< \\FC +.if \n(.g .ds T> \\F[\n[.fam]] +.de URL +\\$2 \(la\\$1\(ra\\$3 +.. +.if \n(.g .mso www.tmac +.TH nft 8 "4 April 2019" "" "" +.SH NAME +nft \- Administration tool for packet filtering and classification +.SH SYNOPSIS +'nh +.fi +.ad l +\fBnft\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fB-n\fR | \fB--numeric\fR] [\fB-N\fR | \fB--reversedns\fR] [\fB-s\fR | \fB--stateless\fR] [\fB-c\fR | \fB--check\fR] [\fB-a\fR | \fB--handle\fR] [\fB-e\fR | \fB--echo\fR] [ +{\fB-I\fR | \fB--includepath\fR} +\fIdirectory\fR +] [ +{\fB-f\fR | \fB--file\fR} +\fIfilename\fR +| +{\fB-i\fR | \fB--interactive\fR} +| +\fIcmd\fR +\&...] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBnft\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fB-h\fR | \fB--help\fR] [\fB-v\fR | \fB--version\fR] +'in \n(.iu-\nxu +.ad b +'hy +.SH DESCRIPTION +nft is used to set up, maintain and inspect packet +filtering and classification rules in the Linux kernel. +.SH OPTIONS +For a full summary of options, run \fBnft --help\fR. +.TP +\*(T<\fB\-h, \-\-help\fR\*(T> +Show help message and all options. +.TP +\*(T<\fB\-v, \-\-version\fR\*(T> +Show version. +.TP +\*(T<\fB\-n, \-\-numeric\fR\*(T> +Show data numerically. When used once (the default behaviour), skip +lookup of addresses to symbolic names. Use twice to also show Internet +services (port numbers) numerically. Use three times to also show +protocols and UIDs/GIDs numerically. +.TP +\*(T<\fB\-s, \-\-stateless\fR\*(T> +Omit stateful information of rules and stateful objects. +.TP +\*(T<\fB\-c, \-\-check\fR\*(T> +Check commands validity without actually applying the changes. +.TP +\*(T<\fB\-N, \-\-reversedns\fR\*(T> +Translate IP addresses to names. Usually requires network traffic for DNS lookup. +.TP +\*(T<\fB\-a, \-\-handle\fR\*(T> +Show rule handles in output. +.TP +\*(T<\fB\-e, \-\-echo\fR\*(T> +When inserting items into the ruleset using \fBadd\fR, +\fBinsert\fR or \fBreplace\fR commands, +print notifications just like \fBnft monitor\fR. +.TP +\*(T<\fB\-I, \-\-includepath \fR\*(T>\fIdirectory\fR +Add the directory \fIdirectory\fR to the list of directories to be searched for included files. This option may be specified multiple times. +.TP +\*(T<\fB\-f, \-\-file \fR\*(T>\fIfilename\fR +Read input from \fIfilename\fR. +.TP +\*(T<\fB\-i, \-\-interactive\fR\*(T> +Read input from an interactive readline CLI. +.SH "INPUT FILE FORMAT" +.SS "LEXICAL CONVENTIONS" +Input is parsed line-wise. When the last character of a line, just before +the newline character, is a non-quoted backslash (\*(T<\e\*(T>), +the next line is treated as a continuation. Multiple commands on the +same line can be separated using a semicolon (\*(T<;\*(T>). +.PP +A hash sign (\*(T<#\*(T>) begins a comment. All following characters +on the same line are ignored. +.PP +Identifiers begin with an alphabetic character (\*(T), +followed zero or more alphanumeric characters (\*(T) +and the characters slash (\*(T), backslash (\*(T<\e\*(T>), +underscore (\*(T<_\*(T>) and dot (\*(T<.\*(T>). Identifiers +using different characters or clashing with a keyword need to be enclosed in +double quotes (\*(T<"\*(T>). +.PP +.SS "INCLUDE FILES" +'nh +.fi +.ad l +\fBinclude\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +\fIfilename\fR +'in \n(.iu-\nxu +.ad b +'hy +.PP +Other files can be included by using the \fBinclude\fR statement. +The directories to be searched for include files can be specified using +the \*(T<\fB\-I/\-\-includepath\fR\*(T> option. You can override this behaviour +either by prepending ./ to your path to force inclusion of files located in the +current working directory (ie. relative path) or / for file location expressed +as an absolute path. +.PP +If -I/--includepath is not specified, then nft relies on the default directory +that is specified at compile time. You can retrieve this default directory via +-h/--help option. +.PP +Include statements support the usual shell wildcard symbols +(\*(T<*,?,[]\*(T>). Having no matches for an include statement is not +an error, if wildcard symbols are used in the include statement. This allows having +potentially empty include directories for statements like +\*(T. The wildcard matches are +loaded in alphabetical order. Files beginning with dot (\*(T<.\*(T>) are +not matched by include statements. +.SS "SYMBOLIC VARIABLES" +'nh +.fi +.ad l +\fBdefine\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +variable \fIexpr\fR +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fB$variable\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +'in \n(.iu-\nxu +.ad b +'hy +.PP +Symbolic variables can be defined using the \fBdefine\fR statement. +Variable references are expressions and can be used initialize other variables. +The scope of a definition is the current block and all blocks contained within. + +\fBUsing symbolic variables\fR +.PP +.nf +\*(T< +define int_if1 = eth0 +define int_if2 = eth1 +define int_ifs = { $int_if1, $int_if2 } + +filter input iif $int_ifs accept + \*(T> +.fi +.SH "ADDRESS FAMILIES" +Address families determine the type of packets which are processed. For each address +family the kernel contains so called hooks at specific stages of the packet processing +paths, which invoke nftables if rules for these hooks exist. +.PP +.TP +\*(T<\fBip\fR\*(T> +IPv4 address family. +.TP +\*(T<\fBip6\fR\*(T> +IPv6 address family. +.TP +\*(T<\fBinet\fR\*(T> +Internet (IPv4/IPv6) address family. +.TP +\*(T<\fBarp\fR\*(T> +ARP address family, handling IPv4 ARP packets. +.TP +\*(T<\fBbridge\fR\*(T> +Bridge address family, handling packets which traverse a bridge device. +.TP +\*(T<\fBnetdev\fR\*(T> +Netdev address family, handling packets from ingress. +.PP +All nftables objects exist in address family specific namespaces, therefore +all identifiers include an address family. If an identifier is specified without +an address family, the \*(T family is used by default. +.SS "IPV4/IPV6/INET ADDRESS FAMILIES" +The IPv4/IPv6/Inet address families handle IPv4, IPv6 or both types of packets. They +contain five hooks at different packet processing stages in the network stack. +.PP +\fBIPv4/IPv6/Inet address family hooks\fR +.TS +allbox ; +l | l. +T{ +Hook +T} T{ +Description +T} +.T& +l | l. +T{ +prerouting +T} T{ +All packets entering the system are processed by the prerouting hook. It is invoked +before the routing process and is used for early filtering or changing packet +attributes that affect routing. +T} +T{ +input +T} T{ +Packets delivered to the local system are processed by the input hook. +T} +T{ +forward +T} T{ +Packets forwarded to a different host are processed by the forward hook. +T} +T{ +output +T} T{ +Packets sent by local processes are processed by the output hook. +T} +T{ +postrouting +T} T{ +All packets leaving the system are processed by the postrouting hook. +T} +.TE +.SS "ARP ADDRESS FAMILY" +The ARP address family handles ARP packets received and sent by the system. It is commonly used +to mangle ARP packets for clustering. +.PP +\fBARP address family hooks\fR +.TS +allbox ; +l | l. +T{ +Hook +T} T{ +Description +T} +.T& +l | l +l | l. +T{ +input +T} T{ +Packets delivered to the local system are processed by the input hook. +T} +T{ +output +T} T{ +Packets send by the local system are processed by the output hook. +T} +.TE +.SS "BRIDGE ADDRESS FAMILY" +The bridge address family handles ethernet packets traversing bridge devices. +.PP +The list of supported hooks is identical to IPv4/IPv6/Inet address families above. +.SS "NETDEV ADDRESS FAMILY" +The Netdev address family handles packets from ingress. +.PP +\fBNetdev address family hooks\fR +.TS +allbox ; +l | l. +T{ +Hook +T} T{ +Description +T} +.T& +l | l. +T{ +ingress +T} T{ +All packets entering the system are processed by this hook. It is invoked +before layer 3 protocol handlers and it can be used for early filtering and +policing. +T} +.TE +.SH RULESET +'nh +.fi +.ad l +{list | flush} \fBruleset\fR [\fIfamily\fR] +.ad b +'hy +.PP +The \fBruleset\fR keyword is used to identify the whole +set of tables, chains, etc. currently in place in kernel. The +following \fBruleset\fR commands exist: +.TP +\*(T<\fBlist\fR\*(T> +Print the ruleset in human-readable format. +.TP +\*(T<\fBflush\fR\*(T> +Clear the whole ruleset. Note that unlike iptables, this +will remove all tables and whatever they contain, +effectively leading to an empty ruleset - no packet +filtering will happen anymore, so the kernel accepts any +valid packet it receives. +.PP +It is possible to limit \fBlist\fR and +\fBflush\fR to a specific address family only. For a +list of valid family names, see \*(T
above. +.PP +By design, \fBlist ruleset\fR command output may be used as +input to \fBnft -f\fR. Effectively, this is the nft-equivalent +of \fBiptables-save\fR and \fBiptables-restore\fR. +.SH TABLES +'nh +.fi +.ad l +{add | delete | list | flush} \fBtable\fR [\fIfamily\fR] {\fItable\fR} +.ad b +'hy +.PP +Tables are containers for chains, sets and stateful objects. They are identified by their address family +and their name. The address family must be one of +\*(T, \*(T, \*(T, \*(T, \*(T, \*(T. +The \*(T address family is a dummy family which is used to create +hybrid IPv4/IPv6 tables. The \*(T expression \*(T +keyword can be used to test which family (ipv4 or ipv6) context the packet is being processed in. +When no address family is specified, \*(T is used by default. +.TP +\*(T<\fBadd\fR\*(T> +Add a new table for the given family with the given name. +.TP +\*(T<\fBdelete\fR\*(T> +Delete the specified table. +.TP +\*(T<\fBlist\fR\*(T> +List all chains and rules of the specified table. +.TP +\*(T<\fBflush\fR\*(T> +Flush all chains and rules of the specified table. +.SH CHAINS +'nh +.fi +.ad l +{add | create} \fBchain\fR [\fIfamily\fR] \fItable\fR \fIchain\fR [ +{ +{\fItype\fR} +{\fIhook\fR} +[\fIdevice\fR] +{\fIpriority\fR ;} +[\fIpolicy\fR ;] +} +] +.ad b +'hy +'nh +.fi +.ad l +{delete | list | flush} \fBchain\fR [\fIfamily\fR] {\fItable\fR} {\fIchain\fR} +.ad b +'hy +'nh +.fi +.ad l +{rename} \fBchain\fR [\fIfamily\fR] {\fItable\fR} {\fIchain\fR} {\fInewname\fR} +.ad b +'hy +.PP +Chains are containers for rules. They exist in two kinds, +base chains and regular chains. A base chain is an entry point for +packets from the networking stack, a regular chain may be used +as jump target and is used for better rule organization. +.TP +\*(T<\fBadd\fR\*(T> +Add a new chain in the specified table. When a hook and priority +value are specified, the chain is created as a base chain and hooked +up to the networking stack. +.TP +\*(T<\fBcreate\fR\*(T> +Similar to the \fBadd\fR command, but returns an error if the +chain already exists. +.TP +\*(T<\fBdelete\fR\*(T> +Delete the specified chain. The chain must not contain any rules or be +used as jump target. +.TP +\*(T<\fBrename\fR\*(T> +Rename the specified chain. +.TP +\*(T<\fBlist\fR\*(T> +List all rules of the specified chain. +.TP +\*(T<\fBflush\fR\*(T> +Flush all rules of the specified chain. +.PP +For base chains, \fBtype\fR, \fBhook\fR and \fBpriority\fR parameters are mandatory. +.PP +\fBSupported chain types\fR +.TS +allbox ; +l | l | l | l. +T{ +Type +T} T{ +Families +T} T{ +Hooks +T} T{ +Description +T} +.T& +l | l | l | l +l | l | l | l +l | l | l | l. +T{ +filter +T} T{ +all +T} T{ +all +T} T{ +Standard chain type to use in doubt. +T} +T{ +nat +T} T{ +ip, ip6 +T} T{ +prerouting, input, output, postrouting +T} T{ +Chains of this type perform Native Address Translation based on conntrack entries. Only the first packet of a connection actually traverses this chain - its rules usually define details of the created conntrack entry (NAT statements for instance). +T} +T{ +route +T} T{ +ip, ip6 +T} T{ +output +T} T{ +If a packet has traversed a chain of this +type and is about to be accepted, a new route +lookup is performed if relevant parts of the IP +header have changed. This allows to e.g. +implement policy routing selectors in +nftables. +T} +.TE +.PP +Apart from the special cases illustrated above (e.g. \*(T type not supporting \*(T hook or \*(T type only supporting \*(T hook), there are two further quirks worth noticing: +.TP 0.2i +\(bu +\*(T family supports merely a single +combination, namely \*(T type and +\*(T hook. Base chains in this family also require the \*(T parameter to be present since they exist per incoming interface only. +.TP 0.2i +\(bu +\*(T family supports only +\*(T and \*(T +hooks, both in chains of type +\*(T. +.PP +The \*(T parameter accepts a signed integer value which specifies the order in which chains with same \*(T value are traversed. The ordering is ascending, i.e. lower priority values have precedence over higher ones. +.PP +Base chains also allow to set the chain's \*(T, i.e. what happens to packets not explicitly accepted or refused in contained rules. Supported policy values are \*(T (which is the default) or \*(T. +.SH RULES +'nh +.fi +.ad l +[add | insert] \fBrule\fR [\fIfamily\fR] {\fItable\fR} {\fIchain\fR} [ +{handle | position} +\fIhandle\fR +] {\fIstatement\fR}\&... +.ad b +'hy +'nh +.fi +.ad l +{replace} \fBrule\fR [\fIfamily\fR] {\fItable\fR} {\fIchain\fR} {handle \fIhandle\fR} {\fIstatement\fR}\&... +.ad b +'hy +'nh +.fi +.ad l +{delete} \fBrule\fR [\fIfamily\fR] {\fItable\fR} {\fIchain\fR} {handle \fIhandle\fR} +.ad b +'hy +.PP +Rules are constructed from two kinds of components according to a set +of grammatical rules: expressions and statements. +.TP +\*(T<\fBadd\fR\*(T> +Add a new rule described by the list of statements. The rule is appended to the +given chain unless a \*(T is specified, in which case the +rule is appended to the rule given by the \fIhandle\fR. +The alternative name \*(T is deprecated and should not be +used anymore. +.TP +\*(T<\fBinsert\fR\*(T> +Similar to the \fBadd\fR command, but the rule is prepended to the +beginning of the chain or before the rule with the given +\fIhandle\fR. +.TP +\*(T<\fBreplace\fR\*(T> +Similar to the \fBadd\fR command, but the rule replaces the specified rule. +.TP +\*(T<\fBdelete\fR\*(T> +Delete the specified rule. +.SH SETS +'nh +.fi +.ad l +{add} \fBset\fR [\fIfamily\fR] {\fItable\fR} {\fIset\fR} +{ +{\fItype\fR} [\fIflags\fR] [\fItimeout\fR] [\fIgc-interval\fR] [\fIelements\fR] [\fIsize\fR] [\fIpolicy\fR] +} +.ad b +'hy +'nh +.fi +.ad l +{delete | list | flush} \fBset\fR [\fIfamily\fR] {\fItable\fR} {\fIset\fR} +.ad b +'hy +'nh +.fi +.ad l +{add | delete} \fBelement\fR [\fIfamily\fR] {\fItable\fR} {\fIset\fR} +{ +{\fIelements\fR} +} +.ad b +'hy +.PP +Sets are elements containers of an user-defined data type, they are uniquely identified by an user-defined name and attached to tables. +.TP +\*(T<\fBadd\fR\*(T> +Add a new set in the specified table. +.TP +\*(T<\fBdelete\fR\*(T> +Delete the specified set. +.TP +\*(T<\fBlist\fR\*(T> +Display the elements in the specified set. +.TP +\*(T<\fBflush\fR\*(T> +Remove all elements from the specified set. +.TP +\*(T<\fBadd element\fR\*(T> +Comma-separated list of elements to add into the specified set. +.TP +\*(T<\fBdelete element\fR\*(T> +Comma-separated list of elements to delete from the specified set. +.PP +\fBSet specifications\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +type +T} T{ +data type of set elements +T} T{ +string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark +T} +T{ +flags +T} T{ +set flags +T} T{ +string: constant, interval, timeout +T} +T{ +timeout +T} T{ +time an element stays in the set +T} T{ +string, decimal followed by unit. Units are: d, h, m, s +T} +T{ +gc-interval +T} T{ +garbage collection interval, only available when timeout or flag timeout are active +T} T{ +string, decimal followed by unit. Units are: d, h, m, s +T} +T{ +elements +T} T{ +elements contained by the set +T} T{ +set data type +T} +T{ +size +T} T{ +maximun number of elements in the set +T} T{ +unsigned integer (64 bit) +T} +T{ +policy +T} T{ +set policy +T} T{ +string: performance [default], memory +T} +.TE +.SH MAPS +'nh +.fi +.ad l +{add} \fBmap\fR [\fIfamily\fR] {\fItable\fR} {\fImap\fR} +{ +{\fItype\fR} [\fIflags\fR] [\fIelements\fR] [\fIsize\fR] [\fIpolicy\fR] +} +.ad b +'hy +'nh +.fi +.ad l +{delete | list | flush} \fBmap\fR [\fIfamily\fR] {\fItable\fR} {\fImap\fR} +.ad b +'hy +'nh +.fi +.ad l +{add | delete} \fBelement\fR [\fIfamily\fR] {\fItable\fR} {\fImap\fR} +{ +{\fIelements\fR} +} +.ad b +'hy +.PP +Maps store data based on some specific key used as input, they are uniquely identified by an user-defined name and attached to tables. +.TP +\*(T<\fBadd\fR\*(T> +Add a new map in the specified table. +.TP +\*(T<\fBdelete\fR\*(T> +Delete the specified map. +.TP +\*(T<\fBlist\fR\*(T> +Display the elements in the specified map. +.TP +\*(T<\fBflush\fR\*(T> +Remove all elements from the specified map. +.TP +\*(T<\fBadd element\fR\*(T> +Comma-separated list of elements to add into the specified map. +.TP +\*(T<\fBdelete element\fR\*(T> +Comma-separated list of element keys to delete from the specified map. +.PP +\fBMap specifications\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +type +T} T{ +data type of map elements +T} T{ +string ':' string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark, counter, quota. Counter and quota can't be used as keys +T} +T{ +flags +T} T{ +map flags +T} T{ +string: constant, interval +T} +T{ +elements +T} T{ +elements contained by the map +T} T{ +map data type +T} +T{ +size +T} T{ +maximun number of elements in the map +T} T{ +unsigned integer (64 bit) +T} +T{ +policy +T} T{ +map policy +T} T{ +string: performance [default], memory +T} +.TE +.SH "STATEFUL OBJECTS" +'nh +.fi +.ad l +{add | delete | list | reset} \fBtype\fR [\fIfamily\fR] {\fItable\fR} {\fIobject\fR} +.ad b +'hy +.PP +Stateful objects are attached to tables and are identified by an unique name. They group stateful information from rules, to reference them in rules the keywords "type name" are used e.g. "counter name". +.TP +\*(T<\fBadd\fR\*(T> +Add a new stateful object in the specified table. +.TP +\*(T<\fBdelete\fR\*(T> +Delete the specified object. +.TP +\*(T<\fBlist\fR\*(T> +Display stateful information the object holds. +.TP +\*(T<\fBreset\fR\*(T> +List-and-reset stateful object. +.SS CT +'nh +.fi +.ad l +\fBct\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{helper} {type} {\fItype\fR} {protocol} {\fIprotocol\fR} [l3proto] [\fIfamily\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +Ct helper is used to define connection tracking helpers that can then be used in combination with the \*(T<"ct helper set"\*(T> statement. +type and protocol are mandatory, l3proto is derived from the table family by default, i.e. in the inet table the kernel will +try to load both the ipv4 and ipv6 helper backends, if they are supported by the kernel. +.PP +\fBconntrack helper specifications\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +type +T} T{ +name of helper type +T} T{ +quoted string (e.g. "ftp") +T} +T{ +protocol +T} T{ +layer 4 protocol of the helper +T} T{ +string (e.g. tcp) +T} +T{ +l3proto +T} T{ +layer 3 protocol of the helper +T} T{ +address family (e.g. ip) +T} +.TE +.PP +\fBdefining and assigning ftp helper\fR +.PP +Unlike iptables, helper assignment needs to be performed after the conntrack lookup has completed, for example +with the default 0 hook priority. +.PP +.nf +\*(T< +table inet myhelpers { + ct helper ftp\-standard { + type "ftp" protocol tcp + } + chain prerouting { + type filter hook prerouting priority 0; + tcp dport 21 ct helper set "ftp\-standard" + } +} + \*(T> +.fi +.SS COUNTER +'nh +.fi +.ad l +\fBcounter\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[packets bytes] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBCounter specifications\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l. +T{ +packets +T} T{ +initial count of packets +T} T{ +unsigned integer (64 bit) +T} +T{ +bytes +T} T{ +initial count of bytes +T} T{ +unsigned integer (64 bit) +T} +.TE +.SS QUOTA +'nh +.fi +.ad l +\fBquota\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[over | until] [used] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBQuota specifications\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l. +T{ +quota +T} T{ +quota limit, used as the quota name +T} T{ +Two arguments, unsigned interger (64 bit) and string: bytes, kbytes, mbytes. "over" and "until" go before these arguments +T} +T{ +used +T} T{ +initial value of used quota +T} T{ +Two arguments, unsigned interger (64 bit) and string: bytes, kbytes, mbytes +T} +.TE +.SH EXPRESSIONS +Expressions represent values, either constants like network addresses, port numbers etc. or data +gathered from the packet during ruleset evaluation. Expressions can be combined using binary, +logical, relational and other types of expressions to form complex or relational (match) expressions. +They are also used as arguments to certain types of operations, like NAT, packet marking etc. +.PP +Each expression has a data type, which determines the size, parsing and representation of +symbolic values and type compatibility with other expressions. +.SS "DESCRIBE COMMAND" +'nh +.fi +.ad l +\fBdescribe\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{\fIexpression\fR} +'in \n(.iu-\nxu +.ad b +'hy +.PP +The \fBdescribe\fR command shows information about the type of an expression and +its data type. +.PP +\fBThe describe command\fR +.PP +.nf +\*(T< +$ nft describe tcp flags +payload expression, datatype tcp_flag (TCP flag) (basetype bitmask, integer), 8 bits + +pre\-defined symbolic constants: +fin 0x01 +syn 0x02 +rst 0x04 +psh 0x08 +ack 0x10 +urg 0x20 +ecn 0x40 +cwr 0x80 + \*(T> +.fi +.SH "DATA TYPES" +Data types determine the size, parsing and representation of symbolic values and type compatibility +of expressions. A number of global data types exist, in addition some expression types define further +data types specific to the expression type. Most data types have a fixed size, some however may have +a dynamic size, f.i. the string type. +.PP +Types may be derived from lower order types, f.i. the IPv4 address type is derived from the integer +type, meaning an IPv4 address can also be specified as an integer value. +.PP +In certain contexts (set and map definitions) it is necessary to explicitly specify a data type. +Each type has a name which is used for this. +.SS "INTEGER TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +Integer +T} T{ +integer +T} T{ +variable +T} T{ +- +T} +.TE +.PP +The integer type is used for numeric values. It may be specified as decimal, hexadecimal +or octal number. The integer type doesn't have a fixed size, its size is determined by the +expression for which it is used. +.SS "BITMASK TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +Bitmask +T} T{ +bitmask +T} T{ +variable +T} T{ +integer +T} +.TE +.PP +The bitmask type (\fBbitmask\fR) is used for bitmasks. +.SS "STRING TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +String +T} T{ +string +T} T{ +variable +T} T{ +- +T} +.TE +.PP +The string type is used to for character strings. A string begins with an alphabetic character +(a-zA-Z) followed by zero or more alphanumeric characters or the characters \*(T, +\*(T<\-\*(T>, \*(T<_\*(T> and \*(T<.\*(T>. In addition anything enclosed +in double quotes (\*(T<"\*(T>) is recognized as a string. +.PP +\fBString specification\fR +.PP +.nf +\*(T< +# Interface name +filter input iifname eth0 + +# Weird interface name +filter input iifname "(eth0)" + \*(T> +.fi +.SS "LINK LAYER ADDRESS TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +Link layer address +T} T{ +lladdr +T} T{ +variable +T} T{ +integer +T} +.TE +.PP +The link layer address type is used for link layer addresses. Link layer addresses are specified +as a variable amount of groups of two hexadecimal digits separated using colons (\*(T<:\*(T>). +.PP +\fBLink layer address specification\fR +.PP +.nf +\*(T< +# Ethernet destination MAC address +filter input ether daddr 20:c9:d0:43:12:d9 + \*(T> +.fi +.SS "IPV4 ADDRESS TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +IPv4 address +T} T{ +ipv4_addr +T} T{ +32 bit +T} T{ +integer +T} +.TE +.PP +The IPv4 address type is used for IPv4 addresses. Addresses are specified in either dotted decimal, +dotted hexadecimal, dotted octal, decimal, hexadecimal, octal notation or as a host name. A host name +will be resolved using the standard system resolver. +.PP +\fBIPv4 address specification\fR +.PP +.nf +\*(T< +# dotted decimal notation +filter output ip daddr 127.0.0.1 + +# host name +filter output ip daddr localhost + \*(T> +.fi +.SS "IPV6 ADDRESS TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +IPv6 address +T} T{ +ipv6_addr +T} T{ +128 bit +T} T{ +integer +T} +.TE +.PP +The IPv6 address type is used for IPv6 addresses. FIXME +.PP +\fBIPv6 address specification\fR +.PP +.nf +\*(T< +# abbreviated loopback address +filter output ip6 daddr ::1 + \*(T> +.fi +.SS "BOOLEAN TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +Boolean +T} T{ +boolean +T} T{ +1 bit +T} T{ +integer +T} +.TE +.PP +The boolean type is a syntactical helper type in user space. +It's use is in the right-hand side of a (typically implicit) +relational expression to change the expression on the left-hand +side into a boolean check (usually for existence). +.PP +The following keywords will automatically resolve into a boolean +type with given value: +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l +l | l. +T{ +exists +T} T{ +1 +T} +T{ +missing +T} T{ +0 +T} +.TE +.PP +\fBBoolean specification\fR +.PP +The following expressions support a boolean comparison: +.TS +allbox ; +l | l. +T{ +Expression +T} T{ +Behaviour +T} +.T& +l | l +l | l +l | l. +T{ +fib +T} T{ +Check route existence. +T} +T{ +exthdr +T} T{ +Check IPv6 extension header existence. +T} +T{ +tcp option +T} T{ +Check TCP option header existence. +T} +.TE +.PP +.nf +\*(T< +# match if route exists +filter input fib daddr . iif oif exists + +# match only non\-fragmented packets in IPv6 traffic +filter input exthdr frag missing + +# match if TCP timestamp option is present +filter input tcp option timestamp exists + \*(T> +.fi +.SS "ICMP TYPE TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +ICMP Type +T} T{ +icmp_type +T} T{ +8 bit +T} T{ +integer +T} +.TE +.PP +The ICMP Type type is used to conveniently specify the ICMP header's type field. +.PP +The following keywords may be used when specifying the ICMP type: +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +echo-reply +T} T{ +0 +T} +T{ +destination-unreachable +T} T{ +3 +T} +T{ +source-quench +T} T{ +4 +T} +T{ +redirect +T} T{ +5 +T} +T{ +echo-request +T} T{ +8 +T} +T{ +router-advertisement +T} T{ +9 +T} +T{ +router-solicitation +T} T{ +10 +T} +T{ +time-exceeded +T} T{ +11 +T} +T{ +parameter-problem +T} T{ +12 +T} +T{ +timestamp-request +T} T{ +13 +T} +T{ +timestamp-reply +T} T{ +14 +T} +T{ +info-request +T} T{ +15 +T} +T{ +info-reply +T} T{ +16 +T} +T{ +address-mask-request +T} T{ +17 +T} +T{ +address-mask-reply +T} T{ +18 +T} +.TE +.PP +\fBICMP Type specification\fR +.PP +.nf +\*(T< +# match ping packets +filter output icmp type { echo\-request, echo\-reply } + \*(T> +.fi +.SS "ICMP CODE TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +ICMP Code +T} T{ +icmp_code +T} T{ +8 bit +T} T{ +integer +T} +.TE +.PP +The ICMP Code type is used to conveniently specify the ICMP header's code field. +.PP +The following keywords may be used when specifying the ICMP code: +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +net-unreachable +T} T{ +0 +T} +T{ +host-unreachable +T} T{ +1 +T} +T{ +prot-unreachable +T} T{ +2 +T} +T{ +port-unreachable +T} T{ +3 +T} +T{ +net-prohibited +T} T{ +9 +T} +T{ +host-prohibited +T} T{ +10 +T} +T{ +admin-prohibited +T} T{ +13 +T} +.TE +.SS "ICMPV6 TYPE TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +ICMPv6 Type +T} T{ +icmpv6_type +T} T{ +8 bit +T} T{ +integer +T} +.TE +.PP +The ICMPv6 Type type is used to conveniently specify the ICMPv6 header's type field. +.PP +The following keywords may be used when specifying the ICMPv6 type: +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +destination-unreachable +T} T{ +1 +T} +T{ +packet-too-big +T} T{ +2 +T} +T{ +time-exceeded +T} T{ +3 +T} +T{ +parameter-problem +T} T{ +4 +T} +T{ +echo-request +T} T{ +128 +T} +T{ +echo-reply +T} T{ +129 +T} +T{ +mld-listener-query +T} T{ +130 +T} +T{ +mld-listener-report +T} T{ +131 +T} +T{ +mld-listener-done +T} T{ +132 +T} +T{ +mld-listener-reduction +T} T{ +132 +T} +T{ +nd-router-solicit +T} T{ +133 +T} +T{ +nd-router-advert +T} T{ +134 +T} +T{ +nd-neighbor-solicit +T} T{ +135 +T} +T{ +nd-neighbor-advert +T} T{ +136 +T} +T{ +nd-redirect +T} T{ +137 +T} +T{ +router-renumbering +T} T{ +138 +T} +T{ +ind-neighbor-solicit +T} T{ +141 +T} +T{ +ind-neighbor-advert +T} T{ +142 +T} +T{ +mld2-listener-report +T} T{ +143 +T} +.TE +.PP +\fBICMPv6 Type specification\fR +.PP +.nf +\*(T< +# match ICMPv6 ping packets +filter output icmpv6 type { echo\-request, echo\-reply } + \*(T> +.fi +.SS "ICMPV6 CODE TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +ICMPv6 Code +T} T{ +icmpv6_code +T} T{ +8 bit +T} T{ +integer +T} +.TE +.PP +The ICMPv6 Code type is used to conveniently specify the ICMPv6 header's code field. +.PP +The following keywords may be used when specifying the ICMPv6 code: +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +no-route +T} T{ +0 +T} +T{ +admin-prohibited +T} T{ +1 +T} +T{ +addr-unreachable +T} T{ +3 +T} +T{ +port-unreachable +T} T{ +4 +T} +T{ +policy-fail +T} T{ +5 +T} +T{ +reject-route +T} T{ +6 +T} +.TE +.SS "ICMPVX CODE TYPE" +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +ICMPvX Code +T} T{ +icmpx_code +T} T{ +8 bit +T} T{ +integer +T} +.TE +.PP +The ICMPvX Code type abstraction is a set of values which +overlap between ICMP and ICMPv6 Code types to be used from the +inet family. +.PP +The following keywords may be used when specifying the ICMPvX code: +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +no-route +T} T{ +0 +T} +T{ +port-unreachable +T} T{ +1 +T} +T{ +host-unreachable +T} T{ +2 +T} +T{ +admin-prohibited +T} T{ +3 +T} +.TE +.SS "CONNTRACK TYPES" +This is an overview of types used in \fBct\fR +expression and statement: +.TS +allbox ; +l | l | l | l. +T{ +Name +T} T{ +Keyword +T} T{ +Size +T} T{ +Base type +T} +.T& +l | l | l | l. +T{ +conntrack state +T} T{ +ct_state +T} T{ +4 byte +T} T{ +bitmask +T} +T{ +conntrack direction +T} T{ +ct_dir +T} T{ +8 bit +T} T{ +integer +T} +T{ +conntrack status +T} T{ +ct_status +T} T{ +4 byte +T} T{ +bitmask +T} +T{ +conntrack event bits +T} T{ +ct_event +T} T{ +4 byte +T} T{ +bitmask +T} +T{ +conntrack label +T} T{ +ct_label +T} T{ +128 bit +T} T{ +bitmask +T} +.TE +.PP +For each of the types above, keywords are available for convenience: + +\fBconntrack state (ct_state)\fR +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +invalid +T} T{ +1 +T} +T{ +established +T} T{ +2 +T} +T{ +related +T} T{ +4 +T} +T{ +new +T} T{ +8 +T} +T{ +untracked +T} T{ +64 +T} +.TE +.PP +\fBconntrack direction (ct_dir)\fR +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l +l | l. +T{ +original +T} T{ +0 +T} +T{ +reply +T} T{ +1 +T} +.TE +.PP +\fBconntrack status (ct_status)\fR +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +expected +T} T{ +1 +T} +T{ +seen-reply +T} T{ +2 +T} +T{ +assured +T} T{ +4 +T} +T{ +confirmed +T} T{ +8 +T} +T{ +snat +T} T{ +16 +T} +T{ +dnat +T} T{ +32 +T} +T{ +dying +T} T{ +512 +T} +.TE +.PP +\fBconntrack event bits (ct_event)\fR +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Value +T} +.T& +l | l. +T{ +new +T} T{ +1 +T} +T{ +related +T} T{ +2 +T} +T{ +destroy +T} T{ +4 +T} +T{ +reply +T} T{ +8 +T} +T{ +assured +T} T{ +16 +T} +T{ +protoinfo +T} T{ +32 +T} +T{ +helper +T} T{ +64 +T} +T{ +mark +T} T{ +128 +T} +T{ +seqadj +T} T{ +256 +T} +T{ +secmark +T} T{ +512 +T} +T{ +label +T} T{ +1024 +T} +.TE +.PP +Possible keywords for conntrack label type +(\fBct_label\fR) are read at runtime from +\*(T. +.SH "PRIMARY EXPRESSIONS" +The lowest order expression is a primary expression, representing either a constant or a single +datum from a packet's payload, meta data or a stateful module. +.SS "META EXPRESSIONS" +'nh +.fi +.ad l +\fBmeta\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{length | nfproto | l4proto | protocol | priority} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +[meta] {mark | iif | iifname | iiftype | oif | oifname | oiftype | skuid | skgid | nftrace | rtclassid | ibriport | obriport | pkttype | cpu | iifgroup | oifgroup | cgroup | random} +.ad b +'hy +.PP +A meta expression refers to meta data associated with a packet. +.PP +There are two types of meta expressions: unqualified and qualified meta expressions. +Qualified meta expressions require the \fBmeta\fR keyword before the +meta key, unqualified meta expressions can be specified by using the meta key directly +or as qualified meta expressions. +.PP +\fBMeta expression types\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +length +T} T{ +Length of the packet in bytes +T} T{ +integer (32 bit) +T} +T{ +nfproto +T} T{ +real hook protocol family, useful only in inet table +T} T{ +integer (32 bit) +T} +T{ +protocol +T} T{ +Ethertype protocol value +T} T{ +ether_type +T} +T{ +priority +T} T{ +TC packet priority +T} T{ +tc_handle +T} +T{ +mark +T} T{ +Packet mark +T} T{ +mark +T} +T{ +iif +T} T{ +Input interface index +T} T{ +iface_index +T} +T{ +iifname +T} T{ +Input interface name +T} T{ +string +T} +T{ +iiftype +T} T{ +Input interface type +T} T{ +iface_type +T} +T{ +oif +T} T{ +Output interface index +T} T{ +iface_index +T} +T{ +oifname +T} T{ +Output interface name +T} T{ +string +T} +T{ +oiftype +T} T{ +Output interface hardware type +T} T{ +iface_type +T} +T{ +skuid +T} T{ +UID associated with originating socket +T} T{ +uid +T} +T{ +skgid +T} T{ +GID associated with originating socket +T} T{ +gid +T} +T{ +rtclassid +T} T{ +Routing realm +T} T{ +realm +T} +T{ +ibriport +T} T{ +Input bridge interface name +T} T{ +string +T} +T{ +obriport +T} T{ +Output bridge interface name +T} T{ +string +T} +T{ +pkttype +T} T{ +packet type +T} T{ +pkt_type +T} +T{ +cpu +T} T{ +cpu number processing the packet +T} T{ +integer (32 bits) +T} +T{ +iifgroup +T} T{ +incoming device group +T} T{ +devgroup +T} +T{ +oifgroup +T} T{ +outgoing device group +T} T{ +devgroup +T} +T{ +cgroup +T} T{ +control group id +T} T{ +integer (32 bits) +T} +T{ +random +T} T{ +pseudo-random number +T} T{ +integer (32 bits) +T} +.TE +.PP +\fBMeta expression specific types\fR +.TS +allbox ; +l | l. +T{ +Type +T} T{ +Description +T} +.T& +l | l. +T{ +iface_index +T} T{ +Interface index (32 bit number). Can be specified numerically +or as name of an existing interface. +T} +T{ +ifname +T} T{ +Interface name (16 byte string). Does not have to exist. +T} +T{ +iface_type +T} T{ +Interface type (16 bit number). +T} +T{ +uid +T} T{ +User ID (32 bit number). Can be specified numerically or as +user name. +T} +T{ +gid +T} T{ +Group ID (32 bit number). Can be specified numerically or as +group name. +T} +T{ +realm +T} T{ +Routing Realm (32 bit number). Can be specified numerically +or as symbolic name defined in /etc/iproute2/rt_realms. +T} +T{ +devgroup_type +T} T{ +Device group (32 bit number). Can be specified numerically +or as symbolic name defined in /etc/iproute2/group. +T} +T{ +pkt_type +T} T{ +Packet type: \*(T (addressed to local host), +\*(T (to all), \*(T (to group), +\*(T (addressed to another host). +T} +.TE +.PP +\fBUsing meta expressions\fR +.PP +.nf +\*(T< +# qualified meta expression +filter output meta oif eth0 + +# unqualified meta expression +filter output oif eth0 + \*(T> +.fi +.SS "FIB EXPRESSIONS" +'nh +.fi +.ad l +\fBfib\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{saddr | daddr | [mark | iif | oif]} {oif | oifname | type} +'in \n(.iu-\nxu +.ad b +'hy +.PP +A fib expression queries the fib (forwarding information base) +to obtain information such as the output interface index a particular address would use. The input is a tuple of elements that is used as input to the fib lookup +functions. +.PP +\fBfib expression specific types\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +oif +T} T{ +Output interface index +T} T{ +integer (32 bit) +T} +T{ +oifname +T} T{ +Output interface name +T} T{ +string +T} +T{ +type +T} T{ +Address type +T} T{ +fib_addrtype +T} +.TE +.PP +\fBUsing fib expressions\fR +.PP +.nf +\*(T< +# drop packets without a reverse path +filter prerouting fib saddr . iif oif missing drop + +# drop packets to address not configured on ininterface +filter prerouting fib daddr . iif type != { local, broadcast, multicast } drop + +# perform lookup in a specific 'blackhole' table (0xdead, needs ip appropriate ip rule) +filter prerouting meta mark set 0xdead fib daddr . mark type vmap { blackhole : drop, prohibit : jump prohibited, unreachable : drop } + \*(T> +.fi +.SS "ROUTING EXPRESSIONS" +'nh +.fi +.ad l +\fBrt\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{classid | nexthop} +'in \n(.iu-\nxu +.ad b +'hy +.PP +A routing expression refers to routing data associated with a packet. +.PP +\fBRouting expression types\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +classid +T} T{ +Routing realm +T} T{ +realm +T} +T{ +nexthop +T} T{ +Routing nexthop +T} T{ +ipv4_addr/ipv6_addr +T} +T{ +mtu +T} T{ +TCP maximum segment size of route +T} T{ +integer (16 bit) +T} +.TE +.PP +\fBRouting expression specific types\fR +.TS +allbox ; +l | l. +T{ +Type +T} T{ +Description +T} +.T& +l | l. +T{ +realm +T} T{ +Routing Realm (32 bit number). Can be specified numerically +or as symbolic name defined in /etc/iproute2/rt_realms. +T} +.TE +.PP +\fBUsing routing expressions\fR +.PP +.nf +\*(T< +# IP family independent rt expression +filter output rt classid 10 + +# IP family dependent rt expressions +ip filter output rt nexthop 192.168.0.1 +ip6 filter output rt nexthop fd00::1 +inet filter output rt ip nexthop 192.168.0.1 +inet filter output rt ip6 nexthop fd00::1 + \*(T> +.fi +.SH "PAYLOAD EXPRESSIONS" +Payload expressions refer to data from the packet's payload. +.SS "ETHERNET HEADER EXPRESSION" +'nh +.fi +.ad l +\fBether\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIethernet header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBEthernet header expression types\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +daddr +T} T{ +Destination MAC address +T} T{ +ether_addr +T} +T{ +saddr +T} T{ +Source MAC address +T} T{ +ether_addr +T} +T{ +type +T} T{ +EtherType +T} T{ +ether_type +T} +.TE +.SS "VLAN HEADER EXPRESSION" +'nh +.fi +.ad l +\fBvlan\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIVLAN header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBVLAN header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +id +T} T{ +VLAN ID (VID) +T} T{ +integer (12 bit) +T} +T{ +cfi +T} T{ +Canonical Format Indicator +T} T{ +integer (1 bit) +T} +T{ +pcp +T} T{ +Priority code point +T} T{ +integer (3 bit) +T} +T{ +type +T} T{ +EtherType +T} T{ +ether_type +T} +.TE +.SS "ARP HEADER EXPRESSION" +'nh +.fi +.ad l +\fBarp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIARP header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBARP header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +htype +T} T{ +ARP hardware type +T} T{ +integer (16 bit) +T} +T{ +ptype +T} T{ +EtherType +T} T{ +ether_type +T} +T{ +hlen +T} T{ +Hardware address len +T} T{ +integer (8 bit) +T} +T{ +plen +T} T{ +Protocol address len +T} T{ +integer (8 bit) +T} +T{ +operation +T} T{ +Operation +T} T{ +arp_op +T} +.TE +.SS "IPV4 HEADER EXPRESSION" +'nh +.fi +.ad l +\fBip\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIIPv4 header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBIPv4 header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +version +T} T{ +IP header version (4) +T} T{ +integer (4 bit) +T} +T{ +hdrlength +T} T{ +IP header length including options +T} T{ +integer (4 bit) FIXME scaling +T} +T{ +dscp +T} T{ +Differentiated Services Code Point +T} T{ +dscp +T} +T{ +ecn +T} T{ +Explicit Congestion Notification +T} T{ +ecn +T} +T{ +length +T} T{ +Total packet length +T} T{ +integer (16 bit) +T} +T{ +id +T} T{ +IP ID +T} T{ +integer (16 bit) +T} +T{ +frag-off +T} T{ +Fragment offset +T} T{ +integer (16 bit) +T} +T{ +ttl +T} T{ +Time to live +T} T{ +integer (8 bit) +T} +T{ +protocol +T} T{ +Upper layer protocol +T} T{ +inet_proto +T} +T{ +checksum +T} T{ +IP header checksum +T} T{ +integer (16 bit) +T} +T{ +saddr +T} T{ +Source address +T} T{ +ipv4_addr +T} +T{ +daddr +T} T{ +Destination address +T} T{ +ipv4_addr +T} +.TE +.SS "ICMP HEADER EXPRESSION" +'nh +.fi +.ad l +\fBicmp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIICMP header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBICMP header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +type +T} T{ +ICMP type field +T} T{ +icmp_type +T} +T{ +code +T} T{ +ICMP code field +T} T{ +integer (8 bit) +T} +T{ +checksum +T} T{ +ICMP checksum field +T} T{ +integer (16 bit) +T} +T{ +id +T} T{ +ID of echo request/response +T} T{ +integer (16 bit) +T} +T{ +sequence +T} T{ +sequence number of echo request/response +T} T{ +integer (16 bit) +T} +T{ +gateway +T} T{ +gateway of redirects +T} T{ +integer (32 bit) +T} +T{ +mtu +T} T{ +MTU of path MTU discovery +T} T{ +integer (16 bit) +T} +.TE +.SS "IPV6 HEADER EXPRESSION" +'nh +.fi +.ad l +\fBip6\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIIPv6 header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBIPv6 header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +version +T} T{ +IP header version (6) +T} T{ +integer (4 bit) +T} +T{ +dscp +T} T{ +Differentiated Services Code Point +T} T{ +dscp +T} +T{ +ecn +T} T{ +Explicit Congestion Notification +T} T{ +ecn +T} +T{ +flowlabel +T} T{ +Flow label +T} T{ +integer (20 bit) +T} +T{ +length +T} T{ +Payload length +T} T{ +integer (16 bit) +T} +T{ +nexthdr +T} T{ +Nexthdr protocol +T} T{ +inet_proto +T} +T{ +hoplimit +T} T{ +Hop limit +T} T{ +integer (8 bit) +T} +T{ +saddr +T} T{ +Source address +T} T{ +ipv6_addr +T} +T{ +daddr +T} T{ +Destination address +T} T{ +ipv6_addr +T} +.TE +.SS "ICMPV6 HEADER EXPRESSION" +'nh +.fi +.ad l +\fBicmpv6\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIICMPv6 header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBICMPv6 header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +type +T} T{ +ICMPv6 type field +T} T{ +icmpv6_type +T} +T{ +code +T} T{ +ICMPv6 code field +T} T{ +integer (8 bit) +T} +T{ +checksum +T} T{ +ICMPv6 checksum field +T} T{ +integer (16 bit) +T} +T{ +parameter-problem +T} T{ +pointer to problem +T} T{ +integer (32 bit) +T} +T{ +packet-too-big +T} T{ +oversized MTU +T} T{ +integer (32 bit) +T} +T{ +id +T} T{ +ID of echo request/response +T} T{ +integer (16 bit) +T} +T{ +sequence +T} T{ +sequence number of echo request/response +T} T{ +integer (16 bit) +T} +T{ +max-delay +T} T{ +maximum response delay of MLD queries +T} T{ +integer (16 bit) +T} +.TE +.SS "TCP HEADER EXPRESSION" +'nh +.fi +.ad l +\fBtcp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fITCP header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBTCP header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +sport +T} T{ +Source port +T} T{ +inet_service +T} +T{ +dport +T} T{ +Destination port +T} T{ +inet_service +T} +T{ +sequence +T} T{ +Sequence number +T} T{ +integer (32 bit) +T} +T{ +ackseq +T} T{ +Acknowledgement number +T} T{ +integer (32 bit) +T} +T{ +doff +T} T{ +Data offset +T} T{ +integer (4 bit) FIXME scaling +T} +T{ +reserved +T} T{ +Reserved area +T} T{ +integer (4 bit) +T} +T{ +flags +T} T{ +TCP flags +T} T{ +tcp_flag +T} +T{ +window +T} T{ +Window +T} T{ +integer (16 bit) +T} +T{ +checksum +T} T{ +Checksum +T} T{ +integer (16 bit) +T} +T{ +urgptr +T} T{ +Urgent pointer +T} T{ +integer (16 bit) +T} +.TE +.SS "UDP HEADER EXPRESSION" +'nh +.fi +.ad l +\fBudp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIUDP header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBUDP header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +sport +T} T{ +Source port +T} T{ +inet_service +T} +T{ +dport +T} T{ +Destination port +T} T{ +inet_service +T} +T{ +length +T} T{ +Total packet length +T} T{ +integer (16 bit) +T} +T{ +checksum +T} T{ +Checksum +T} T{ +integer (16 bit) +T} +.TE +.SS "UDP-LITE HEADER EXPRESSION" +'nh +.fi +.ad l +\fBudplite\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIUDP-Lite header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBUDP-Lite header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +sport +T} T{ +Source port +T} T{ +inet_service +T} +T{ +dport +T} T{ +Destination port +T} T{ +inet_service +T} +T{ +checksum +T} T{ +Checksum +T} T{ +integer (16 bit) +T} +.TE +.SS "SCTP HEADER EXPRESSION" +'nh +.fi +.ad l +\fBsctp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fISCTP header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBSCTP header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +sport +T} T{ +Source port +T} T{ +inet_service +T} +T{ +dport +T} T{ +Destination port +T} T{ +inet_service +T} +T{ +vtag +T} T{ +Verfication Tag +T} T{ +integer (32 bit) +T} +T{ +checksum +T} T{ +Checksum +T} T{ +integer (32 bit) +T} +.TE +.SS "DCCP HEADER EXPRESSION" +'nh +.fi +.ad l +\fBdccp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIDCCP header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBDCCP header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l. +T{ +sport +T} T{ +Source port +T} T{ +inet_service +T} +T{ +dport +T} T{ +Destination port +T} T{ +inet_service +T} +.TE +.SS "AUTHENTICATION HEADER EXPRESSION" +'nh +.fi +.ad l +\fBah\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIAH header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBAH header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +nexthdr +T} T{ +Next header protocol +T} T{ +inet_proto +T} +T{ +hdrlength +T} T{ +AH Header length +T} T{ +integer (8 bit) +T} +T{ +reserved +T} T{ +Reserved area +T} T{ +integer (16 bit) +T} +T{ +spi +T} T{ +Security Parameter Index +T} T{ +integer (32 bit) +T} +T{ +sequence +T} T{ +Sequence number +T} T{ +integer (32 bit) +T} +.TE +.SS "ENCRYPTED SECURITY PAYLOAD HEADER EXPRESSION" +'nh +.fi +.ad l +\fBesp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIESP header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBESP header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l. +T{ +spi +T} T{ +Security Parameter Index +T} T{ +integer (32 bit) +T} +T{ +sequence +T} T{ +Sequence number +T} T{ +integer (32 bit) +T} +.TE +.SS "IPCOMP HEADER EXPRESSION" +'nh +.fi +.ad l +\fBcomp\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[\fIIPComp header field\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBIPComp header expression\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +nexthdr +T} T{ +Next header protocol +T} T{ +inet_proto +T} +T{ +flags +T} T{ +Flags +T} T{ +bitmask +T} +T{ +cpi +T} T{ +Compression Parameter Index +T} T{ +integer (16 bit) +T} +.TE +.SS "EXTENSION HEADER EXPRESSIONS" +Extension header expressions refer to data from variable-sized protocol headers, such as IPv6 extension headers and +TCPs options. +.PP +nftables currently supports matching (finding) a given ipv6 extension header or TCP option. +'nh +.fi +.ad l +\fBhbh\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{nexthdr | hdrlength} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBfrag\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{nexthdr | frag-off | more-fragments | id} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBrt\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{nexthdr | hdrlength | type | seg-left} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBdst\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{nexthdr | hdrlength} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBmh\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{nexthdr | hdrlength | checksum | type} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBtcp option\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{eol | noop | maxseg | window | sack-permitted | sack | sack0 | sack1 | sack2 | sack3 | timestamp} \fItcp_option_field\fR +'in \n(.iu-\nxu +.ad b +'hy +.PP +The following syntaxes are valid only in a relational expression +with boolean type on right-hand side for checking header existence only: +'nh +.fi +.ad l +\fBexthdr\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{hbh | frag | rt | dst | mh} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBtcp option\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{eol | noop | maxseg | window | sack-permitted | sack | sack0 | sack1 | sack2 | sack3 | timestamp} +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBIPv6 extension headers\fR +.TS +allbox ; +l | l. +T{ +Keyword +T} T{ +Description +T} +.T& +l | l. +T{ +hbh +T} T{ +Hop by Hop +T} +T{ +rt +T} T{ +Routing Header +T} +T{ +frag +T} T{ +Fragmentation header +T} +T{ +dst +T} T{ +dst options +T} +T{ +mh +T} T{ +Mobility Header +T} +.TE +.PP +\fBTCP Options\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +TCP option fields +T} +.T& +l | l | l. +T{ +eol +T} T{ +End of option list +T} T{ +kind +T} +T{ +noop +T} T{ +1 Byte TCP No-op options +T} T{ +kind +T} +T{ +maxseg +T} T{ +TCP Maximum Segment Size +T} T{ +kind, length, size +T} +T{ +window +T} T{ +TCP Window Scaling +T} T{ +kind, length, count +T} +T{ +sack-permitted +T} T{ +TCP SACK permitted +T} T{ +kind, length +T} +T{ +sack +T} T{ +TCP Selective Acknowledgement (alias of block 0) +T} T{ +kind, length, left, right +T} +T{ +sack0 +T} T{ +TCP Selective Acknowledgement (block 0) +T} T{ +kind, length, left, right +T} +T{ +sack1 +T} T{ +TCP Selective Acknowledgement (block 1) +T} T{ +kind, length, left, right +T} +T{ +sack2 +T} T{ +TCP Selective Acknowledgement (block 2) +T} T{ +kind, length, left, right +T} +T{ +sack3 +T} T{ +TCP Selective Acknowledgement (block 3) +T} T{ +kind, length, left, right +T} +T{ +timestamp +T} T{ +TCP Timestamps +T} T{ +kind, length, tsval, tsecr +T} +.TE +.PP +\fBfinding TCP options\fR +.PP +.nf +\*(T< +filter input tcp option sack\-permitted kind 1 counter + \*(T> +.fi +.PP +\fBmatching IPv6 exthdr\fR +.PP +.nf +\*(T< +ip6 filter input frag more\-fragments 1 counter + \*(T> +.fi +.SS "CONNTRACK EXPRESSIONS" +Conntrack expressions refer to meta data of the connection tracking entry associated with a packet. +.PP +There are three types of conntrack expressions. Some conntrack expressions require the flow +direction before the conntrack key, others must be used directly because they are direction agnostic. +The \fBpackets\fR, \fBbytes\fR and \fBavgpkt\fR keywords can be +used with or without a direction. If the direction is omitted, the sum of the original and the reply +direction is returned. The same is true for the \fBzone\fR, if a direction is given, the zone +is only matched if the zone id is tied to the given direction. +.PP +'nh +.fi +.ad l +\fBct\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{state | direction | status | mark | expiration | helper | label | l3proto | protocol | bytes | packets | avgpkt | zone} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBct\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{original | reply} {l3proto | protocol | proto-src | proto-dst | bytes | packets | avgpkt | zone} +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBct\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{original | reply} {ip | ip6} {saddr | daddr} +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBConntrack expressions\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +state +T} T{ +State of the connection +T} T{ +ct_state +T} +T{ +direction +T} T{ +Direction of the packet relative to the connection +T} T{ +ct_dir +T} +T{ +status +T} T{ +Status of the connection +T} T{ +ct_status +T} +T{ +mark +T} T{ +Connection mark +T} T{ +mark +T} +T{ +expiration +T} T{ +Connection expiration time +T} T{ +time +T} +T{ +helper +T} T{ +Helper associated with the connection +T} T{ +string +T} +T{ +label +T} T{ +Connection tracking label bit or symbolic name defined in connlabel.conf in the nftables include path +T} T{ +ct_label +T} +T{ +l3proto +T} T{ +Layer 3 protocol of the connection +T} T{ +nf_proto +T} +T{ +saddr +T} T{ +Source address of the connection for the given direction +T} T{ +ipv4_addr/ipv6_addr +T} +T{ +daddr +T} T{ +Destination address of the connection for the given direction +T} T{ +ipv4_addr/ipv6_addr +T} +T{ +protocol +T} T{ +Layer 4 protocol of the connection for the given direction +T} T{ +inet_proto +T} +T{ +proto-src +T} T{ +Layer 4 protocol source for the given direction +T} T{ +integer (16 bit) +T} +T{ +proto-dst +T} T{ +Layer 4 protocol destination for the given direction +T} T{ +integer (16 bit) +T} +T{ +packets +T} T{ +packet count seen in the given direction or sum of original and reply +T} T{ +integer (64 bit) +T} +T{ +bytes +T} T{ +bytecount seen, see description for \fBpackets\fR keyword +T} T{ +integer (64 bit) +T} +T{ +avgpkt +T} T{ +average bytes per packet, see description for \fBpackets\fR keyword +T} T{ +integer (64 bit) +T} +T{ +zone +T} T{ +conntrack zone +T} T{ +integer (16 bit) +T} +.TE +.PP +A description of conntrack-specific types listed above can be +found sub-section \*(T above. +.SH STATEMENTS +Statements represent actions to be performed. They can alter control flow (return, jump +to a different chain, accept or drop the packet) or can perform actions, such as logging, +rejecting a packet, etc. +.PP +Statements exist in two kinds. Terminal statements unconditionally terminate evaluation +of the current rule, non-terminal statements either only conditionally or never terminate +evaluation of the current rule, in other words, they are passive from the ruleset evaluation +perspective. There can be an arbitrary amount of non-terminal statements in a rule, but +only a single terminal statement as the final statement. +.SS "VERDICT STATEMENT" +The verdict statement alters control flow in the ruleset and issues +policy decisions for packets. +.PP +'nh +.fi +.ad l +{accept | drop | queue | continue | return} +.ad b +'hy +'nh +.fi +.ad l +{jump | goto} {\fIchain\fR} +.ad b +'hy +.PP +.TP +\*(T<\fBaccept\fR\*(T> +Terminate ruleset evaluation and accept the packet. +.TP +\*(T<\fBdrop\fR\*(T> +Terminate ruleset evaluation and drop the packet. +.TP +\*(T<\fBqueue\fR\*(T> +Terminate ruleset evaluation and queue the packet to userspace. +.TP +\*(T<\fBcontinue\fR\*(T> +Continue ruleset evaluation with the next rule. FIXME +.TP +\*(T<\fBreturn\fR\*(T> +Return from the current chain and continue evaluation at the +next rule in the last chain. If issued in a base chain, it is +equivalent to \fBaccept\fR. +.TP +\*(T<\fBjump \fR\*(T>\fIchain\fR +Continue evaluation at the first rule in \fIchain\fR. +The current position in the ruleset is pushed to a call stack and evaluation +will continue there when the new chain is entirely evaluated of a +\fBreturn\fR verdict is issued. +.TP +\*(T<\fBgoto \fR\*(T>\fIchain\fR +Similar to \fBjump\fR, but the current position is not pushed +to the call stack, meaning that after the new chain evaluation will continue +at the last chain instead of the one containing the goto statement. +.PP +\fBVerdict statements\fR +.PP +.nf +\*(T< +# process packets from eth0 and the internal network in from_lan +# chain, drop all packets from eth0 with different source addresses. + +filter input iif eth0 ip saddr 192.168.0.0/24 jump from_lan +filter input iif eth0 drop + \*(T> +.fi +.SS "PAYLOAD STATEMENT" +The payload statement alters packet content. +It can be used for example to set ip DSCP (differv) header field or ipv6 flow labels. +.PP +\fBroute some packets instead of bridging\fR +.PP +.nf +\*(T< +# redirect tcp:http from 192.160.0.0/16 to local machine for routing instead of bridging +# assumes 00:11:22:33:44:55 is local MAC address. +bridge input meta iif eth0 ip saddr 192.168.0.0/16 tcp dport 80 meta pkttype set unicast ether daddr set 00:11:22:33:44:55 + \*(T> +.fi +.PP +\fBSet IPv4 DSCP header field\fR +.PP +.nf +\*(T< +ip forward ip dscp set 42 + \*(T> +.fi +.SS "EXTENSION HEADER STATEMENT" +The extension header statement alters packet content in variable-sized headers. +This can currently be used to alter the TCP Maximum segment size of packets, +similar to TCPMSS. +.PP +\fBchange tcp mss\fR +.PP +.nf +\*(T< +tcp flags syn tcp option maxseg size set 1360 +# set a size based on route information: +tcp flags syn tcp option maxseg size set rt mtu + \*(T> +.fi +.SS "LOG STATEMENT" +'nh +.fi +.ad l +\fBlog\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[prefix +\fIquoted_string\fR] [level +\fIsyslog-level\fR] [flags +\fIlog-flags\fR] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBlog\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +group +\fInflog_group\fR [prefix +\fIquoted_string\fR] [queue-threshold +\fIvalue\fR] [snaplen +\fIsize\fR] +'in \n(.iu-\nxu +.ad b +'hy +.PP +The log statement enables logging of matching packets. When this statement is used from a rule, the Linux kernel will print some information on all matching packets, such as header fields, via the kernel log (where it can be read with dmesg(1) or read in the syslog). If the group number is specified, the Linux kernel will pass the packet to nfnetlink_log which will multicast the packet through a netlink socket to the specified multicast group. One or more userspace processes may subscribe to the group to receive the packets, see libnetfilter_queue documentation for details. This is a non-terminating statement, so the rule evaluation continues after the packet is logged. +.PP +\fBlog statement options\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l. +T{ +prefix +T} T{ +Log message prefix +T} T{ +quoted string +T} +T{ +syslog-level +T} T{ +Syslog level of logging +T} T{ +string: emerg, alert, crit, err, warn [default], notice, info, debug +T} +T{ +group +T} T{ +NFLOG group to send messages to +T} T{ +unsigned integer (16 bit) +T} +T{ +snaplen +T} T{ +Length of packet payload to include in netlink message +T} T{ +unsigned integer (32 bit) +T} +T{ +queue-threshold +T} T{ +Number of packets to queue inside the kernel before sending them to userspace +T} T{ +unsigned integer (32 bit) +T} +.TE +.PP +\fBlog-flags\fR +.TS +allbox ; +l | l. +T{ +Flag +T} T{ +Description +T} +.T& +l | l. +T{ +tcp sequence +T} T{ +Log TCP sequence numbers. +T} +T{ +tcp options +T} T{ +Log options from the TCP packet header. +T} +T{ +ip options +T} T{ +Log options from the IP/IPv6 packet header. +T} +T{ +skuid +T} T{ +Log the userid of the process which generated the packet. +T} +T{ +ether +T} T{ +Decode MAC addresses and protocol. +T} +T{ +all +T} T{ +Enable all log flags listed above. +T} +.TE +.PP +\fBUsing log statement\fR +.PP +.nf +\*(T< +# log the UID which generated the packet and ip options +ip filter output log flags skuid flags ip options + +# log the tcp sequence numbers and tcp options from the TCP packet +ip filter output log flags tcp sequence,options + +# enable all supported log flags +ip6 filter output log flags all + \*(T> +.fi +.SS "REJECT STATEMENT" +'nh +.fi +.ad l +\fBreject\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[ +with +{icmp | icmpv6 | icmpx} +type +{icmp_code | icmpv6_code | icmpx_code} +] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBreject\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[ +with +{tcp} +{reset} +] +'in \n(.iu-\nxu +.ad b +'hy +.PP +A reject statement is used to send back an error packet in response to the matched packet otherwise it is equivalent to drop so it is a terminating statement, ending rule traversal. This statement is only valid in the input, forward and output chains, and user-defined chains which are only called from those chains. +.PP +The different ICMP reject variants are meant for use in different table families: +.TS +allbox ; +l | l | l. +T{ +Variant +T} T{ +Family +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +icmp +T} T{ +ip +T} T{ +icmp_code +T} +T{ +icmpv6 +T} T{ +ip6 +T} T{ +icmpv6_code +T} +T{ +icmpx +T} T{ +inet +T} T{ +icmpx_code +T} +.TE +.PP +For a description of the different types and a list of supported +keywords refer to \*(T section above. +The common default reject value is +\fBport-unreachable\fR. +.SS "COUNTER STATEMENT" +A counter statement sets the hit count of packets along with the number of bytes. +.PP +'nh +.fi +.ad l +\fBcounter\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{packets +\fInumber\fR +} {bytes +\fInumber\fR +} +'in \n(.iu-\nxu +.ad b +'hy +.SS "CONNTRACK STATEMENT" +The conntrack statement can be used to set the conntrack mark and conntrack labels. +.PP +'nh +.fi +.ad l +\fBct\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{mark | event | label | zone} set \fIvalue\fR +'in \n(.iu-\nxu +.ad b +'hy +.PP +The ct statement sets meta data associated with a connection. +The zone id has to be assigned before a conntrack lookup takes place, +i.e. this has to be done in prerouting and possibly output (if locally +generated packets need to be placed in a distinct zone), with a hook +priority of -300. +.PP +\fBConntrack statement types\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Value +T} +.T& +l | l | l. +T{ +event +T} T{ +conntrack event bits +T} T{ +bitmask, integer (32 bit) +T} +T{ +helper +T} T{ +name of ct helper object to assign to the connection +T} T{ +quoted string +T} +T{ +mark +T} T{ +Connection tracking mark +T} T{ +mark +T} +T{ +label +T} T{ +Connection tracking label +T} T{ +label +T} +T{ +zone +T} T{ +conntrack zone +T} T{ +integer (16 bit) +T} +.TE +.PP +\fBsave packet nfmark in conntrack\fR +.PP +.nf +\*(T< +ct mark set meta mark + \*(T> +.fi +.PP +\fBset zone mapped via interface\fR +.PP +.nf +\*(T< +table inet raw { + chain prerouting { + type filter hook prerouting priority \-300; + ct zone set iif map { "eth1" : 1, "veth1" : 2 } + } + chain output { + type filter hook output priority \-300; + ct zone set oif map { "eth1" : 1, "veth1" : 2 } + } +} + \*(T> +.fi +.PP +\fBrestrict events reported by ctnetlink\fR +.PP +.nf +\*(T< +ct event set new,related,destroy + \*(T> +.fi +.SS "META STATEMENT" +A meta statement sets the value of a meta expression. +The existing meta fields are: priority, mark, pkttype, nftrace. +.PP +'nh +.fi +.ad l +\fBmeta\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +{mark | priority | pkttype | nftrace} set \fIvalue\fR +'in \n(.iu-\nxu +.ad b +'hy +.PP +A meta statement sets meta data associated with a packet. +.PP +\fBMeta statement types\fR +.TS +allbox ; +l | l | l. +T{ +Keyword +T} T{ +Description +T} T{ +Value +T} +.T& +l | l | l. +T{ +priority +T} T{ +TC packet priority +T} T{ +tc_handle +T} +T{ +mark +T} T{ +Packet mark +T} T{ +mark +T} +T{ +pkttype +T} T{ +packet type +T} T{ +pkt_type +T} +T{ +nftrace +T} T{ +ruleset packet tracing on/off. Use \fBmonitor trace\fR command to watch traces +T} T{ +0, 1 +T} +.TE +.SS "LIMIT STATEMENT" +'nh +.fi +.ad l +\fBlimit\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +rate [over] \fIpacket_number\fR / {second | minute | hour | day} [burst \fIpacket_number\fR packets] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBlimit\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +rate [over] \fIbyte_number\fR {bytes | kbytes | mbytes} / {second | minute | hour | day | week} [burst \fIbyte_number\fR bytes] +'in \n(.iu-\nxu +.ad b +'hy +.PP +A limit statement matches at a limited rate using a token bucket filter. A rule using this statement will match until this limit is reached. It can be used in combination with the log statement to give limited logging. The \fBover\fR keyword, that is optional, makes it match over the specified rate. +.PP +\fBlimit statement values\fR +.TS +allbox ; +l | l | l. +T{ +Value +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l. +T{ +packet_number +T} T{ +Number of packets +T} T{ +unsigned integer (32 bit) +T} +T{ +byte_number +T} T{ +Number of bytes +T} T{ +unsigned integer (32 bit) +T} +.TE +.SS "NAT STATEMENTS" +'nh +.fi +.ad l +\fBsnat\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +\fIaddress\fR +[:port] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBsnat\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +\fIaddress\fR - \fIaddress\fR +[:\fIport\fR - \fIport\fR] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBdnat\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +\fIaddress\fR +[:\fIport\fR] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBdnat\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +\fIaddress\fR +[:\fIport\fR - \fIport\fR] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBmasquerade\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +[:\fIport\fR] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBmasquerade\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +[:\fIport\fR - \fIport\fR] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBredirect\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +[:\fIport\fR] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBredirect\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +to +[:\fIport\fR - \fIport\fR] [persistent, random, fully-random] +'in \n(.iu-\nxu +.ad b +'hy +.PP +The nat statements are only valid from nat chain types. +.PP +The \fBsnat\fR and \fBmasquerade\fR statements specify that the source address of the packet should be modified. While \fBsnat\fR is only valid in the postrouting and input chains, \fBmasquerade\fR makes sense only in postrouting. The \fBdnat\fR and \fBredirect\fR statements are only valid in the prerouting and output chains, they specify that the destination address of the packet should be modified. You can use non-base chains which are called from base chains of nat chain type too. All future packets in this connection will also be mangled, and rules should cease being examined. +.PP +The \fBmasquerade\fR statement is a special form of \fBsnat\fR which always uses the outgoing interface's IP address to translate to. It is particularly useful on gateways with dynamic (public) IP addresses. +.PP +The \fBredirect\fR statement is a special form of \fBdnat\fR which always translates the destination address to the local host's one. It comes in handy if one only wants to alter the destination port of incoming traffic on different interfaces. +.PP +Note that all nat statements require both prerouting and postrouting base chains to be present since otherwise packets on the return path won't be seen by netfilter and therefore no reverse translation will take place. +.PP +\fBNAT statement values\fR +.TS +allbox ; +l | l | l. +T{ +Expression +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l. +T{ +address +T} T{ +Specifies that the source/destination address of the packet should be modified. You may specify a mapping to relate a list of tuples composed of arbitrary expression key with address value. +T} T{ +ipv4_addr, ipv6_addr, eg. abcd::1234, or you can use a mapping, eg. meta mark map { 10 : 192.168.1.2, 20 : 192.168.1.3 } +T} +T{ +port +T} T{ +Specifies that the source/destination address of the packet should be modified. +T} T{ +port number (16 bits) +T} +.TE +.PP +\fBNAT statement flags\fR +.TS +allbox ; +l | l. +T{ +Flag +T} T{ +Description +T} +.T& +l | l +l | l +l | l. +T{ +persistent +T} T{ +Gives a client the same source-/destination-address for each connection. +T} +T{ +random +T} T{ +If used then port mapping will be randomized using a random seeded MD5 hash mix using source and destination address and destination port. +T} +T{ +fully-random +T} T{ +If used then port mapping is generated based on a 32-bit pseudo-random algorithm. +T} +.TE +.PP +\fBUsing NAT statements\fR +.PP +.nf +\*(T< +# create a suitable table/chain setup for all further examples +add table nat +add chain nat prerouting { type nat hook prerouting priority 0; } +add chain nat postrouting { type nat hook postrouting priority 100; } + +# translate source addresses of all packets leaving via eth0 to address 1.2.3.4 +add rule nat postrouting oif eth0 snat to 1.2.3.4 + +# redirect all traffic entering via eth0 to destination address 192.168.1.120 +add rule nat prerouting iif eth0 dnat to 192.168.1.120 + +# translate source addresses of all packets leaving via eth0 to whatever +# locally generated packets would use as source to reach the same destination +add rule nat postrouting oif eth0 masquerade + +# redirect incoming TCP traffic for port 22 to port 2222 +add rule nat prerouting tcp dport 22 redirect to :2222 + \*(T> +.fi +.SS "QUEUE STATEMENT" +This statement passes the packet to userspace using the nfnetlink_queue handler. The packet is put into the queue identified by its 16-bit queue number. Userspace can inspect and modify the packet if desired. Userspace must then drop or reinject the packet into the kernel. See libnetfilter_queue documentation for details. +.PP +'nh +.fi +.ad l +\fBqueue\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[num +\fIqueue_number\fR] [bypass] +'in \n(.iu-\nxu +.ad b +'hy +'nh +.fi +.ad l +\fBqueue\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[num +\fIqueue_number_from\fR - \fIqueue_number_to\fR] [bypass,fanout] +'in \n(.iu-\nxu +.ad b +'hy +.PP +\fBqueue statement values\fR +.TS +allbox ; +l | l | l. +T{ +Value +T} T{ +Description +T} T{ +Type +T} +.T& +l | l | l +l | l | l +l | l | l. +T{ +queue_number +T} T{ +Sets queue number, default is 0. +T} T{ +unsigned integer (16 bit) +T} +T{ +queue_number_from +T} T{ +Sets initial queue in the range, if fanout is used. +T} T{ +unsigned integer (16 bit) +T} +T{ +queue_number_to +T} T{ +Sets closing queue in the range, if fanout is used. +T} T{ +unsigned integer (16 bit) +T} +.TE +.PP +\fBqueue statement flags\fR +.TS +allbox ; +l | l. +T{ +Flag +T} T{ +Description +T} +.T& +l | l +l | l. +T{ +bypass +T} T{ +Let packets go through if userspace application cannot back off. Before using this flag, read libnetfilter_queue documentation for performance tuning recomendations. +T} +T{ +fanout +T} T{ +Distribute packets between several queues. +T} +.TE +.SS "MAP STATEMENT" +The map statement is used to lookup data based on some specific input key. +.PP +'nh +.fi +.ad l +\fIexpression\fR \fBmap {\fR \fIkey\fR \fB:\fR \fIvalue\fR [ +\fB,\fR +\fIkey\fR +\fB:\fR +\fIvalue\fR +]\&... \fB}\fR +.ad b +'hy +.PP +\fBusing the map statement\fR +.PP +.nf +\*(T< +# select DNAT target based on TCP dport: +# connections to port 80 are redirected to 192.168.1.100, +# connections to port 8888 are redirected to 192.168.1.101 +nft add rule ip nat prerouting dnat tcp dport map { 80 : 192.168.1.100, 8888 : 192.168.1.101 } + +# source address based SNAT: +# packets from net 192.168.1.0/24 will appear as originating from 10.0.0.1, +# packets from net 192.168.2.0/24 will appear as originating from 10.0.0.2 +nft add rule ip nat postrouting snat to ip saddr map { 192.168.1.0/24 : 10.0.0.1, 192.168.2.0/24 : 10.0.0.2 } + \*(T> +.fi +.SS "VMAP STATEMENT" +The verdict map (vmap) statement works analogous to the map statement, but contains verdicts as values. +.PP +'nh +.fi +.ad l +\fIexpression\fR \fBvmap {\fR \fIkey\fR \fB:\fR \fIvalue\fR [ +\fB,\fR +\fIkey\fR +\fB:\fR +\fIvalue\fR +]\&... \fB}\fR +.ad b +'hy +.PP +\fBusing the vmap statement\fR +.PP +.nf +\*(T< +# jump to different chains depending on layer 4 protocol type: +nft add rule ip filter input ip protocol vmap { tcp : jump tcp\-chain, udp : jump udp\-chain , icmp : jump icmp\-chain } + \*(T> +.fi +.SH "ADDITIONAL COMMANDS" +These are some additional commands included in nft. +.SS MONITOR +The monitor command allows you to listen to Netlink events produced +by the nf_tables subsystem, related to creation and deletion of objects. +When they occur, nft will print to stdout the monitored events in either +XML, JSON or native nft format. +.PP +To filter events related to a concrete object, use one of the keywords 'tables', 'chains', 'sets', 'rules', 'elements' , 'ruleset'. +.PP +To filter events related to a concrete action, use keyword 'new' or 'destroy'. +.PP +Hit ^C to finish the monitor operation. +.PP +\fBListen to all events, report in native nft format\fR +.PP +.nf +\*(T< +% nft monitor + \*(T> +.fi +.PP +\fBListen to added tables, report in XML format\fR +.PP +.nf +\*(T< +% nft monitor new tables xml + \*(T> +.fi +.PP +\fBListen to deleted rules, report in JSON format\fR +.PP +.nf +\*(T< +% nft monitor destroy rules json + \*(T> +.fi +.PP +\fBListen to both new and destroyed chains, in native nft format\fR +.PP +.nf +\*(T< +% nft monitor chains + \*(T> +.fi +.PP +\fBListen to ruleset events such as table, chain, rule, set, counters and quotas, in native nft format\fR +.PP +.nf +\*(T< +% nft monitor ruleset + \*(T> +.fi +.SH "ERROR REPORTING" +When an error is detected, nft shows the line(s) containing the error, the position +of the erroneous parts in the input stream and marks up the erroneous parts using +carrets (\*(T<^\*(T>). If the error results from the combination of two +expressions or statements, the part imposing the constraints which are violated is +marked using tildes (\*(T<~\*(T>). +.PP +For errors returned by the kernel, nft can't detect which parts of the input caused +the error and the entire command is marked. +.PP +\fBError caused by single incorrect expression\fR +.PP +.nf +\*(T< +:1:19\-22: Error: Interface does not exist +filter output oif eth0 + ^^^^ + \*(T> +.fi +.PP +\fBError caused by invalid combination of two expressions\fR +.PP +.nf +\*(T< +:1:28\-36: Error: Right hand side of relational expression (==) must be constant +filter output tcp dport == tcp dport + ~~ ^^^^^^^^^ + \*(T> +.fi +.PP +\fBError returned by the kernel\fR +.PP +.nf +\*(T< +:0:0\-23: Error: Could not process rule: Operation not permitted +filter output oif wlan0 +^^^^^^^^^^^^^^^^^^^^^^^ + \*(T> +.fi +.SH "EXIT STATUS" +On success, nft exits with a status of 0. Unspecified +errors cause it to exit with a status of 1, memory allocation +errors with a status of 2, unable to open Netlink socket with 3. +.SH "SEE ALSO" +iptables(8), ip6tables(8), arptables(8), ebtables(8), ip(8), tc(8) +.PP +There is an official wiki at: https://wiki.nftables.org +.SH AUTHORS +nftables was written by Patrick McHardy and Pablo Neira Ayuso, among many other contributors from the Netfilter community. +.SH COPYRIGHT +.nf + +Copyright \(co 2008\-2014 Patrick McHardy <\*(T> +Copyright \(co 2013\-2016 Pablo Neira Ayuso <\*(T> + +.fi +.PP +nftables 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. +.PP +This documentation is licenced under the terms of the Creative +Commons Attribution-ShareAlike 4.0 license, +.URL http://creativecommons.org/licenses/by-sa/4.0/ "CC BY-SA 4.0" +\&. diff --git a/SOURCES/nftables.conf b/SOURCES/nftables.conf new file mode 100644 index 0000000..3653a23 --- /dev/null +++ b/SOURCES/nftables.conf @@ -0,0 +1,6 @@ +# +# This this will contain your nftables rules and +# is read by the systemd service when restarting +# +# These provide an iptables like set of filters +# (uncomment to include) diff --git a/SOURCES/nftables.service b/SOURCES/nftables.service new file mode 100644 index 0000000..1e8c194 --- /dev/null +++ b/SOURCES/nftables.service @@ -0,0 +1,17 @@ +[Unit] +Description=Netfilter Tables +Documentation=man:nft(8) +Wants=network-pre.target +Before=network-pre.target + +[Service] +Type=oneshot +ProtectSystem=full +ProtectHome=true +ExecStart=/sbin/nft -f /etc/sysconfig/nftables.conf +ExecReload=/sbin/nft 'flush ruleset; include "/etc/sysconfig/nftables.conf";' +ExecStop=/sbin/nft flush ruleset +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/SPECS/nftables.spec b/SPECS/nftables.spec new file mode 100644 index 0000000..f8328df --- /dev/null +++ b/SPECS/nftables.spec @@ -0,0 +1,176 @@ +%define rpmversion 0.8 +%define specrelease 14%{?dist} +%define libnftnlversion 1.0.8-1 + +Name: nftables +Version: %{rpmversion} +Release: %{specrelease} +Epoch: 1 +Summary: Netfilter Tables userspace utillites +License: GPLv2 +URL: http://netfilter.org/projects/nftables/ +Source0: http://ftp.netfilter.org/pub/nftables/nftables-%{version}.tar.bz2 +Source1: nftables.service +Source2: nftables.conf +Source3: nft.8 +BuildRequires: flex +BuildRequires: bison +BuildRequires: libmnl-devel +BuildRequires: gmp-devel +BuildRequires: readline-devel +BuildRequires: libnftnl-devel >= %{libnftnlversion} +# docbook2X is available in EPEL repo only, which is not included in Brew +#BuildRequires: docbook2X +#BuildRequires: docbook-dtds +BuildRequires: systemd +Patch0: 0001-src-fix-protocol-context-update-on-big-endian-system.patch +Patch1: 0002-netlink_linearize-exthdr-op-must-be-u32.patch +Patch2: 0003-src-avoid-errouneous-assert-with-map-concat.patch +Patch3: 0004-Review-switch-statements-for-unmarked-fall-through-c.patch +Patch4: 0005-monitor-Make-trace-events-respect-output_fp.patch +Patch5: 0006-monitor-Make-JSON-XML-output-respect-output_fp.patch +Patch6: 0007-cli-Drop-pointless-check-in-cli_append_multiline.patch +Patch7: 0008-erec-Avoid-passing-negative-offset-to-fseek.patch +Patch8: 0009-evaluate-Fix-memleak-in-stmt_reject_gen_dependency.patch +Patch9: 0010-hash-Fix-potential-null-pointer-dereference-in-hash_.patch +Patch10: 0011-netlink-Complain-if-setting-O_NONBLOCK-fails.patch +Patch11: 0012-netlink_delinearize-Fix-resource-leaks.patch +Patch12: 0013-nft.8-Fix-reject-statement-documentation.patch +Patch13: 0014-doc-reword-insert-position-this-expects-rule-handle-.patch +Patch14: 0015-Deprecate-add-insert-rule-position-argument.patch +Patch15: 0016-evaluate-explicitly-deny-concatenated-types-in-inter.patch +Patch16: 0017-src-bail-out-when-exporting-ruleset-with-unsupported.patch +Patch17: 0018-monitor-Drop-fake-XML-support.patch +Patch18: 0019-src-Reject-export-vm-json-command.patch +Patch19: 0020-include-fix-build-failure.patch +Patch20: 0021-nft.8-Update-meta-pkt_type-value-description.patch +Patch21: 0022-doc-Add-minimal-description-of-v-map-statements.patch + +%description +Netfilter Tables userspace utilities. + +%prep +%autosetup -p1 + +%build +%configure --disable-silent-rules DOCBOOK2X_MAN="no" DOCBOOK2MAN="no" DB2X_DOCBOOK2MAN="no" +make %{?_smp_mflags} + +%install +%make_install +find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' +mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man8 +cp -a %{SOURCE3} $RPM_BUILD_ROOT/%{_mandir}/man8/ +chmod 644 $RPM_BUILD_ROOT/%{_mandir}/man8/nft* + +mkdir -p $RPM_BUILD_ROOT/%{_unitdir} +cp -a %{SOURCE1} $RPM_BUILD_ROOT/%{_unitdir}/ + +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig +cp -a %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ +for f in $RPM_BUILD_ROOT/%{_sysconfdir}/nftables/*; do + echo "# include \"%{_sysconfdir}/nftables/$(basename $f)\"" +done >> $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/nftables.conf +chmod 600 $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/nftables.conf +chmod 750 $RPM_BUILD_ROOT/%{_sysconfdir}/nftables/ +chmod 600 $RPM_BUILD_ROOT/%{_sysconfdir}/nftables/* + +%post +%systemd_post nftables.service + +%preun +%systemd_preun nftables.service + +%postun +%systemd_postun_with_restart nftables.service + +%files +%doc COPYING TODO +%config(noreplace) %{_sysconfdir}/nftables/ +%config(noreplace) %{_sysconfdir}/sysconfig/nftables.conf +%{_sbindir}/nft +%{_mandir}/man8/nft* +%{_unitdir}/nftables.service + +%changelog +* Thu Apr 04 2019 Phil Sutter [0.8-14.el7] +- Update pre-generated nft.8 (Phil Sutter) [1628974] + +* Thu Apr 04 2019 Phil Sutter [0.8-13.el7] +- doc: Add minimal description of (v)map statements (Phil Sutter) [1628974] +- nft.8: Update meta pkt_type value description (Phil Sutter) [1628694] + +* Fri Mar 15 2019 Phil Sutter [0.8-12.el7] +- include: fix build failure (Phil Sutter) [1646336] + +* Fri Mar 15 2019 Phil Sutter [0.8-11.el7] +- src: Reject 'export vm json' command (Phil Sutter) [1646336] +- monitor: Drop fake XML support (Phil Sutter) [1646336] +- src: bail out when exporting ruleset with unsupported output (Phil Sutter) [1646336] + +* Wed Jun 20 2018 Phil Sutter [0.8-10.el7] +- Bump epoch to allow upgrading from EPEL (Phil Sutter) [1575059] + +* Wed Jun 20 2018 Phil Sutter [0.8-9.el7] +- evaluate: explicitly deny concatenated types in interval sets (Phil Sutter) [1576426] +- Deprecate add/insert rule 'position' argument (Phil Sutter) [1571968] +- doc: reword insert position, this expects rule handle to insert, not a relative postition (Phil Sutter) [1571968] +- nft.8: Fix reject statement documentation (Phil Sutter) [1571938] +- netlink_delinearize: Fix resource leaks (Phil Sutter) [1504157] +- netlink: Complain if setting O_NONBLOCK fails (Phil Sutter) [1504157] +- hash: Fix potential null-pointer dereference in hash_expr_cmp() (Phil Sutter) [1504157] +- evaluate: Fix memleak in stmt_reject_gen_dependency() (Phil Sutter) [1504157] +- erec: Avoid passing negative offset to fseek() (Phil Sutter) [1504157] +- cli: Drop pointless check in cli_append_multiline() (Phil Sutter) [1504157] +- monitor: Make JSON/XML output respect output_fp (Phil Sutter) [1504157] +- monitor: Make trace events respect output_fp (Phil Sutter) [1504157] +- Review switch statements for unmarked fall through cases (Phil Sutter) [1504157] + +* Wed Jun 06 2018 Phil Sutter [0.8-8.el7] +- src: avoid errouneous assert with map+concat (Phil Sutter) [1540917] + +* Mon Dec 18 2017 Phil Sutter [0.8-7.el7] +- A proper fix for incompatible docbook2man (Phil Sutter) [1523239] + +* Thu Dec 14 2017 Phil Sutter [0.8-6.el7] +- netlink_linearize: exthdr op must be u32 (Phil Sutter) [1524246] +- src: fix protocol context update on big-endian systems (Phil Sutter) [1523016] + +* Fri Dec 08 2017 Phil Sutter [0.8-5.el7] +- Prevent build failure due to incompatible docbook2man (Phil Sutter) [1523239] + +* Sat Oct 14 2017 Phil Sutter [0.8-4.el7] +- Update /etc/sysconfig/nftables.conf with new config samples (Phil Sutter) [1472261] + +* Fri Oct 13 2017 Phil Sutter [0.8-3.el7] +- Fix typo in spec file (Phil Sutter) [1451404] + +* Fri Oct 13 2017 Phil Sutter [0.8-2.el7] +- Fix permissions of installed config files (Phil Sutter) [1451404] + +* Fri Oct 13 2017 Phil Sutter [0.8-1.el7] +- Rebase onto upstream version 0.8 (Phil Sutter) [1472261] + +* Fri May 12 2017 Phil Sutter [0.6-4.el7] +- evaluate: Avoid undefined behaviour in concat_subtype_id() (Phil Sutter) [1360789] +- src: Interpret OP_NEQ against a set as OP_LOOKUP (Phil Sutter) [1440011] +- include: refresh uapi/linux/netfilter/nf_tables.h copy (Phil Sutter) [1440011] +- datatype: time_type should send milliseconds to userspace (Phil Sutter) [1427114] +- meta: fix memory leak in tc classid parser (Phil Sutter) [1380326] +- src: meta priority support using tc classid (Phil Sutter) [1380326] +- src: simplify classid printing using x instead of 04x (Phil Sutter) [1380326] +- src: rename datatype name from tc_handle to classid (Phil Sutter) [1380326] +- payload: don't update protocol context if we can't find a description (Timothy Redaelli) [1446534 1399764] +- evaluate: reject: Have a generic fix for missing network context (Timothy Redaelli) [1360354] + +* Mon Mar 06 2017 Phil Sutter [0.6-3.el7] +- nftables.spec: Require at least libnftnl-1.0.6-4 (Phil Sutter) [1358705] +- evaluate: Fix datalen checks in expr_evaluate_string() (Phil Sutter) [1360240] +- netlink_delinearize: Avoid potential null pointer deref (Timothy Redaelli) [1360257] +- src: use new range expression for != [a,b] intervals (Phil Sutter) [1358705] + +* Tue Jul 19 2016 Phil Sutter 0.6-2 +- Add pre-generated nft.8 to overcome missing docbook2X package. + +* Wed Jun 29 2016 Phil Sutter 0.6-1 +- Rebased from Fedora Rawhide and adjusted for RHEL review.