diff options
-rw-r--r-- | include/statement.h | 1 | ||||
-rw-r--r-- | src/evaluate.c | 9 | ||||
-rw-r--r-- | src/netlink_delinearize.c | 2 | ||||
-rw-r--r-- | src/netlink_linearize.c | 2 | ||||
-rw-r--r-- | src/parser.y | 34 | ||||
-rw-r--r-- | src/scanner.l | 1 | ||||
-rw-r--r-- | src/statement.c | 31 |
7 files changed, 74 insertions, 6 deletions
diff --git a/include/statement.h b/include/statement.h index 480b7190..28f9a354 100644 --- a/include/statement.h +++ b/include/statement.h @@ -47,6 +47,7 @@ extern struct stmt *limit_stmt_alloc(const struct location *loc); struct reject_stmt { enum nft_reject_types type; + int8_t icmp_code; }; extern struct stmt *reject_stmt_alloc(const struct location *loc); diff --git a/src/evaluate.c b/src/evaluate.c index c15cd55f..216194f1 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -17,6 +17,7 @@ #include <linux/netfilter.h> #include <linux/netfilter_arp.h> #include <linux/netfilter/nf_tables.h> +#include <linux/icmp.h> #include <expression.h> #include <statement.h> @@ -1139,10 +1140,14 @@ static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt) if (base == NULL) return -1; - if (strcmp(base->name, "tcp") == 0) + if (strcmp(base->name, "tcp") == 0 && stmt->reject.icmp_code == -1) { stmt->reject.type = NFT_REJECT_TCP_RST; - else + stmt->reject.icmp_code = ICMP_NET_UNREACH; + } else { stmt->reject.type = NFT_REJECT_ICMP_UNREACH; + if (stmt->reject.icmp_code < 0) + stmt->reject.icmp_code = ICMP_NET_UNREACH; + } stmt->flags |= STMT_F_TERMINAL; return 0; diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index a98c68fc..8d30b2d2 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -457,6 +457,8 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx, 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); } diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 8db333cc..b0ca2419 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -609,7 +609,7 @@ 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); + 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 3e08e21e..a4272168 100644 --- a/src/parser.y +++ b/src/parser.y @@ -18,6 +18,7 @@ #include <linux/netfilter.h> #include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_conntrack_tuple_common.h> +#include <linux/icmp.h> #include <libnftnl/common.h> #include <rule.h> @@ -359,6 +360,7 @@ static int monitor_lookup_event(const char *event) %token WEEK "week" %token _REJECT "reject" +%token WITH "with" %token SNAT "snat" %token DNAT "dnat" @@ -419,8 +421,8 @@ static int monitor_lookup_event(const char *event) %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 queue_range @@ -1396,12 +1398,38 @@ 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.icmp_code = -1; + } + | WITH STRING + { + if (strcmp($2, "net-unreach") == 0) + $<stmt>0->reject.icmp_code = ICMP_NET_UNREACH; + else if (strcmp($2, "host-unreach") == 0) + $<stmt>0->reject.icmp_code = ICMP_HOST_UNREACH; + else if (strcmp($2, "prot-unreach") == 0) + $<stmt>0->reject.icmp_code = ICMP_PROT_UNREACH; + else if (strcmp($2, "port-unreach") == 0) + $<stmt>0->reject.icmp_code = ICMP_PORT_UNREACH; + else if (strcmp($2, "net-prohibited") == 0) + $<stmt>0->reject.icmp_code = ICMP_NET_ANO; + else if (strcmp($2, "host-prohibited") == 0) + $<stmt>0->reject.icmp_code = ICMP_HOST_ANO; + else if (strcmp($2, "admin-prohibited") == 0) + $<stmt>0->reject.icmp_code = ICMP_PKT_FILTERED; + } + ; + nat_stmt : nat_stmt_alloc nat_stmt_args ; diff --git a/src/scanner.l b/src/scanner.l index 73a1a3f1..f91886cf 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -295,6 +295,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "week" { return WEEK; } "reject" { return _REJECT; } +"with" { return WITH; } "snat" { return SNAT; } "dnat" { return DNAT; } diff --git a/src/statement.c b/src/statement.c index 2dd3f187..c566fb85 100644 --- a/src/statement.c +++ b/src/statement.c @@ -18,6 +18,7 @@ #include <statement.h> #include <utils.h> #include <list.h> +#include <linux/icmp.h> struct stmt *stmt_alloc(const struct location *loc, const struct stmt_ops *ops) @@ -198,7 +199,37 @@ struct stmt *queue_stmt_alloc(const struct location *loc) static void reject_stmt_print(const struct stmt *stmt) { + const char *icmp_code_name = NULL; + printf("reject"); + if (stmt->reject.type != NFT_REJECT_TCP_RST) { + switch (stmt->reject.icmp_code) { + case ICMP_NET_UNREACH: + icmp_code_name = "net-unreach"; + break; + case ICMP_HOST_UNREACH: + icmp_code_name = "host-unreach"; + break; + case ICMP_PROT_UNREACH: + icmp_code_name = "prot-unreach"; + break; + case ICMP_PORT_UNREACH: + icmp_code_name = "port-unreach"; + break; + case ICMP_NET_ANO: + icmp_code_name = "net-prohibited"; + break; + case ICMP_HOST_ANO: + icmp_code_name = "host-prohibited"; + break; + case ICMP_PKT_FILTERED: + icmp_code_name = "admin-prohibited"; + break; + default: + icmp_code_name = "Unknown icmp code"; + } + printf(" with %s", icmp_code_name); + } } static const struct stmt_ops reject_stmt_ops = { |