diff options
Diffstat (limited to 'src/statement.c')
-rw-r--r-- | src/statement.c | 208 |
1 files changed, 176 insertions, 32 deletions
diff --git a/src/statement.c b/src/statement.c index be35bcef..ab144d63 100644 --- a/src/statement.c +++ b/src/statement.c @@ -8,19 +8,21 @@ * Development of this code funded by Astaro AG (http://www.astaro.com/) */ +#include <nft.h> + #include <stddef.h> -#include <stdlib.h> #include <stdio.h> -#include <stdint.h> #include <inttypes.h> -#include <string.h> #include <syslog.h> +#include <rule.h> #include <arpa/inet.h> #include <linux/netfilter.h> +#include <linux/netfilter/nf_log.h> #include <netinet/ip_icmp.h> #include <netinet/icmp6.h> #include <statement.h> +#include <tcpopt.h> #include <utils.h> #include <list.h> #include <xt.h> @@ -49,7 +51,7 @@ void stmt_free(struct stmt *stmt) return; if (stmt->ops->destroy) stmt->ops->destroy(stmt); - xfree(stmt); + free(stmt); } void stmt_list_free(struct list_head *list) @@ -111,6 +113,50 @@ struct stmt *verdict_stmt_alloc(const struct location *loc, struct expr *expr) return stmt; } +static const char *chain_verdict(const struct expr *expr) +{ + switch (expr->verdict) { + case NFT_JUMP: + return "jump"; + case NFT_GOTO: + return "goto"; + default: + BUG("unknown chain verdict"); + } +} + +static void chain_stmt_print(const struct stmt *stmt, struct output_ctx *octx) +{ + nft_print(octx, "%s {\n", chain_verdict(stmt->chain.expr)); + chain_rules_print(stmt->chain.chain, octx, "\t"); + nft_print(octx, "\t\t}"); +} + +static void chain_stmt_destroy(struct stmt *stmt) +{ + expr_free(stmt->chain.expr); +} + +static const struct stmt_ops chain_stmt_ops = { + .type = STMT_CHAIN, + .name = "chain", + .print = chain_stmt_print, + .destroy = chain_stmt_destroy, +}; + +struct stmt *chain_stmt_alloc(const struct location *loc, struct chain *chain, + enum nft_verdicts verdict) +{ + struct stmt *stmt; + + stmt = stmt_alloc(loc, &chain_stmt_ops); + stmt->chain.chain = chain; + stmt->chain.expr = verdict_expr_alloc(loc, verdict, NULL); + stmt->chain.expr->chain_id = chain->handle.chain_id; + + return stmt; +} + static void meter_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { unsigned int flags = octx->flags; @@ -137,7 +183,7 @@ static void meter_stmt_destroy(struct stmt *stmt) expr_free(stmt->meter.key); expr_free(stmt->meter.set); stmt_free(stmt->meter.stmt); - xfree(stmt->meter.name); + free_const(stmt->meter.name); } static const struct stmt_ops meter_stmt_ops = { @@ -155,7 +201,7 @@ struct stmt *meter_stmt_alloc(const struct location *loc) static void connlimit_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { - nft_print(octx, "ct count %s%u ", + nft_print(octx, "ct count %s%u", stmt->connlimit.flags ? "over " : "", stmt->connlimit.count); } @@ -202,6 +248,37 @@ struct stmt *counter_stmt_alloc(const struct location *loc) return stmt; } +static void last_stmt_print(const struct stmt *stmt, struct output_ctx *octx) +{ + nft_print(octx, "last"); + + if (nft_output_stateless(octx)) + return; + + nft_print(octx, " used "); + + if (stmt->last.set) + time_print(stmt->last.used, octx); + else + nft_print(octx, "never"); +} + +static const struct stmt_ops last_stmt_ops = { + .type = STMT_LAST, + .name = "last", + .print = last_stmt_print, + .json = last_stmt_json, +}; + +struct stmt *last_stmt_alloc(const struct location *loc) +{ + struct stmt *stmt; + + stmt = stmt_alloc(loc, &last_stmt_ops); + stmt->flags |= STMT_F_STATEFUL; + return stmt; +} + static const char *objref_type[NFT_OBJECT_MAX + 1] = { [NFT_OBJECT_COUNTER] = "counter", [NFT_OBJECT_QUOTA] = "quota", @@ -300,8 +377,12 @@ int log_level_parse(const char *level) static void log_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { nft_print(octx, "log"); - if (stmt->log.flags & STMT_LOG_PREFIX) - nft_print(octx, " prefix \"%s\"", stmt->log.prefix); + if (stmt->log.flags & STMT_LOG_PREFIX) { + char prefix[NF_LOG_PREFIXLEN] = {}; + + expr_to_string(stmt->log.prefix, prefix); + nft_print(octx, " prefix \"%s\"", prefix); + } if (stmt->log.flags & STMT_LOG_GROUP) nft_print(octx, " group %u", stmt->log.group); if (stmt->log.flags & STMT_LOG_SNAPLEN) @@ -338,7 +419,7 @@ static void log_stmt_print(const struct stmt *stmt, struct output_ctx *octx) static void log_stmt_destroy(struct stmt *stmt) { - xfree(stmt->log.prefix); + expr_free(stmt->log.prefix); } static const struct stmt_ops log_stmt_ops = { @@ -404,9 +485,7 @@ static void limit_stmt_print(const struct stmt *stmt, struct output_ctx *octx) nft_print(octx, "limit rate %s%" PRIu64 "/%s", inv ? "over " : "", stmt->limit.rate, get_unit(stmt->limit.unit)); - if (stmt->limit.burst && stmt->limit.burst != 5) - nft_print(octx, " burst %u packets", - stmt->limit.burst); + nft_print(octx, " burst %u packets", stmt->limit.burst); break; case NFT_LIMIT_PKT_BYTES: data_unit = get_rate(stmt->limit.rate, &rate); @@ -414,7 +493,7 @@ static void limit_stmt_print(const struct stmt *stmt, struct output_ctx *octx) nft_print(octx, "limit rate %s%" PRIu64 " %s/%s", inv ? "over " : "", rate, data_unit, get_unit(stmt->limit.unit)); - if (stmt->limit.burst > 0) { + if (stmt->limit.burst != 0) { uint64_t burst; data_unit = get_rate(stmt->limit.burst, &burst); @@ -443,20 +522,25 @@ struct stmt *limit_stmt_alloc(const struct location *loc) static void queue_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { - const char *delim = " "; + struct expr *e = stmt->queue.queue; + const char *delim = " flags "; nft_print(octx, "queue"); - if (stmt->queue.queue != NULL) { - nft_print(octx, " num "); - expr_print(stmt->queue.queue, octx); - } + if (stmt->queue.flags & NFT_QUEUE_FLAG_BYPASS) { nft_print(octx, "%sbypass", delim); delim = ","; } + if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT) nft_print(octx, "%sfanout", delim); + if (e) { + nft_print(octx, " to "); + expr_print(stmt->queue.queue, octx); + } else { + nft_print(octx, " to 0"); + } } static void queue_stmt_destroy(struct stmt *stmt) @@ -472,9 +556,15 @@ static const struct stmt_ops queue_stmt_ops = { .destroy = queue_stmt_destroy, }; -struct stmt *queue_stmt_alloc(const struct location *loc) +struct stmt *queue_stmt_alloc(const struct location *loc, struct expr *e, uint16_t flags) { - return stmt_alloc(loc, &queue_stmt_ops); + struct stmt *stmt; + + stmt = stmt_alloc(loc, &queue_stmt_ops); + stmt->queue.queue = e; + stmt->queue.flags = flags; + + return stmt; } static void quota_stmt_print(const struct stmt *stmt, struct output_ctx *octx) @@ -519,7 +609,7 @@ static void reject_stmt_print(const struct stmt *stmt, struct output_ctx *octx) case NFT_REJECT_ICMPX_UNREACH: if (stmt->reject.icmp_code == NFT_REJECT_ICMPX_PORT_UNREACH) break; - nft_print(octx, " with icmpx type "); + nft_print(octx, " with icmpx "); expr_print(stmt->reject.expr, octx); break; case NFT_REJECT_ICMP_UNREACH: @@ -528,14 +618,14 @@ static void reject_stmt_print(const struct stmt *stmt, struct output_ctx *octx) if (!stmt->reject.verbose_print && stmt->reject.icmp_code == ICMP_PORT_UNREACH) break; - nft_print(octx, " with icmp type "); + nft_print(octx, " with icmp "); expr_print(stmt->reject.expr, octx); break; case NFPROTO_IPV6: if (!stmt->reject.verbose_print && stmt->reject.icmp_code == ICMP6_DST_UNREACH_NOPORT) break; - nft_print(octx, " with icmpv6 type "); + nft_print(octx, " with icmpv6 "); expr_print(stmt->reject.expr, octx); break; } @@ -607,6 +697,9 @@ static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx) break; } + if (stmt->nat.type_flags & STMT_NAT_F_PREFIX) + nft_print(octx, " prefix"); + nft_print(octx, " to"); } @@ -675,15 +768,16 @@ const char * const set_stmt_op_names[] = { static void set_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { unsigned int flags = octx->flags; + struct stmt *this; nft_print(octx, "%s ", set_stmt_op_names[stmt->set.op]); expr_print(stmt->set.set, octx); nft_print(octx, " { "); expr_print(stmt->set.key, octx); - if (stmt->set.stmt) { + list_for_each_entry(this, &stmt->set.stmt_list, list) { nft_print(octx, " "); octx->flags |= NFT_CTX_OUTPUT_STATELESS; - stmt_print(stmt->set.stmt, octx); + stmt_print(this, octx); octx->flags = flags; } nft_print(octx, " }"); @@ -691,9 +785,12 @@ static void set_stmt_print(const struct stmt *stmt, struct output_ctx *octx) static void set_stmt_destroy(struct stmt *stmt) { + struct stmt *this, *next; + expr_free(stmt->set.key); expr_free(stmt->set.set); - stmt_free(stmt->set.stmt); + list_for_each_entry_safe(this, next, &stmt->set.stmt_list, list) + stmt_free(this); } static const struct stmt_ops set_stmt_ops = { @@ -706,21 +803,27 @@ static const struct stmt_ops set_stmt_ops = { struct stmt *set_stmt_alloc(const struct location *loc) { - return stmt_alloc(loc, &set_stmt_ops); + struct stmt *stmt; + + stmt = stmt_alloc(loc, &set_stmt_ops); + init_list_head(&stmt->set.stmt_list); + + return stmt; } static void map_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { unsigned int flags = octx->flags; + struct stmt *this; nft_print(octx, "%s ", set_stmt_op_names[stmt->map.op]); expr_print(stmt->map.set, octx); nft_print(octx, " { "); expr_print(stmt->map.key, octx); - if (stmt->map.stmt) { + list_for_each_entry(this, &stmt->map.stmt_list, list) { nft_print(octx, " "); octx->flags |= NFT_CTX_OUTPUT_STATELESS; - stmt_print(stmt->map.stmt, octx); + stmt_print(this, octx); octx->flags = flags; } nft_print(octx, " : "); @@ -730,10 +833,13 @@ static void map_stmt_print(const struct stmt *stmt, struct output_ctx *octx) static void map_stmt_destroy(struct stmt *stmt) { + struct stmt *this, *next; + expr_free(stmt->map.key); expr_free(stmt->map.data); expr_free(stmt->map.set); - stmt_free(stmt->map.stmt); + list_for_each_entry_safe(this, next, &stmt->map.stmt_list, list) + stmt_free(this); } static const struct stmt_ops map_stmt_ops = { @@ -741,11 +847,17 @@ static const struct stmt_ops map_stmt_ops = { .name = "map", .print = map_stmt_print, .destroy = map_stmt_destroy, + .json = map_stmt_json, }; struct stmt *map_stmt_alloc(const struct location *loc) { - return stmt_alloc(loc, &map_stmt_ops); + struct stmt *stmt; + + stmt = stmt_alloc(loc, &map_stmt_ops); + init_list_head(&stmt->map.stmt_list); + + return stmt; } static void dup_stmt_print(const struct stmt *stmt, struct output_ctx *octx) @@ -827,6 +939,37 @@ struct stmt *fwd_stmt_alloc(const struct location *loc) return stmt_alloc(loc, &fwd_stmt_ops); } +static void optstrip_stmt_print(const struct stmt *stmt, struct output_ctx *octx) +{ + const struct expr *expr = stmt->optstrip.expr; + + nft_print(octx, "reset "); + expr_print(expr, octx); +} + +static void optstrip_stmt_destroy(struct stmt *stmt) +{ + expr_free(stmt->optstrip.expr); +} + +static const struct stmt_ops optstrip_stmt_ops = { + .type = STMT_OPTSTRIP, + .name = "optstrip", + .print = optstrip_stmt_print, + .json = optstrip_stmt_json, + .destroy = optstrip_stmt_destroy, +}; + +struct stmt *optstrip_stmt_alloc(const struct location *loc, struct expr *e) +{ + struct stmt *stmt = stmt_alloc(loc, &optstrip_stmt_ops); + + e->exthdr.flags |= NFT_EXTHDR_F_PRESENT; + stmt->optstrip.expr = e; + + return stmt; +} + static void tproxy_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { nft_print(octx, "tproxy"); @@ -846,7 +989,7 @@ static void tproxy_stmt_print(const struct stmt *stmt, struct output_ctx *octx) expr_print(stmt->tproxy.addr, octx); } } - if (stmt->tproxy.port && stmt->tproxy.port->etype == EXPR_VALUE) { + if (stmt->tproxy.port) { if (!stmt->tproxy.addr) nft_print(octx, " "); nft_print(octx, ":"); @@ -883,6 +1026,7 @@ static const struct stmt_ops xt_stmt_ops = { .name = "xt", .print = xt_stmt_print, .destroy = xt_stmt_destroy, + .json = xt_stmt_json, }; struct stmt *xt_stmt_alloc(const struct location *loc) |