From: "Álvaro Neira Ayuso" <alvaroneay@gmail.com>
To: netfilter-devel@vger.kernel.org
Cc: Patrick McHardy <kaber@trash.net>
Subject: Re: [nft PATCH 4/4 v4] nft: complete reject support
Date: Fri, 26 Sep 2014 18:56:57 +0200 [thread overview]
Message-ID: <54259AD9.3020101@gmail.com> (raw)
In-Reply-To: <1411750255-7663-4-git-send-email-alvaroneay@gmail.com>
El 26/09/14 18:50, Alvaro Neira Ayuso escribió:
> This patch allows to use the reject action in rules. For example:
>
> nft add rule filter input udp dport 22 reject
>
> In this rule, we assume that the reason is network unreachable. Also
> we can specify the reason with the option "with" and the reason. For example:
>
> nft add rule filter input tcp dport 22 reject with icmp type host-unreach
>
> In the bridge tables and inet tables, we can use this action too. For example:
>
> nft add rule inet filter input reject with icmp type host-unreach
>
> In this rule above, this generates a meta nfproto dependency to match
> ipv4 traffic because we use a icmpv4 reason to reject.
>
> If the reason is not specified, we infer it from the context.
>
> Moreover, we have the new icmpx datatype. You can use this datatype for
> the bridge and the inet tables to simplify your ruleset. For example:
>
> nft add rule inet filter input reject with icmpx type host-unreach
>
> We have four icmpx reason and the mapping is:
>
> ICMPX REASON | ICMPv6 | ICMPv4
> | |
> admin-prohibited | admin-prohibited | admin-prohibited
> port-unreach | port-unreach | port-unreach
> no-route | no-route | net-unreach
> host-unreach | addr-unreach | host-unreach
>
> Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com>
> ---
> [Changes in v4]
> * Fixed some cosmetic errors
> * Added the new datatype icmpx.
>
> [Tested with the rules]
> [Error ways]
> Reject not supported for arp
> * nft add rule arp filter input reject (reject not supported for arp)
>
> Use icmp code field in a ipv6 table or icmpv6 code field in ipv4 table
> * nft add rule ip filter input reject with icmp type no-route
> * nft add rule ip6 filter input reject with icmpv6 type host-unreach
>
> Use tcp reset with a udp rule
> * nft add rule ip filter input udp dport 9999 reject with tcp reset
>
> [Hits ways]
> IPV4
> * nft add rule ip filter input udp dport 9999 /
> reject with icmp type host-unreach
> * nft add rule ip filter input tcp dport 9999 reject
> * nft add rule ip filter input reject
> * nft add rule ip filter input reject with tcp reset
>
> IPV6
> * nft add rule ip6 filter input udp dport 9999 reject
> * nft add rule ip6 filter input tcp dport 9999 /
> reject with icmpv6 type admin-prohibited
> * nft add rule ip6 filter input reject
>
> INET
> * nft add rule inet filter input reject with icmp type host-unreach
> * nft add rule inet filter input reject with icmpv6 type no-route
> * nft add rule inet filter input udp dport 9999 counter /
> reject with icmpv6 type no-route
> * nft add rule inet filter input reject with tcp reset
> * nft add rule inet filter input reject
>
> BRIDGE
> * nft add rule bridge filter input reject with icmp type host-unreach
> * nft add rule bridge filter input reject with icmpv6 type no-route
> * nft add rule bridge filter input reject
Sorry, I forgot to add a example with icmpx. For example:
* nft add rule inet filter input reject with icmpx type no-route
>
> include/datatype.h | 9 ++
> include/linux/netfilter/nf_tables.h | 21 +++++
> include/statement.h | 3 +
> src/datatype.c | 105 +++++++++++++++++++++++
> src/evaluate.c | 160 ++++++++++++++++++++++++++++++++++-
> src/netlink_delinearize.c | 41 +++++++++
> src/netlink_linearize.c | 5 +-
> src/parser.y | 54 +++++++++++-
> src/payload.c | 31 +++++--
> src/scanner.l | 3 +
> src/statement.c | 49 +++++++++++
> 11 files changed, 471 insertions(+), 10 deletions(-)
>
> diff --git a/include/datatype.h b/include/datatype.h
> index 5182263..15fea44 100644
> --- a/include/datatype.h
> +++ b/include/datatype.h
> @@ -36,6 +36,9 @@
> * @TYPE_ICMP6_TYPE: ICMPv6 type codes (integer subtype)
> * @TYPE_CT_LABEL: Conntrack Label (bitmask subtype)
> * @TYPE_PKTTYPE: packet type (integer subtype)
> + * @TYPE_ICMP_CODE: icmp code (integer subtype)
> + * @TYPE_ICMPV6_CODE: icmpv6 code (integer subtype)
> + * @TYPE_ICMPX_CODE: icmpx code (integer subtype)
> */
> enum datatypes {
> TYPE_INVALID,
> @@ -70,6 +73,9 @@ enum datatypes {
> TYPE_ICMP6_TYPE,
> TYPE_CT_LABEL,
> TYPE_PKTTYPE,
> + TYPE_ICMP_CODE,
> + TYPE_ICMPV6_CODE,
> + TYPE_ICMPX_CODE,
> __TYPE_MAX
> };
> #define TYPE_MAX (__TYPE_MAX - 1)
> @@ -194,6 +200,9 @@ extern const struct datatype arphrd_type;
> extern const struct datatype inet_protocol_type;
> extern const struct datatype inet_service_type;
> extern const struct datatype mark_type;
> +extern const struct datatype icmp_code_type;
> +extern const struct datatype icmpv6_code_type;
> +extern const struct datatype icmpx_code_type;
> extern const struct datatype time_type;
>
> extern const struct datatype *concat_type_alloc(const struct expr *expr);
> diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> index b72ccfe..f04d997 100644
> --- a/include/linux/netfilter/nf_tables.h
> +++ b/include/linux/netfilter/nf_tables.h
> @@ -749,13 +749,34 @@ enum nft_queue_attributes {
> *
> * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
> * @NFT_REJECT_TCP_RST: reject using TCP RST
> + * @NFT_REJECT_ICMPX_UNREACH: abstracted ICMP unreachable for bridge and inet
> */
> enum nft_reject_types {
> NFT_REJECT_ICMP_UNREACH,
> NFT_REJECT_TCP_RST,
> + NFT_REJECT_ICMPX_UNREACH,
> };
>
> /**
> + * enum nft_reject_code - Abstracted reject codes
> + *
> + * @NFT_REJECT_ICMPX_NO_ROUTE: no route to host - network unreachable
> + * @NFT_REJECT_ICMPX_PORT_UNREACH: port unreachable
> + * @NFT_REJECT_ICMPX_HOST_UNREACH: host unreachable
> + * @NFT_REJECT_ICMPX_ADMIN_PROHIBITED: administratevely prohibited
> + *
> + * These codes are mapped to real ICMP and ICMPv6 codes.
> + */
> +enum nft_reject_inet_code {
> + NFT_REJECT_ICMPX_NO_ROUTE = 0,
> + NFT_REJECT_ICMPX_PORT_UNREACH,
> + NFT_REJECT_ICMPX_HOST_UNREACH,
> + NFT_REJECT_ICMPX_ADMIN_PROHIBITED,
> + __NFT_REJECT_ICMPX_MAX
> +};
> +#define NFT_REJECT_ICMPX_MAX (__NFT_REJECT_ICMPX_MAX + 1)
> +
> +/**
> * enum nft_reject_attributes - nf_tables reject expression netlink attributes
> *
> * @NFTA_REJECT_TYPE: packet type to use (NLA_U32: nft_reject_types)
> diff --git a/include/statement.h b/include/statement.h
> index 7a57f7d..574835c 100644
> --- a/include/statement.h
> +++ b/include/statement.h
> @@ -56,7 +56,10 @@ struct limit_stmt {
> extern struct stmt *limit_stmt_alloc(const struct location *loc);
>
> struct reject_stmt {
> + struct expr *expr;
> enum nft_reject_types type;
> + int8_t icmp_code;
> + unsigned int family;
> };
>
> extern struct stmt *reject_stmt_alloc(const struct location *loc);
> diff --git a/src/datatype.c b/src/datatype.c
> index 9bfe46d..8ab6913 100644
> --- a/src/datatype.c
> +++ b/src/datatype.c
> @@ -24,6 +24,9 @@
> #include <gmputil.h>
> #include <erec.h>
>
> +#include <netinet/ip_icmp.h>
> +#include <netinet/icmp6.h>
> +
> static const struct datatype *datatypes[TYPE_MAX + 1] = {
> [TYPE_INVALID] = &invalid_type,
> [TYPE_VERDICT] = &verdict_type,
> @@ -41,6 +44,9 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = {
> [TYPE_TIME] = &time_type,
> [TYPE_MARK] = &mark_type,
> [TYPE_ARPHRD] = &arphrd_type,
> + [TYPE_ICMP_CODE] = &icmp_code_type,
> + [TYPE_ICMPV6_CODE] = &icmpv6_code_type,
> + [TYPE_ICMPX_CODE] = &icmpx_code_type,
> };
>
> void datatype_register(const struct datatype *dtype)
> @@ -683,6 +689,105 @@ const struct datatype mark_type = {
> .flags = DTYPE_F_PREFIX,
> };
>
> +static const struct symbol_table icmp_code_tbl = {
> + .symbols = {
> + SYMBOL("net-unreach", ICMP_NET_UNREACH),
> + SYMBOL("host-unreach", ICMP_HOST_UNREACH),
> + SYMBOL("prot-unreach", ICMP_PROT_UNREACH),
> + SYMBOL("port-unreach", ICMP_PORT_UNREACH),
> + SYMBOL("net-prohibited", ICMP_NET_ANO),
> + SYMBOL("host-prohibited", ICMP_HOST_ANO),
> + SYMBOL("admin-prohibited", ICMP_PKT_FILTERED),
> + SYMBOL_LIST_END
> + },
> +};
> +
> +static void icmp_code_type_print(const struct expr *expr)
> +{
> + return symbolic_constant_print(&icmp_code_tbl, expr);
> +}
> +
> +static struct error_record *icmp_code_type_parse(const struct expr *sym,
> + struct expr **res)
> +{
> + return symbolic_constant_parse(sym, &icmp_code_tbl, res);
> +}
> +
> +const struct datatype icmp_code_type = {
> + .type = TYPE_ICMP_CODE,
> + .name = "icmp code",
> + .desc = "icmp code type",
> + .size = BITS_PER_BYTE,
> + .byteorder = BYTEORDER_BIG_ENDIAN,
> + .basetype = &integer_type,
> + .print = icmp_code_type_print,
> + .parse = icmp_code_type_parse,
> +};
> +
> +static const struct symbol_table icmpv6_code_tbl = {
> + .symbols = {
> + SYMBOL("no-route", ICMP6_DST_UNREACH_NOROUTE),
> + SYMBOL("admin-prohibited", ICMP6_DST_UNREACH_ADMIN),
> + SYMBOL("addr-unreach", ICMP6_DST_UNREACH_ADDR),
> + SYMBOL("port-unreach", ICMP6_DST_UNREACH_NOPORT),
> + SYMBOL_LIST_END
> + },
> +};
> +
> +static void icmpv6_code_type_print(const struct expr *expr)
> +{
> + return symbolic_constant_print(&icmpv6_code_tbl, expr);
> +}
> +
> +static struct error_record *icmpv6_code_type_parse(const struct expr *sym,
> + struct expr **res)
> +{
> + return symbolic_constant_parse(sym, &icmpv6_code_tbl, res);
> +}
> +
> +const struct datatype icmpv6_code_type = {
> + .type = TYPE_ICMPV6_CODE,
> + .name = "icmpv6 code",
> + .desc = "icmpv6 code type",
> + .size = BITS_PER_BYTE,
> + .byteorder = BYTEORDER_BIG_ENDIAN,
> + .basetype = &integer_type,
> + .print = icmpv6_code_type_print,
> + .parse = icmpv6_code_type_parse,
> +};
> +
> +static const struct symbol_table icmpx_code_tbl = {
> + .symbols = {
> + SYMBOL("port-unreach", NFT_REJECT_ICMPX_PORT_UNREACH),
> + SYMBOL("admin-prohibited", NFT_REJECT_ICMPX_ADMIN_PROHIBITED),
> + SYMBOL("no-route", NFT_REJECT_ICMPX_NO_ROUTE),
> + SYMBOL("host-unreach", NFT_REJECT_ICMPX_HOST_UNREACH),
> + SYMBOL_LIST_END
> + },
> +};
> +
> +static void icmpx_code_type_print(const struct expr *expr)
> +{
> + return symbolic_constant_print(&icmpx_code_tbl, expr);
> +}
> +
> +static struct error_record *icmpx_code_type_parse(const struct expr *sym,
> + struct expr **res)
> +{
> + return symbolic_constant_parse(sym, &icmpx_code_tbl, res);
> +}
> +
> +const struct datatype icmpx_code_type = {
> + .type = TYPE_ICMPX_CODE,
> + .name = "icmpx code",
> + .desc = "icmpx code type",
> + .size = BITS_PER_BYTE,
> + .byteorder = BYTEORDER_BIG_ENDIAN,
> + .basetype = &integer_type,
> + .print = icmpx_code_type_print,
> + .parse = icmpx_code_type_parse,
> +};
> +
> static void time_type_print(const struct expr *expr)
> {
> uint64_t days, hours, minutes, seconds;
> diff --git a/src/evaluate.c b/src/evaluate.c
> index 52ce548..41a23d1 100644
> --- a/src/evaluate.c
> +++ b/src/evaluate.c
> @@ -17,6 +17,8 @@
> #include <linux/netfilter.h>
> #include <linux/netfilter_arp.h>
> #include <linux/netfilter/nf_tables.h>
> +#include <netinet/ip_icmp.h>
> +#include <netinet/icmp6.h>
>
> #include <expression.h>
> #include <statement.h>
> @@ -1126,12 +1128,168 @@ static int stmt_evaluate_meta(struct eval_ctx *ctx, struct stmt *stmt)
> return 0;
> }
>
> -static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt)
> +static int stmt_reject_gen_dependency(struct stmt *stmt, struct expr *expr,
> + struct eval_ctx *ctx)
> {
> + struct expr *payload;
> + struct stmt *nstmt;
> + const struct proto_desc *desc, *base;
> +
> + if (stmt->reject.type == NFT_REJECT_TCP_RST) {
> + desc = ctx->pctx.protocol[PROTO_BASE_TRANSPORT_HDR].desc;
> + if (desc != NULL)
> + return 0;
> + /* Generate a TCP dependency */
> + payload = payload_expr_alloc(&stmt->location, &proto_tcp,
> + TCPHDR_DPORT);
> + goto gen_dep;
> + }
> +
> + base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
> + if (base != NULL)
> + return 0;
> +
> + if (stmt->reject.icmp_code < 0)
> + return stmt_error(ctx, stmt, "missing icmp error type");
> +
> + /* Generate a network dependency */
> + switch (stmt->reject.family) {
> + case NFPROTO_IPV4:
> + payload = payload_expr_alloc(&stmt->location, &proto_ip,
> + IPHDR_PROTOCOL);
> + break;
> + case NFPROTO_IPV6:
> + payload = payload_expr_alloc(&stmt->location, &proto_ip6,
> + IP6HDR_NEXTHDR);
> + break;
> + default:
> + BUG("unknown reject family");
> + }
> +
> +gen_dep:
> + if (payload_gen_dependency(ctx, payload, &nstmt) < 0)
> + return -1;
> +
> + list_add(&nstmt->list, &ctx->cmd->rule->stmts);
> + return 0;
> +}
> +
> +static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
> + struct expr *expr)
> +{
> + switch (ctx->pctx.family) {
> + case NFPROTO_ARP:
> + return stmt_error(ctx, stmt, "cannot use reject with arp");
> + case NFPROTO_IPV4:
> + case NFPROTO_IPV6:
> + switch (stmt->reject.type) {
> + case NFT_REJECT_TCP_RST:
> + if (stmt_reject_gen_dependency(stmt, expr, ctx) < 0)
> + return -1;
> + break;
> + case NFT_REJECT_ICMPX_UNREACH:
> + return stmt_error(ctx, stmt,
> + "abstracted ICMP unreachable not supported");
> + default:
> + break;
> + }
> + break;
> + case NFPROTO_INET:
> + case NFPROTO_BRIDGE:
> + if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
> + break;
> + if (stmt_reject_gen_dependency(stmt, expr, ctx) < 0)
> + return -1;
> + break;
> + }
> +
> stmt->flags |= STMT_F_TERMINAL;
> return 0;
> }
>
> +/* The reason to reject this hasn't been specified */
> +static int stmt_evaluate_reject_no_reason(struct eval_ctx *ctx,
> + struct stmt *stmt)
> +{
> + switch (ctx->pctx.family) {
> + case NFPROTO_IPV4:
> + case NFPROTO_IPV6:
> + stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
> + stmt->reject.family = ctx->pctx.family;
> + if (ctx->pctx.family == NFPROTO_IPV4)
> + stmt->reject.icmp_code = ICMP_PORT_UNREACH;
> + else
> + stmt->reject.icmp_code = ICMP6_DST_UNREACH_NOPORT;
> + break;
> + case NFPROTO_INET:
> + case NFPROTO_BRIDGE:
> + stmt->reject.type = NFT_REJECT_ICMPX_UNREACH;
> + stmt->reject.icmp_code = NFT_REJECT_ICMPX_PORT_UNREACH;
> + break;
> + }
> + return 0;
> +}
> +
> +/* The reason to reject this has been specified with icmp reason */
> +static int stmt_evaluate_reject_icmp_reason(struct eval_ctx *ctx,
> + struct stmt *stmt)
> +{
> + struct error_record *erec;
> + struct expr *code;
> +
> + erec = symbol_parse(stmt->reject.expr, &code);
> + if (erec != NULL) {
> + erec_queue(erec, ctx->msgs);
> + return -1;
> + }
> + stmt->reject.icmp_code = mpz_get_uint8(code->value);
> + return 0;
> +}
> +
> +/* The reason to reject this has been specified with tcp reset */
> +static int stmt_evaluate_reject_tcp_reason(struct eval_ctx *ctx,
> + struct stmt *stmt)
> +{
> + int protonum;
> + const struct proto_desc *desc, *base;
> + struct proto_ctx *pctx = &ctx->pctx;
> +
> + base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
> + desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
> + if (desc == NULL)
> + return 0;
> +
> + protonum = proto_find_num(base, desc);
> + switch (protonum) {
> + case IPPROTO_TCP:
> + break;
> + default:
> + if (stmt->reject.type == NFT_REJECT_TCP_RST) {
> + return stmt_error(ctx, stmt,
> + "you cannot use tcp reset with this protocol");
> + }
> + break;
> + }
> + return 0;
> +}
> +
> +static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt)
> +{
> + struct expr *expr = ctx->cmd->expr;
> +
> + if (stmt->reject.icmp_code < 0) {
> + stmt_evaluate_reject_no_reason(ctx, stmt);
> + } else if (stmt->reject.expr != NULL) {
> + if (stmt_evaluate_reject_icmp_reason(ctx, stmt) < 0)
> + return -1;
> + } else {
> + if (stmt_evaluate_reject_tcp_reason(ctx, stmt) < 0)
> + return -1;
> + }
> +
> + return stmt_evaluate_reject_family(ctx, stmt, expr);
> +}
> +
> static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
> {
> struct proto_ctx *pctx = &ctx->pctx;
> diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
> index 796b632..12cb9e0 100644
> --- a/src/netlink_delinearize.c
> +++ b/src/netlink_delinearize.c
> @@ -14,6 +14,9 @@
> #include <string.h>
> #include <limits.h>
> #include <linux/netfilter/nf_tables.h>
> +#include <arpa/inet.h>
> +#include <linux/netfilter.h>
> +#include <net/ethernet.h>
> #include <netlink.h>
> #include <rule.h>
> #include <statement.h>
> @@ -474,6 +477,9 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
> struct stmt *stmt;
>
> stmt = reject_stmt_alloc(loc);
> + stmt->reject.type = nft_rule_expr_get_u32(expr, NFT_EXPR_REJECT_TYPE);
> + stmt->reject.icmp_code = nft_rule_expr_get_u8(expr,
> + NFT_EXPR_REJECT_CODE);
> list_add_tail(&stmt->list, &ctx->rule->stmts);
> }
>
> @@ -899,6 +905,38 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
> }
> }
>
> +static void stmt_reject_postprocess(struct rule_pp_ctx rctx, struct stmt *stmt)
> +{
> + const struct proto_desc *desc, *base;
> + int protocol;
> +
> + switch (rctx.pctx.family) {
> + case NFPROTO_IPV4:
> + case NFPROTO_IPV6:
> + stmt->reject.family = rctx.pctx.family;
> + break;
> + case NFPROTO_INET:
> + case NFPROTO_BRIDGE:
> + if (rctx.pbase == PROTO_BASE_INVALID)
> + return;
> +
> + if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
> + break;
> +
> + base = rctx.pctx.protocol[PROTO_BASE_LL_HDR].desc;
> + desc = rctx.pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
> + protocol = proto_find_num(base, desc);
> + if (protocol == __constant_htons(ETH_P_IP))
> + stmt->reject.family = NFPROTO_IPV4;
> + else if (protocol == __constant_htons(ETH_P_IPV6))
> + stmt->reject.family = NFPROTO_IPV6;
> + else
> + stmt->reject.family = protocol;
> + break;
> + default:
> + break;
> + }
> +}
> static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *rule)
> {
> struct rule_pp_ctx rctx;
> @@ -926,6 +964,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
> if (stmt->nat.proto != NULL)
> expr_postprocess(&rctx, stmt, &stmt->nat.proto);
> break;
> + case STMT_REJECT:
> + stmt_reject_postprocess(rctx, stmt);
> + break;
> default:
> break;
> }
> diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
> index c46b6d4..29f8e9a 100644
> --- a/src/netlink_linearize.c
> +++ b/src/netlink_linearize.c
> @@ -612,7 +612,10 @@ static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
>
> nle = alloc_nft_expr("reject");
> nft_rule_expr_set_u32(nle, NFT_EXPR_REJECT_TYPE, stmt->reject.type);
> - nft_rule_expr_set_u8(nle, NFT_EXPR_REJECT_CODE, 0);
> + if (stmt->reject.icmp_code != -1)
> + nft_rule_expr_set_u8(nle, NFT_EXPR_REJECT_CODE,
> + stmt->reject.icmp_code);
> +
> nft_rule_add_expr(ctx->nlr, nle);
> }
>
> diff --git a/src/parser.y b/src/parser.y
> index 32d5455..83d45d3 100644
> --- a/src/parser.y
> +++ b/src/parser.y
> @@ -19,6 +19,8 @@
> #include <linux/netfilter.h>
> #include <linux/netfilter/nf_tables.h>
> #include <linux/netfilter/nf_conntrack_tuple_common.h>
> +#include <netinet/ip_icmp.h>
> +#include <netinet/icmp6.h>
> #include <libnftnl/common.h>
>
> #include <rule.h>
> @@ -362,6 +364,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
> %token WEEK "week"
>
> %token _REJECT "reject"
> +%token RESET "reset"
> +%token WITH "with"
> +%token ICMPX "icmpx"
>
> %token SNAT "snat"
> %token DNAT "dnat"
> @@ -423,8 +428,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
> %type <stmt> limit_stmt
> %destructor { stmt_free($$); } limit_stmt
> %type <val> time_unit
> -%type <stmt> reject_stmt
> -%destructor { stmt_free($$); } reject_stmt
> +%type <stmt> reject_stmt reject_stmt_alloc
> +%destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
> %type <stmt> nat_stmt nat_stmt_alloc
> %destructor { stmt_free($$); } nat_stmt nat_stmt_alloc
> %type <stmt> queue_stmt queue_stmt_alloc
> @@ -1346,12 +1351,55 @@ time_unit : SECOND { $$ = 1ULL; }
> | WEEK { $$ = 1ULL * 60 * 60 * 24 * 7; }
> ;
>
> -reject_stmt : _REJECT
> +reject_stmt : reject_stmt_alloc reject_opts
> + ;
> +
> +reject_stmt_alloc : _REJECT
> {
> $$ = reject_stmt_alloc(&@$);
> }
> ;
>
> +reject_opts : /* empty */
> + {
> + $<stmt>0->reject.type = -1;
> + $<stmt>0->reject.icmp_code = -1;
> + }
> + | WITH ICMP TYPE STRING
> + {
> + $<stmt>0->reject.family = NFPROTO_IPV4;
> + $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
> + $<stmt>0->reject.expr = symbol_expr_alloc(&@$,
> + SYMBOL_VALUE,
> + current_scope(state),
> + $4);
> + $<stmt>0->reject.expr->dtype = &icmp_code_type;
> + }
> + | WITH ICMP6 TYPE STRING
> + {
> + $<stmt>0->reject.family = NFPROTO_IPV6;
> + $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
> + $<stmt>0->reject.expr = symbol_expr_alloc(&@$,
> + SYMBOL_VALUE,
> + current_scope(state),
> + $4);
> + $<stmt>0->reject.expr->dtype = &icmpv6_code_type;
> + }
> + | WITH ICMPX TYPE STRING
> + {
> + $<stmt>0->reject.type = NFT_REJECT_ICMPX_UNREACH;
> + $<stmt>0->reject.expr = symbol_expr_alloc(&@$,
> + SYMBOL_VALUE,
> + current_scope(state),
> + $4);
> + $<stmt>0->reject.expr->dtype = &icmpx_code_type;
> + }
> + | WITH TCP RESET
> + {
> + $<stmt>0->reject.type = NFT_REJECT_TCP_RST;
> + }
> + ;
> +
> nat_stmt : nat_stmt_alloc nat_stmt_args
> ;
>
> diff --git a/src/payload.c b/src/payload.c
> index b7b74ed..ebf8079 100644
> --- a/src/payload.c
> +++ b/src/payload.c
> @@ -198,11 +198,32 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
> }
>
> desc = ctx->pctx.protocol[expr->payload.base - 1].desc;
> - /* Special case for mixed IPv4/IPv6 tables: use meta L4 proto */
> - if (desc == NULL &&
> - ctx->pctx.family == NFPROTO_INET &&
> - expr->payload.base == PROTO_BASE_TRANSPORT_HDR)
> - desc = &proto_inet_service;
> + /* Special case for mixed IPv4/IPv6 and bridge tables */
> + if (desc == NULL) {
> + switch (ctx->pctx.family) {
> + case NFPROTO_INET:
> + switch (expr->payload.base) {
> + case PROTO_BASE_TRANSPORT_HDR:
> + desc = &proto_inet_service;
> + break;
> + case PROTO_BASE_LL_HDR:
> + desc = &proto_inet;
> + break;
> + default:
> + break;
> + }
> + break;
> + case NFPROTO_BRIDGE:
> + switch (expr->payload.base) {
> + case PROTO_BASE_LL_HDR:
> + desc = &proto_eth;
> + break;
> + default:
> + break;
> + }
> + break;
> + }
> + }
>
> if (desc == NULL)
> return expr_error(ctx->msgs, expr,
> diff --git a/src/scanner.l b/src/scanner.l
> index 772f658..bbf2797 100644
> --- a/src/scanner.l
> +++ b/src/scanner.l
> @@ -308,6 +308,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
> "week" { return WEEK; }
>
> "reject" { return _REJECT; }
> +"with" { return WITH; }
> +"reset" { return RESET; }
> +"icmpx" { return ICMPX; }
>
> "snat" { return SNAT; }
> "dnat" { return DNAT; }
> diff --git a/src/statement.c b/src/statement.c
> index 8e4b49e..9ff6749 100644
> --- a/src/statement.c
> +++ b/src/statement.c
> @@ -16,6 +16,10 @@
> #include <string.h>
> #include <syslog.h>
>
> +#include <arpa/inet.h>
> +#include <linux/netfilter.h>
> +#include <netinet/ip_icmp.h>
> +#include <netinet/icmp6.h>
> #include <statement.h>
> #include <utils.h>
> #include <list.h>
> @@ -224,9 +228,54 @@ struct stmt *queue_stmt_alloc(const struct location *loc)
> return stmt_alloc(loc, &queue_stmt_ops);
> }
>
> +const char *reject_stmt_code_ip[] = {
> + [ICMP_NET_UNREACH] = "net-unreach",
> + [ICMP_HOST_UNREACH] = "host-unreach",
> + [ICMP_PROT_UNREACH] = "prot-unreach",
> + [ICMP_NET_ANO] = "net-prohibited",
> + [ICMP_HOST_ANO] = "host-prohibited",
> + [ICMP_PKT_FILTERED] = "admin-prohibited",
> +};
> +
> +const char *reject_stmt_code_ip6[] = {
> + [ICMP6_DST_UNREACH_NOROUTE] = "no-route",
> + [ICMP6_DST_UNREACH_ADMIN] = "admin-prohibited",
> + [ICMP6_DST_UNREACH_ADDR] = "addr-unreach",
> +};
> +
> +const char *reject_stmt_code_icmpx[] = {
> + [NFT_REJECT_ICMPX_NO_ROUTE] = "no-route",
> + [NFT_REJECT_ICMPX_HOST_UNREACH] = "host-unreach",
> + [NFT_REJECT_ICMPX_ADMIN_PROHIBITED] = "admin-prohibited",
> +};
> +
> static void reject_stmt_print(const struct stmt *stmt)
> {
> printf("reject");
> + switch (stmt->reject.type) {
> + case NFT_REJECT_TCP_RST:
> + printf(" with tcp reset");
> + break;
> + case NFT_REJECT_ICMPX_UNREACH:
> + if (stmt->reject.icmp_code == NFT_REJECT_ICMPX_PORT_UNREACH)
> + break;
> + printf(" with icmpx type %s",
> + reject_stmt_code_icmpx[stmt->reject.icmp_code]);
> + break;
> + case NFT_REJECT_ICMP_UNREACH:
> + if (stmt->reject.family == NFPROTO_IPV4) {
> + if (stmt->reject.icmp_code == ICMP_PORT_UNREACH)
> + break;
> + printf(" with icmp type %s",
> + reject_stmt_code_ip[stmt->reject.icmp_code]);
> + } else if (stmt->reject.family == NFPROTO_IPV6) {
> + if (stmt->reject.icmp_code == ICMP6_DST_UNREACH_NOPORT)
> + break;
> +
> + printf(" with icmpv6 type %s",
> + reject_stmt_code_ip6[stmt->reject.icmp_code]);
> + }
> + }
> }
>
> static const struct stmt_ops reject_stmt_ops = {
>
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2014-09-26 16:56 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-26 16:50 [nft PATCH 1/4 v2] payload: generate dependency in the appropriate byteorder Alvaro Neira Ayuso
2014-09-26 16:50 ` [nft PATCH 2/4 v2] src: Enhance payload_gen_dependency() Alvaro Neira Ayuso
2014-09-26 16:50 ` [nft PATCH 3/4 v2] datatype: Enhance symbolic_constant_parse() Alvaro Neira Ayuso
2014-09-26 16:50 ` [nft PATCH 4/4 v4] nft: complete reject support Alvaro Neira Ayuso
2014-09-26 16:56 ` Álvaro Neira Ayuso [this message]
2014-09-26 18:06 ` Pablo Neira Ayuso
2014-09-26 18:18 ` Patrick McHardy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54259AD9.3020101@gmail.com \
--to=alvaroneay@gmail.com \
--cc=kaber@trash.net \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).