Commit 268c6aa1 authored by Arturo Borrero Gonzalez's avatar Arturo Borrero Gonzalez
Browse files

Merge tag 'debian/1.8.5-3' into debian/buster-backports



Debian package 1.8.5-3
Signed-off-by: default avatarArturo Borrero Gonzalez <arturo@debian.org>
parents ada8a2c9 9fa0e185
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter/nf_tables.h>
#include <libmnl/libmnl.h>
#include <libnftnl/gen.h>
#include <libnftnl/set.h>
#include <libnftnl/table.h>
#include "nft.h"
#include "nft-cache.h"
static void cache_chain_list_insert(struct list_head *list, const char *name)
{
struct cache_chain *pos = NULL, *new;
list_for_each_entry(pos, list, head) {
int cmp = strcmp(pos->name, name);
if (!cmp)
return;
if (cmp > 0)
break;
}
new = xtables_malloc(sizeof(*new));
new->name = strdup(name);
list_add_tail(&new->head, pos ? &pos->head : list);
}
void nft_cache_level_set(struct nft_handle *h, int level,
const struct nft_cmd *cmd)
{
struct nft_cache_req *req = &h->cache_req;
if (level > req->level)
req->level = level;
if (!cmd || !cmd->table || req->all_chains)
return;
if (!req->table)
req->table = strdup(cmd->table);
else
assert(!strcmp(req->table, cmd->table));
if (!cmd->chain) {
req->all_chains = true;
return;
}
cache_chain_list_insert(&req->chain_list, cmd->chain);
if (cmd->rename)
cache_chain_list_insert(&req->chain_list, cmd->rename);
if (cmd->jumpto)
cache_chain_list_insert(&req->chain_list, cmd->jumpto);
}
static int genid_cb(const struct nlmsghdr *nlh, void *data)
{
uint32_t *genid = data;
struct nftnl_gen *gen;
gen = nftnl_gen_alloc();
if (!gen)
return MNL_CB_ERROR;
if (nftnl_gen_nlmsg_parse(nlh, gen) < 0)
goto out;
*genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID);
nftnl_gen_free(gen);
return MNL_CB_STOP;
out:
nftnl_gen_free(gen);
return MNL_CB_ERROR;
}
static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
int ret;
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq);
ret = mnl_talk(h, nlh, genid_cb, genid);
if (ret == 0)
return;
xtables_error(RESOURCE_PROBLEM,
"Could not fetch rule set generation id: %s\n", nft_strerror(errno));
}
static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_table *t;
struct nftnl_table_list *list = data;
t = nftnl_table_alloc();
if (t == NULL)
goto err;
if (nftnl_table_nlmsg_parse(nlh, t) < 0)
goto out;
nftnl_table_list_add_tail(t, list);
return MNL_CB_OK;
out:
nftnl_table_free(t);
err:
return MNL_CB_OK;
}
static int fetch_table_cache(struct nft_handle *h)
{
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_table_list *list;
int i, ret;
if (h->cache->tables)
return 0;
list = nftnl_table_list_alloc();
if (list == NULL)
return 0;
nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
NLM_F_DUMP, h->seq);
ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
h->cache->tables = list;
for (i = 0; i < NFT_TABLE_MAX; i++) {
enum nft_table_type type = h->tables[i].type;
if (!h->tables[i].name)
continue;
h->cache->table[type].chains = nftnl_chain_list_alloc();
if (!h->cache->table[type].chains)
return 0;
h->cache->table[type].sets = nftnl_set_list_alloc();
if (!h->cache->table[type].sets)
return 0;
}
return 1;
}
struct nftnl_chain_list_cb_data {
struct nft_handle *h;
const struct builtin_table *t;
};
static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_chain_list_cb_data *d = data;
const struct builtin_table *t = d->t;
struct nftnl_chain_list *list;
struct nft_handle *h = d->h;
const char *tname, *cname;
struct nftnl_chain *c;
c = nftnl_chain_alloc();
if (c == NULL)
goto err;
if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
goto out;
tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
if (!t) {
t = nft_table_builtin_find(h, tname);
if (!t)
goto out;
} else if (strcmp(t->name, tname)) {
goto out;
}
list = h->cache->table[t->type].chains;
cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
if (nftnl_chain_list_lookup_byname(list, cname))
goto out;
nftnl_chain_list_add_tail(c, list);
return MNL_CB_OK;
out:
nftnl_chain_free(c);
err:
return MNL_CB_OK;
}
struct nftnl_set_list_cb_data {
struct nft_handle *h;
const struct builtin_table *t;
};
static int nftnl_set_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_set_list_cb_data *d = data;
const struct builtin_table *t = d->t;
struct nftnl_set_list *list;
struct nft_handle *h = d->h;
const char *tname, *sname;
struct nftnl_set *s;
s = nftnl_set_alloc();
if (s == NULL)
return MNL_CB_OK;
if (nftnl_set_nlmsg_parse(nlh, s) < 0)
goto out_free;
tname = nftnl_set_get_str(s, NFTNL_SET_TABLE);
if (!t)
t = nft_table_builtin_find(h, tname);
else if (strcmp(t->name, tname))
goto out_free;
if (!t)
goto out_free;
list = h->cache->table[t->type].sets;
sname = nftnl_set_get_str(s, NFTNL_SET_NAME);
if (nftnl_set_list_lookup_byname(list, sname))
goto out_free;
nftnl_set_list_add_tail(s, list);
return MNL_CB_OK;
out_free:
nftnl_set_free(s);
return MNL_CB_OK;
}
static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
{
return nftnl_set_elems_nlmsg_parse(nlh, data) ? -1 : MNL_CB_OK;
}
static bool set_has_elements(struct nftnl_set *s)
{
struct nftnl_set_elems_iter *iter;
bool ret = false;
iter = nftnl_set_elems_iter_create(s);
if (iter) {
ret = !!nftnl_set_elems_iter_cur(iter);
nftnl_set_elems_iter_destroy(iter);
}
return ret;
}
static int set_fetch_elem_cb(struct nftnl_set *s, void *data)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nft_handle *h = data;
struct nlmsghdr *nlh;
if (set_has_elements(s))
return 0;
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, h->family,
NLM_F_DUMP, h->seq);
nftnl_set_elems_nlmsg_build_payload(nlh, s);
return mnl_talk(h, nlh, set_elem_cb, s);
}
static int fetch_set_cache(struct nft_handle *h,
const struct builtin_table *t, const char *set)
{
struct nftnl_set_list_cb_data d = {
.h = h,
.t = t,
};
uint16_t flags = NLM_F_DUMP;
struct nftnl_set *s = NULL;
struct nlmsghdr *nlh;
char buf[16536];
int i, ret;
if (t) {
s = nftnl_set_alloc();
if (!s)
return -1;
nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
if (set) {
nftnl_set_set_str(s, NFTNL_SET_NAME, set);
flags = NLM_F_ACK;
}
}
nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
h->family, flags, h->seq);
if (s) {
nftnl_set_nlmsg_build_payload(nlh, s);
nftnl_set_free(s);
}
ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
if (ret < 0 && errno == EINTR) {
assert(nft_restart(h) >= 0);
return ret;
}
if (t) {
nftnl_set_list_foreach(h->cache->table[t->type].sets,
set_fetch_elem_cb, h);
} else {
for (i = 0; i < NFT_TABLE_MAX; i++) {
enum nft_table_type type = h->tables[i].type;
if (!h->tables[i].name)
continue;
nftnl_set_list_foreach(h->cache->table[type].sets,
set_fetch_elem_cb, h);
}
}
return ret;
}
static int __fetch_chain_cache(struct nft_handle *h,
const struct builtin_table *t,
const struct nftnl_chain *c)
{
struct nftnl_chain_list_cb_data d = {
.h = h,
.t = t,
};
char buf[16536];
struct nlmsghdr *nlh;
int ret;
nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
if (c)
nftnl_chain_nlmsg_build_payload(nlh, c);
ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
return ret;
}
static int fetch_chain_cache(struct nft_handle *h,
const struct builtin_table *t,
struct list_head *chains)
{
struct cache_chain *cc;
struct nftnl_chain *c;
int rc, ret = 0;
if (!chains)
return __fetch_chain_cache(h, t, NULL);
assert(t);
c = nftnl_chain_alloc();
if (!c)
return -1;
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
list_for_each_entry(cc, chains, head) {
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, cc->name);
rc = __fetch_chain_cache(h, t, c);
if (rc)
ret = rc;
}
nftnl_chain_free(c);
return ret;
}
static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_chain *c = data;
struct nftnl_rule *r;
r = nftnl_rule_alloc();
if (r == NULL)
return MNL_CB_OK;
if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
nftnl_rule_free(r);
return MNL_CB_OK;
}
nftnl_chain_rule_add_tail(r, c);
return MNL_CB_OK;
}
static int nft_rule_list_update(struct nftnl_chain *c, void *data)
{
struct nft_handle *h = data;
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_rule *rule;
int ret;
if (nftnl_rule_lookup_byindex(c, 0))
return 0;
rule = nftnl_rule_alloc();
if (!rule)
return -1;
nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
NLM_F_DUMP, h->seq);
nftnl_rule_nlmsg_build_payload(nlh, rule);
ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
nftnl_rule_free(rule);
if (h->family == NFPROTO_BRIDGE)
nft_bridge_chain_postprocess(h, c);
return 0;
}
static int fetch_rule_cache(struct nft_handle *h,
const struct builtin_table *t)
{
int i;
if (t) {
struct nftnl_chain_list *list =
h->cache->table[t->type].chains;
return nftnl_chain_list_foreach(list, nft_rule_list_update, h);
}
for (i = 0; i < NFT_TABLE_MAX; i++) {
enum nft_table_type type = h->tables[i].type;
if (!h->tables[i].name)
continue;
if (nftnl_chain_list_foreach(h->cache->table[type].chains,
nft_rule_list_update, h))
return -1;
}
return 0;
}
static int flush_cache(struct nft_handle *h, struct nft_cache *c,
const char *tablename);
static void
__nft_build_cache(struct nft_handle *h)
{
struct nft_cache_req *req = &h->cache_req;
const struct builtin_table *t = NULL;
struct list_head *chains = NULL;
uint32_t genid_check;
if (h->cache_init)
return;
if (req->table) {
t = nft_table_builtin_find(h, req->table);
if (!req->all_chains)
chains = &req->chain_list;
}
h->cache_init = true;
retry:
mnl_genid_get(h, &h->nft_genid);
if (req->level >= NFT_CL_TABLES)
fetch_table_cache(h);
if (req->level == NFT_CL_FAKE)
return;
if (req->level >= NFT_CL_CHAINS)
fetch_chain_cache(h, t, chains);
if (req->level >= NFT_CL_SETS)
fetch_set_cache(h, t, NULL);
if (req->level >= NFT_CL_RULES)
fetch_rule_cache(h, t);
mnl_genid_get(h, &genid_check);
if (h->nft_genid != genid_check) {
flush_cache(h, h->cache, NULL);
goto retry;
}
}
static void __nft_flush_cache(struct nft_handle *h)
{
if (!h->cache_index) {
h->cache_index++;
h->cache = &h->__cache[h->cache_index];
} else {
flush_chain_cache(h, NULL);
}
}
static int ____flush_rule_cache(struct nftnl_rule *r, void *data)
{
nftnl_rule_list_del(r);
nftnl_rule_free(r);
return 0;
}
static int __flush_rule_cache(struct nftnl_chain *c, void *data)
{
return nftnl_rule_foreach(c, ____flush_rule_cache, NULL);
}
int flush_rule_cache(struct nft_handle *h, const char *table,
struct nftnl_chain *c)
{
const struct builtin_table *t;
if (c)
return __flush_rule_cache(c, NULL);
t = nft_table_builtin_find(h, table);
if (!t || !h->cache->table[t->type].chains)
return 0;
return nftnl_chain_list_foreach(h->cache->table[t->type].chains,
__flush_rule_cache, NULL);
}
static int __flush_chain_cache(struct nftnl_chain *c, void *data)
{
nftnl_chain_list_del(c);
nftnl_chain_free(c);
return 0;
}
static int __flush_set_cache(struct nftnl_set *s, void *data)
{
nftnl_set_list_del(s);
nftnl_set_free(s);
return 0;
}
static int flush_cache(struct nft_handle *h, struct nft_cache *c,
const char *tablename)
{
const struct builtin_table *table;
int i;
if (tablename) {
table = nft_table_builtin_find(h, tablename);
if (!table)
return 0;
if (c->table[table->type].chains)
nftnl_chain_list_foreach(c->table[table->type].chains,
__flush_chain_cache, NULL);
if (c->table[table->type].sets)
nftnl_set_list_foreach(c->table[table->type].sets,
__flush_set_cache, NULL);
return 0;
}
for (i = 0; i < NFT_TABLE_MAX; i++) {
if (h->tables[i].name == NULL)
continue;
if (c->table[i].chains) {
nftnl_chain_list_free(c->table[i].chains);
c->table[i].chains = NULL;
}
if (c->table[i].sets) {
nftnl_set_list_free(c->table[i].sets);
c->table[i].sets = NULL;
}
}
if (c->tables) {
nftnl_table_list_free(c->tables);
c->tables = NULL;
}
return 1;
}
void flush_chain_cache(struct nft_handle *h, const char *tablename)
{
if (!h->cache_init)
return;
if (flush_cache(h, h->cache, tablename))
h->cache_init = false;
}
void nft_rebuild_cache(struct nft_handle *h)
{
if (h->cache_init) {
__nft_flush_cache(h);
h->cache_init = false;
}
__nft_build_cache(h);
}
void nft_cache_build(struct nft_handle *h)
{
struct nft_cache_req *req = &h->cache_req;
const struct builtin_table *t = NULL;
int i;
if (req->table)
t = nft_table_builtin_find(h, req->table);
/* fetch builtin chains as well (if existing) so nft_xt_builtin_init()
* doesn't override policies by accident */
if (t && !req->all_chains) {
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
const char *cname = t->chains[i].name;
if (!cname)
break;
cache_chain_list_insert(&req->chain_list, cname);
}
}
__nft_build_cache(h);
}
void nft_release_cache(struct nft_handle *h)
{
struct nft_cache_req *req = &h->cache_req;
struct cache_chain *cc, *cc_tmp;
while (h->cache_index)
flush_cache(h, &h->__cache[h->cache_index--], NULL);
flush_cache(h, &h->__cache[0], NULL);
h->cache = &h->__cache[0];
h->cache_init = false;
if (req->level != NFT_CL_FAKE)
req->level = NFT_CL_TABLES;
if (req->table) {
free(req->table);
req->table = NULL;
}
req->all_chains = false;
list_for_each_entry_safe(cc, cc_tmp, &req->chain_list, head) {
list_del(&cc->head);
free(cc->name);
free(cc);
}
}
struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
{
return h->cache->tables;
}
struct nftnl_set_list *
nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
{
const struct builtin_table *t;
t = nft_table_builtin_find(h, table);
if (!t)
return NULL;
return h->cache->table[t->type].sets;
}
struct nftnl_chain_list *
nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain)
{
const struct builtin_table *t;
t = nft_table_builtin_find(h, table);
if (!t)
return NULL;
return h->cache->table[t->type].chains;
}
#ifndef _NFT_CACHE_H_
#define _NFT_CACHE_H_
struct nft_handle;
struct nft_cmd;
void nft_cache_level_set(struct nft_handle *h, int level,
const struct nft_cmd *cmd);
void nft_rebuild_cache(struct nft_handle *h);
void nft_release_cache(struct nft_handle *h);
void flush_chain_cache(struct nft_handle *h, const char *tablename);
int flush_rule_cache(struct nft_handle *h, const char *table,
struct nftnl_chain *c);
void nft_cache_build(struct nft_handle *h);
struct nftnl_chain_list *
nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain);
struct nftnl_set_list *
nft_set_list_get(struct nft_handle *h, const char *table, const char *set);
struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h);
#endif /* _NFT_CACHE_H_ */
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
#include <stdlib.h>
#include <string.h>
#include "nft.h"
#include "nft-cmd.h"
struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
const char *table, const char *chain,
struct iptables_command_state *state,
int rulenum, bool verbose)
{
struct nftnl_rule *rule;
struct nft_cmd *cmd;
cmd = calloc(1, sizeof(struct nft_cmd));
if (!cmd)
return NULL;
cmd->command = command;
cmd->table = strdup(table);
if (chain)
cmd->chain = strdup(chain);
cmd->rulenum = rulenum;
cmd->verbose = verbose;
if (state) {
rule = nft_rule_new(h, chain, table, state);
if (!rule)
return NULL;
cmd->obj.rule = rule;
if (!state->target && strlen(state->jumpto) > 0)
cmd->jumpto = strdup(state->jumpto);
}
list_add_tail(&cmd->head, &h->cmd_list);
return cmd;
}
void nft_cmd_free(struct nft_cmd *cmd)
{
free((void *)cmd->table);
free((void *)cmd->chain);
free((void *)cmd->policy);
free((void *)cmd->rename);
free((void *)cmd->jumpto);
switch (cmd->command) {
case NFT_COMPAT_RULE_CHECK:
case NFT_COMPAT_RULE_DELETE:
if (cmd->obj.rule)
nftnl_rule_free(cmd->obj.rule);
break;
default:
break;
}
list_del(&cmd->head);
free(cmd);
}
static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
{
const struct builtin_table *t;
t = nft_table_builtin_find(h, cmd->table);
if (!t)
return;
/* Since ebtables user-defined chain policies are implemented as last
* rule in nftables, rule cache is required here to treat them right.
*/
if (h->family == NFPROTO_BRIDGE &&
!nft_chain_builtin_find(t, cmd->chain))
nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
}
int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
void *ref, bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_APPEND, table, chain, state, -1,
verbose);
if (!cmd)
return 0;
nft_cmd_rule_bridge(h, cmd);
return 1;
}
int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
int rulenum, bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_INSERT, table, chain, state,
rulenum, verbose);
if (!cmd)
return 0;
nft_cmd_rule_bridge(h, cmd);
if (cmd->rulenum > 0)
nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, state,
-1, verbose);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
const char *table, int rulenum, bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, NULL,
rulenum, verbose);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
const char *table, bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_FLUSH, table, chain, NULL, -1,
verbose);
if (!cmd)
return 0;
if (chain || verbose)
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
else
nft_cache_level_set(h, NFT_CL_TABLES, cmd);
return 1;
}
int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_ZERO, table, chain, NULL, -1,
verbose);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
const char *table)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_ADD, table, chain, NULL, -1,
false);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
const char *table, bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1,
verbose);
if (!cmd)
return 0;
/* This triggers nft_bridge_chain_postprocess() when fetching the
* rule cache.
*/
if (h->family == NFPROTO_BRIDGE)
nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
const char *table, const char *newname)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RENAME, table, chain, NULL, -1,
false);
if (!cmd)
return 0;
cmd->rename = strdup(newname);
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
const char *table, int rulenum, unsigned int format)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_LIST, table, chain, NULL, rulenum,
false);
if (!cmd)
return 0;
cmd->format = format;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
const char *table, void *data, int rulenum,
bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_REPLACE, table, chain, data,
rulenum, verbose);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
const char *table, void *data, bool verbose)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_CHECK, table, chain, data, -1,
verbose);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
int nft_cmd_chain_set(struct nft_handle *h, const char *table,
const char *chain, const char *policy,
const struct xt_counters *counters)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_UPDATE, table, chain, NULL, -1,
false);
if (!cmd)
return 0;
cmd->policy = strdup(policy);
if (counters)
cmd->counters = *counters;
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
int nft_cmd_table_flush(struct nft_handle *h, const char *table)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
false);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_TABLES, cmd);
return 1;
}
int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
const char *table)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RESTORE, table, chain, NULL, -1,
false);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
return 1;
}
int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
const char *table, int rulenum)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_ZERO, table, chain, NULL, rulenum,
false);
if (!cmd)
return 0;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
const char *table, int rulenum, int counters)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_RULE_SAVE, table, chain, NULL, rulenum,
false);
if (!cmd)
return 0;
cmd->counters_save = counters;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy)
{
struct nft_cmd *cmd;
cmd = nft_cmd_new(h, NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE, table, chain,
NULL, -1, false);
if (!cmd)
return 0;
cmd->policy = strdup(policy);
nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
void nft_cmd_table_new(struct nft_handle *h, const char *table)
{
nft_cmd_new(h, NFT_COMPAT_TABLE_NEW, table, NULL, NULL, -1, false);
}
#ifndef _NFT_CMD_H_
#define _NFT_CMD_H_
#include <libiptc/linux_list.h>
#include <stdbool.h>
#include "nft.h"
struct nftnl_rule;
struct nft_cmd {
struct list_head head;
int command;
const char *table;
const char *chain;
const char *jumpto;
int rulenum;
bool verbose;
unsigned int format;
struct {
struct nftnl_rule *rule;
struct nftnl_set *set;
} obj;
const char *policy;
struct xt_counters counters;
const char *rename;
int counters_save;
};
struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
const char *table, const char *chain,
struct iptables_command_state *state,
int rulenum, bool verbose);
void nft_cmd_free(struct nft_cmd *cmd);
int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
void *ref, bool verbose);
int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
int rulenum, bool verbose);
int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
bool verbose);
int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
const char *table, int rulenum, bool verbose);
int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
const char *table);
int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
const char *table, int rulenum, unsigned int format);
int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
const char *table, void *data, bool verbose);
int nft_cmd_chain_set(struct nft_handle *h, const char *table,
const char *chain, const char *policy,
const struct xt_counters *counters);
int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
const char *table, const char *newname);
int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
const char *table, void *data, int rulenum,
bool verbose);
int nft_cmd_table_flush(struct nft_handle *h, const char *table);
int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
const char *table);
int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
const char *table, int rulenum);
int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
const char *table, int rulenum, int counters);
int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy);
void nft_cmd_table_new(struct nft_handle *h, const char *table);
#endif /* _NFT_CMD_H_ */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "nft.h" #include "nft.h"
#include "nft-shared.h" #include "nft-shared.h"
static int nft_ipv4_add(struct nftnl_rule *r, void *data) static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
{ {
struct iptables_command_state *cs = data; struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp; struct xtables_rule_match *matchp;
...@@ -77,7 +77,7 @@ static int nft_ipv4_add(struct nftnl_rule *r, void *data) ...@@ -77,7 +77,7 @@ static int nft_ipv4_add(struct nftnl_rule *r, void *data)
add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO); add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) { for (matchp = cs->matches; matchp; matchp = matchp->next) {
ret = add_match(r, matchp->match->m); ret = add_match(h, r, matchp->match->m);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -261,12 +261,12 @@ static void print_fragment(unsigned int flags, unsigned int invflags, ...@@ -261,12 +261,12 @@ static void print_fragment(unsigned int flags, unsigned int invflags,
fputc(' ', stdout); fputc(' ', stdout);
} }
static void nft_ipv4_print_rule(struct nftnl_rule *r, unsigned int num, static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int format) unsigned int num, unsigned int format)
{ {
struct iptables_command_state cs = {}; struct iptables_command_state cs = {};
nft_rule_to_iptables_command_state(r, &cs); nft_rule_to_iptables_command_state(h, r, &cs);
print_rule_details(&cs, cs.jumpto, cs.fw.ip.flags, print_rule_details(&cs, cs.jumpto, cs.fw.ip.flags,
cs.fw.ip.invflags, cs.fw.ip.proto, num, format); cs.fw.ip.invflags, cs.fw.ip.proto, num, format);
...@@ -288,7 +288,7 @@ static void nft_ipv4_print_rule(struct nftnl_rule *r, unsigned int num, ...@@ -288,7 +288,7 @@ static void nft_ipv4_print_rule(struct nftnl_rule *r, unsigned int num,
if (!(format & FMT_NONEWLINE)) if (!(format & FMT_NONEWLINE))
fputc('\n', stdout); fputc('\n', stdout);
xtables_rule_matches_free(&cs.matches); nft_clear_iptables_command_state(&cs);
} }
static void save_ipv4_addr(char letter, const struct in_addr *addr, static void save_ipv4_addr(char letter, const struct in_addr *addr,
...@@ -450,13 +450,11 @@ struct nft_family_ops nft_family_ops_ipv4 = { ...@@ -450,13 +450,11 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.print_header = print_header, .print_header = print_header,
.print_rule = nft_ipv4_print_rule, .print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule, .save_rule = nft_ipv4_save_rule,
.save_counters = save_counters,
.save_chain = nft_ipv46_save_chain, .save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv4_proto_parse, .proto_parse = nft_ipv4_proto_parse,
.post_parse = nft_ipv4_post_parse, .post_parse = nft_ipv4_post_parse,
.parse_target = nft_ipv46_parse_target, .parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state, .rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state, .clear_cs = nft_clear_iptables_command_state,
.rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv4_xlate, .xlate = nft_ipv4_xlate,
}; };
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "nft.h" #include "nft.h"
#include "nft-shared.h" #include "nft-shared.h"
static int nft_ipv6_add(struct nftnl_rule *r, void *data) static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
{ {
struct iptables_command_state *cs = data; struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp; struct xtables_rule_match *matchp;
...@@ -66,7 +66,7 @@ static int nft_ipv6_add(struct nftnl_rule *r, void *data) ...@@ -66,7 +66,7 @@ static int nft_ipv6_add(struct nftnl_rule *r, void *data)
add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO); add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) { for (matchp = cs->matches; matchp; matchp = matchp->next) {
ret = add_match(r, matchp->match->m); ret = add_match(h, r, matchp->match->m);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -187,12 +187,12 @@ static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto, ...@@ -187,12 +187,12 @@ static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
cs->fw6.ipv6.flags |= IP6T_F_GOTO; cs->fw6.ipv6.flags |= IP6T_F_GOTO;
} }
static void nft_ipv6_print_rule(struct nftnl_rule *r, unsigned int num, static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int format) unsigned int num, unsigned int format)
{ {
struct iptables_command_state cs = {}; struct iptables_command_state cs = {};
nft_rule_to_iptables_command_state(r, &cs); nft_rule_to_iptables_command_state(h, r, &cs);
print_rule_details(&cs, cs.jumpto, cs.fw6.ipv6.flags, print_rule_details(&cs, cs.jumpto, cs.fw6.ipv6.flags,
cs.fw6.ipv6.invflags, cs.fw6.ipv6.proto, cs.fw6.ipv6.invflags, cs.fw6.ipv6.proto,
...@@ -217,7 +217,7 @@ static void nft_ipv6_print_rule(struct nftnl_rule *r, unsigned int num, ...@@ -217,7 +217,7 @@ static void nft_ipv6_print_rule(struct nftnl_rule *r, unsigned int num,
if (!(format & FMT_NONEWLINE)) if (!(format & FMT_NONEWLINE))
fputc('\n', stdout); fputc('\n', stdout);
xtables_rule_matches_free(&cs.matches); nft_clear_iptables_command_state(&cs);
} }
static void save_ipv6_addr(char letter, const struct in6_addr *addr, static void save_ipv6_addr(char letter, const struct in6_addr *addr,
...@@ -402,13 +402,11 @@ struct nft_family_ops nft_family_ops_ipv6 = { ...@@ -402,13 +402,11 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.print_header = print_header, .print_header = print_header,
.print_rule = nft_ipv6_print_rule, .print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule, .save_rule = nft_ipv6_save_rule,
.save_counters = save_counters,
.save_chain = nft_ipv46_save_chain, .save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv6_proto_parse, .proto_parse = nft_ipv6_proto_parse,
.post_parse = nft_ipv6_post_parse, .post_parse = nft_ipv6_post_parse,
.parse_target = nft_ipv46_parse_target, .parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state, .rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state, .clear_cs = nft_clear_iptables_command_state,
.rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv6_xlate, .xlate = nft_ipv6_xlate,
}; };
...@@ -69,7 +69,7 @@ void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base) ...@@ -69,7 +69,7 @@ void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base)
} }
/* bitwise operation is = sreg & mask ^ xor */ /* bitwise operation is = sreg & mask ^ xor */
void add_bitwise_u16(struct nftnl_rule *r, int mask, int xor) void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor)
{ {
struct nftnl_expr *expr; struct nftnl_expr *expr;
...@@ -310,7 +310,6 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -310,7 +310,6 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
struct xtables_target *target; struct xtables_target *target;
struct xt_entry_target *t; struct xt_entry_target *t;
size_t size; size_t size;
struct nft_family_ops *ops;
void *data = ctx->cs; void *data = ctx->cs;
target = xtables_find_target(targname, XTF_TRY_LOAD); target = xtables_find_target(targname, XTF_TRY_LOAD);
...@@ -327,8 +326,7 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -327,8 +326,7 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
target->t = t; target->t = t;
ops = nft_family_ops_lookup(ctx->family); ctx->h->ops->parse_target(target, data);
ops->parse_target(target, data);
} }
static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
...@@ -339,9 +337,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -339,9 +337,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
struct xtables_match *match; struct xtables_match *match;
struct xtables_rule_match **matches; struct xtables_rule_match **matches;
struct xt_entry_match *m; struct xt_entry_match *m;
struct nft_family_ops *ops;
switch (ctx->family) { switch (ctx->h->family) {
case NFPROTO_IPV4: case NFPROTO_IPV4:
case NFPROTO_IPV6: case NFPROTO_IPV6:
case NFPROTO_BRIDGE: case NFPROTO_BRIDGE:
...@@ -349,7 +346,7 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -349,7 +346,7 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break; break;
default: default:
fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
ctx->family); ctx->h->family);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
...@@ -365,9 +362,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -365,9 +362,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
match->m = m; match->m = m;
ops = nft_family_ops_lookup(ctx->family); if (ctx->h->ops->parse_match != NULL)
if (ops->parse_match != NULL) ctx->h->ops->parse_match(match, ctx->cs);
ops->parse_match(match, ctx->cs);
} }
void print_proto(uint16_t proto, int invert) void print_proto(uint16_t proto, int invert)
...@@ -400,7 +396,6 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) ...@@ -400,7 +396,6 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
{ {
const struct nft_family_ops *ops;
struct xtables_target *target; struct xtables_target *target;
struct xt_entry_target *t; struct xt_entry_target *t;
unsigned int size; unsigned int size;
...@@ -429,8 +424,7 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) ...@@ -429,8 +424,7 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
target->t = t; target->t = t;
ops = nft_family_ops_lookup(ctx->family); ctx->h->ops->parse_target(target, ctx->cs);
ops->parse_target(target, ctx->cs);
} }
static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
...@@ -451,8 +445,16 @@ static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -451,8 +445,16 @@ static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{ {
if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
memcpy(&ctx->prev_payload, &ctx->payload,
sizeof(ctx->prev_payload));
ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD;
}
ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
ctx->flags |= NFT_XT_CTX_PAYLOAD; ctx->flags |= NFT_XT_CTX_PAYLOAD;
} }
...@@ -474,7 +476,6 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -474,7 +476,6 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{ {
struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family);
void *data = ctx->cs; void *data = ctx->cs;
uint32_t reg; uint32_t reg;
...@@ -483,12 +484,12 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -483,12 +484,12 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
return; return;
if (ctx->flags & NFT_XT_CTX_META) { if (ctx->flags & NFT_XT_CTX_META) {
ops->parse_meta(ctx, e, data); ctx->h->ops->parse_meta(ctx, e, data);
ctx->flags &= ~NFT_XT_CTX_META; ctx->flags &= ~NFT_XT_CTX_META;
} }
/* bitwise context is interpreted from payload */ /* bitwise context is interpreted from payload */
if (ctx->flags & NFT_XT_CTX_PAYLOAD) { if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
ops->parse_payload(ctx, e, data); ctx->h->ops->parse_payload(ctx, e, data);
ctx->flags &= ~NFT_XT_CTX_PAYLOAD; ctx->flags &= ~NFT_XT_CTX_PAYLOAD;
} }
} }
...@@ -502,7 +503,6 @@ static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters ...@@ -502,7 +503,6 @@ static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters
static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{ {
const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN); const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
struct nft_family_ops *ops;
const char *jumpto = NULL; const char *jumpto = NULL;
bool nft_goto = false; bool nft_goto = false;
void *data = ctx->cs; void *data = ctx->cs;
...@@ -544,8 +544,7 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -544,8 +544,7 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break; break;
} }
ops = nft_family_ops_lookup(ctx->family); ctx->h->ops->parse_immediate(jumpto, nft_goto, data);
ops->parse_immediate(jumpto, nft_goto, data);
} }
static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
...@@ -555,19 +554,18 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -555,19 +554,18 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
__u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE);
struct xtables_rule_match **matches; struct xtables_rule_match **matches;
struct xtables_match *match; struct xtables_match *match;
struct nft_family_ops *ops;
struct xt_rateinfo *rinfo; struct xt_rateinfo *rinfo;
size_t size; size_t size;
switch (ctx->family) { switch (ctx->h->family) {
case NFPROTO_IPV4: case NFPROTO_IPV4:
case NFPROTO_IPV6: case NFPROTO_IPV6:
case NFPROTO_BRIDGE: case NFPROTO_BRIDGE:
matches = &ctx->cs->matches; matches = &ctx->cs->matches;
break; break;
default: default:
fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n",
ctx->family); ctx->h->family);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
...@@ -586,20 +584,27 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ...@@ -586,20 +584,27 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
rinfo->avg = XT_LIMIT_SCALE * unit / rate; rinfo->avg = XT_LIMIT_SCALE * unit / rate;
rinfo->burst = burst; rinfo->burst = burst;
ops = nft_family_ops_lookup(ctx->family); if (ctx->h->ops->parse_match != NULL)
if (ops->parse_match != NULL) ctx->h->ops->parse_match(match, ctx->cs);
ops->parse_match(match, ctx->cs); }
static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h,
struct nftnl_expr *e)
{
if (ctx->h->ops->parse_lookup)
ctx->h->ops->parse_lookup(ctx, e, NULL);
} }
void nft_rule_to_iptables_command_state(const struct nftnl_rule *r, void nft_rule_to_iptables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
struct iptables_command_state *cs) struct iptables_command_state *cs)
{ {
struct nftnl_expr_iter *iter; struct nftnl_expr_iter *iter;
struct nftnl_expr *expr; struct nftnl_expr *expr;
int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
struct nft_xt_ctx ctx = { struct nft_xt_ctx ctx = {
.cs = cs, .cs = cs,
.family = family, .h = h,
.table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE),
}; };
iter = nftnl_expr_iter_create(r); iter = nftnl_expr_iter_create(r);
...@@ -630,6 +635,8 @@ void nft_rule_to_iptables_command_state(const struct nftnl_rule *r, ...@@ -630,6 +635,8 @@ void nft_rule_to_iptables_command_state(const struct nftnl_rule *r,
nft_parse_target(&ctx, expr); nft_parse_target(&ctx, expr);
else if (strcmp(name, "limit") == 0) else if (strcmp(name, "limit") == 0)
nft_parse_limit(&ctx, expr); nft_parse_limit(&ctx, expr);
else if (strcmp(name, "lookup") == 0)
nft_parse_lookup(&ctx, h, expr);
expr = nftnl_expr_iter_next(iter); expr = nftnl_expr_iter_next(iter);
} }
...@@ -824,14 +831,6 @@ void save_rule_details(const struct iptables_command_state *cs, ...@@ -824,14 +831,6 @@ void save_rule_details(const struct iptables_command_state *cs,
} }
} }
void save_counters(const void *data)
{
const struct iptables_command_state *cs = data;
printf("[%llu:%llu] ", (unsigned long long)cs->counters.pcnt,
(unsigned long long)cs->counters.bcnt);
}
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy)
{ {
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
...@@ -982,42 +981,6 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data) ...@@ -982,42 +981,6 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data)
cs->target = t; cs->target = t;
} }
bool nft_ipv46_rule_find(struct nft_family_ops *ops,
struct nftnl_rule *r, void *data)
{
struct iptables_command_state *cs = data, this = {};
bool ret = false;
nft_rule_to_iptables_command_state(r, &this);
DEBUGP("comparing with... ");
#ifdef DEBUG_DEL
nft_rule_print_save(r, NFT_RULE_APPEND, 0);
#endif
if (!ops->is_same(cs, &this))
goto out;
if (!compare_matches(cs->matches, this.matches)) {
DEBUGP("Different matches\n");
goto out;
}
if (!compare_targets(cs->target, this.target)) {
DEBUGP("Different target\n");
goto out;
}
if (strcmp(cs->jumpto, this.jumpto) != 0) {
DEBUGP("Different verdict\n");
goto out;
}
ret = true;
out:
ops->clear_cs(&this);
return ret;
}
void nft_check_xt_legacy(int family, bool is_ipt_save) void nft_check_xt_legacy(int family, bool is_ipt_save)
{ {
static const char tables6[] = "/proc/net/ip6_tables_names"; static const char tables6[] = "/proc/net/ip6_tables_names";
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) #define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
struct xtables_args; struct xtables_args;
struct nft_handle;
struct xt_xlate; struct xt_xlate;
enum { enum {
...@@ -42,19 +43,22 @@ enum { ...@@ -42,19 +43,22 @@ enum {
NFT_XT_CTX_META = (1 << 1), NFT_XT_CTX_META = (1 << 1),
NFT_XT_CTX_BITWISE = (1 << 2), NFT_XT_CTX_BITWISE = (1 << 2),
NFT_XT_CTX_IMMEDIATE = (1 << 3), NFT_XT_CTX_IMMEDIATE = (1 << 3),
NFT_XT_CTX_PREV_PAYLOAD = (1 << 4),
}; };
struct nft_xt_ctx { struct nft_xt_ctx {
struct iptables_command_state *cs; struct iptables_command_state *cs;
struct nftnl_expr_iter *iter; struct nftnl_expr_iter *iter;
int family; struct nft_handle *h;
uint32_t flags; uint32_t flags;
const char *table;
uint32_t reg; uint32_t reg;
struct { struct {
uint32_t base;
uint32_t offset; uint32_t offset;
uint32_t len; uint32_t len;
} payload; } payload, prev_payload;
struct { struct {
uint32_t key; uint32_t key;
} meta; } meta;
...@@ -69,7 +73,7 @@ struct nft_xt_ctx { ...@@ -69,7 +73,7 @@ struct nft_xt_ctx {
}; };
struct nft_family_ops { struct nft_family_ops {
int (*add)(struct nftnl_rule *r, void *data); int (*add)(struct nft_handle *h, struct nftnl_rule *r, void *data);
bool (*is_same)(const void *data_a, bool (*is_same)(const void *data_a,
const void *data_b); const void *data_b);
void (*print_payload)(struct nftnl_expr *e, void (*print_payload)(struct nftnl_expr *e,
...@@ -82,6 +86,8 @@ struct nft_family_ops { ...@@ -82,6 +86,8 @@ struct nft_family_ops {
void *data); void *data);
void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
void *data); void *data);
void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
void *data);
void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data); void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data);
void (*print_table_header)(const char *tablename); void (*print_table_header)(const char *tablename);
...@@ -89,10 +95,9 @@ struct nft_family_ops { ...@@ -89,10 +95,9 @@ struct nft_family_ops {
const char *pol, const char *pol,
const struct xt_counters *counters, bool basechain, const struct xt_counters *counters, bool basechain,
uint32_t refs, uint32_t entries); uint32_t refs, uint32_t entries);
void (*print_rule)(struct nftnl_rule *r, unsigned int num, void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int format); unsigned int num, unsigned int format);
void (*save_rule)(const void *data, unsigned int format); void (*save_rule)(const void *data, unsigned int format);
void (*save_counters)(const void *data);
void (*save_chain)(const struct nftnl_chain *c, const char *policy); void (*save_chain)(const struct nftnl_chain *c, const char *policy);
void (*proto_parse)(struct iptables_command_state *cs, void (*proto_parse)(struct iptables_command_state *cs,
struct xtables_args *args); struct xtables_args *args);
...@@ -100,18 +105,16 @@ struct nft_family_ops { ...@@ -100,18 +105,16 @@ struct nft_family_ops {
struct xtables_args *args); struct xtables_args *args);
void (*parse_match)(struct xtables_match *m, void *data); void (*parse_match)(struct xtables_match *m, void *data);
void (*parse_target)(struct xtables_target *t, void *data); void (*parse_target)(struct xtables_target *t, void *data);
void (*rule_to_cs)(const struct nftnl_rule *r, void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r,
struct iptables_command_state *cs); struct iptables_command_state *cs);
void (*clear_cs)(struct iptables_command_state *cs); void (*clear_cs)(struct iptables_command_state *cs);
bool (*rule_find)(struct nft_family_ops *ops, struct nftnl_rule *r,
void *data);
int (*xlate)(const void *data, struct xt_xlate *xl); int (*xlate)(const void *data, struct xt_xlate *xl);
}; };
void add_meta(struct nftnl_rule *r, uint32_t key); void add_meta(struct nftnl_rule *r, uint32_t key);
void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base); void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base);
void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len); void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len);
void add_bitwise_u16(struct nftnl_rule *r, int mask, int xor); void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor);
void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len); void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len);
void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op); void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op);
void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op); void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op);
...@@ -137,7 +140,8 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, ...@@ -137,7 +140,8 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
unsigned char *outiface_mask, uint8_t *invflags); unsigned char *outiface_mask, uint8_t *invflags);
void print_proto(uint16_t proto, int invert); void print_proto(uint16_t proto, int invert);
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv);
void nft_rule_to_iptables_command_state(const struct nftnl_rule *r, void nft_rule_to_iptables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
struct iptables_command_state *cs); struct iptables_command_state *cs);
void nft_clear_iptables_command_state(struct iptables_command_state *cs); void nft_clear_iptables_command_state(struct iptables_command_state *cs);
void print_header(unsigned int format, const char *chain, const char *pol, void print_header(unsigned int format, const char *chain, const char *pol,
...@@ -155,7 +159,6 @@ void save_rule_details(const struct iptables_command_state *cs, ...@@ -155,7 +159,6 @@ void save_rule_details(const struct iptables_command_state *cs,
unsigned const char *iniface_mask, unsigned const char *iniface_mask,
const char *outiface, const char *outiface,
unsigned const char *outiface_mask); unsigned const char *outiface_mask);
void save_counters(const void *data);
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy); void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy);
void save_matches_and_target(const struct iptables_command_state *cs, void save_matches_and_target(const struct iptables_command_state *cs,
bool goto_flag, const void *fw, bool goto_flag, const void *fw,
...@@ -163,10 +166,7 @@ void save_matches_and_target(const struct iptables_command_state *cs, ...@@ -163,10 +166,7 @@ void save_matches_and_target(const struct iptables_command_state *cs,
struct nft_family_ops *nft_family_ops_lookup(int family); struct nft_family_ops *nft_family_ops_lookup(int family);
struct nft_handle;
void nft_ipv46_parse_target(struct xtables_target *t, void *data); void nft_ipv46_parse_target(struct xtables_target *t, void *data);
bool nft_ipv46_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
void *data);
bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2); bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2); bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2);
...@@ -199,23 +199,6 @@ struct xtables_args { ...@@ -199,23 +199,6 @@ struct xtables_args {
unsigned long long pcnt_cnt, bcnt_cnt; unsigned long long pcnt_cnt, bcnt_cnt;
}; };
#define CMD_NONE 0x0000U
#define CMD_INSERT 0x0001U
#define CMD_DELETE 0x0002U
#define CMD_DELETE_NUM 0x0004U
#define CMD_REPLACE 0x0008U
#define CMD_APPEND 0x0010U
#define CMD_LIST 0x0020U
#define CMD_FLUSH 0x0040U
#define CMD_ZERO 0x0080U
#define CMD_NEW_CHAIN 0x0100U
#define CMD_DELETE_CHAIN 0x0200U
#define CMD_SET_POLICY 0x0400U
#define CMD_RENAME_CHAIN 0x0800U
#define CMD_LIST_RULES 0x1000U
#define CMD_ZERO_NUM 0x2000U
#define CMD_CHECK 0x4000U
struct nft_xt_cmd_parse { struct nft_xt_cmd_parse {
unsigned int command; unsigned int command;
unsigned int rulenum; unsigned int rulenum;
...@@ -232,19 +215,10 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], ...@@ -232,19 +215,10 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
struct nft_xt_cmd_parse *p, struct iptables_command_state *cs, struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
struct xtables_args *args); struct xtables_args *args);
struct nft_xt_restore_parse {
FILE *in;
int testing;
const char *tablename;
bool commit;
};
struct nftnl_chain_list; struct nftnl_chain_list;
struct nft_xt_restore_cb { struct nft_xt_restore_cb {
void (*table_new)(struct nft_handle *h, const char *table); void (*table_new)(struct nft_handle *h, const char *table);
struct nftnl_chain_list *(*chain_list)(struct nft_handle *h,
const char *table);
int (*chain_set)(struct nft_handle *h, const char *table, int (*chain_set)(struct nft_handle *h, const char *table,
const char *chain, const char *policy, const char *chain, const char *policy,
const struct xt_counters *counters); const struct xt_counters *counters);
...@@ -260,10 +234,16 @@ struct nft_xt_restore_cb { ...@@ -260,10 +234,16 @@ struct nft_xt_restore_cb {
int (*abort)(struct nft_handle *h); int (*abort)(struct nft_handle *h);
}; };
struct nft_xt_restore_parse {
FILE *in;
int testing;
const char *tablename;
bool commit;
const struct nft_xt_restore_cb *cb;
};
void xtables_restore_parse(struct nft_handle *h, void xtables_restore_parse(struct nft_handle *h,
struct nft_xt_restore_parse *p, const struct nft_xt_restore_parse *p);
struct nft_xt_restore_cb *cb,
int argc, char *argv[]);
void nft_check_xt_legacy(int family, bool is_ipt_save); void nft_check_xt_legacy(int family, bool is_ipt_save);
#endif #endif
...@@ -55,48 +55,18 @@ ...@@ -55,48 +55,18 @@
#include "nft.h" #include "nft.h"
#include "xshared.h" /* proto_to_name */ #include "xshared.h" /* proto_to_name */
#include "nft-cache.h"
#include "nft-shared.h" #include "nft-shared.h"
#include "nft-bridge.h" /* EBT_NOPROTO */ #include "nft-bridge.h" /* EBT_NOPROTO */
#include "xtables-config-parser.h"
static void *nft_fn; static void *nft_fn;
static int genid_cb(const struct nlmsghdr *nlh, void *data)
{
uint32_t *genid = data;
struct nftnl_gen *gen;
gen = nftnl_gen_alloc();
if (!gen)
return MNL_CB_ERROR;
if (nftnl_gen_nlmsg_parse(nlh, gen) < 0)
goto out;
*genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID);
nftnl_gen_free(gen);
return MNL_CB_STOP;
out:
nftnl_gen_free(gen);
return MNL_CB_ERROR;
}
static int mnl_genid_get(struct nft_handle *h, uint32_t *genid)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq);
return mnl_talk(h, nlh, genid_cb, genid);
}
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data), int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data) void *data)
{ {
int ret; int ret;
char buf[16536]; char buf[32768];
if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0) if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
return -1; return -1;
...@@ -186,33 +156,42 @@ static void mnl_err_list_free(struct mnl_err *err) ...@@ -186,33 +156,42 @@ static void mnl_err_list_free(struct mnl_err *err)
free(err); free(err);
} }
static int nlbuffsiz; static void mnl_set_sndbuffer(struct nft_handle *h)
static void mnl_set_sndbuffer(const struct mnl_socket *nl,
struct nftnl_batch *batch)
{ {
int newbuffsiz; int newbuffsiz = nftnl_batch_iovec_len(h->batch) * BATCH_PAGE_SIZE;
if (nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE <= nlbuffsiz) if (newbuffsiz <= h->nlsndbuffsiz)
return; return;
newbuffsiz = nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE;
/* Rise sender buffer length to avoid hitting -EMSGSIZE */ /* Rise sender buffer length to avoid hitting -EMSGSIZE */
if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE, if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_SNDBUFFORCE,
&newbuffsiz, sizeof(socklen_t)) < 0)
return;
h->nlsndbuffsiz = newbuffsiz;
}
static void mnl_set_rcvbuffer(struct nft_handle *h, int numcmds)
{
int newbuffsiz = getpagesize() * numcmds;
if (newbuffsiz <= h->nlrcvbuffsiz)
return;
/* Rise receiver buffer length to avoid hitting -ENOBUFS */
if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_RCVBUFFORCE,
&newbuffsiz, sizeof(socklen_t)) < 0) &newbuffsiz, sizeof(socklen_t)) < 0)
return; return;
nlbuffsiz = newbuffsiz; h->nlrcvbuffsiz = newbuffsiz;
} }
static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock, static ssize_t mnl_nft_socket_sendmsg(struct nft_handle *h, int numcmds)
struct nftnl_batch *batch)
{ {
static const struct sockaddr_nl snl = { static const struct sockaddr_nl snl = {
.nl_family = AF_NETLINK .nl_family = AF_NETLINK
}; };
uint32_t iov_len = nftnl_batch_iovec_len(batch); uint32_t iov_len = nftnl_batch_iovec_len(h->batch);
struct iovec iov[iov_len]; struct iovec iov[iov_len];
struct msghdr msg = { struct msghdr msg = {
.msg_name = (struct sockaddr *) &snl, .msg_name = (struct sockaddr *) &snl,
...@@ -221,16 +200,16 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock, ...@@ -221,16 +200,16 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock,
.msg_iovlen = iov_len, .msg_iovlen = iov_len,
}; };
mnl_set_sndbuffer(nf_sock, batch); mnl_set_sndbuffer(h);
nftnl_batch_iovec(batch, iov, iov_len); mnl_set_rcvbuffer(h, numcmds);
nftnl_batch_iovec(h->batch, iov, iov_len);
return sendmsg(mnl_socket_get_fd(nf_sock), &msg, 0); return sendmsg(mnl_socket_get_fd(h->nl), &msg, 0);
} }
static int mnl_batch_talk(const struct mnl_socket *nf_sock, static int mnl_batch_talk(struct nft_handle *h, int numcmds)
struct nftnl_batch *batch, struct list_head *err_list)
{ {
const struct mnl_socket *nl = nf_sock; const struct mnl_socket *nl = h->nl;
int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl); int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
char rcv_buf[MNL_SOCKET_BUFFER_SIZE]; char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
fd_set readfds; fd_set readfds;
...@@ -240,7 +219,7 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock, ...@@ -240,7 +219,7 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock,
}; };
int err = 0; int err = 0;
ret = mnl_nft_socket_sendmsg(nf_sock, batch); ret = mnl_nft_socket_sendmsg(h, numcmds);
if (ret == -1) if (ret == -1)
return -1; return -1;
...@@ -262,7 +241,8 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock, ...@@ -262,7 +241,8 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock,
ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL); ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL);
/* Continue on error, make sure we get all acknowledgments */ /* Continue on error, make sure we get all acknowledgments */
if (ret == -1) { if (ret == -1) {
mnl_err_list_node_add(err_list, errno, nlh->nlmsg_seq); mnl_err_list_node_add(&h->err_list, errno,
nlh->nlmsg_seq);
err = -1; err = -1;
} }
...@@ -276,23 +256,6 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock, ...@@ -276,23 +256,6 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock,
return err; return err;
} }
enum obj_update_type {
NFT_COMPAT_TABLE_ADD,
NFT_COMPAT_TABLE_FLUSH,
NFT_COMPAT_CHAIN_ADD,
NFT_COMPAT_CHAIN_USER_ADD,
NFT_COMPAT_CHAIN_USER_DEL,
NFT_COMPAT_CHAIN_USER_FLUSH,
NFT_COMPAT_CHAIN_UPDATE,
NFT_COMPAT_CHAIN_RENAME,
NFT_COMPAT_CHAIN_ZERO,
NFT_COMPAT_RULE_APPEND,
NFT_COMPAT_RULE_INSERT,
NFT_COMPAT_RULE_REPLACE,
NFT_COMPAT_RULE_DELETE,
NFT_COMPAT_RULE_FLUSH,
};
enum obj_action { enum obj_action {
NFT_COMPAT_COMMIT, NFT_COMPAT_COMMIT,
NFT_COMPAT_ABORT, NFT_COMPAT_ABORT,
...@@ -308,6 +271,7 @@ struct obj_update { ...@@ -308,6 +271,7 @@ struct obj_update {
struct nftnl_table *table; struct nftnl_table *table;
struct nftnl_chain *chain; struct nftnl_chain *chain;
struct nftnl_rule *rule; struct nftnl_rule *rule;
struct nftnl_set *set;
void *ptr; void *ptr;
}; };
struct { struct {
...@@ -335,6 +299,7 @@ static int mnl_append_error(const struct nft_handle *h, ...@@ -335,6 +299,7 @@ static int mnl_append_error(const struct nft_handle *h,
[NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE", [NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
[NFT_COMPAT_RULE_DELETE] = "RULE_DELETE", [NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
[NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH", [NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
[NFT_COMPAT_SET_ADD] = "SET_ADD",
}; };
char errmsg[256]; char errmsg[256];
char tcr[128]; char tcr[128];
...@@ -371,10 +336,23 @@ static int mnl_append_error(const struct nft_handle *h, ...@@ -371,10 +336,23 @@ static int mnl_append_error(const struct nft_handle *h,
nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN)); nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
#if 0 #if 0
{ {
nft_rule_print_save(o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS); nft_rule_print_save(h, o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
} }
#endif #endif
break; break;
case NFT_COMPAT_SET_ADD:
snprintf(tcr, sizeof(tcr), "set %s",
nftnl_set_get_str(o->set, NFTNL_SET_NAME));
break;
case NFT_COMPAT_RULE_LIST:
case NFT_COMPAT_RULE_CHECK:
case NFT_COMPAT_CHAIN_RESTORE:
case NFT_COMPAT_RULE_SAVE:
case NFT_COMPAT_RULE_ZERO:
case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
case NFT_COMPAT_TABLE_NEW:
assert(0);
break;
} }
return snprintf(buf, len, "%s: %s", errmsg, tcr); return snprintf(buf, len, "%s: %s", errmsg, tcr);
...@@ -404,6 +382,13 @@ batch_table_add(struct nft_handle *h, enum obj_update_type type, ...@@ -404,6 +382,13 @@ batch_table_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, t); return batch_add(h, type, t);
} }
static struct obj_update *
batch_set_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_set *s)
{
return batch_add(h, type, s);
}
static int batch_chain_add(struct nft_handle *h, enum obj_update_type type, static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_chain *c) struct nftnl_chain *c)
{ {
...@@ -417,6 +402,38 @@ batch_rule_add(struct nft_handle *h, enum obj_update_type type, ...@@ -417,6 +402,38 @@ batch_rule_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, r); return batch_add(h, type, r);
} }
static void batch_obj_del(struct nft_handle *h, struct obj_update *o);
static void batch_chain_flush(struct nft_handle *h,
const char *table, const char *chain)
{
struct obj_update *obj, *tmp;
list_for_each_entry_safe(obj, tmp, &h->obj_list, head) {
struct nftnl_rule *r = obj->ptr;
switch (obj->type) {
case NFT_COMPAT_RULE_APPEND:
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
break;
default:
continue;
}
if (table &&
strcmp(table, nftnl_rule_get_str(r, NFTNL_RULE_TABLE)))
continue;
if (chain &&
strcmp(chain, nftnl_rule_get_str(r, NFTNL_RULE_CHAIN)))
continue;
batch_obj_del(h, obj);
}
}
const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
[NFT_TABLE_RAW] = { [NFT_TABLE_RAW] = {
.name = "raw", .name = "raw",
...@@ -647,7 +664,7 @@ static int nft_table_builtin_add(struct nft_handle *h, ...@@ -647,7 +664,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
if (t == NULL) if (t == NULL)
return -1; return -1;
nftnl_table_set(t, NFTNL_TABLE_NAME, (char *)_t->name); nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name);
ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1; ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
...@@ -664,12 +681,12 @@ nft_chain_builtin_alloc(const struct builtin_table *table, ...@@ -664,12 +681,12 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
if (c == NULL) if (c == NULL)
return NULL; return NULL;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table->name); nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->name);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain->name); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook); nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio); nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy); nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
nftnl_chain_set(c, NFTNL_CHAIN_TYPE, (char *)chain->type); nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
return c; return c;
} }
...@@ -688,31 +705,25 @@ static void nft_chain_builtin_add(struct nft_handle *h, ...@@ -688,31 +705,25 @@ static void nft_chain_builtin_add(struct nft_handle *h,
nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains); nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains);
} }
static const struct builtin_table * /* find if built-in table already exists */
__nft_table_builtin_find(const struct builtin_table *tables, const char *table) const struct builtin_table *
nft_table_builtin_find(struct nft_handle *h, const char *table)
{ {
int i; int i;
bool found = false; bool found = false;
for (i = 0; i < NFT_TABLE_MAX; i++) { for (i = 0; i < NFT_TABLE_MAX; i++) {
if (tables[i].name == NULL) if (h->tables[i].name == NULL)
continue; continue;
if (strcmp(tables[i].name, table) != 0) if (strcmp(h->tables[i].name, table) != 0)
continue; continue;
found = true; found = true;
break; break;
} }
return found ? &tables[i] : NULL; return found ? &h->tables[i] : NULL;
}
/* find if built-in table already exists */
const struct builtin_table *
nft_table_builtin_find(struct nft_handle *h, const char *table)
{
return __nft_table_builtin_find(h->tables, table);
} }
/* find if built-in chain already exists */ /* find if built-in chain already exists */
...@@ -735,15 +746,16 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain) ...@@ -735,15 +746,16 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
static void nft_chain_builtin_init(struct nft_handle *h, static void nft_chain_builtin_init(struct nft_handle *h,
const struct builtin_table *table) const struct builtin_table *table)
{ {
struct nftnl_chain_list *list = nft_chain_list_get(h, table->name); struct nftnl_chain_list *list;
struct nftnl_chain *c; struct nftnl_chain *c;
int i; int i;
if (!list)
return;
/* Initialize built-in chains if they don't exist yet */ /* Initialize built-in chains if they don't exist yet */
for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) { for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
list = nft_chain_list_get(h, table->name,
table->chains[i].name);
if (!list)
continue;
c = nftnl_chain_list_lookup_byname(list, table->chains[i].name); c = nftnl_chain_list_lookup_byname(list, table->chains[i].name);
if (c != NULL) if (c != NULL)
...@@ -757,6 +769,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table) ...@@ -757,6 +769,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
{ {
const struct builtin_table *t; const struct builtin_table *t;
if (!h->cache_init)
return 0;
t = nft_table_builtin_find(h, table); t = nft_table_builtin_find(h, table);
if (t == NULL) if (t == NULL)
return -1; return -1;
...@@ -767,6 +782,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table) ...@@ -767,6 +782,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
if (nft_table_builtin_add(h, t) < 0) if (nft_table_builtin_add(h, t) < 0)
return -1; return -1;
if (h->cache_req.level < NFT_CL_CHAINS)
return 0;
nft_chain_builtin_init(h, t); nft_chain_builtin_init(h, t);
h->cache->table[t->type].initialized = true; h->cache->table[t->type].initialized = true;
...@@ -782,7 +800,7 @@ static bool nft_chain_builtin(struct nftnl_chain *c) ...@@ -782,7 +800,7 @@ static bool nft_chain_builtin(struct nftnl_chain *c)
return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL; return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
} }
static int nft_restart(struct nft_handle *h) int nft_restart(struct nft_handle *h)
{ {
mnl_socket_close(h->nl); mnl_socket_close(h->nl);
...@@ -794,13 +812,16 @@ static int nft_restart(struct nft_handle *h) ...@@ -794,13 +812,16 @@ static int nft_restart(struct nft_handle *h)
return -1; return -1;
h->portid = mnl_socket_get_portid(h->nl); h->portid = mnl_socket_get_portid(h->nl);
nlbuffsiz = 0; h->nlsndbuffsiz = 0;
h->nlrcvbuffsiz = 0;
return 0; return 0;
} }
int nft_init(struct nft_handle *h, const struct builtin_table *t) int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
{ {
memset(h, 0, sizeof(*h));
h->nl = mnl_socket_open(NETLINK_NETFILTER); h->nl = mnl_socket_open(NETLINK_NETFILTER);
if (h->nl == NULL) if (h->nl == NULL)
return -1; return -1;
...@@ -810,80 +831,37 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t) ...@@ -810,80 +831,37 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t)
return -1; return -1;
} }
h->ops = nft_family_ops_lookup(family);
if (!h->ops)
xtables_error(PARAMETER_PROBLEM, "Unknown family");
h->portid = mnl_socket_get_portid(h->nl); h->portid = mnl_socket_get_portid(h->nl);
h->tables = t; h->tables = t;
h->cache = &h->__cache[0]; h->cache = &h->__cache[0];
h->family = family;
INIT_LIST_HEAD(&h->obj_list); INIT_LIST_HEAD(&h->obj_list);
INIT_LIST_HEAD(&h->err_list); INIT_LIST_HEAD(&h->err_list);
INIT_LIST_HEAD(&h->cmd_list);
INIT_LIST_HEAD(&h->cache_req.chain_list);
return 0; return 0;
} }
static int __flush_rule_cache(struct nftnl_rule *r, void *data) void nft_fini(struct nft_handle *h)
{
nftnl_rule_list_del(r);
nftnl_rule_free(r);
return 0;
}
static void flush_rule_cache(struct nftnl_chain *c)
{
nftnl_rule_foreach(c, __flush_rule_cache, NULL);
}
static int __flush_chain_cache(struct nftnl_chain *c, void *data)
{
nftnl_chain_list_del(c);
nftnl_chain_free(c);
return 0;
}
static int flush_cache(struct nft_cache *c, const struct builtin_table *tables,
const char *tablename)
{ {
const struct builtin_table *table; struct list_head *pos, *n;
int i;
if (tablename) { list_for_each_safe(pos, n, &h->cmd_list)
table = __nft_table_builtin_find(tables, tablename); nft_cmd_free(list_entry(pos, struct nft_cmd, head));
if (!table || !c->table[table->type].chains)
return 0;
nftnl_chain_list_foreach(c->table[table->type].chains,
__flush_chain_cache, NULL);
return 0;
}
for (i = 0; i < NFT_TABLE_MAX; i++) {
if (tables[i].name == NULL)
continue;
if (!c->table[i].chains)
continue;
nftnl_chain_list_free(c->table[i].chains);
c->table[i].chains = NULL;
}
nftnl_table_list_free(c->tables);
c->tables = NULL;
return 1;
}
static void flush_chain_cache(struct nft_handle *h, const char *tablename) list_for_each_safe(pos, n, &h->obj_list)
{ batch_obj_del(h, list_entry(pos, struct obj_update, head));
if (!h->have_cache)
return;
if (flush_cache(h->cache, h->tables, tablename)) list_for_each_safe(pos, n, &h->err_list)
h->have_cache = false; mnl_err_list_free(list_entry(pos, struct mnl_err, head));
}
void nft_fini(struct nft_handle *h) nft_release_cache(h);
{
flush_chain_cache(h, NULL);
mnl_socket_close(h->nl); mnl_socket_close(h->nl);
} }
...@@ -1015,13 +993,189 @@ static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m) ...@@ -1015,13 +993,189 @@ static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
return 0; return 0;
} }
int add_match(struct nftnl_rule *r, struct xt_entry_match *m) static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
uint32_t flags, uint32_t key_type,
uint32_t key_len, uint32_t size)
{
static uint32_t set_id = 0;
struct nftnl_set *s;
struct nft_cmd *cmd;
s = nftnl_set_alloc();
if (!s)
return NULL;
nftnl_set_set_u32(s, NFTNL_SET_FAMILY, h->family);
nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
nftnl_set_set_str(s, NFTNL_SET_NAME, "__set%d");
nftnl_set_set_u32(s, NFTNL_SET_ID, ++set_id);
nftnl_set_set_u32(s, NFTNL_SET_FLAGS,
NFT_SET_ANONYMOUS | NFT_SET_CONSTANT | flags);
nftnl_set_set_u32(s, NFTNL_SET_KEY_TYPE, key_type);
nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len);
nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size);
cmd = nft_cmd_new(h, NFT_COMPAT_SET_ADD, table, NULL, NULL, -1, false);
if (!cmd) {
nftnl_set_free(s);
return NULL;
}
cmd->obj.set = s;
return s;
}
static struct nftnl_expr *
gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg)
{
struct nftnl_expr *e = nftnl_expr_alloc("payload");
if (!e)
return NULL;
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
return e;
}
static struct nftnl_expr *
gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags)
{
struct nftnl_expr *e = nftnl_expr_alloc("lookup");
if (!e)
return NULL;
nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SET_ID, set_id);
nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_FLAGS, flags);
return e;
}
/* simplified nftables:include/netlink.h, netlink_padded_len() */
#define NETLINK_ALIGN 4
/* from nftables:include/datatype.h, TYPE_BITS */
#define CONCAT_TYPE_BITS 6
/* from nftables:include/datatype.h, enum datatypes */
#define NFT_DATATYPE_IPADDR 7
#define NFT_DATATYPE_ETHERADDR 9
static int __add_nft_among(struct nft_handle *h, const char *table,
struct nftnl_rule *r, struct nft_among_pair *pairs,
int cnt, bool dst, bool inv, bool ip)
{
uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN;
/* { !dst, dst } */
static const int eth_addr_off[] = {
offsetof(struct ether_header, ether_shost),
offsetof(struct ether_header, ether_dhost)
};
static const int ip_addr_off[] = {
offsetof(struct iphdr, saddr),
offsetof(struct iphdr, daddr)
};
struct nftnl_expr *e;
struct nftnl_set *s;
uint32_t flags = 0;
int idx = 0;
if (ip) {
type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
len &= ~(NETLINK_ALIGN - 1);
flags = NFT_SET_INTERVAL;
}
s = add_anon_set(h, table, flags, type, len, cnt);
if (!s)
return -ENOMEM;
set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
if (ip) {
uint8_t field_len[2] = { ETH_ALEN, sizeof(struct in_addr) };
nftnl_set_set_data(s, NFTNL_SET_DESC_CONCAT,
field_len, sizeof(field_len));
}
for (idx = 0; idx < cnt; idx++) {
struct nftnl_set_elem *elem = nftnl_set_elem_alloc();
if (!elem)
return -ENOMEM;
nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY,
&pairs[idx], len);
if (ip) {
struct in_addr tmp = pairs[idx].in;
if (tmp.s_addr == INADDR_ANY)
pairs[idx].in.s_addr = INADDR_BROADCAST;
nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY_END,
&pairs[idx], len);
pairs[idx].in = tmp;
}
nftnl_set_elem_add(s, elem);
}
e = gen_payload(NFT_PAYLOAD_LL_HEADER,
eth_addr_off[dst], ETH_ALEN, NFT_REG_1);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
if (ip) {
e = gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
sizeof(struct in_addr), NFT_REG32_02);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
}
e = gen_lookup(NFT_REG_1, "__set%d", set_id, inv);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
return 0;
}
static int add_nft_among(struct nft_handle *h,
struct nftnl_rule *r, struct xt_entry_match *m)
{
struct nft_among_data *data = (struct nft_among_data *)m->data;
const char *table = nftnl_rule_get(r, NFTNL_RULE_TABLE);
if ((data->src.cnt && data->src.ip) ||
(data->dst.cnt && data->dst.ip)) {
uint16_t eth_p_ip = htons(ETH_P_IP);
add_meta(r, NFT_META_PROTOCOL);
add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2);
}
if (data->src.cnt)
__add_nft_among(h, table, r, data->pairs, data->src.cnt,
false, data->src.inv, data->src.ip);
if (data->dst.cnt)
__add_nft_among(h, table, r, data->pairs + data->src.cnt,
data->dst.cnt, true, data->dst.inv,
data->dst.ip);
return 0;
}
int add_match(struct nft_handle *h,
struct nftnl_rule *r, struct xt_entry_match *m)
{ {
struct nftnl_expr *expr; struct nftnl_expr *expr;
int ret; int ret;
if (!strcmp(m->u.user.name, "limit")) if (!strcmp(m->u.user.name, "limit"))
return add_nft_limit(r, m); return add_nft_limit(r, m);
else if (!strcmp(m->u.user.name, "among"))
return add_nft_among(h, r, m);
expr = nftnl_expr_alloc("match"); expr = nftnl_expr_alloc("match");
if (expr == NULL) if (expr == NULL)
...@@ -1223,7 +1377,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv) ...@@ -1223,7 +1377,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
inv ? NFT_RULE_COMPAT_F_INV : 0); inv ? NFT_RULE_COMPAT_F_INV : 0);
} }
static struct nftnl_rule * struct nftnl_rule *
nft_rule_new(struct nft_handle *h, const char *chain, const char *table, nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
void *data) void *data)
{ {
...@@ -1234,10 +1388,10 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table, ...@@ -1234,10 +1388,10 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
return NULL; return NULL;
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table); nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain); nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
if (h->ops->add(r, data) < 0) if (h->ops->add(h, r, data) < 0)
goto err; goto err;
return r; return r;
...@@ -1251,22 +1405,15 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain); ...@@ -1251,22 +1405,15 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
int int
nft_rule_append(struct nft_handle *h, const char *chain, const char *table, nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
void *data, struct nftnl_rule *ref, bool verbose) struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
{ {
struct nftnl_chain *c; struct nftnl_chain *c;
struct nftnl_rule *r;
int type; int type;
/* If built-in chains don't exist for this table, create them */ nft_xt_builtin_init(h, table);
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
nft_fn = nft_rule_append; nft_fn = nft_rule_append;
r = nft_rule_new(h, chain, table, data);
if (r == NULL)
return 0;
if (ref) { if (ref) {
nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE)); nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
...@@ -1274,17 +1421,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, ...@@ -1274,17 +1421,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
} else } else
type = NFT_COMPAT_RULE_APPEND; type = NFT_COMPAT_RULE_APPEND;
if (batch_rule_add(h, type, r) == NULL) { if (batch_rule_add(h, type, r) == NULL)
nftnl_rule_free(r);
return 0; return 0;
}
if (verbose) if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE); h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
if (ref) { if (ref) {
nftnl_chain_rule_insert_at(r, ref); nftnl_chain_rule_insert_at(r, ref);
nftnl_chain_rule_del(r); nftnl_chain_rule_del(ref);
nftnl_rule_free(ref);
} else { } else {
c = nft_chain_find(h, table, chain); c = nft_chain_find(h, table, chain);
if (!c) { if (!c) {
...@@ -1298,19 +1444,18 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, ...@@ -1298,19 +1444,18 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
} }
void void
nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type, nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
unsigned int format) enum nft_rule_print type, unsigned int format)
{ {
const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
struct iptables_command_state cs = {}; struct iptables_command_state cs = {};
struct nft_family_ops *ops; struct nft_family_ops *ops = h->ops;
ops = nft_family_ops_lookup(family); ops->rule_to_cs(h, r, &cs);
ops->rule_to_cs(r, &cs);
if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters) if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
ops->save_counters(&cs); printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
(unsigned long long)cs.counters.bcnt);
/* print chain name */ /* print chain name */
switch(type) { switch(type) {
...@@ -1329,106 +1474,6 @@ nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type, ...@@ -1329,106 +1474,6 @@ nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
ops->clear_cs(&cs); ops->clear_cs(&cs);
} }
static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nft_handle *h = data;
const struct builtin_table *t;
struct nftnl_chain *c;
c = nftnl_chain_alloc();
if (c == NULL)
goto err;
if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
goto out;
t = nft_table_builtin_find(h,
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
if (!t)
goto out;
nftnl_chain_list_add_tail(c, h->cache->table[t->type].chains);
return MNL_CB_OK;
out:
nftnl_chain_free(c);
err:
return MNL_CB_OK;
}
static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_table *t;
struct nftnl_table_list *list = data;
t = nftnl_table_alloc();
if (t == NULL)
goto err;
if (nftnl_table_nlmsg_parse(nlh, t) < 0)
goto out;
nftnl_table_list_add_tail(t, list);
return MNL_CB_OK;
out:
nftnl_table_free(t);
err:
return MNL_CB_OK;
}
static int fetch_table_cache(struct nft_handle *h)
{
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_table_list *list;
int ret;
list = nftnl_table_list_alloc();
if (list == NULL)
return 0;
nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
NLM_F_DUMP, h->seq);
ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
h->cache->tables = list;
return 1;
}
static int fetch_chain_cache(struct nft_handle *h)
{
char buf[16536];
struct nlmsghdr *nlh;
int i, ret;
fetch_table_cache(h);
for (i = 0; i < NFT_TABLE_MAX; i++) {
enum nft_table_type type = h->tables[i].type;
if (!h->tables[i].name)
continue;
h->cache->table[type].chains = nftnl_chain_list_alloc();
if (!h->cache->table[type].chains)
return -1;
}
nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
NLM_F_DUMP, h->seq);
ret = mnl_talk(h, nlh, nftnl_chain_list_cb, h);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
return ret;
}
static bool nft_rule_is_policy_rule(struct nftnl_rule *r) static bool nft_rule_is_policy_rule(struct nftnl_rule *r)
{ {
const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {}; const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
...@@ -1467,8 +1512,8 @@ static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c) ...@@ -1467,8 +1512,8 @@ static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
return last; return last;
} }
static void nft_bridge_chain_postprocess(struct nft_handle *h, void nft_bridge_chain_postprocess(struct nft_handle *h,
struct nftnl_chain *c) struct nftnl_chain *c)
{ {
struct nftnl_rule *last = nft_chain_last_rule(c); struct nftnl_rule *last = nft_chain_last_rule(c);
struct nftnl_expr_iter *iter; struct nftnl_expr_iter *iter;
...@@ -1487,160 +1532,28 @@ static void nft_bridge_chain_postprocess(struct nft_handle *h, ...@@ -1487,160 +1532,28 @@ static void nft_bridge_chain_postprocess(struct nft_handle *h,
strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME))) strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)))
goto out_iter; goto out_iter;
expr = nftnl_expr_iter_next(iter); expr = nftnl_expr_iter_next(iter);
if (!expr || if (!expr ||
strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) || strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) ||
!nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT)) !nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT))
goto out_iter; goto out_iter;
verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT);
switch (verdict) {
case NF_ACCEPT:
case NF_DROP:
break;
default:
goto out_iter;
}
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict);
if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) == NULL)
fprintf(stderr, "Failed to delete old policy rule\n");
nftnl_chain_rule_del(last);
out_iter:
nftnl_expr_iter_destroy(iter);
}
static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_chain *c = data;
struct nftnl_rule *r;
r = nftnl_rule_alloc();
if (r == NULL)
return MNL_CB_OK;
if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
nftnl_rule_free(r);
return MNL_CB_OK;
}
nftnl_chain_rule_add_tail(r, c);
return MNL_CB_OK;
}
static int nft_rule_list_update(struct nftnl_chain *c, void *data)
{
struct nft_handle *h = data;
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_rule *rule;
int ret;
rule = nftnl_rule_alloc();
if (!rule)
return -1;
nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
NLM_F_DUMP, h->seq);
nftnl_rule_nlmsg_build_payload(nlh, rule);
ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
nftnl_rule_free(rule);
if (h->family == NFPROTO_BRIDGE)
nft_bridge_chain_postprocess(h, c);
return 0;
}
static int fetch_rule_cache(struct nft_handle *h)
{
int i;
for (i = 0; i < NFT_TABLE_MAX; i++) {
enum nft_table_type type = h->tables[i].type;
if (!h->tables[i].name)
continue;
if (nftnl_chain_list_foreach(h->cache->table[type].chains,
nft_rule_list_update, h))
return -1;
}
return 0;
}
static void __nft_build_cache(struct nft_handle *h)
{
uint32_t genid_start, genid_stop;
retry:
mnl_genid_get(h, &genid_start);
fetch_chain_cache(h);
fetch_rule_cache(h);
h->have_cache = true;
mnl_genid_get(h, &genid_stop);
if (genid_start != genid_stop) {
flush_chain_cache(h, NULL);
goto retry;
}
h->nft_genid = genid_start;
}
void nft_build_cache(struct nft_handle *h)
{
if (!h->have_cache)
__nft_build_cache(h);
}
static void __nft_flush_cache(struct nft_handle *h)
{
if (!h->cache_index) {
h->cache_index++;
h->cache = &h->__cache[h->cache_index];
} else {
flush_chain_cache(h, NULL);
}
}
static void nft_rebuild_cache(struct nft_handle *h)
{
if (h->have_cache)
__nft_flush_cache(h);
__nft_build_cache(h);
}
static void nft_release_cache(struct nft_handle *h)
{
if (h->cache_index)
flush_cache(&h->__cache[0], h->tables, NULL);
}
struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
const char *table)
{
const struct builtin_table *t;
t = nft_table_builtin_find(h, table);
if (!t)
return NULL;
nft_build_cache(h);
return h->cache->table[t->type].chains; verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT);
} switch (verdict) {
case NF_ACCEPT:
case NF_DROP:
break;
default:
goto out_iter;
}
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict);
if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) == NULL)
fprintf(stderr, "Failed to delete old policy rule\n");
nftnl_chain_rule_del(last);
out_iter:
nftnl_expr_iter_destroy(iter);
}
static const char *policy_name[NF_ACCEPT+1] = { static const char *policy_name[NF_ACCEPT+1] = {
[NF_DROP] = "DROP", [NF_DROP] = "DROP",
[NF_ACCEPT] = "ACCEPT", [NF_ACCEPT] = "ACCEPT",
...@@ -1648,12 +1561,10 @@ static const char *policy_name[NF_ACCEPT+1] = { ...@@ -1648,12 +1561,10 @@ static const char *policy_name[NF_ACCEPT+1] = {
int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list) int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
{ {
struct nft_family_ops *ops = h->ops;
struct nftnl_chain_list_iter *iter; struct nftnl_chain_list_iter *iter;
struct nft_family_ops *ops;
struct nftnl_chain *c; struct nftnl_chain *c;
ops = nft_family_ops_lookup(h->family);
iter = nftnl_chain_list_iter_create(list); iter = nftnl_chain_list_iter_create(list);
if (iter == NULL) if (iter == NULL)
return 0; return 0;
...@@ -1702,7 +1613,7 @@ static int nft_chain_save_rules(struct nft_handle *h, ...@@ -1702,7 +1613,7 @@ static int nft_chain_save_rules(struct nft_handle *h,
r = nftnl_rule_iter_next(iter); r = nftnl_rule_iter_next(iter);
while (r != NULL) { while (r != NULL) {
nft_rule_print_save(r, NFT_RULE_APPEND, format); nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
r = nftnl_rule_iter_next(iter); r = nftnl_rule_iter_next(iter);
} }
...@@ -1717,7 +1628,7 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) ...@@ -1717,7 +1628,7 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
struct nftnl_chain *c; struct nftnl_chain *c;
int ret = 0; int ret = 0;
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, NULL);
if (!list) if (!list)
return 0; return 0;
...@@ -1740,6 +1651,20 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) ...@@ -1740,6 +1651,20 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
return ret == 0 ? 1 : 0; return ret == 0 ? 1 : 0;
} }
struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
uint32_t set_id)
{
struct obj_update *n;
list_for_each_entry(n, &h->obj_list, head) {
if (n->type == NFT_COMPAT_SET_ADD &&
nftnl_set_get_u32(n->set, NFTNL_SET_ID) == set_id)
return n->set;
}
return NULL;
}
static void static void
__nft_rule_flush(struct nft_handle *h, const char *table, __nft_rule_flush(struct nft_handle *h, const char *table,
const char *chain, bool verbose, bool implicit) const char *chain, bool verbose, bool implicit)
...@@ -1747,15 +1672,16 @@ __nft_rule_flush(struct nft_handle *h, const char *table, ...@@ -1747,15 +1672,16 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
struct obj_update *obj; struct obj_update *obj;
struct nftnl_rule *r; struct nftnl_rule *r;
if (verbose) if (verbose && chain)
fprintf(stdout, "Flushing chain `%s'\n", chain); fprintf(stdout, "Flushing chain `%s'\n", chain);
r = nftnl_rule_alloc(); r = nftnl_rule_alloc();
if (r == NULL) if (r == NULL)
return; return;
nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table); nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain); if (chain)
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r); obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r);
if (!obj) { if (!obj) {
...@@ -1769,29 +1695,35 @@ __nft_rule_flush(struct nft_handle *h, const char *table, ...@@ -1769,29 +1695,35 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
bool verbose) bool verbose)
{ {
int ret = 0;
struct nftnl_chain_list *list;
struct nftnl_chain_list_iter *iter; struct nftnl_chain_list_iter *iter;
struct nftnl_chain *c; struct nftnl_chain_list *list;
struct nftnl_chain *c = NULL;
int ret = 0;
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_xt_builtin_init(h, table);
nft_xt_builtin_init(h, table);
nft_fn = nft_rule_flush; nft_fn = nft_rule_flush;
list = nft_chain_list_get(h, table); if (chain || verbose) {
if (list == NULL) { list = nft_chain_list_get(h, table, chain);
ret = 1; if (list == NULL) {
goto err; ret = 1;
goto err;
}
} }
if (chain) { if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain); c = nftnl_chain_list_lookup_byname(list, chain);
if (!c) if (!c) {
errno = ENOENT;
return 0; return 0;
}
}
if (chain || !verbose) {
batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false); __nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(c); flush_rule_cache(h, table, c);
return 1; return 1;
} }
...@@ -1803,11 +1735,11 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, ...@@ -1803,11 +1735,11 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
c = nftnl_chain_list_iter_next(iter); c = nftnl_chain_list_iter_next(iter);
while (c != NULL) { while (c != NULL) {
const char *chain_name = chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
__nft_rule_flush(h, table, chain_name, verbose, false); batch_chain_flush(h, table, chain);
flush_rule_cache(c); __nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(h, table, c);
c = nftnl_chain_list_iter_next(iter); c = nftnl_chain_list_iter_next(iter);
} }
nftnl_chain_list_iter_destroy(iter); nftnl_chain_list_iter_destroy(iter);
...@@ -1824,9 +1756,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl ...@@ -1824,9 +1756,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
nft_fn = nft_chain_user_add; nft_fn = nft_chain_user_add;
/* If built-in chains don't exist for this table, create them */ nft_xt_builtin_init(h, table);
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
if (nft_chain_exists(h, table, chain)) { if (nft_chain_exists(h, table, chain)) {
errno = EEXIST; errno = EEXIST;
...@@ -1837,14 +1767,14 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl ...@@ -1837,14 +1767,14 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (c == NULL) if (c == NULL)
return 0; return 0;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table); nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
if (h->family == NFPROTO_BRIDGE) if (h->family == NFPROTO_BRIDGE)
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT); nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, chain);
if (list) if (list)
nftnl_chain_list_add(c, list); nftnl_chain_list_add(c, list);
...@@ -1869,10 +1799,10 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table ...@@ -1869,10 +1799,10 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
} else { } else {
c = nftnl_chain_alloc(); c = nftnl_chain_alloc();
if (!c) if (!c)
return -1; return 0;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table); nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true; created = true;
} }
...@@ -1880,15 +1810,16 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table ...@@ -1880,15 +1810,16 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT); nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
if (!created) if (!created)
return 0; return 1;
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, chain);
if (list) if (list)
nftnl_chain_list_add(c, list); nftnl_chain_list_add(c, list);
return ret; /* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
} }
/* From linux/netlink.h */ /* From linux/netlink.h */
...@@ -1939,7 +1870,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, ...@@ -1939,7 +1870,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
nft_fn = nft_chain_user_del; nft_fn = nft_chain_user_del;
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, chain);
if (list == NULL) if (list == NULL)
return 0; return 0;
...@@ -1967,7 +1898,7 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) ...@@ -1967,7 +1898,7 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
{ {
struct nftnl_chain_list *list; struct nftnl_chain_list *list;
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, chain);
if (list == NULL) if (list == NULL)
return NULL; return NULL;
...@@ -2003,9 +1934,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, ...@@ -2003,9 +1934,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0; return 0;
} }
/* If built-in chains don't exist for this table, create them */ nft_xt_builtin_init(h, table);
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
/* Config load changed errno. Ensure genuine info for our callers. */ /* Config load changed errno. Ensure genuine info for our callers. */
errno = 0; errno = 0;
...@@ -2023,8 +1952,8 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, ...@@ -2023,8 +1952,8 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
if (c == NULL) if (c == NULL)
return 0; return 0;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table); nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)newname); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle); nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c); ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
...@@ -2033,13 +1962,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, ...@@ -2033,13 +1962,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return ret == 0 ? 1 : 0; return ret == 0 ? 1 : 0;
} }
static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
{
nft_build_cache(h);
return h->cache->tables;
}
bool nft_table_find(struct nft_handle *h, const char *tablename) bool nft_table_find(struct nft_handle *h, const char *tablename)
{ {
struct nftnl_table_list_iter *iter; struct nftnl_table_list_iter *iter;
...@@ -2075,8 +1997,8 @@ err: ...@@ -2075,8 +1997,8 @@ err:
} }
int nft_for_each_table(struct nft_handle *h, int nft_for_each_table(struct nft_handle *h,
int (*func)(struct nft_handle *h, const char *tablename, bool counters), int (*func)(struct nft_handle *h, const char *tablename, void *data),
bool counters) void *data)
{ {
struct nftnl_table_list *list; struct nftnl_table_list *list;
struct nftnl_table_list_iter *iter; struct nftnl_table_list_iter *iter;
...@@ -2095,7 +2017,7 @@ int nft_for_each_table(struct nft_handle *h, ...@@ -2095,7 +2017,7 @@ int nft_for_each_table(struct nft_handle *h,
const char *tablename = const char *tablename =
nftnl_table_get(t, NFTNL_TABLE_NAME); nftnl_table_get(t, NFTNL_TABLE_NAME);
func(h, tablename, counters); func(h, tablename, data);
t = nftnl_table_list_iter_next(iter); t = nftnl_table_list_iter_next(iter);
} }
...@@ -2179,8 +2101,7 @@ err_out: ...@@ -2179,8 +2101,7 @@ err_out:
void nft_table_new(struct nft_handle *h, const char *table) void nft_table_new(struct nft_handle *h, const char *table)
{ {
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_xt_builtin_init(h, table);
nft_xt_builtin_init(h, table);
} }
static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
...@@ -2189,6 +2110,9 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) ...@@ -2189,6 +2110,9 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
nftnl_rule_list_del(r); nftnl_rule_list_del(r);
if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE))
nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id);
obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r); obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
if (!obj) { if (!obj) {
nftnl_rule_free(r); nftnl_rule_free(r);
...@@ -2197,8 +2121,48 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) ...@@ -2197,8 +2121,48 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
return 1; return 1;
} }
static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r,
struct nftnl_rule *rule)
{
struct iptables_command_state _cs = {}, this = {}, *cs = &_cs;
bool ret = false;
h->ops->rule_to_cs(h, r, &this);
h->ops->rule_to_cs(h, rule, cs);
DEBUGP("comparing with... ");
#ifdef DEBUG_DEL
nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
#endif
if (!h->ops->is_same(cs, &this))
goto out;
if (!compare_matches(cs->matches, this.matches)) {
DEBUGP("Different matches\n");
goto out;
}
if (!compare_targets(cs->target, this.target)) {
DEBUGP("Different target\n");
goto out;
}
if ((!cs->target || !this.target) &&
strcmp(cs->jumpto, this.jumpto) != 0) {
DEBUGP("Different verdict\n");
goto out;
}
ret = true;
out:
h->ops->clear_cs(&this);
h->ops->clear_cs(cs);
return ret;
}
static struct nftnl_rule * static struct nftnl_rule *
nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum) nft_rule_find(struct nft_handle *h, struct nftnl_chain *c,
struct nftnl_rule *rule, int rulenum)
{ {
struct nftnl_rule *r; struct nftnl_rule *r;
struct nftnl_rule_iter *iter; struct nftnl_rule_iter *iter;
...@@ -2214,7 +2178,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen ...@@ -2214,7 +2178,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
r = nftnl_rule_iter_next(iter); r = nftnl_rule_iter_next(iter);
while (r != NULL) { while (r != NULL) {
found = h->ops->rule_find(h->ops, r, data); found = nft_rule_cmp(h, r, rule);
if (found) if (found)
break; break;
r = nftnl_rule_iter_next(iter); r = nftnl_rule_iter_next(iter);
...@@ -2226,7 +2190,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen ...@@ -2226,7 +2190,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
} }
int nft_rule_check(struct nft_handle *h, const char *chain, int nft_rule_check(struct nft_handle *h, const char *chain,
const char *table, void *data, bool verbose) const char *table, struct nftnl_rule *rule, bool verbose)
{ {
struct nftnl_chain *c; struct nftnl_chain *c;
struct nftnl_rule *r; struct nftnl_rule *r;
...@@ -2237,12 +2201,12 @@ int nft_rule_check(struct nft_handle *h, const char *chain, ...@@ -2237,12 +2201,12 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
if (!c) if (!c)
goto fail_enoent; goto fail_enoent;
r = nft_rule_find(h, c, data, -1); r = nft_rule_find(h, c, rule, -1);
if (r == NULL) if (r == NULL)
goto fail_enoent; goto fail_enoent;
if (verbose) if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE); h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
return 1; return 1;
fail_enoent: fail_enoent:
...@@ -2251,7 +2215,7 @@ fail_enoent: ...@@ -2251,7 +2215,7 @@ fail_enoent:
} }
int nft_rule_delete(struct nft_handle *h, const char *chain, int nft_rule_delete(struct nft_handle *h, const char *chain,
const char *table, void *data, bool verbose) const char *table, struct nftnl_rule *rule, bool verbose)
{ {
int ret = 0; int ret = 0;
struct nftnl_chain *c; struct nftnl_chain *c;
...@@ -2265,13 +2229,13 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, ...@@ -2265,13 +2229,13 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
return 0; return 0;
} }
r = nft_rule_find(h, c, data, -1); r = nft_rule_find(h, c, rule, -1);
if (r != NULL) { if (r != NULL) {
ret =__nft_rule_del(h, r); ret =__nft_rule_del(h, r);
if (ret < 0) if (ret < 0)
errno = ENOMEM; errno = ENOMEM;
if (verbose) if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE); h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
} else } else
errno = ENOENT; errno = ENOENT;
...@@ -2280,16 +2244,11 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, ...@@ -2280,16 +2244,11 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
static struct nftnl_rule * static struct nftnl_rule *
nft_rule_add(struct nft_handle *h, const char *chain, nft_rule_add(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *cs, const char *table, struct nftnl_rule *r,
struct nftnl_rule *ref, bool verbose) struct nftnl_rule *ref, bool verbose)
{ {
struct nftnl_rule *r;
uint64_t ref_id; uint64_t ref_id;
r = nft_rule_new(h, chain, table, cs);
if (r == NULL)
return NULL;
if (ref) { if (ref) {
ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE); ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
if (ref_id > 0) { if (ref_id > 0) {
...@@ -2306,26 +2265,23 @@ nft_rule_add(struct nft_handle *h, const char *chain, ...@@ -2306,26 +2265,23 @@ nft_rule_add(struct nft_handle *h, const char *chain,
} }
} }
if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) { if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r))
nftnl_rule_free(r);
return NULL; return NULL;
}
if (verbose) if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE); h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
return r; return r;
} }
int nft_rule_insert(struct nft_handle *h, const char *chain, int nft_rule_insert(struct nft_handle *h, const char *chain,
const char *table, void *data, int rulenum, bool verbose) const char *table, struct nftnl_rule *new_rule, int rulenum,
bool verbose)
{ {
struct nftnl_rule *r = NULL, *new_rule; struct nftnl_rule *r = NULL;
struct nftnl_chain *c; struct nftnl_chain *c;
/* If built-in chains don't exist for this table, create them */ nft_xt_builtin_init(h, table);
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
nft_fn = nft_rule_insert; nft_fn = nft_rule_insert;
...@@ -2336,22 +2292,22 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, ...@@ -2336,22 +2292,22 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
} }
if (rulenum > 0) { if (rulenum > 0) {
r = nft_rule_find(h, c, data, rulenum); r = nft_rule_find(h, c, new_rule, rulenum);
if (r == NULL) { if (r == NULL) {
/* special case: iptables allows to insert into /* special case: iptables allows to insert into
* rule_count + 1 position. * rule_count + 1 position.
*/ */
r = nft_rule_find(h, c, data, rulenum - 1); r = nft_rule_find(h, c, new_rule, rulenum - 1);
if (r != NULL) if (r != NULL)
return nft_rule_append(h, chain, table, data, return nft_rule_append(h, chain, table,
NULL, verbose); new_rule, NULL, verbose);
errno = E2BIG; errno = E2BIG;
goto err; goto err;
} }
} }
new_rule = nft_rule_add(h, chain, table, data, r, verbose); new_rule = nft_rule_add(h, chain, table, new_rule, r, verbose);
if (!new_rule) if (!new_rule)
goto err; goto err;
...@@ -2393,7 +2349,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain, ...@@ -2393,7 +2349,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
} }
int nft_rule_replace(struct nft_handle *h, const char *chain, int nft_rule_replace(struct nft_handle *h, const char *chain,
const char *table, void *data, int rulenum, bool verbose) const char *table, struct nftnl_rule *rule,
int rulenum, bool verbose)
{ {
int ret = 0; int ret = 0;
struct nftnl_chain *c; struct nftnl_chain *c;
...@@ -2407,13 +2364,13 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, ...@@ -2407,13 +2364,13 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
return 0; return 0;
} }
r = nft_rule_find(h, c, data, rulenum); r = nft_rule_find(h, c, rule, rulenum);
if (r != NULL) { if (r != NULL) {
DEBUGP("replacing rule with handle=%llu\n", DEBUGP("replacing rule with handle=%llu\n",
(unsigned long long) (unsigned long long)
nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE)); nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
ret = nft_rule_append(h, chain, table, data, r, verbose); ret = nft_rule_append(h, chain, table, rule, r, verbose);
} else } else
errno = E2BIG; errno = E2BIG;
...@@ -2423,8 +2380,8 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, ...@@ -2423,8 +2380,8 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
static int static int
__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c, __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
int rulenum, unsigned int format, int rulenum, unsigned int format,
void (*cb)(struct nftnl_rule *r, unsigned int num, void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int format)) unsigned int num, unsigned int format))
{ {
struct nftnl_rule_iter *iter; struct nftnl_rule_iter *iter;
struct nftnl_rule *r; struct nftnl_rule *r;
...@@ -2437,7 +2394,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c, ...@@ -2437,7 +2394,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
* valid chain but invalid rule number * valid chain but invalid rule number
*/ */
return 1; return 1;
cb(r, rulenum, format); cb(h, r, rulenum, format);
return 1; return 1;
} }
...@@ -2447,7 +2404,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c, ...@@ -2447,7 +2404,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
r = nftnl_rule_iter_next(iter); r = nftnl_rule_iter_next(iter);
while (r != NULL) { while (r != NULL) {
cb(r, ++rule_ctr, format); cb(h, r, ++rule_ctr, format);
r = nftnl_rule_iter_next(iter); r = nftnl_rule_iter_next(iter);
} }
...@@ -2476,7 +2433,6 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c) ...@@ -2476,7 +2433,6 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
} }
static void __nft_print_header(struct nft_handle *h, static void __nft_print_header(struct nft_handle *h,
const struct nft_family_ops *ops,
struct nftnl_chain *c, unsigned int format) struct nftnl_chain *c, unsigned int format)
{ {
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
...@@ -2492,31 +2448,23 @@ static void __nft_print_header(struct nft_handle *h, ...@@ -2492,31 +2448,23 @@ static void __nft_print_header(struct nft_handle *h,
if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)]; pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
ops->print_header(format, chain_name, pname, h->ops->print_header(format, chain_name, pname,
&ctrs, basechain, refs - entries, entries); &ctrs, basechain, refs - entries, entries);
} }
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
int rulenum, unsigned int format) int rulenum, unsigned int format)
{ {
const struct nft_family_ops *ops; const struct nft_family_ops *ops = h->ops;
struct nftnl_chain_list *list; struct nftnl_chain_list *list;
struct nftnl_chain_list_iter *iter; struct nftnl_chain_list_iter *iter;
struct nftnl_chain *c; struct nftnl_chain *c;
bool found = false; bool found = false;
/* If built-in chains don't exist for this table, create them */ nft_xt_builtin_init(h, table);
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_assert_table_compatible(h, table, chain);
nft_xt_builtin_init(h, table);
ops = nft_family_ops_lookup(h->family);
if (!nft_is_table_compatible(h, table)) {
xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table);
return 0;
}
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, chain);
if (!list) if (!list)
return 0; return 0;
...@@ -2528,7 +2476,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, ...@@ -2528,7 +2476,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (!rulenum) { if (!rulenum) {
if (ops->print_table_header) if (ops->print_table_header)
ops->print_table_header(table); ops->print_table_header(table);
__nft_print_header(h, ops, c, format); __nft_print_header(h, c, format);
} }
__nft_rule_list(h, c, rulenum, format, ops->print_rule); __nft_rule_list(h, c, rulenum, format, ops->print_rule);
return 1; return 1;
...@@ -2546,7 +2494,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, ...@@ -2546,7 +2494,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (found) if (found)
printf("\n"); printf("\n");
__nft_print_header(h, ops, c, format); __nft_print_header(h, c, format);
__nft_rule_list(h, c, rulenum, format, ops->print_rule); __nft_rule_list(h, c, rulenum, format, ops->print_rule);
found = true; found = true;
...@@ -2557,9 +2505,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, ...@@ -2557,9 +2505,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
} }
static void static void
list_save(struct nftnl_rule *r, unsigned int num, unsigned int format) list_save(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format)
{ {
nft_rule_print_save(r, NFT_RULE_APPEND, format); nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
} }
static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data) static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
...@@ -2612,16 +2561,10 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, ...@@ -2612,16 +2561,10 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
struct nftnl_chain *c; struct nftnl_chain *c;
int ret = 0; int ret = 0;
/* If built-in chains don't exist for this table, create them */ nft_xt_builtin_init(h, table);
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_assert_table_compatible(h, table, chain);
nft_xt_builtin_init(h, table);
if (!nft_is_table_compatible(h, table)) {
xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table);
return 0;
}
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, chain);
if (!list) if (!list)
return 0; return 0;
...@@ -2660,8 +2603,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, ...@@ -2660,8 +2603,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
const char *table, int rulenum) const char *table, int rulenum)
{ {
struct iptables_command_state cs = {}; struct iptables_command_state cs = {};
struct nftnl_rule *r, *new_rule;
struct nftnl_chain *c; struct nftnl_chain *c;
struct nftnl_rule *r;
int ret = 0; int ret = 0;
nft_fn = nft_rule_delete; nft_fn = nft_rule_delete;
...@@ -2677,11 +2620,14 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, ...@@ -2677,11 +2620,14 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
goto error; goto error;
} }
nft_rule_to_iptables_command_state(r, &cs); nft_rule_to_iptables_command_state(h, r, &cs);
cs.counters.pcnt = cs.counters.bcnt = 0; cs.counters.pcnt = cs.counters.bcnt = 0;
new_rule = nft_rule_new(h, chain, table, &cs);
if (!new_rule)
return 1;
ret = nft_rule_append(h, chain, table, &cs, r, false); ret = nft_rule_append(h, chain, table, new_rule, r, false);
error: error:
return ret; return ret;
...@@ -2698,6 +2644,39 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type, ...@@ -2698,6 +2644,39 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
nftnl_table_nlmsg_build_payload(nlh, table); nftnl_table_nlmsg_build_payload(nlh, table);
} }
static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type,
uint16_t flags, uint32_t seq,
struct nftnl_set *set)
{
struct nlmsghdr *nlh;
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
type, h->family, flags, seq);
nftnl_set_nlmsg_build_payload(nlh, set);
}
static void nft_compat_setelem_batch_add(struct nft_handle *h, uint16_t type,
uint16_t flags, uint32_t *seq,
struct nftnl_set *set)
{
struct nftnl_set_elems_iter *iter;
struct nlmsghdr *nlh;
iter = nftnl_set_elems_iter_create(set);
if (!iter)
return;
while (nftnl_set_elems_iter_cur(iter)) {
(*seq)++;
mnl_nft_batch_continue(h->batch);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
type, h->family, flags, *seq);
if (nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter) <= 0)
break;
}
nftnl_set_elems_iter_destroy(iter);
}
static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type, static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
uint16_t flags, uint32_t seq, uint16_t flags, uint32_t seq,
struct nftnl_chain *chain) struct nftnl_chain *chain)
...@@ -2742,11 +2721,23 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) ...@@ -2742,11 +2721,23 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_RULE_APPEND: case NFT_COMPAT_RULE_APPEND:
case NFT_COMPAT_RULE_INSERT: case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE: case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
break; break;
case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH: case NFT_COMPAT_RULE_FLUSH:
nftnl_rule_free(o->rule); nftnl_rule_free(o->rule);
break; break;
case NFT_COMPAT_SET_ADD:
nftnl_set_free(o->set);
break;
case NFT_COMPAT_RULE_LIST:
case NFT_COMPAT_RULE_CHECK:
case NFT_COMPAT_CHAIN_RESTORE:
case NFT_COMPAT_RULE_SAVE:
case NFT_COMPAT_RULE_ZERO:
case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
case NFT_COMPAT_TABLE_NEW:
assert(0);
break;
} }
h->obj_list_num--; h->obj_list_num--;
list_del(&o->head); list_del(&o->head);
...@@ -2813,6 +2804,14 @@ static void nft_refresh_transaction(struct nft_handle *h) ...@@ -2813,6 +2804,14 @@ static void nft_refresh_transaction(struct nft_handle *h)
case NFT_COMPAT_RULE_REPLACE: case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE: case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH: case NFT_COMPAT_RULE_FLUSH:
case NFT_COMPAT_SET_ADD:
case NFT_COMPAT_RULE_LIST:
case NFT_COMPAT_RULE_CHECK:
case NFT_COMPAT_CHAIN_RESTORE:
case NFT_COMPAT_RULE_SAVE:
case NFT_COMPAT_RULE_ZERO:
case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
case NFT_COMPAT_TABLE_NEW:
break; break;
} }
} }
...@@ -2903,6 +2902,21 @@ retry: ...@@ -2903,6 +2902,21 @@ retry:
nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0, nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
n->seq, n->rule); n->seq, n->rule);
break; break;
case NFT_COMPAT_SET_ADD:
nft_compat_set_batch_add(h, NFT_MSG_NEWSET,
NLM_F_CREATE, n->seq, n->set);
nft_compat_setelem_batch_add(h, NFT_MSG_NEWSETELEM,
NLM_F_CREATE, &n->seq, n->set);
seq = n->seq;
break;
case NFT_COMPAT_RULE_LIST:
case NFT_COMPAT_RULE_CHECK:
case NFT_COMPAT_CHAIN_RESTORE:
case NFT_COMPAT_RULE_SAVE:
case NFT_COMPAT_RULE_ZERO:
case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
case NFT_COMPAT_TABLE_NEW:
assert(0);
} }
mnl_nft_batch_continue(h->batch); mnl_nft_batch_continue(h->batch);
...@@ -2917,13 +2931,12 @@ retry: ...@@ -2917,13 +2931,12 @@ retry:
} }
errno = 0; errno = 0;
ret = mnl_batch_talk(h->nl, h->batch, &h->err_list); ret = mnl_batch_talk(h, seq);
if (ret && errno == ERESTART) { if (ret && errno == ERESTART) {
nft_rebuild_cache(h); nft_rebuild_cache(h);
nft_refresh_transaction(h); nft_refresh_transaction(h);
i=0;
list_for_each_entry_safe(err, ne, &h->err_list, head) list_for_each_entry_safe(err, ne, &h->err_list, head)
mnl_err_list_free(err); mnl_err_list_free(err);
...@@ -2998,27 +3011,33 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data) ...@@ -2998,27 +3011,33 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME), r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs); nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
ebt_cs_clean(&cs);
if (!r) if (!r)
return -1; return -1;
udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udata) if (!udata)
return -1; goto err_free_rule;
if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1)) if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
return -1; goto err_free_rule;
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
nftnl_udata_buf_data(udata), nftnl_udata_buf_data(udata),
nftnl_udata_buf_len(udata)); nftnl_udata_buf_len(udata));
nftnl_udata_buf_free(udata); nftnl_udata_buf_free(udata);
if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) { if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r))
nftnl_rule_free(r); goto err_free_rule;
return -1;
} /* add the rule to chain so it is freed later */
nftnl_chain_rule_add_tail(r, c);
return 0; return 0;
err_free_rule:
nftnl_rule_free(r);
return -1;
} }
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
...@@ -3063,37 +3082,152 @@ static void nft_bridge_commit_prepare(struct nft_handle *h) ...@@ -3063,37 +3082,152 @@ static void nft_bridge_commit_prepare(struct nft_handle *h)
} }
} }
int nft_commit(struct nft_handle *h) static void assert_chain_exists(struct nft_handle *h,
const char *table, const char *chain)
{ {
if (h->family == NFPROTO_BRIDGE) if (chain && !nft_chain_exists(h, table, chain))
nft_bridge_commit_prepare(h); xtables_error(PARAMETER_PROBLEM,
return nft_action(h, NFT_COMPAT_COMMIT); "Chain '%s' does not exist", chain);
} }
int nft_abort(struct nft_handle *h) static int nft_prepare(struct nft_handle *h)
{ {
return nft_action(h, NFT_COMPAT_ABORT); struct nft_cmd *cmd, *next;
int ret = 1;
nft_cache_build(h);
list_for_each_entry_safe(cmd, next, &h->cmd_list, head) {
switch (cmd->command) {
case NFT_COMPAT_TABLE_FLUSH:
ret = nft_table_flush(h, cmd->table);
break;
case NFT_COMPAT_CHAIN_USER_ADD:
ret = nft_chain_user_add(h, cmd->chain, cmd->table);
break;
case NFT_COMPAT_CHAIN_USER_DEL:
ret = nft_chain_user_del(h, cmd->chain, cmd->table,
cmd->verbose);
break;
case NFT_COMPAT_CHAIN_RESTORE:
ret = nft_chain_restore(h, cmd->chain, cmd->table);
break;
case NFT_COMPAT_CHAIN_UPDATE:
ret = nft_chain_set(h, cmd->table, cmd->chain,
cmd->policy, &cmd->counters);
break;
case NFT_COMPAT_CHAIN_RENAME:
ret = nft_chain_user_rename(h, cmd->chain, cmd->table,
cmd->rename);
break;
case NFT_COMPAT_CHAIN_ZERO:
ret = nft_chain_zero_counters(h, cmd->chain, cmd->table,
cmd->verbose);
break;
case NFT_COMPAT_RULE_APPEND:
assert_chain_exists(h, cmd->table, cmd->jumpto);
ret = nft_rule_append(h, cmd->chain, cmd->table,
cmd->obj.rule, NULL, cmd->verbose);
break;
case NFT_COMPAT_RULE_INSERT:
assert_chain_exists(h, cmd->table, cmd->jumpto);
ret = nft_rule_insert(h, cmd->chain, cmd->table,
cmd->obj.rule, cmd->rulenum,
cmd->verbose);
break;
case NFT_COMPAT_RULE_REPLACE:
assert_chain_exists(h, cmd->table, cmd->jumpto);
ret = nft_rule_replace(h, cmd->chain, cmd->table,
cmd->obj.rule, cmd->rulenum,
cmd->verbose);
break;
case NFT_COMPAT_RULE_DELETE:
assert_chain_exists(h, cmd->table, cmd->jumpto);
if (cmd->rulenum >= 0)
ret = nft_rule_delete_num(h, cmd->chain,
cmd->table,
cmd->rulenum,
cmd->verbose);
else
ret = nft_rule_delete(h, cmd->chain, cmd->table,
cmd->obj.rule, cmd->verbose);
break;
case NFT_COMPAT_RULE_FLUSH:
ret = nft_rule_flush(h, cmd->chain, cmd->table,
cmd->verbose);
break;
case NFT_COMPAT_RULE_LIST:
ret = nft_rule_list(h, cmd->chain, cmd->table,
cmd->rulenum, cmd->format);
break;
case NFT_COMPAT_RULE_CHECK:
assert_chain_exists(h, cmd->table, cmd->jumpto);
ret = nft_rule_check(h, cmd->chain, cmd->table,
cmd->obj.rule, cmd->rulenum);
break;
case NFT_COMPAT_RULE_ZERO:
ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
cmd->rulenum);
break;
case NFT_COMPAT_RULE_SAVE:
ret = nft_rule_list_save(h, cmd->chain, cmd->table,
cmd->rulenum,
cmd->counters_save);
break;
case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
ret = ebt_set_user_chain_policy(h, cmd->table,
cmd->chain, cmd->policy);
break;
case NFT_COMPAT_TABLE_NEW:
nft_xt_builtin_init(h, cmd->table);
ret = 1;
break;
case NFT_COMPAT_SET_ADD:
nft_xt_builtin_init(h, cmd->table);
batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
ret = 1;
break;
case NFT_COMPAT_TABLE_ADD:
case NFT_COMPAT_CHAIN_ADD:
assert(0);
break;
}
nft_cmd_free(cmd);
if (ret == 0)
return 0;
}
return 1;
} }
int nft_abort_policy_rule(struct nft_handle *h, const char *table) int nft_commit(struct nft_handle *h)
{ {
struct obj_update *n, *tmp; if (!nft_prepare(h))
return 0;
list_for_each_entry_safe(n, tmp, &h->obj_list, head) { return nft_action(h, NFT_COMPAT_COMMIT);
if (n->type != NFT_COMPAT_RULE_APPEND && }
n->type != NFT_COMPAT_RULE_DELETE)
continue;
if (strcmp(table, int nft_bridge_commit(struct nft_handle *h)
nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE))) {
continue; if (!nft_prepare(h))
return 0;
if (!nft_rule_is_policy_rule(n->rule)) nft_bridge_commit_prepare(h);
continue;
batch_obj_del(h, n); return nft_action(h, NFT_COMPAT_COMMIT);
} }
return 0;
int nft_abort(struct nft_handle *h)
{
struct nft_cmd *cmd, *next;
list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
nft_cmd_free(cmd);
return nft_action(h, NFT_COMPAT_ABORT);
} }
int nft_compatible_revision(const char *name, uint8_t rev, int opt) int nft_compatible_revision(const char *name, uint8_t rev, int opt)
...@@ -3204,7 +3338,7 @@ const char *nft_strerror(int err) ...@@ -3204,7 +3338,7 @@ const char *nft_strerror(int err)
{ NULL, ENOENT, "No chain/target/match by that name" }, { NULL, ENOENT, "No chain/target/match by that name" },
}; };
for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { for (i = 0; i < ARRAY_SIZE(table); i++) {
if ((!table[i].fn || table[i].fn == nft_fn) if ((!table[i].fn || table[i].fn == nft_fn)
&& table[i].err == err) && table[i].err == err)
return table[i].message; return table[i].message;
...@@ -3213,136 +3347,42 @@ const char *nft_strerror(int err) ...@@ -3213,136 +3347,42 @@ const char *nft_strerror(int err)
return strerror(err); return strerror(err);
} }
static void xtables_config_perror(uint32_t flags, const char *fmt, ...) static int recover_rule_compat(struct nftnl_rule *r)
{
va_list args;
va_start(args, fmt);
if (flags & NFT_LOAD_VERBOSE)
vfprintf(stderr, fmt, args);
va_end(args);
}
static int __nft_xtables_config_load(struct nft_handle *h, const char *filename,
uint32_t flags)
{ {
struct nftnl_table_list *table_list = NULL; struct nftnl_expr_iter *iter;
struct nftnl_chain_list *chain_list = NULL; struct nftnl_expr *e;
struct nftnl_table_list_iter *titer = NULL; uint32_t reg;
struct nftnl_chain_list_iter *citer = NULL; int ret = -1;
struct nftnl_table *table;
struct nftnl_chain *chain;
uint32_t table_family, chain_family;
bool found = false;
table_list = nftnl_table_list_alloc();
chain_list = nftnl_chain_list_alloc();
if (xtables_config_parse(filename, table_list, chain_list) < 0) {
if (errno == ENOENT) {
xtables_config_perror(flags,
"configuration file `%s' does not exists\n",
filename);
} else {
xtables_config_perror(flags,
"Fatal error parsing config file: %s\n",
strerror(errno));
}
goto err;
}
/* Stage 1) create tables */
titer = nftnl_table_list_iter_create(table_list);
while ((table = nftnl_table_list_iter_next(titer)) != NULL) {
table_family = nftnl_table_get_u32(table,
NFTNL_TABLE_FAMILY);
if (h->family != table_family)
continue;
found = true;
if (batch_table_add(h, NFT_COMPAT_TABLE_ADD, table) < 0) {
if (errno == EEXIST) {
xtables_config_perror(flags,
"table `%s' already exists, skipping\n",
(char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
} else {
xtables_config_perror(flags,
"table `%s' cannot be create, reason `%s'. Exitting\n",
(char *)nftnl_table_get(table, NFTNL_TABLE_NAME),
strerror(errno));
goto err;
}
continue;
}
xtables_config_perror(flags, "table `%s' has been created\n",
(char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
}
nftnl_table_list_iter_destroy(titer);
nftnl_table_list_free(table_list);
if (!found)
goto err;
/* Stage 2) create chains */
citer = nftnl_chain_list_iter_create(chain_list);
while ((chain = nftnl_chain_list_iter_next(citer)) != NULL) {
chain_family = nftnl_chain_get_u32(chain,
NFTNL_CHAIN_TABLE);
if (h->family != chain_family)
continue;
if (batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, chain) < 0) {
if (errno == EEXIST) {
xtables_config_perror(flags,
"chain `%s' already exists in table `%s', skipping\n",
(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
(char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
} else {
xtables_config_perror(flags,
"chain `%s' cannot be create, reason `%s'. Exitting\n",
(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
strerror(errno));
goto err;
}
continue;
}
xtables_config_perror(flags,
"chain `%s' in table `%s' has been created\n",
(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
(char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
}
nftnl_chain_list_iter_destroy(citer);
nftnl_chain_list_free(chain_list);
h->config_done = 1;
return 0; iter = nftnl_expr_iter_create(r);
if (!iter)
return -1;
err: next_expr:
nftnl_table_list_free(table_list); e = nftnl_expr_iter_next(iter);
nftnl_chain_list_free(chain_list); if (!e)
goto out;
if (titer != NULL) if (strcmp("meta", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
nftnl_table_list_iter_destroy(titer); nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) != NFT_META_L4PROTO)
if (citer != NULL) goto next_expr;
nftnl_chain_list_iter_destroy(citer);
h->config_done = -1; reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
return -1; e = nftnl_expr_iter_next(iter);
} if (!e)
goto out;
int nft_xtables_config_load(struct nft_handle *h, const char *filename, if (strcmp("cmp", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
uint32_t flags) reg != nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG))
{ goto next_expr;
if (!h->config_done)
return __nft_xtables_config_load(h, filename, flags);
return h->config_done; add_compat(r, nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA),
nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ);
ret = 0;
out:
nftnl_expr_iter_destroy(iter);
return ret;
} }
struct chain_zero_data { struct chain_zero_data {
...@@ -3407,6 +3447,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data) ...@@ -3407,6 +3447,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
* Unset RULE_POSITION for older kernels, we want to replace * Unset RULE_POSITION for older kernels, we want to replace
* rule based on its handle only. * rule based on its handle only.
*/ */
recover_rule_compat(r);
nftnl_rule_unset(r, NFTNL_RULE_POSITION); nftnl_rule_unset(r, NFTNL_RULE_POSITION);
if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) { if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) {
nftnl_rule_iter_destroy(iter); nftnl_rule_iter_destroy(iter);
...@@ -3431,7 +3472,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, ...@@ -3431,7 +3472,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
struct nftnl_chain *c; struct nftnl_chain *c;
int ret = 0; int ret = 0;
list = nft_chain_list_get(h, table); list = nft_chain_list_get(h, table, chain);
if (list == NULL) if (list == NULL)
goto err; goto err;
...@@ -3460,9 +3501,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag) ...@@ -3460,9 +3501,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
return NFT_CMP_EQ; return NFT_CMP_EQ;
} }
#define NFT_COMPAT_EXPR_MAX 8 static const char *supported_exprs[] = {
static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
"match", "match",
"target", "target",
"payload", "payload",
...@@ -3470,7 +3509,8 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = { ...@@ -3470,7 +3509,8 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
"cmp", "cmp",
"bitwise", "bitwise",
"counter", "counter",
"immediate" "immediate",
"lookup",
}; };
...@@ -3479,7 +3519,7 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data) ...@@ -3479,7 +3519,7 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
int i; int i;
for (i = 0; i < NFT_COMPAT_EXPR_MAX; i++) { for (i = 0; i < ARRAY_SIZE(supported_exprs); i++) {
if (strcmp(supported_exprs[i], name) == 0) if (strcmp(supported_exprs[i], name) == 0)
return 0; return 0;
} }
...@@ -3533,11 +3573,12 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data) ...@@ -3533,11 +3573,12 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
return 0; return 0;
} }
bool nft_is_table_compatible(struct nft_handle *h, const char *tablename) bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain)
{ {
struct nftnl_chain_list *clist; struct nftnl_chain_list *clist;
clist = nft_chain_list_get(h, tablename); clist = nft_chain_list_get(h, table, chain);
if (clist == NULL) if (clist == NULL)
return false; return false;
...@@ -3546,3 +3587,22 @@ bool nft_is_table_compatible(struct nft_handle *h, const char *tablename) ...@@ -3546,3 +3587,22 @@ bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
return true; return true;
} }
void nft_assert_table_compatible(struct nft_handle *h,
const char *table, const char *chain)
{
const char *pfx = "", *sfx = "";
if (nft_is_table_compatible(h, table, chain))
return;
if (chain) {
pfx = "chain `";
sfx = "' in ";
} else {
chain = "";
}
xtables_error(OTHER_PROBLEM,
"%s%s%stable `%s' is incompatible, use 'nft' tool.\n",
pfx, chain, sfx, table);
}
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#include "xshared.h" #include "xshared.h"
#include "nft-shared.h" #include "nft-shared.h"
#include "nft-cache.h"
#include "nft-cmd.h"
#include <libiptc/linux_list.h> #include <libiptc/linux_list.h>
enum nft_table_type { enum nft_table_type {
...@@ -27,17 +29,65 @@ struct builtin_table { ...@@ -27,17 +29,65 @@ struct builtin_table {
struct builtin_chain chains[NF_INET_NUMHOOKS]; struct builtin_chain chains[NF_INET_NUMHOOKS];
}; };
enum nft_cache_level {
NFT_CL_TABLES,
NFT_CL_CHAINS,
NFT_CL_SETS,
NFT_CL_RULES,
NFT_CL_FAKE /* must be last entry */
};
struct nft_cache { struct nft_cache {
struct nftnl_table_list *tables; struct nftnl_table_list *tables;
struct { struct {
struct nftnl_chain_list *chains; struct nftnl_chain_list *chains;
struct nftnl_set_list *sets;
bool initialized; bool initialized;
} table[NFT_TABLE_MAX]; } table[NFT_TABLE_MAX];
}; };
enum obj_update_type {
NFT_COMPAT_TABLE_ADD,
NFT_COMPAT_TABLE_FLUSH,
NFT_COMPAT_CHAIN_ADD,
NFT_COMPAT_CHAIN_USER_ADD,
NFT_COMPAT_CHAIN_USER_DEL,
NFT_COMPAT_CHAIN_USER_FLUSH,
NFT_COMPAT_CHAIN_UPDATE,
NFT_COMPAT_CHAIN_RENAME,
NFT_COMPAT_CHAIN_ZERO,
NFT_COMPAT_RULE_APPEND,
NFT_COMPAT_RULE_INSERT,
NFT_COMPAT_RULE_REPLACE,
NFT_COMPAT_RULE_DELETE,
NFT_COMPAT_RULE_FLUSH,
NFT_COMPAT_SET_ADD,
NFT_COMPAT_RULE_LIST,
NFT_COMPAT_RULE_CHECK,
NFT_COMPAT_CHAIN_RESTORE,
NFT_COMPAT_RULE_SAVE,
NFT_COMPAT_RULE_ZERO,
NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE,
NFT_COMPAT_TABLE_NEW,
};
struct cache_chain {
struct list_head head;
char *name;
};
struct nft_cache_req {
enum nft_cache_level level;
char *table;
bool all_chains;
struct list_head chain_list;
};
struct nft_handle { struct nft_handle {
int family; int family;
struct mnl_socket *nl; struct mnl_socket *nl;
int nlsndbuffsiz;
int nlrcvbuffsiz;
uint32_t portid; uint32_t portid;
uint32_t seq; uint32_t seq;
uint32_t nft_genid; uint32_t nft_genid;
...@@ -51,10 +101,12 @@ struct nft_handle { ...@@ -51,10 +101,12 @@ struct nft_handle {
unsigned int cache_index; unsigned int cache_index;
struct nft_cache __cache[2]; struct nft_cache __cache[2];
struct nft_cache *cache; struct nft_cache *cache;
bool have_cache; struct nft_cache_req cache_req;
bool restore; bool restore;
bool noflush; bool noflush;
int8_t config_done; int8_t config_done;
struct list_head cmd_list;
bool cache_init;
/* meta data, for error reporting */ /* meta data, for error reporting */
struct { struct {
...@@ -69,9 +121,9 @@ extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX]; ...@@ -69,9 +121,9 @@ extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX];
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data), int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data); void *data);
int nft_init(struct nft_handle *h, const struct builtin_table *t); int nft_init(struct nft_handle *h, int family, const struct builtin_table *t);
void nft_fini(struct nft_handle *h); void nft_fini(struct nft_handle *h);
void nft_build_cache(struct nft_handle *h); int nft_restart(struct nft_handle *h);
/* /*
* Operations with tables. * Operations with tables.
...@@ -79,7 +131,7 @@ void nft_build_cache(struct nft_handle *h); ...@@ -79,7 +131,7 @@ void nft_build_cache(struct nft_handle *h);
struct nftnl_table; struct nftnl_table;
struct nftnl_chain_list; struct nftnl_chain_list;
int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, bool counters), bool counters); int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, void *data), void *data);
bool nft_table_find(struct nft_handle *h, const char *tablename); bool nft_table_find(struct nft_handle *h, const char *tablename);
int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list); int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list);
int nft_table_flush(struct nft_handle *h, const char *table); int nft_table_flush(struct nft_handle *h, const char *table);
...@@ -92,8 +144,6 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c ...@@ -92,8 +144,6 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c
struct nftnl_chain; struct nftnl_chain;
int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
const char *table);
int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list); int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list);
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table); int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table);
int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose); int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
...@@ -102,18 +152,28 @@ int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *t ...@@ -102,18 +152,28 @@ int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *t
int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose); int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose);
const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t, const char *chain); const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t, const char *chain);
bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain); bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain);
void nft_bridge_chain_postprocess(struct nft_handle *h,
struct nftnl_chain *c);
/*
* Operations with sets.
*/
struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
uint32_t set_id);
/* /*
* Operations with rule-set. * Operations with rule-set.
*/ */
struct nftnl_rule; struct nftnl_rule;
int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, void *data, struct nftnl_rule *ref, bool verbose); struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose); int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose);
int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose); int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose); int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose); int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose);
int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose); int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format); int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format);
int nft_rule_list_save(struct nft_handle *h, const char *chain, const char *table, int rulenum, int counters); int nft_rule_list_save(struct nft_handle *h, const char *chain, const char *table, int rulenum, int counters);
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format); int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format);
...@@ -125,7 +185,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char * ...@@ -125,7 +185,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char *
*/ */
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes); int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes);
int add_verdict(struct nftnl_rule *r, int verdict); int add_verdict(struct nftnl_rule *r, int verdict);
int add_match(struct nftnl_rule *r, struct xt_entry_match *m); int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m);
int add_target(struct nftnl_rule *r, struct xt_entry_target *t); int add_target(struct nftnl_rule *r, struct xt_entry_target *t);
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict); int add_jumpto(struct nftnl_rule *r, const char *name, int verdict);
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set); int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set);
...@@ -136,8 +196,8 @@ enum nft_rule_print { ...@@ -136,8 +196,8 @@ enum nft_rule_print {
NFT_RULE_DEL, NFT_RULE_DEL,
}; };
void nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type, void nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
unsigned int format); enum nft_rule_print type, unsigned int format);
uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag); uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
...@@ -145,8 +205,8 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag); ...@@ -145,8 +205,8 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
* global commit and abort * global commit and abort
*/ */
int nft_commit(struct nft_handle *h); int nft_commit(struct nft_handle *h);
int nft_bridge_commit(struct nft_handle *h);
int nft_abort(struct nft_handle *h); int nft_abort(struct nft_handle *h);
int nft_abort_policy_rule(struct nft_handle *h, const char *table);
/* /*
* revision compatibility. * revision compatibility.
...@@ -165,25 +225,10 @@ int nft_init_arp(struct nft_handle *h, const char *pname); ...@@ -165,25 +225,10 @@ int nft_init_arp(struct nft_handle *h, const char *pname);
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, bool restore); int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
/* For xtables-eb.c */ /* For xtables-eb.c */
int nft_init_eb(struct nft_handle *h, const char *pname); int nft_init_eb(struct nft_handle *h, const char *pname);
void nft_fini_eb(struct nft_handle *h);
int ebt_get_current_chain(const char *chain); int ebt_get_current_chain(const char *chain);
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, bool restore); int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
/*
* Parse config for tables and chain helper functions
*/
#define XTABLES_CONFIG_DEFAULT "/etc/xtables.conf"
struct nftnl_table_list;
struct nftnl_chain_list;
extern int xtables_config_parse(const char *filename, struct nftnl_table_list *table_list, struct nftnl_chain_list *chain_list);
enum {
NFT_LOAD_VERBOSE = (1 << 0),
};
int nft_xtables_config_load(struct nft_handle *h, const char *filename, uint32_t flags);
/* /*
* Translation from iptables to nft * Translation from iptables to nft
*/ */
...@@ -211,7 +256,10 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain, ...@@ -211,7 +256,10 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain,
void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw); void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw);
bool nft_is_table_compatible(struct nft_handle *h, const char *name); bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain);
void nft_assert_table_compatible(struct nft_handle *h,
const char *table, const char *chain);
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy); const char *chain, const char *policy);
......
...@@ -38,6 +38,18 @@ while [ -n "$1" ]; do ...@@ -38,6 +38,18 @@ while [ -n "$1" ]; do
HOST=y HOST=y
shift shift
;; ;;
-l|--legacy)
LEGACY_ONLY=y
shift
;;
-n|--nft)
NFT_ONLY=y
shift
;;
-V|--valgrind)
VALGRIND=y
shift
;;
*${RETURNCODE_SEPARATOR}+([0-9])) *${RETURNCODE_SEPARATOR}+([0-9]))
SINGLE+=" $1" SINGLE+=" $1"
VERBOSE=y VERBOSE=y
...@@ -59,6 +71,49 @@ else ...@@ -59,6 +71,49 @@ else
XTABLES_LEGACY_MULTI="xtables-legacy-multi" XTABLES_LEGACY_MULTI="xtables-legacy-multi"
fi fi
printscript() { # (cmd, tmpd)
cat <<EOF
#!/bin/bash
CMD="$1"
# note: valgrind man page warns about --log-file with --trace-children, the
# last child executed overwrites previous reports unless %p or %q is used.
# Since libtool wrapper calls exec but none of the iptables tools do, this is
# perfect for us as it effectively hides bash-related errors
valgrind --log-file=$2/valgrind.log --trace-children=yes \
--leak-check=full --show-leak-kinds=all \$CMD "\$@"
RC=\$?
# don't keep uninteresting logs
if grep -q 'no leaks are possible' $2/valgrind.log; then
rm $2/valgrind.log
else
mv $2/valgrind.log $2/valgrind_\$\$.log
fi
# drop logs for failing commands for now
[ \$RC -eq 0 ] || rm $2/valgrind_\$\$.log
exit \$RC
EOF
}
if [ "$VALGRIND" == "y" ]; then
tmpd=$(mktemp -d)
msg_info "writing valgrind logs to $tmpd"
chmod a+rx $tmpd
printscript "$XTABLES_NFT_MULTI" "$tmpd" >${tmpd}/xtables-nft-multi
printscript "$XTABLES_LEGACY_MULTI" "$tmpd" >${tmpd}/xtables-legacy-multi
trap "rm ${tmpd}/xtables-*-multi" EXIT
chmod a+x ${tmpd}/xtables-nft-multi ${tmpd}/xtables-legacy-multi
XTABLES_NFT_MULTI="${tmpd}/xtables-nft-multi"
XTABLES_LEGACY_MULTI="${tmpd}/xtables-legacy-multi"
fi
find_tests() { find_tests() {
if [ ! -z "$SINGLE" ] ; then if [ ! -z "$SINGLE" ] ; then
echo $SINGLE echo $SINGLE
...@@ -98,19 +153,23 @@ do_test() { ...@@ -98,19 +153,23 @@ do_test() {
} }
echo "" echo ""
for testfile in $(find_tests);do if [ "$NFT_ONLY" != "y" ]; then
do_test "$testfile" "$XTABLES_LEGACY_MULTI" for testfile in $(find_tests);do
done do_test "$testfile" "$XTABLES_LEGACY_MULTI"
msg_info "legacy results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))" done
msg_info "legacy results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
fi
legacy_ok=$ok legacy_ok=$ok
legacy_fail=$failed legacy_fail=$failed
ok=0 ok=0
failed=0 failed=0
for testfile in $(find_tests);do if [ "$LEGACY_ONLY" != "y" ]; then
do_test "$testfile" "$XTABLES_NFT_MULTI" for testfile in $(find_tests);do
done do_test "$testfile" "$XTABLES_NFT_MULTI"
msg_info "nft results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))" done
msg_info "nft results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
fi
ok=$((legacy_ok+ok)) ok=$((legacy_ok+ok))
failed=$((legacy_fail+failed)) failed=$((legacy_fail+failed))
......
...@@ -4,7 +4,7 @@ set -e ...@@ -4,7 +4,7 @@ set -e
#set -x #set -x
# there is no legacy backend to test # there is no legacy backend to test
[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } [[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# fill arptables manually # fill arptables manually
...@@ -50,13 +50,12 @@ DUMP='*filter ...@@ -50,13 +50,12 @@ DUMP='*filter
-A foo -j MARK --set-mark 12345 -A foo -j MARK --set-mark 12345
-A foo -j ACCEPT --opcode 1 -A foo -j ACCEPT --opcode 1
-A foo -j ACCEPT --proto-type 0x800 -A foo -j ACCEPT --proto-type 0x800
-A foo -j ACCEPT -i lo --opcode 1 --proto-type 0x800 -A foo -j ACCEPT -i lo --opcode 1 --proto-type 0x800'
'
diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save) diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save | grep -v "^#")
# make sure dump can be restored and check it didn't change # make sure dump can be restored and check it didn't change
$XT_MULTI arptables -F $XT_MULTI arptables -F
$XT_MULTI arptables-restore <<<$DUMP $XT_MULTI arptables-restore <<<$DUMP
diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save) diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save | grep -v "^#")
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
set -e set -e
# there is no legacy backend to test # there is no legacy backend to test
[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } [[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# arptables-restore reuses preloaded targets and matches, make sure defaults # arptables-restore reuses preloaded targets and matches, make sure defaults
# apply to consecutive rules using the same target/match as a previous one # apply to consecutive rules using the same target/match as a previous one
...@@ -11,8 +11,7 @@ set -e ...@@ -11,8 +11,7 @@ set -e
DUMP='*filter DUMP='*filter
:OUTPUT ACCEPT :OUTPUT ACCEPT
-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1 -A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2 -A OUTPUT -j mangle --mangle-ip-d 10.0.0.2'
'
# note how mangle-ip-s is unset in second rule # note how mangle-ip-s is unset in second rule
...@@ -20,8 +19,7 @@ EXPECT='*filter ...@@ -20,8 +19,7 @@ EXPECT='*filter
:INPUT ACCEPT :INPUT ACCEPT
:OUTPUT ACCEPT :OUTPUT ACCEPT
-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1 -A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2 -A OUTPUT -j mangle --mangle-ip-d 10.0.0.2'
'
$XT_MULTI arptables -F $XT_MULTI arptables -F
$XT_MULTI arptables-restore <<<$DUMP $XT_MULTI arptables-restore <<<$DUMP
......
...@@ -4,7 +4,7 @@ set -e ...@@ -4,7 +4,7 @@ set -e
set -x set -x
# there is no legacy backend to test # there is no legacy backend to test
[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } [[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
$XT_MULTI arptables -N foo $XT_MULTI arptables -N foo
...@@ -58,7 +58,6 @@ EXPECT='*filter ...@@ -58,7 +58,6 @@ EXPECT='*filter
-A INPUT -j MARK -i eth23 --set-mark 42 -A INPUT -j MARK -i eth23 --set-mark 42
-A OUTPUT -j CLASSIFY -o eth23 --set-class 23:42 -A OUTPUT -j CLASSIFY -o eth23 --set-class 23:42
-A OUTPUT -j foo -o eth23 -A OUTPUT -j foo -o eth23
-A foo -j mangle -o eth23 --mangle-ip-s 10.0.0.1 -A foo -j mangle -o eth23 --mangle-ip-s 10.0.0.1'
'
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables-save) diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables-save | grep -v '^#')
#!/bin/sh #!/bin/sh
set -x
case "$XT_MULTI" in case "$XT_MULTI" in
*/xtables-nft-multi) *xtables-nft-multi)
for t in filter nat;do ;;
$XT_MULTI ebtables -t $t -L || exit 1 *)
$XT_MULTI ebtables -t $t -X || exit 1 echo "skip $XT_MULTI"
$XT_MULTI ebtables -t $t -F || exit 1 exit 0
done ;;
esac
for t in broute foobar ;do get_entries_count() { # (chain)
$XT_MULTI ebtables -t $t -L && $XT_MULTI ebtables -L $1 | sed -n 's/.*entries: \([0-9]*\).*/\1/p'
$XT_MULTI ebtables -t $t -X && }
$XT_MULTI ebtables -t $t -F
if [ $? -eq 0 ]; then
echo "Expect nonzero return for unsupported table"
exit 1
fi
done
set -x
$XT_MULTI ebtables -t filter -N FOO || exit 1 for t in filter nat;do
$XT_MULTI ebtables -t filter -N FOO $XT_MULTI ebtables -t $t -L || exit 1
$XT_MULTI ebtables -t $t -X || exit 1
$XT_MULTI ebtables -t $t -F || exit 1
done
for t in broute foobar ;do
$XT_MULTI ebtables -t $t -L &&
$XT_MULTI ebtables -t $t -X &&
$XT_MULTI ebtables -t $t -F
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "Duplicate chain FOO" echo "Expect nonzero return for unsupported table"
$XT_MULTI ebtables -t filter -L
exit 1 exit 1
fi fi
done
$XT_MULTI ebtables -L FOO | grep -q 'entries: 0'
if [ $? -ne 0 ]; then
echo "Unexpected entries count in empty unreferenced chain"
$XT_MULTI ebtables -L
exit 1
fi
$XT_MULTI ebtables -A FORWARD -j FOO $XT_MULTI ebtables -t filter -N FOO || exit 1
$XT_MULTI ebtables -L FORWARD | grep -q 'entries: 1' $XT_MULTI ebtables -t filter -N FOO
if [ $? -ne 0 ]; then if [ $? -eq 0 ]; then
echo "Unexpected entries count in FORWARD chain" echo "Duplicate chain FOO"
$XT_MULTI ebtables -L $XT_MULTI ebtables -t filter -L
exit 1 exit 1
fi fi
$XT_MULTI ebtables -L FOO | grep -q 'entries: 0' entries=$(get_entries_count FOO)
if [ $? -ne 0 ]; then if [ $entries -ne 0 ]; then
echo "Unexpected entries count in empty referenced chain" echo "Unexpected entries count in empty unreferenced chain (expected 0, have $entries)"
$XT_MULTI ebtables -L $XT_MULTI ebtables -L
exit 1 exit 1
fi fi
$XT_MULTI ebtables -A FOO -j ACCEPT $XT_MULTI ebtables -A FORWARD -j FOO
$XT_MULTI ebtables -L FOO | grep -q 'entries: 1' entries=$(get_entries_count FORWARD)
if [ $? -ne 0 ]; then if [ $entries -ne 1 ]; then
echo "Unexpected entries count in non-empty referenced chain" echo "Unexpected entries count in FORWARD chain (expected 1, have $entries)"
$XT_MULTI ebtables -L $XT_MULTI ebtables -L
exit 1 exit 1
fi fi
$XT_MULTI ebtables -t filter -N BAR || exit 1 entries=$(get_entries_count FOO)
$XT_MULTI ebtables -t filter -N BAZ || exit 1 if [ $entries -ne 0 ]; then
echo "Unexpected entries count in empty referenced chain (expected 0, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
$XT_MULTI ebtables -t filter -L | grep -q FOO || exit 1 $XT_MULTI ebtables -A FOO -j ACCEPT
$XT_MULTI ebtables -t filter -L | grep -q BAR || exit 1 entries=$(get_entries_count FOO)
$XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1 if [ $entries -ne 1 ]; then
echo "Unexpected entries count in non-empty referenced chain (expected 1, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
$XT_MULTI ebtables -t filter -L BAZ || exit 1 $XT_MULTI ebtables -t filter -N BAR || exit 1
$XT_MULTI ebtables -t filter -X BAZ || exit 1 $XT_MULTI ebtables -t filter -N BAZ || exit 1
$XT_MULTI ebtables -t filter -L BAZ | grep -q BAZ
if [ $? -eq 0 ]; then
echo "Deleted chain -L BAZ ok, expected failure"
$XT_MULTI ebtables -t filter -L
exit 1
fi
$XT_MULTI ebtables -t $t -F || exit 0 $XT_MULTI ebtables -t filter -L | grep -q FOO || exit 1
;; $XT_MULTI ebtables -t filter -L | grep -q BAR || exit 1
*) $XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
echo "skip $XT_MULTI"
;; $XT_MULTI ebtables -t filter -L BAZ || exit 1
esac $XT_MULTI ebtables -t filter -X BAZ || exit 1
$XT_MULTI ebtables -t filter -L BAZ | grep -q BAZ
if [ $? -eq 0 ]; then
echo "Deleted chain -L BAZ ok, expected failure"
$XT_MULTI ebtables -t filter -L
exit 1
fi
$XT_MULTI ebtables -t $t -F || exit 0
...@@ -4,7 +4,7 @@ set -e ...@@ -4,7 +4,7 @@ set -e
#set -x #set -x
# there is no legacy backend to test # there is no legacy backend to test
[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } [[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# fill ebtables manually # fill ebtables manually
...@@ -99,7 +99,6 @@ DUMP='*filter ...@@ -99,7 +99,6 @@ DUMP='*filter
-A foo --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT -A foo --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT
-A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE -A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE
-A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT -A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT
*nat *nat
:PREROUTING ACCEPT :PREROUTING ACCEPT
:OUTPUT DROP :OUTPUT DROP
...@@ -107,8 +106,7 @@ DUMP='*filter ...@@ -107,8 +106,7 @@ DUMP='*filter
:nat_foo DROP :nat_foo DROP
-A PREROUTING -j redirect -A PREROUTING -j redirect
-A OUTPUT -j ACCEPT -A OUTPUT -j ACCEPT
-A POSTROUTING -j ACCEPT -A POSTROUTING -j ACCEPT'
'
diff -u <(echo -e "$DUMP") <($XT_MULTI ebtables-save | grep -v '^#') diff -u <(echo -e "$DUMP") <($XT_MULTI ebtables-save | grep -v '^#')
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
set -e set -e
# there is no legacy backend to test # there is no legacy backend to test
[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } [[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# ebtables-restore reuses preloaded targets and matches, make sure defaults # ebtables-restore reuses preloaded targets and matches, make sure defaults
# apply to consecutive rules using the same target/match as a previous one # apply to consecutive rules using the same target/match as a previous one
...@@ -13,8 +13,7 @@ DUMP='*filter ...@@ -13,8 +13,7 @@ DUMP='*filter
-A FORWARD --limit 100 --limit-burst 42 -j ACCEPT -A FORWARD --limit 100 --limit-burst 42 -j ACCEPT
-A FORWARD --limit 1000 -j ACCEPT -A FORWARD --limit 1000 -j ACCEPT
-A FORWARD --log --log-prefix "foobar" -A FORWARD --log --log-prefix "foobar"
-A FORWARD --log -A FORWARD --log'
'
# note how limit-burst is 5 in second rule and log-prefix empty in fourth one # note how limit-burst is 5 in second rule and log-prefix empty in fourth one
...@@ -25,8 +24,7 @@ EXPECT='*filter ...@@ -25,8 +24,7 @@ EXPECT='*filter
-A FORWARD --limit 100/sec --limit-burst 42 -j ACCEPT -A FORWARD --limit 100/sec --limit-burst 42 -j ACCEPT
-A FORWARD --limit 1000/sec --limit-burst 5 -j ACCEPT -A FORWARD --limit 1000/sec --limit-burst 5 -j ACCEPT
-A FORWARD --log-level notice --log-prefix "foobar" -j CONTINUE -A FORWARD --log-level notice --log-prefix "foobar" -j CONTINUE
-A FORWARD --log-level notice --log-prefix "" -j CONTINUE -A FORWARD --log-level notice --log-prefix "" -j CONTINUE'
'
$XT_MULTI ebtables --init-table $XT_MULTI ebtables --init-table
$XT_MULTI ebtables-restore <<<$DUMP $XT_MULTI ebtables-restore <<<$DUMP
......
#!/bin/bash
set -e
# there is no legacy backend to test
[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
$XT_MULTI ebtables --init-table
$XT_MULTI ebtables -A FORWARD -i nodev123 -o nodev432 -j ACCEPT
$XT_MULTI ebtables -A FORWARD -i nodev432 -o nodev123 -j ACCEPT
EXPECT='Bridge table: filter
Bridge chain: FORWARD, entries: 2, policy: ACCEPT
-i nodev123 -o nodev432 -j ACCEPT
-i nodev432 -o nodev123 -j ACCEPT'
echo "ebtables -L FORWARD"
diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables -L FORWARD)
EXPECT='Bridge table: filter
Bridge chain: FORWARD, entries: 2, policy: ACCEPT
-i nodev123 -o nodev432 -j ACCEPT , pcnt = 0 -- bcnt = 0
-i nodev432 -o nodev123 -j ACCEPT , pcnt = 0 -- bcnt = 0'
echo "ebtables -L FORWARD --Lc"
diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables -L FORWARD --Lc)
EXPECT='*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
-A FORWARD -i nodev123 -o nodev432 -j ACCEPT
-A FORWARD -i nodev432 -o nodev123 -j ACCEPT'
echo "ebtables-save"
diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
EXPECT='*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
[0:0] -A FORWARD -i nodev123 -o nodev432 -j ACCEPT
[0:0] -A FORWARD -i nodev432 -o nodev123 -j ACCEPT'
echo "ebtables-save -c"
diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save -c | grep -v '^#')
export EBTABLES_SAVE_COUNTER=yes
# -c flag overrides EBTABLES_SAVE_COUNTER variable
echo "EBTABLES_SAVE_COUNTER=yes ebtables-save -c"
diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save -c | grep -v '^#')
EXPECT='*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
-A FORWARD -i nodev123 -o nodev432 -j ACCEPT -c 0 0
-A FORWARD -i nodev432 -o nodev123 -j ACCEPT -c 0 0'
echo "EBTABLES_SAVE_COUNTER=yes ebtables-save"
diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
#!/bin/bash
set -e
# there is no legacy backend to test
[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
EXPECT='*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
:PVEFW-FORWARD ACCEPT
:PVEFW-FWBR-OUT ACCEPT
-A FORWARD -j PVEFW-FORWARD
-A PVEFW-FORWARD -p IPv4 -j ACCEPT
-A PVEFW-FORWARD -p IPv6 -j ACCEPT
-A PVEFW-FORWARD -i fwln+ -j ACCEPT
-A PVEFW-FORWARD -o fwln+ -j PVEFW-FWBR-OUT'
$XT_MULTI ebtables-restore <<<$EXPECT
exec diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
...@@ -231,7 +231,7 @@ for table in nat mangle raw filter;do ...@@ -231,7 +231,7 @@ for table in nat mangle raw filter;do
done done
case "$XT_MULTI" in case "$XT_MULTI" in
*/xtables-nft-multi) *xtables-nft-multi)
# nft-multi displays chain names in different order, work around this for now # nft-multi displays chain names in different order, work around this for now
tmpfile2=$(mktemp) tmpfile2=$(mktemp)
sort "$tmpfile" > "$tmpfile2" sort "$tmpfile" > "$tmpfile2"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment