summaryrefslogtreecommitdiffstats
path: root/src/rule.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rule.c')
-rw-r--r--src/rule.c219
1 files changed, 131 insertions, 88 deletions
diff --git a/src/rule.c b/src/rule.c
index 633a5a12..65ff0fbb 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -8,11 +8,10 @@
* 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 <string.h>
#include <inttypes.h>
#include <errno.h>
@@ -27,6 +26,7 @@
#include <cache.h>
#include <owner.h>
#include <intervals.h>
+#include "nftutils.h"
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
@@ -76,7 +76,7 @@ static uint32_t udp_dflt_timeout[] = {
[NFTNL_CTTIMEOUT_UDP_REPLIED] = 120,
};
-struct timeout_protocol timeout_protocol[IPPROTO_MAX] = {
+struct timeout_protocol timeout_protocol[UINT8_MAX + 1] = {
[IPPROTO_TCP] = {
.array_size = NFTNL_CTTIMEOUT_TCP_MAX,
.state_to_name = tcp_state_to_name,
@@ -104,11 +104,11 @@ int timeout_str2num(uint16_t l4proto, struct timeout_state *ts)
void handle_free(struct handle *h)
{
- xfree(h->table.name);
- xfree(h->chain.name);
- xfree(h->set.name);
- xfree(h->flowtable.name);
- xfree(h->obj.name);
+ free_const(h->table.name);
+ free_const(h->chain.name);
+ free_const(h->set.name);
+ free_const(h->flowtable.name);
+ free_const(h->obj.name);
}
void handle_merge(struct handle *dst, const struct handle *src)
@@ -146,11 +146,12 @@ struct set *set_alloc(const struct location *loc)
{
struct set *set;
+ assert(loc);
+
set = xzalloc(sizeof(*set));
set->refcnt = 1;
set->handle.set_id = ++set_id;
- if (loc != NULL)
- set->location = *loc;
+ set->location = *loc;
init_list_head(&set->stmt_list);
@@ -161,7 +162,7 @@ struct set *set_clone(const struct set *set)
{
struct set *new_set;
- new_set = set_alloc(NULL);
+ new_set = set_alloc(&internal_location);
handle_merge(&new_set->handle, &set->handle);
new_set->flags = set->flags;
new_set->gc_int = set->gc_int;
@@ -190,16 +191,16 @@ void set_free(struct set *set)
if (--set->refcnt > 0)
return;
- if (set->init != NULL)
- expr_free(set->init);
+
+ expr_free(set->init);
if (set->comment)
- xfree(set->comment);
+ free_const(set->comment);
handle_free(&set->handle);
list_for_each_entry_safe(stmt, next, &set->stmt_list, list)
stmt_free(stmt);
expr_free(set->key);
expr_free(set->data);
- xfree(set);
+ free(set);
}
struct set *set_lookup_fuzzy(const char *set_name,
@@ -453,6 +454,8 @@ struct rule *rule_alloc(const struct location *loc, const struct handle *h)
{
struct rule *rule;
+ assert(loc);
+
rule = xzalloc(sizeof(*rule));
rule->location = *loc;
init_list_head(&rule->list);
@@ -476,8 +479,8 @@ void rule_free(struct rule *rule)
return;
stmt_list_free(&rule->stmts);
handle_free(&rule->handle);
- xfree(rule->comment);
- xfree(rule);
+ free_const(rule->comment);
+ free(rule);
}
void rule_print(const struct rule *rule, struct output_ctx *octx)
@@ -554,16 +557,16 @@ void scope_release(const struct scope *scope)
list_for_each_entry_safe(sym, next, &scope->symbols, list) {
assert(sym->refcnt == 1);
list_del(&sym->list);
- xfree(sym->identifier);
+ free_const(sym->identifier);
expr_free(sym->expr);
- xfree(sym);
+ free(sym);
}
}
void scope_free(struct scope *scope)
{
scope_release(scope);
- xfree(scope);
+ free(scope);
}
void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
@@ -594,9 +597,9 @@ struct symbol *symbol_get(const struct scope *scope, const char *identifier)
static void symbol_put(struct symbol *sym)
{
if (--sym->refcnt == 0) {
- xfree(sym->identifier);
+ free_const(sym->identifier);
expr_free(sym->expr);
- xfree(sym);
+ free(sym);
}
}
@@ -695,17 +698,16 @@ const char *chain_hookname_lookup(const char *name)
/* internal ID to uniquely identify a set in the batch */
static uint32_t chain_id;
-struct chain *chain_alloc(const char *name)
+struct chain *chain_alloc(void)
{
struct chain *chain;
chain = xzalloc(sizeof(*chain));
+ chain->location = internal_location;
chain->refcnt = 1;
chain->handle.chain_id = ++chain_id;
init_list_head(&chain->rules);
init_list_head(&chain->scope.symbols);
- if (name != NULL)
- chain->handle.chain.name = xstrdup(name);
chain->policy = NULL;
return chain;
@@ -727,16 +729,20 @@ void chain_free(struct chain *chain)
list_for_each_entry_safe(rule, next, &chain->rules, list)
rule_free(rule);
handle_free(&chain->handle);
- scope_release(&chain->scope);
- xfree(chain->type.str);
+ free_const(chain->type.str);
expr_free(chain->dev_expr);
for (i = 0; i < chain->dev_array_len; i++)
- xfree(chain->dev_array[i]);
- xfree(chain->dev_array);
+ free_const(chain->dev_array[i]);
+ free(chain->dev_array);
expr_free(chain->priority.expr);
expr_free(chain->policy);
- xfree(chain->comment);
- xfree(chain);
+ free_const(chain->comment);
+
+ /* MUST be released after all expressions, they could
+ * hold refcounts.
+ */
+ scope_release(&chain->scope);
+ free(chain);
}
struct chain *chain_binding_lookup(const struct table *table,
@@ -864,7 +870,7 @@ struct prio_tag {
const char *str;
};
-const static struct prio_tag std_prios[] = {
+static const struct prio_tag std_prios[] = {
{ NF_IP_PRI_RAW, "raw" },
{ NF_IP_PRI_MANGLE, "mangle" },
{ NF_IP_PRI_NAT_DST, "dstnat" },
@@ -873,7 +879,7 @@ const static struct prio_tag std_prios[] = {
{ NF_IP_PRI_NAT_SRC, "srcnat" },
};
-const static struct prio_tag bridge_std_prios[] = {
+static const struct prio_tag bridge_std_prios[] = {
{ NF_BR_PRI_NAT_DST_BRIDGED, "dstnat" },
{ NF_BR_PRI_FILTER_BRIDGED, "filter" },
{ NF_BR_PRI_NAT_DST_OTHER, "out" },
@@ -927,7 +933,8 @@ static bool std_prio_family_hook_compat(int prio, int family, int hook)
case NFPROTO_INET:
case NFPROTO_IPV4:
case NFPROTO_IPV6:
- if (hook == NF_INET_PRE_ROUTING)
+ if (hook == NF_INET_PRE_ROUTING ||
+ hook == NF_INET_LOCAL_OUT)
return true;
}
break;
@@ -936,7 +943,8 @@ static bool std_prio_family_hook_compat(int prio, int family, int hook)
case NFPROTO_INET:
case NFPROTO_IPV4:
case NFPROTO_IPV6:
- if (hook == NF_INET_POST_ROUTING)
+ if (hook == NF_INET_LOCAL_IN ||
+ hook == NF_INET_POST_ROUTING)
return true;
}
}
@@ -969,10 +977,11 @@ static const char *prio2str(const struct output_ctx *octx,
const struct expr *expr)
{
const struct prio_tag *prio_arr;
- int std_prio, offset, prio;
+ const uint32_t reach = 10;
const char *std_prio_str;
- const int reach = 10;
+ int std_prio, prio;
size_t i, arr_size;
+ int64_t offset;
mpz_export_data(&prio, expr->value, BYTEORDER_HOST_ENDIAN, sizeof(int));
if (family == NFPROTO_BRIDGE) {
@@ -987,19 +996,21 @@ static const char *prio2str(const struct output_ctx *octx,
for (i = 0; i < arr_size; ++i) {
std_prio = prio_arr[i].val;
std_prio_str = prio_arr[i].str;
- if (abs(prio - std_prio) <= reach) {
+
+ offset = (int64_t)prio - std_prio;
+ if (llabs(offset) <= reach) {
if (!std_prio_family_hook_compat(std_prio,
family, hook))
break;
- offset = prio - std_prio;
+
strncpy(buf, std_prio_str, bufsize);
if (offset > 0)
snprintf(buf + strlen(buf),
- bufsize - strlen(buf), " + %d",
+ bufsize - strlen(buf), " + %" PRIu64,
offset);
else if (offset < 0)
snprintf(buf + strlen(buf),
- bufsize - strlen(buf), " - %d",
+ bufsize - strlen(buf), " - %" PRIu64,
-offset);
return buf;
}
@@ -1120,6 +1131,7 @@ struct table *table_alloc(void)
struct table *table;
table = xzalloc(sizeof(*table));
+ table->location = internal_location;
init_list_head(&table->chains);
init_list_head(&table->sets);
init_list_head(&table->objs);
@@ -1146,7 +1158,7 @@ void table_free(struct table *table)
if (--table->refcnt > 0)
return;
if (table->comment)
- xfree(table->comment);
+ free_const(table->comment);
list_for_each_entry_safe(chain, next, &table->chains, list)
chain_free(chain);
list_for_each_entry_safe(chain, next, &table->chain_bindings, cache.list)
@@ -1176,7 +1188,7 @@ void table_free(struct table *table)
cache_free(&table->set_cache);
cache_free(&table->obj_cache);
cache_free(&table->ft_cache);
- xfree(table);
+ free(table);
}
struct table *table_get(struct table *table)
@@ -1203,6 +1215,7 @@ struct table *table_lookup_fuzzy(const struct handle *h,
static const char *table_flags_name[TABLE_FLAGS_MAX] = {
"dormant",
"owner",
+ "persist",
};
const char *table_flag_name(uint32_t flag)
@@ -1213,6 +1226,17 @@ const char *table_flag_name(uint32_t flag)
return table_flags_name[flag];
}
+unsigned int parse_table_flag(const char *name)
+{
+ int i;
+
+ for (i = 0; i < TABLE_FLAGS_MAX; i++) {
+ if (!strcmp(name, table_flags_name[i]))
+ return 1 << i;
+ }
+ return 0;
+}
+
static void table_print_flags(const struct table *table, const char **delim,
struct output_ctx *octx)
{
@@ -1296,6 +1320,8 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
{
struct cmd *cmd;
+ assert(loc);
+
cmd = xzalloc(sizeof(*cmd));
init_list_head(&cmd->list);
cmd->op = op;
@@ -1323,7 +1349,7 @@ struct markup *markup_alloc(uint32_t format)
void markup_free(struct markup *m)
{
- xfree(m);
+ free(m);
}
struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
@@ -1341,8 +1367,8 @@ struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
void monitor_free(struct monitor *m)
{
- xfree(m->event);
- xfree(m);
+ free_const(m->event);
+ free(m);
}
void cmd_free(struct cmd *cmd)
@@ -1356,6 +1382,8 @@ void cmd_free(struct cmd *cmd)
set_free(cmd->elem.set);
break;
case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_METER:
case CMD_OBJ_SETELEMS:
set_free(cmd->set);
break;
@@ -1394,9 +1422,9 @@ void cmd_free(struct cmd *cmd)
BUG("invalid command object type %u\n", cmd->obj);
}
}
- xfree(cmd->attr);
- xfree(cmd->arg);
- xfree(cmd);
+ free(cmd->attr);
+ free_const(cmd->arg);
+ free(cmd);
}
#include <netlink.h>
@@ -1448,7 +1476,13 @@ static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
return -1;
}
- return mnl_nft_set_add(ctx, cmd, flags);
+ if (mnl_nft_set_add(ctx, cmd, flags) < 0)
+ return -1;
+
+ if (set_is_anonymous(set->flags))
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
+
+ return 0;
}
static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
@@ -1574,11 +1608,6 @@ static int do_list_table(struct netlink_ctx *ctx, struct table *table)
static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct print_fmt_options opts = {
- .tab = "\t",
- .nl = "\n",
- .stmt_separator = "\n",
- };
struct table *table;
struct set *set;
@@ -1596,13 +1625,12 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
!set_is_literal(set->flags))
continue;
if (cmd->obj == CMD_OBJ_METERS &&
- !set_is_meter(set->flags))
+ !set_is_meter_compat(set->flags))
continue;
if (cmd->obj == CMD_OBJ_MAPS &&
!map_is_literal(set->flags))
continue;
- set_print_declaration(set, &opts, &ctx->nft->output);
- nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
+ set_print(set, &ctx->nft->output);
}
nft_print(&ctx->nft->output, "}\n");
@@ -1614,9 +1642,10 @@ struct obj *obj_alloc(const struct location *loc)
{
struct obj *obj;
+ assert(loc);
+
obj = xzalloc(sizeof(*obj));
- if (loc != NULL)
- obj->location = *loc;
+ obj->location = *loc;
obj->refcnt = 1;
return obj;
@@ -1632,18 +1661,18 @@ void obj_free(struct obj *obj)
{
if (--obj->refcnt > 0)
return;
- xfree(obj->comment);
+ free_const(obj->comment);
handle_free(&obj->handle);
if (obj->type == NFT_OBJECT_CT_TIMEOUT) {
struct timeout_state *ts, *next;
list_for_each_entry_safe(ts, next, &obj->ct_timeout.timeout_list, head) {
list_del(&ts->head);
- xfree(ts->timeout_str);
- xfree(ts);
+ free_const(ts->timeout_str);
+ free(ts);
}
}
- xfree(obj);
+ free(obj);
}
struct obj *obj_lookup_fuzzy(const char *obj_name,
@@ -1668,10 +1697,10 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
static void print_proto_name_proto(uint8_t l4, struct output_ctx *octx)
{
- const struct protoent *p = getprotobynumber(l4);
+ char name[NFT_PROTONAME_MAXSIZE];
- if (p)
- nft_print(octx, "%s", p->p_name);
+ if (nft_getprotobynumber(l4, name, sizeof(name)))
+ nft_print(octx, "%s", name);
else
nft_print(octx, "%d", l4);
}
@@ -1686,11 +1715,14 @@ static void print_proto_timeout_policy(uint8_t l4, const uint32_t *timeout,
nft_print(octx, "%s%spolicy = { ", opts->tab, opts->tab);
for (i = 0; i < timeout_protocol[l4].array_size; i++) {
if (timeout[i] != timeout_protocol[l4].dflt_timeout[i]) {
+ uint64_t timeout_ms;
+
if (comma)
nft_print(octx, ", ");
- nft_print(octx, "%s : %u",
- timeout_protocol[l4].state_to_name[i],
- timeout[i]);
+ timeout_ms = timeout[i] * 1000u;
+ nft_print(octx, "%s : ",
+ timeout_protocol[l4].state_to_name[i]);
+ time_print(timeout_ms, octx);
comma = true;
}
}
@@ -2022,9 +2054,10 @@ struct flowtable *flowtable_alloc(const struct location *loc)
{
struct flowtable *flowtable;
+ assert(loc);
+
flowtable = xzalloc(sizeof(*flowtable));
- if (loc != NULL)
- flowtable->location = *loc;
+ flowtable->location = *loc;
flowtable->refcnt = 1;
return flowtable;
@@ -2048,10 +2081,10 @@ void flowtable_free(struct flowtable *flowtable)
if (flowtable->dev_array != NULL) {
for (i = 0; i < flowtable->dev_array_len; i++)
- xfree(flowtable->dev_array[i]);
- xfree(flowtable->dev_array);
+ free_const(flowtable->dev_array[i]);
+ free(flowtable->dev_array);
}
- xfree(flowtable);
+ free(flowtable);
}
static void flowtable_print_declaration(const struct flowtable *flowtable,
@@ -2289,11 +2322,13 @@ static void __do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
static int do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
struct table *table)
{
- struct set *set;
+ struct set *set = cmd->set;
- set = set_cache_find(table, cmd->handle.set.name);
- if (set == NULL)
- return -1;
+ if (!set) {
+ set = set_cache_find(table, cmd->handle.set.name);
+ if (set == NULL)
+ return -1;
+ }
__do_list_set(ctx, cmd, set);
@@ -2357,8 +2392,10 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_CT_HELPERS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_TIMEOUTS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_CT_EXPECTATIONS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_EXPECT);
case CMD_OBJ_LIMIT:
case CMD_OBJ_LIMITS:
@@ -2382,7 +2419,7 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return 0;
}
-static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
+static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd, bool reset)
{
struct set *set, *new_set;
struct expr *init;
@@ -2400,7 +2437,7 @@ static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
/* Fetch from kernel the elements that have been requested .*/
err = netlink_get_setelem(ctx, &cmd->handle, &cmd->location,
- cmd->elem.set, new_set, init);
+ cmd->elem.set, new_set, init, reset);
if (err >= 0)
__do_list_set(ctx, cmd, new_set);
@@ -2416,7 +2453,7 @@ static int do_command_get(struct netlink_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
case CMD_OBJ_ELEMENTS:
- return do_get_setelems(ctx, cmd);
+ return do_get_setelems(ctx, cmd, false);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2453,6 +2490,15 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
return do_command_list(ctx, cmd);
case CMD_OBJ_RULE:
return netlink_reset_rules(ctx, cmd, false);
+ case CMD_OBJ_ELEMENTS:
+ return do_get_setelems(ctx, cmd, true);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ ret = netlink_list_setelems(ctx, &cmd->handle, cmd->set, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2717,10 +2763,8 @@ static void stmt_reduce(const struct rule *rule)
/* Must not merge across other statements */
if (stmt->ops->type != STMT_EXPRESSION) {
- if (idx < 2)
- continue;
-
- payload_do_merge(sa, idx);
+ if (idx >= 2)
+ payload_do_merge(sa, idx);
idx = 0;
continue;
}
@@ -2734,7 +2778,6 @@ static void stmt_reduce(const struct rule *rule)
switch (stmt->expr->op) {
case OP_EQ:
case OP_IMPLICIT:
- case OP_NEQ:
break;
default:
continue;