diff options
Diffstat (limited to 'src/statement.c')
-rw-r--r-- | src/statement.c | 204 |
1 files changed, 165 insertions, 39 deletions
diff --git a/src/statement.c b/src/statement.c index f7f1c0c4..695b57a6 100644 --- a/src/statement.c +++ b/src/statement.c @@ -8,12 +8,11 @@ * 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> @@ -23,6 +22,7 @@ #include <netinet/ip_icmp.h> #include <netinet/icmp6.h> #include <statement.h> +#include <tcpopt.h> #include <utils.h> #include <list.h> #include <xt.h> @@ -33,25 +33,28 @@ #include <linux/netfilter/nf_log.h> #include <linux/netfilter/nf_synproxy.h> -struct stmt *stmt_alloc(const struct location *loc, - const struct stmt_ops *ops) +struct stmt *stmt_alloc(const struct location *loc, const struct stmt_ops *ops) { struct stmt *stmt; stmt = xzalloc(sizeof(*stmt)); init_list_head(&stmt->list); stmt->location = *loc; - stmt->ops = ops; + stmt->type = ops->type; return stmt; } void stmt_free(struct stmt *stmt) { + const struct stmt_ops *ops; + if (stmt == NULL) return; - if (stmt->ops->destroy) - stmt->ops->destroy(stmt); - xfree(stmt); + + ops = stmt_ops(stmt); + if (ops->destroy) + ops->destroy(stmt); + free(stmt); } void stmt_list_free(struct list_head *list) @@ -66,7 +69,9 @@ void stmt_list_free(struct list_head *list) void stmt_print(const struct stmt *stmt, struct output_ctx *octx) { - stmt->ops->print(stmt, octx); + const struct stmt_ops *ops = stmt_ops(stmt); + + ops->print(stmt, octx); } static void expr_stmt_print(const struct stmt *stmt, struct output_ctx *octx) @@ -183,7 +188,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 = { @@ -201,7 +206,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); } @@ -248,6 +253,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", @@ -346,12 +382,8 @@ 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) { - char prefix[NF_LOG_PREFIXLEN] = {}; - - expr_to_string(stmt->log.prefix, prefix); - nft_print(octx, " prefix \"%s\"", prefix); - } + if (stmt->log.flags & STMT_LOG_PREFIX) + nft_print(octx, " prefix \"%s\"", stmt->log.prefix); if (stmt->log.flags & STMT_LOG_GROUP) nft_print(octx, " group %u", stmt->log.group); if (stmt->log.flags & STMT_LOG_SNAPLEN) @@ -388,7 +420,7 @@ static void log_stmt_print(const struct stmt *stmt, struct output_ctx *octx) static void log_stmt_destroy(struct stmt *stmt) { - expr_free(stmt->log.prefix); + free_const(stmt->log.prefix); } static const struct stmt_ops log_stmt_ops = { @@ -454,9 +486,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); @@ -464,7 +494,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 != 5) { + if (stmt->limit.burst != 0) { uint64_t burst; data_unit = get_rate(stmt->limit.burst, &burst); @@ -493,20 +523,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) @@ -522,9 +557,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) @@ -569,7 +610,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: @@ -578,14 +619,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; } @@ -657,12 +698,8 @@ static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx) break; } - if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) - nft_print(octx, " addr . port"); - else if (stmt->nat.type_flags & STMT_NAT_F_PREFIX) + if (stmt->nat.type_flags & STMT_NAT_F_PREFIX) nft_print(octx, " prefix"); - else if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL) - nft_print(octx, " interval"); nft_print(octx, " to"); } @@ -811,6 +848,7 @@ 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) @@ -902,6 +940,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"); @@ -921,7 +990,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, ":"); @@ -958,6 +1027,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) @@ -1014,3 +1084,59 @@ struct stmt *synproxy_stmt_alloc(const struct location *loc) { return stmt_alloc(loc, &synproxy_stmt_ops); } + +/* For src/optimize.c */ +static struct stmt_ops invalid_stmt_ops = { + .type = STMT_INVALID, + .name = "unsupported", +}; + +static const struct stmt_ops *__stmt_ops_by_type(enum stmt_types type) +{ + switch (type) { + case STMT_INVALID: return &invalid_stmt_ops; + case STMT_EXPRESSION: return &expr_stmt_ops; + case STMT_VERDICT: return &verdict_stmt_ops; + case STMT_METER: return &meter_stmt_ops; + case STMT_COUNTER: return &counter_stmt_ops; + case STMT_PAYLOAD: return &payload_stmt_ops; + case STMT_META: return &meta_stmt_ops; + case STMT_LIMIT: return &limit_stmt_ops; + case STMT_LOG: return &log_stmt_ops; + case STMT_REJECT: return &reject_stmt_ops; + case STMT_NAT: return &nat_stmt_ops; + case STMT_TPROXY: return &tproxy_stmt_ops; + case STMT_QUEUE: return &queue_stmt_ops; + case STMT_CT: return &ct_stmt_ops; + case STMT_SET: return &set_stmt_ops; + case STMT_DUP: return &dup_stmt_ops; + case STMT_FWD: return &fwd_stmt_ops; + case STMT_XT: return &xt_stmt_ops; + case STMT_QUOTA: return "a_stmt_ops; + case STMT_NOTRACK: return ¬rack_stmt_ops; + case STMT_OBJREF: return &objref_stmt_ops; + case STMT_EXTHDR: return &exthdr_stmt_ops; + case STMT_FLOW_OFFLOAD: return &flow_offload_stmt_ops; + case STMT_CONNLIMIT: return &connlimit_stmt_ops; + case STMT_MAP: return &map_stmt_ops; + case STMT_SYNPROXY: return &synproxy_stmt_ops; + case STMT_CHAIN: return &chain_stmt_ops; + case STMT_OPTSTRIP: return &optstrip_stmt_ops; + case STMT_LAST: return &last_stmt_ops; + default: + break; + } + + return NULL; +} + +const struct stmt_ops *stmt_ops(const struct stmt *stmt) +{ + const struct stmt_ops *ops; + + ops = __stmt_ops_by_type(stmt->type); + if (!ops) + BUG("Unknown statement type %d\n", stmt->type); + + return ops; +} |