|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <stddef.h>
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
#include <stdio.h>
|
|
Packit |
c5a612 |
#include <stdint.h>
|
|
Packit |
c5a612 |
#include <inttypes.h>
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <syslog.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <arpa/inet.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter.h>
|
|
Packit |
c5a612 |
#include <netinet/ip_icmp.h>
|
|
Packit |
c5a612 |
#include <netinet/icmp6.h>
|
|
Packit |
c5a612 |
#include <statement.h>
|
|
Packit |
c5a612 |
#include <utils.h>
|
|
Packit |
c5a612 |
#include <list.h>
|
|
Packit |
c5a612 |
#include <xt.h>
|
|
Packit |
c5a612 |
#include <json.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <netinet/in.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter/nf_nat.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter/nf_log.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter/nf_synproxy.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *stmt_alloc(const struct location *loc,
|
|
Packit |
c5a612 |
const struct stmt_ops *ops)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = xzalloc(sizeof(*stmt));
|
|
Packit |
c5a612 |
init_list_head(&stmt->list);
|
|
Packit |
c5a612 |
stmt->location = *loc;
|
|
Packit |
c5a612 |
stmt->ops = ops;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void stmt_free(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (stmt == NULL)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
if (stmt->ops->destroy)
|
|
Packit |
c5a612 |
stmt->ops->destroy(stmt);
|
|
Packit |
c5a612 |
xfree(stmt);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void stmt_list_free(struct list_head *list)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *i, *next;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry_safe(i, next, list, list) {
|
|
Packit |
c5a612 |
list_del(&i->list);
|
|
Packit |
c5a612 |
stmt_free(i);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
stmt->ops->print(stmt, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void expr_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_print(stmt->expr, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void expr_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->expr);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops expr_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_EXPRESSION,
|
|
Packit |
c5a612 |
.name = "expression",
|
|
Packit |
c5a612 |
.print = expr_stmt_print,
|
|
Packit |
c5a612 |
.json = expr_stmt_json,
|
|
Packit |
c5a612 |
.destroy = expr_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *expr_stmt_alloc(const struct location *loc, struct expr *expr)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, &expr_stmt_ops);
|
|
Packit |
c5a612 |
stmt->expr = expr;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops verdict_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_VERDICT,
|
|
Packit |
c5a612 |
.name = "verdict",
|
|
Packit |
c5a612 |
.print = expr_stmt_print,
|
|
Packit |
c5a612 |
.json = verdict_stmt_json,
|
|
Packit |
c5a612 |
.destroy = expr_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *verdict_stmt_alloc(const struct location *loc, struct expr *expr)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, &verdict_stmt_ops);
|
|
Packit |
c5a612 |
stmt->expr = expr;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void meter_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int flags = octx->flags;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, "meter ");
|
|
Packit |
c5a612 |
if (stmt->meter.set) {
|
|
Packit |
c5a612 |
expr_print(stmt->meter.set, octx);
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_print(octx, "size %u { ", stmt->meter.size);
|
|
Packit |
c5a612 |
expr_print(stmt->meter.key, octx);
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
octx->flags |= NFT_CTX_OUTPUT_STATELESS;
|
|
Packit |
c5a612 |
stmt_print(stmt->meter.stmt, octx);
|
|
Packit |
c5a612 |
octx->flags = flags;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, " }");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void meter_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->meter.key);
|
|
Packit |
c5a612 |
expr_free(stmt->meter.set);
|
|
Packit |
c5a612 |
stmt_free(stmt->meter.stmt);
|
|
Packit |
c5a612 |
xfree(stmt->meter.name);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops meter_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_METER,
|
|
Packit |
c5a612 |
.name = "meter",
|
|
Packit |
c5a612 |
.print = meter_stmt_print,
|
|
Packit |
c5a612 |
.json = meter_stmt_json,
|
|
Packit |
c5a612 |
.destroy = meter_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *meter_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &meter_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void connlimit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_print(octx, "ct count %s%u ",
|
|
Packit |
c5a612 |
stmt->connlimit.flags ? "over " : "", stmt->connlimit.count);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops connlimit_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_CONNLIMIT,
|
|
Packit |
c5a612 |
.name = "connlimit",
|
|
Packit |
c5a612 |
.print = connlimit_stmt_print,
|
|
Packit |
c5a612 |
.json = connlimit_stmt_json,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *connlimit_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, &connlimit_stmt_ops);
|
|
Packit |
c5a612 |
stmt->flags |= STMT_F_STATEFUL;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void counter_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_print(octx, "counter");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_output_stateless(octx))
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, " packets %" PRIu64 " bytes %" PRIu64,
|
|
Packit |
c5a612 |
stmt->counter.packets, stmt->counter.bytes);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops counter_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_COUNTER,
|
|
Packit |
c5a612 |
.name = "counter",
|
|
Packit |
c5a612 |
.print = counter_stmt_print,
|
|
Packit |
c5a612 |
.json = counter_stmt_json,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *counter_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, &counter_stmt_ops);
|
|
Packit |
c5a612 |
stmt->flags |= STMT_F_STATEFUL;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *objref_type[NFT_OBJECT_MAX + 1] = {
|
|
Packit |
c5a612 |
[NFT_OBJECT_COUNTER] = "counter",
|
|
Packit |
c5a612 |
[NFT_OBJECT_QUOTA] = "quota",
|
|
Packit |
c5a612 |
[NFT_OBJECT_CT_HELPER] = "ct helper",
|
|
Packit |
c5a612 |
[NFT_OBJECT_LIMIT] = "limit",
|
|
Packit |
c5a612 |
[NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
|
|
Packit |
c5a612 |
[NFT_OBJECT_SECMARK] = "secmark",
|
|
Packit |
c5a612 |
[NFT_OBJECT_SYNPROXY] = "synproxy",
|
|
Packit |
c5a612 |
[NFT_OBJECT_CT_EXPECT] = "ct expectation",
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const char *objref_type_name(uint32_t type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (type > NFT_OBJECT_MAX)
|
|
Packit |
c5a612 |
return "unknown";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return objref_type[type];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void objref_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (stmt->objref.type) {
|
|
Packit |
c5a612 |
case NFT_OBJECT_CT_HELPER:
|
|
Packit |
c5a612 |
nft_print(octx, "ct helper set ");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_CT_TIMEOUT:
|
|
Packit |
c5a612 |
nft_print(octx, "ct timeout set ");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_CT_EXPECT:
|
|
Packit |
c5a612 |
nft_print(octx, "ct expectation set ");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_SECMARK:
|
|
Packit |
c5a612 |
nft_print(octx, "meta secmark set ");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
nft_print(octx, "%s name ",
|
|
Packit |
c5a612 |
objref_type_name(stmt->objref.type));
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
expr_print(stmt->objref.expr, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void objref_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->objref.expr);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops objref_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_OBJREF,
|
|
Packit |
c5a612 |
.name = "objref",
|
|
Packit |
c5a612 |
.print = objref_stmt_print,
|
|
Packit |
c5a612 |
.json = objref_stmt_json,
|
|
Packit |
c5a612 |
.destroy = objref_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *objref_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, &objref_stmt_ops);
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *syslog_level[NFT_LOGLEVEL_MAX + 1] = {
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_EMERG] = "emerg",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_ALERT] = "alert",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_CRIT] = "crit",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_ERR] = "err",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_WARNING] = "warn",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_NOTICE] = "notice",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_INFO] = "info",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_DEBUG] = "debug",
|
|
Packit |
c5a612 |
[NFT_LOGLEVEL_AUDIT] = "audit"
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const char *log_level(uint32_t level)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (level > NFT_LOGLEVEL_MAX)
|
|
Packit |
c5a612 |
return "unknown";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return syslog_level[level];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int log_level_parse(const char *level)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; i <= NFT_LOGLEVEL_MAX; i++) {
|
|
Packit |
c5a612 |
if (syslog_level[i] &&
|
|
Packit |
c5a612 |
!strcmp(level, syslog_level[i]))
|
|
Packit |
c5a612 |
return i;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void log_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_print(octx, "log");
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_PREFIX)
|
|
Packit |
c5a612 |
nft_print(octx, " prefix \"%s\"", stmt->log.prefix);
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_GROUP)
|
|
Packit |
c5a612 |
nft_print(octx, " group %u", stmt->log.group);
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_SNAPLEN)
|
|
Packit |
c5a612 |
nft_print(octx, " snaplen %u", stmt->log.snaplen);
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_QTHRESHOLD)
|
|
Packit |
c5a612 |
nft_print(octx, " queue-threshold %u", stmt->log.qthreshold);
|
|
Packit |
c5a612 |
if ((stmt->log.flags & STMT_LOG_LEVEL) &&
|
|
Packit |
c5a612 |
stmt->log.level != LOG_WARNING)
|
|
Packit |
c5a612 |
nft_print(octx, " level %s", log_level(stmt->log.level));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if ((stmt->log.logflags & NF_LOG_MASK) == NF_LOG_MASK) {
|
|
Packit |
c5a612 |
nft_print(octx, " flags all");
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
if (stmt->log.logflags & (NF_LOG_TCPSEQ | NF_LOG_TCPOPT)) {
|
|
Packit |
c5a612 |
const char *delim = " ";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, " flags tcp");
|
|
Packit |
c5a612 |
if (stmt->log.logflags & NF_LOG_TCPSEQ) {
|
|
Packit |
c5a612 |
nft_print(octx, " sequence");
|
|
Packit |
c5a612 |
delim = ",";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->log.logflags & NF_LOG_TCPOPT)
|
|
Packit |
c5a612 |
nft_print(octx, "%soptions",
|
|
Packit |
c5a612 |
delim);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->log.logflags & NF_LOG_IPOPT)
|
|
Packit |
c5a612 |
nft_print(octx, " flags ip options");
|
|
Packit |
c5a612 |
if (stmt->log.logflags & NF_LOG_UID)
|
|
Packit |
c5a612 |
nft_print(octx, " flags skuid");
|
|
Packit |
c5a612 |
if (stmt->log.logflags & NF_LOG_MACDECODE)
|
|
Packit |
c5a612 |
nft_print(octx, " flags ether");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void log_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
xfree(stmt->log.prefix);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops log_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_LOG,
|
|
Packit |
c5a612 |
.name = "log",
|
|
Packit |
c5a612 |
.print = log_stmt_print,
|
|
Packit |
c5a612 |
.json = log_stmt_json,
|
|
Packit |
c5a612 |
.destroy = log_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *log_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &log_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const char *get_unit(uint64_t u)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (u) {
|
|
Packit |
c5a612 |
case 1: return "second";
|
|
Packit |
c5a612 |
case 60: return "minute";
|
|
Packit |
c5a612 |
case 60 * 60: return "hour";
|
|
Packit |
c5a612 |
case 60 * 60 * 24: return "day";
|
|
Packit |
c5a612 |
case 60 * 60 * 24 * 7: return "week";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return "error";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char * const data_unit[] = {
|
|
Packit |
c5a612 |
"bytes",
|
|
Packit |
c5a612 |
"kbytes",
|
|
Packit |
c5a612 |
"mbytes",
|
|
Packit |
c5a612 |
NULL
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const char *get_rate(uint64_t byte_rate, uint64_t *rate)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!byte_rate) {
|
|
Packit |
c5a612 |
*rate = 0;
|
|
Packit |
c5a612 |
return data_unit[0];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; data_unit[i + 1] != NULL; i++) {
|
|
Packit |
c5a612 |
if (byte_rate % 1024)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
byte_rate /= 1024;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*rate = byte_rate;
|
|
Packit |
c5a612 |
return data_unit[i];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void limit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
bool inv = stmt->limit.flags & NFT_LIMIT_F_INV;
|
|
Packit |
c5a612 |
const char *data_unit;
|
|
Packit |
c5a612 |
uint64_t rate;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (stmt->limit.type) {
|
|
Packit |
c5a612 |
case NFT_LIMIT_PKTS:
|
|
Packit |
c5a612 |
nft_print(octx, "limit rate %s%" PRIu64 "/%s",
|
|
Packit |
c5a612 |
inv ? "over " : "", stmt->limit.rate,
|
|
Packit |
c5a612 |
get_unit(stmt->limit.unit));
|
|
Packit |
c5a612 |
if (stmt->limit.burst && stmt->limit.burst != 5)
|
|
Packit |
c5a612 |
nft_print(octx, " burst %u packets",
|
|
Packit |
c5a612 |
stmt->limit.burst);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_LIMIT_PKT_BYTES:
|
|
Packit |
c5a612 |
data_unit = get_rate(stmt->limit.rate, &rate;;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, "limit rate %s%" PRIu64 " %s/%s",
|
|
Packit |
c5a612 |
inv ? "over " : "", rate, data_unit,
|
|
Packit |
c5a612 |
get_unit(stmt->limit.unit));
|
|
Packit |
c5a612 |
if (stmt->limit.burst > 0) {
|
|
Packit |
c5a612 |
uint64_t burst;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
data_unit = get_rate(stmt->limit.burst, &burst);
|
|
Packit |
c5a612 |
nft_print(octx, " burst %" PRIu64 " %s", burst,
|
|
Packit |
c5a612 |
data_unit);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops limit_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_LIMIT,
|
|
Packit |
c5a612 |
.name = "limit",
|
|
Packit |
c5a612 |
.print = limit_stmt_print,
|
|
Packit |
c5a612 |
.json = limit_stmt_json,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *limit_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, &limit_stmt_ops);
|
|
Packit |
c5a612 |
stmt->flags |= STMT_F_STATEFUL;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void queue_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const char *delim = " ";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, "queue");
|
|
Packit |
c5a612 |
if (stmt->queue.queue != NULL) {
|
|
Packit |
c5a612 |
nft_print(octx, " num ");
|
|
Packit |
c5a612 |
expr_print(stmt->queue.queue, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->queue.flags & NFT_QUEUE_FLAG_BYPASS) {
|
|
Packit |
c5a612 |
nft_print(octx, "%sbypass", delim);
|
|
Packit |
c5a612 |
delim = ",";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT)
|
|
Packit |
c5a612 |
nft_print(octx, "%sfanout", delim);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void queue_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->queue.queue);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops queue_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_QUEUE,
|
|
Packit |
c5a612 |
.name = "queue",
|
|
Packit |
c5a612 |
.print = queue_stmt_print,
|
|
Packit |
c5a612 |
.json = queue_stmt_json,
|
|
Packit |
c5a612 |
.destroy = queue_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *queue_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &queue_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void quota_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
bool inv = stmt->quota.flags & NFT_QUOTA_F_INV;
|
|
Packit |
c5a612 |
const char *data_unit;
|
|
Packit |
c5a612 |
uint64_t bytes, used;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
data_unit = get_rate(stmt->quota.bytes, &bytes);
|
|
Packit |
c5a612 |
nft_print(octx, "quota %s%" PRIu64 " %s",
|
|
Packit |
c5a612 |
inv ? "over " : "", bytes, data_unit);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!nft_output_stateless(octx) && stmt->quota.used) {
|
|
Packit |
c5a612 |
data_unit = get_rate(stmt->quota.used, &used);
|
|
Packit |
c5a612 |
nft_print(octx, " used %" PRIu64 " %s", used, data_unit);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops quota_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_QUOTA,
|
|
Packit |
c5a612 |
.name = "quota",
|
|
Packit |
c5a612 |
.print = quota_stmt_print,
|
|
Packit |
c5a612 |
.json = quota_stmt_json,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *quota_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt = stmt_alloc(loc, "a_stmt_ops);
|
|
Packit |
c5a612 |
stmt->flags |= STMT_F_STATEFUL;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void reject_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_print(octx, "reject");
|
|
Packit |
c5a612 |
switch (stmt->reject.type) {
|
|
Packit |
c5a612 |
case NFT_REJECT_TCP_RST:
|
|
Packit |
c5a612 |
nft_print(octx, " with tcp reset");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_REJECT_ICMPX_UNREACH:
|
|
Packit |
c5a612 |
if (stmt->reject.icmp_code == NFT_REJECT_ICMPX_PORT_UNREACH)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
nft_print(octx, " with icmpx type ");
|
|
Packit |
c5a612 |
expr_print(stmt->reject.expr, octx);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_REJECT_ICMP_UNREACH:
|
|
Packit |
c5a612 |
switch (stmt->reject.family) {
|
|
Packit |
c5a612 |
case NFPROTO_IPV4:
|
|
Packit |
c5a612 |
if (!stmt->reject.verbose_print &&
|
|
Packit |
c5a612 |
stmt->reject.icmp_code == ICMP_PORT_UNREACH)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
nft_print(octx, " with icmp type ");
|
|
Packit |
c5a612 |
expr_print(stmt->reject.expr, octx);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFPROTO_IPV6:
|
|
Packit |
c5a612 |
if (!stmt->reject.verbose_print &&
|
|
Packit |
c5a612 |
stmt->reject.icmp_code == ICMP6_DST_UNREACH_NOPORT)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
nft_print(octx, " with icmpv6 type ");
|
|
Packit |
c5a612 |
expr_print(stmt->reject.expr, octx);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void reject_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->reject.expr);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops reject_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_REJECT,
|
|
Packit |
c5a612 |
.name = "reject",
|
|
Packit |
c5a612 |
.print = reject_stmt_print,
|
|
Packit |
c5a612 |
.json = reject_stmt_json,
|
|
Packit |
c5a612 |
.destroy = reject_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *reject_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &reject_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void print_nf_nat_flags(uint32_t flags, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const char *delim = " ";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (flags == 0)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (flags & NF_NAT_RANGE_PROTO_RANDOM) {
|
|
Packit |
c5a612 |
nft_print(octx, "%srandom", delim);
|
|
Packit |
c5a612 |
delim = ",";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
|
|
Packit |
c5a612 |
nft_print(octx, "%sfully-random", delim);
|
|
Packit |
c5a612 |
delim = ",";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (flags & NF_NAT_RANGE_PERSISTENT)
|
|
Packit |
c5a612 |
nft_print(octx, "%spersistent", delim);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const char *nat_etype2str(enum nft_nat_etypes type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
static const char * const nat_types[] = {
|
|
Packit |
c5a612 |
[NFT_NAT_SNAT] = "snat",
|
|
Packit |
c5a612 |
[NFT_NAT_DNAT] = "dnat",
|
|
Packit |
c5a612 |
[NFT_NAT_MASQ] = "masquerade",
|
|
Packit |
c5a612 |
[NFT_NAT_REDIR] = "redirect",
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nat_types[type];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_print(octx, "%s", nat_etype2str(stmt->nat.type));
|
|
Packit |
c5a612 |
if (stmt->nat.addr || stmt->nat.proto) {
|
|
Packit |
c5a612 |
switch (stmt->nat.family) {
|
|
Packit |
c5a612 |
case NFPROTO_IPV4:
|
|
Packit |
c5a612 |
nft_print(octx, " ip");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFPROTO_IPV6:
|
|
Packit |
c5a612 |
nft_print(octx, " ip6");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, " to");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->nat.addr) {
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
if (stmt->nat.proto) {
|
|
Packit |
c5a612 |
if (stmt->nat.addr->etype == EXPR_VALUE &&
|
|
Packit |
c5a612 |
stmt->nat.addr->dtype->type == TYPE_IP6ADDR) {
|
|
Packit |
c5a612 |
nft_print(octx, "[");
|
|
Packit |
c5a612 |
expr_print(stmt->nat.addr, octx);
|
|
Packit |
c5a612 |
nft_print(octx, "]");
|
|
Packit |
c5a612 |
} else if (stmt->nat.addr->etype == EXPR_RANGE &&
|
|
Packit |
c5a612 |
stmt->nat.addr->left->dtype->type == TYPE_IP6ADDR) {
|
|
Packit |
c5a612 |
nft_print(octx, "[");
|
|
Packit |
c5a612 |
expr_print(stmt->nat.addr->left, octx);
|
|
Packit |
c5a612 |
nft_print(octx, "]-[");
|
|
Packit |
c5a612 |
expr_print(stmt->nat.addr->right, octx);
|
|
Packit |
c5a612 |
nft_print(octx, "]");
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
expr_print(stmt->nat.addr, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
expr_print(stmt->nat.addr, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->nat.proto) {
|
|
Packit |
c5a612 |
if (!stmt->nat.addr)
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
nft_print(octx, ":");
|
|
Packit |
c5a612 |
expr_print(stmt->nat.proto, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
print_nf_nat_flags(stmt->nat.flags, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void nat_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->nat.addr);
|
|
Packit |
c5a612 |
expr_free(stmt->nat.proto);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops nat_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_NAT,
|
|
Packit |
c5a612 |
.name = "nat",
|
|
Packit |
c5a612 |
.print = nat_stmt_print,
|
|
Packit |
c5a612 |
.json = nat_stmt_json,
|
|
Packit |
c5a612 |
.destroy = nat_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *nat_stmt_alloc(const struct location *loc,
|
|
Packit |
c5a612 |
enum nft_nat_etypes type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct stmt *stmt = stmt_alloc(loc, &nat_stmt_ops);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
stmt->nat.type = type;
|
|
Packit |
c5a612 |
return stmt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const char * const set_stmt_op_names[] = {
|
|
Packit |
c5a612 |
[NFT_DYNSET_OP_ADD] = "add",
|
|
Packit |
c5a612 |
[NFT_DYNSET_OP_UPDATE] = "update",
|
|
Packit |
c5a612 |
[NFT_DYNSET_OP_DELETE] = "delete",
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void set_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int flags = octx->flags;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, "%s ", set_stmt_op_names[stmt->set.op]);
|
|
Packit |
c5a612 |
expr_print(stmt->set.set, octx);
|
|
Packit |
c5a612 |
nft_print(octx, " { ");
|
|
Packit |
c5a612 |
expr_print(stmt->set.key, octx);
|
|
Packit |
c5a612 |
if (stmt->set.stmt) {
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
octx->flags |= NFT_CTX_OUTPUT_STATELESS;
|
|
Packit |
c5a612 |
stmt_print(stmt->set.stmt, octx);
|
|
Packit |
c5a612 |
octx->flags = flags;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_print(octx, " }");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void set_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->set.key);
|
|
Packit |
c5a612 |
expr_free(stmt->set.set);
|
|
Packit |
c5a612 |
stmt_free(stmt->set.stmt);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops set_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_SET,
|
|
Packit |
c5a612 |
.name = "set",
|
|
Packit |
c5a612 |
.print = set_stmt_print,
|
|
Packit |
c5a612 |
.json = set_stmt_json,
|
|
Packit |
c5a612 |
.destroy = set_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *set_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &set_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void map_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int flags = octx->flags;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, "%s ", set_stmt_op_names[stmt->map.op]);
|
|
Packit |
c5a612 |
expr_print(stmt->map.set, octx);
|
|
Packit |
c5a612 |
nft_print(octx, " { ");
|
|
Packit |
c5a612 |
expr_print(stmt->map.key, octx);
|
|
Packit |
c5a612 |
if (stmt->map.stmt) {
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
octx->flags |= NFT_CTX_OUTPUT_STATELESS;
|
|
Packit |
c5a612 |
stmt_print(stmt->map.stmt, octx);
|
|
Packit |
c5a612 |
octx->flags = flags;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_print(octx, " : ");
|
|
Packit |
c5a612 |
expr_print(stmt->map.data, octx);
|
|
Packit |
c5a612 |
nft_print(octx, " }");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void map_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->map.key);
|
|
Packit |
c5a612 |
expr_free(stmt->map.data);
|
|
Packit |
c5a612 |
expr_free(stmt->map.set);
|
|
Packit |
c5a612 |
stmt_free(stmt->map.stmt);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops map_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_MAP,
|
|
Packit |
c5a612 |
.name = "map",
|
|
Packit |
c5a612 |
.print = map_stmt_print,
|
|
Packit |
c5a612 |
.destroy = map_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *map_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &map_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void dup_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_print(octx, "dup");
|
|
Packit |
c5a612 |
if (stmt->dup.to != NULL) {
|
|
Packit |
c5a612 |
nft_print(octx, " to ");
|
|
Packit |
c5a612 |
expr_print(stmt->dup.to, octx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->dup.dev != NULL) {
|
|
Packit |
c5a612 |
nft_print(octx, " device ");
|
|
Packit |
c5a612 |
expr_print(stmt->dup.dev, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void dup_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->dup.to);
|
|
Packit |
c5a612 |
expr_free(stmt->dup.dev);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops dup_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_DUP,
|
|
Packit |
c5a612 |
.name = "dup",
|
|
Packit |
c5a612 |
.print = dup_stmt_print,
|
|
Packit |
c5a612 |
.json = dup_stmt_json,
|
|
Packit |
c5a612 |
.destroy = dup_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *dup_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &dup_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char * const nfproto_family_name_array[NFPROTO_NUMPROTO] = {
|
|
Packit |
c5a612 |
[NFPROTO_IPV4] = "ip",
|
|
Packit |
c5a612 |
[NFPROTO_IPV6] = "ip6",
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *nfproto_family_name(uint8_t nfproto)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (nfproto >= NFPROTO_NUMPROTO || !nfproto_family_name_array[nfproto])
|
|
Packit |
c5a612 |
return "unknown";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nfproto_family_name_array[nfproto];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void fwd_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (stmt->fwd.addr) {
|
|
Packit |
c5a612 |
nft_print(octx, "fwd %s to ",
|
|
Packit |
c5a612 |
nfproto_family_name(stmt->fwd.family));
|
|
Packit |
c5a612 |
expr_print(stmt->fwd.addr, octx);
|
|
Packit |
c5a612 |
nft_print(octx, " device ");
|
|
Packit |
c5a612 |
expr_print(stmt->fwd.dev, octx);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
nft_print(octx, "fwd to ");
|
|
Packit |
c5a612 |
expr_print(stmt->fwd.dev, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void fwd_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->fwd.addr);
|
|
Packit |
c5a612 |
expr_free(stmt->fwd.dev);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops fwd_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_FWD,
|
|
Packit |
c5a612 |
.name = "fwd",
|
|
Packit |
c5a612 |
.print = fwd_stmt_print,
|
|
Packit |
c5a612 |
.json = fwd_stmt_json,
|
|
Packit |
c5a612 |
.destroy = fwd_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *fwd_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &fwd_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void tproxy_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_print(octx, "tproxy");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->tproxy.table_family == NFPROTO_INET &&
|
|
Packit |
c5a612 |
stmt->tproxy.family != NFPROTO_UNSPEC)
|
|
Packit |
c5a612 |
nft_print(octx, " %s", nfproto_family_name(stmt->tproxy.family));
|
|
Packit |
c5a612 |
nft_print(octx, " to");
|
|
Packit |
c5a612 |
if (stmt->tproxy.addr) {
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
if (stmt->tproxy.addr->etype == EXPR_VALUE &&
|
|
Packit |
c5a612 |
stmt->tproxy.addr->dtype->type == TYPE_IP6ADDR) {
|
|
Packit |
c5a612 |
nft_print(octx, "[");
|
|
Packit |
c5a612 |
expr_print(stmt->tproxy.addr, octx);
|
|
Packit |
c5a612 |
nft_print(octx, "]");
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
expr_print(stmt->tproxy.addr, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->tproxy.port && stmt->tproxy.port->etype == EXPR_VALUE) {
|
|
Packit |
c5a612 |
if (!stmt->tproxy.addr)
|
|
Packit |
c5a612 |
nft_print(octx, " ");
|
|
Packit |
c5a612 |
nft_print(octx, ":");
|
|
Packit |
c5a612 |
expr_print(stmt->tproxy.port, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void tproxy_stmt_destroy(struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
expr_free(stmt->tproxy.addr);
|
|
Packit |
c5a612 |
expr_free(stmt->tproxy.port);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops tproxy_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_TPROXY,
|
|
Packit |
c5a612 |
.name = "tproxy",
|
|
Packit |
c5a612 |
.print = tproxy_stmt_print,
|
|
Packit |
c5a612 |
.json = tproxy_stmt_json,
|
|
Packit |
c5a612 |
.destroy = tproxy_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *tproxy_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &tproxy_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void xt_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
xt_stmt_xlate(stmt, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops xt_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_XT,
|
|
Packit |
c5a612 |
.name = "xt",
|
|
Packit |
c5a612 |
.print = xt_stmt_print,
|
|
Packit |
c5a612 |
.destroy = xt_stmt_destroy,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *xt_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &xt_stmt_ops);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *synproxy_sack_to_str(const uint32_t flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (flags & NF_SYNPROXY_OPT_SACK_PERM)
|
|
Packit |
c5a612 |
return " sack-perm";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return "";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *synproxy_timestamp_to_str(const uint32_t flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (flags & NF_SYNPROXY_OPT_TIMESTAMP)
|
|
Packit |
c5a612 |
return " timestamp";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return "";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void synproxy_stmt_print(const struct stmt *stmt,
|
|
Packit |
c5a612 |
struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
uint32_t flags = stmt->synproxy.flags;
|
|
Packit |
c5a612 |
const char *ts_str = synproxy_timestamp_to_str(flags);
|
|
Packit |
c5a612 |
const char *sack_str = synproxy_sack_to_str(flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (flags & (NF_SYNPROXY_OPT_MSS | NF_SYNPROXY_OPT_WSCALE))
|
|
Packit |
c5a612 |
nft_print(octx, "synproxy mss %u wscale %u%s%s",
|
|
Packit |
c5a612 |
stmt->synproxy.mss, stmt->synproxy.wscale,
|
|
Packit |
c5a612 |
ts_str, sack_str);
|
|
Packit |
c5a612 |
else if (flags & NF_SYNPROXY_OPT_MSS)
|
|
Packit |
c5a612 |
nft_print(octx, "synproxy mss %u%s%s", stmt->synproxy.mss,
|
|
Packit |
c5a612 |
ts_str, sack_str);
|
|
Packit |
c5a612 |
else if (flags & NF_SYNPROXY_OPT_WSCALE)
|
|
Packit |
c5a612 |
nft_print(octx, "synproxy wscale %u%s%s", stmt->synproxy.wscale,
|
|
Packit |
c5a612 |
ts_str, sack_str);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
nft_print(octx, "synproxy%s%s", ts_str, sack_str);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct stmt_ops synproxy_stmt_ops = {
|
|
Packit |
c5a612 |
.type = STMT_SYNPROXY,
|
|
Packit |
c5a612 |
.name = "synproxy",
|
|
Packit |
c5a612 |
.print = synproxy_stmt_print,
|
|
Packit |
c5a612 |
.json = synproxy_stmt_json,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct stmt *synproxy_stmt_alloc(const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return stmt_alloc(loc, &synproxy_stmt_ops);
|
|
Packit |
c5a612 |
}
|