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 @@
#include "nft.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 xtables_rule_match *matchp;
......@@ -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);
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)
return ret;
}
......@@ -261,12 +261,12 @@ static void print_fragment(unsigned int flags, unsigned int invflags,
fputc(' ', stdout);
}
static void nft_ipv4_print_rule(struct nftnl_rule *r, unsigned int num,
unsigned int format)
static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format)
{
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,
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,
if (!(format & FMT_NONEWLINE))
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,
......@@ -450,13 +450,11 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.print_header = print_header,
.print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule,
.save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv4_proto_parse,
.post_parse = nft_ipv4_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
.rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv4_xlate,
};
......@@ -25,7 +25,7 @@
#include "nft.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 xtables_rule_match *matchp;
......@@ -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);
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)
return ret;
}
......@@ -187,12 +187,12 @@ static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
cs->fw6.ipv6.flags |= IP6T_F_GOTO;
}
static void nft_ipv6_print_rule(struct nftnl_rule *r, unsigned int num,
unsigned int format)
static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format)
{
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,
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,
if (!(format & FMT_NONEWLINE))
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,
......@@ -402,13 +402,11 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.print_header = print_header,
.print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule,
.save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv6_proto_parse,
.post_parse = nft_ipv6_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
.rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv6_xlate,
};
......@@ -69,7 +69,7 @@ void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base)
}
/* 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;
......@@ -310,7 +310,6 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
struct xtables_target *target;
struct xt_entry_target *t;
size_t size;
struct nft_family_ops *ops;
void *data = ctx->cs;
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)
target->t = t;
ops = nft_family_ops_lookup(ctx->family);
ops->parse_target(target, data);
ctx->h->ops->parse_target(target, data);
}
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_rule_match **matches;
struct xt_entry_match *m;
struct nft_family_ops *ops;
switch (ctx->family) {
switch (ctx->h->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
case NFPROTO_BRIDGE:
......@@ -349,7 +346,7 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break;
default:
fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
ctx->family);
ctx->h->family);
exit(EXIT_FAILURE);
}
......@@ -365,9 +362,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
match->m = m;
ops = nft_family_ops_lookup(ctx->family);
if (ops->parse_match != NULL)
ops->parse_match(match, ctx->cs);
if (ctx->h->ops->parse_match != NULL)
ctx->h->ops->parse_match(match, ctx->cs);
}
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)
static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
{
const struct nft_family_ops *ops;
struct xtables_target *target;
struct xt_entry_target *t;
unsigned int size;
......@@ -429,8 +424,7 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
target->t = t;
ops = nft_family_ops_lookup(ctx->family);
ops->parse_target(target, ctx->cs);
ctx->h->ops->parse_target(target, ctx->cs);
}
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)
{
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->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.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
ctx->flags |= NFT_XT_CTX_PAYLOAD;
}
......@@ -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)
{
struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family);
void *data = ctx->cs;
uint32_t reg;
......@@ -483,12 +484,12 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
return;
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;
}
/* bitwise context is interpreted from 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;
}
}
......@@ -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)
{
const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
struct nft_family_ops *ops;
const char *jumpto = NULL;
bool nft_goto = false;
void *data = ctx->cs;
......@@ -544,8 +544,7 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break;
}
ops = nft_family_ops_lookup(ctx->family);
ops->parse_immediate(jumpto, nft_goto, data);
ctx->h->ops->parse_immediate(jumpto, nft_goto, data);
}
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);
struct xtables_rule_match **matches;
struct xtables_match *match;
struct nft_family_ops *ops;
struct xt_rateinfo *rinfo;
size_t size;
switch (ctx->family) {
switch (ctx->h->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
case NFPROTO_BRIDGE:
matches = &ctx->cs->matches;
break;
default:
fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
ctx->family);
fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n",
ctx->h->family);
exit(EXIT_FAILURE);
}
......@@ -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->burst = burst;
ops = nft_family_ops_lookup(ctx->family);
if (ops->parse_match != NULL)
ops->parse_match(match, ctx->cs);
if (ctx->h->ops->parse_match != NULL)
ctx->h->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 nftnl_expr_iter *iter;
struct nftnl_expr *expr;
int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
struct nft_xt_ctx ctx = {
.cs = cs,
.family = family,
.h = h,
.table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE),
};
iter = nftnl_expr_iter_create(r);
......@@ -630,6 +635,8 @@ void nft_rule_to_iptables_command_state(const struct nftnl_rule *r,
nft_parse_target(&ctx, expr);
else if (strcmp(name, "limit") == 0)
nft_parse_limit(&ctx, expr);
else if (strcmp(name, "lookup") == 0)
nft_parse_lookup(&ctx, h, expr);
expr = nftnl_expr_iter_next(iter);
}
......@@ -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)
{
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)
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)
{
static const char tables6[] = "/proc/net/ip6_tables_names";
......
......@@ -35,6 +35,7 @@
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
struct xtables_args;
struct nft_handle;
struct xt_xlate;
enum {
......@@ -42,19 +43,22 @@ enum {
NFT_XT_CTX_META = (1 << 1),
NFT_XT_CTX_BITWISE = (1 << 2),
NFT_XT_CTX_IMMEDIATE = (1 << 3),
NFT_XT_CTX_PREV_PAYLOAD = (1 << 4),
};
struct nft_xt_ctx {
struct iptables_command_state *cs;
struct nftnl_expr_iter *iter;
int family;
struct nft_handle *h;
uint32_t flags;
const char *table;
uint32_t reg;
struct {
uint32_t base;
uint32_t offset;
uint32_t len;
} payload;
} payload, prev_payload;
struct {
uint32_t key;
} meta;
......@@ -69,7 +73,7 @@ struct nft_xt_ctx {
};
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,
const void *data_b);
void (*print_payload)(struct nftnl_expr *e,
......@@ -82,6 +86,8 @@ struct nft_family_ops {
void *data);
void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
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 (*print_table_header)(const char *tablename);
......@@ -89,10 +95,9 @@ struct nft_family_ops {
const char *pol,
const struct xt_counters *counters, bool basechain,
uint32_t refs, uint32_t entries);
void (*print_rule)(struct nftnl_rule *r, unsigned int num,
unsigned int format);
void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, 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 (*proto_parse)(struct iptables_command_state *cs,
struct xtables_args *args);
......@@ -100,18 +105,16 @@ struct nft_family_ops {
struct xtables_args *args);
void (*parse_match)(struct xtables_match *m, 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);
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);
};
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_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_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);
......@@ -137,7 +140,8 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
unsigned char *outiface_mask, uint8_t *invflags);
void print_proto(uint16_t proto, int invert);
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);
void nft_clear_iptables_command_state(struct iptables_command_state *cs);
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,
unsigned const char *iniface_mask,
const char *outiface,
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 save_matches_and_target(const struct iptables_command_state *cs,
bool goto_flag, const void *fw,
......@@ -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_handle;
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_targets(struct xtables_target *tg1, struct xtables_target *tg2);
......@@ -199,23 +199,6 @@ struct xtables_args {
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 {
unsigned int command;
unsigned int rulenum;
......@@ -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 xtables_args *args);
struct nft_xt_restore_parse {
FILE *in;
int testing;
const char *tablename;
bool commit;
};
struct nftnl_chain_list;
struct nft_xt_restore_cb {
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,
const char *chain, const char *policy,
const struct xt_counters *counters);
......@@ -260,10 +234,16 @@ struct nft_xt_restore_cb {
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,
struct nft_xt_restore_parse *p,
struct nft_xt_restore_cb *cb,
int argc, char *argv[]);
const struct nft_xt_restore_parse *p);
void nft_check_xt_legacy(int family, bool is_ipt_save);
#endif
......@@ -55,48 +55,18 @@
#include "nft.h"
#include "xshared.h" /* proto_to_name */
#include "nft-cache.h"
#include "nft-shared.h"
#include "nft-bridge.h" /* EBT_NOPROTO */
#include "xtables-config-parser.h"
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 (*cb)(const struct nlmsghdr *nlh, void *data),
void *data)
{
int ret;
char buf[16536];
char buf[32768];
if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
return -1;
......@@ -186,33 +156,42 @@ static void mnl_err_list_free(struct mnl_err *err)
free(err);
}
static int nlbuffsiz;
static void mnl_set_sndbuffer(const struct mnl_socket *nl,
struct nftnl_batch *batch)
static void mnl_set_sndbuffer(struct nft_handle *h)
{
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;
newbuffsiz = nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE;
/* 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)
return;
nlbuffsiz = newbuffsiz;
h->nlrcvbuffsiz = newbuffsiz;
}
static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock,
struct nftnl_batch *batch)
static ssize_t mnl_nft_socket_sendmsg(struct nft_handle *h, int numcmds)
{
static const struct sockaddr_nl snl = {
.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 msghdr msg = {
.msg_name = (struct sockaddr *) &snl,
......@@ -221,16 +200,16 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock,
.msg_iovlen = iov_len,
};
mnl_set_sndbuffer(nf_sock, batch);
nftnl_batch_iovec(batch, iov, iov_len);
mnl_set_sndbuffer(h);
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,
struct nftnl_batch *batch, struct list_head *err_list)
static int mnl_batch_talk(struct nft_handle *h, int numcmds)
{
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);
char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
fd_set readfds;
......@@ -240,7 +219,7 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock,
};
int err = 0;
ret = mnl_nft_socket_sendmsg(nf_sock, batch);
ret = mnl_nft_socket_sendmsg(h, numcmds);
if (ret == -1)
return -1;
......@@ -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);
/* Continue on error, make sure we get all acknowledgments */
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;
}
......@@ -276,23 +256,6 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock,
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 {
NFT_COMPAT_COMMIT,
NFT_COMPAT_ABORT,
......@@ -308,6 +271,7 @@ struct obj_update {
struct nftnl_table *table;
struct nftnl_chain *chain;
struct nftnl_rule *rule;
struct nftnl_set *set;
void *ptr;
};
struct {
......@@ -335,6 +299,7 @@ static int mnl_append_error(const struct nft_handle *h,
[NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
[NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
[NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
[NFT_COMPAT_SET_ADD] = "SET_ADD",
};
char errmsg[256];
char tcr[128];
......@@ -371,10 +336,23 @@ static int mnl_append_error(const struct nft_handle *h,
nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
#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
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);
......@@ -404,6 +382,13 @@ batch_table_add(struct nft_handle *h, enum obj_update_type type,
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,
struct nftnl_chain *c)
{
......@@ -417,6 +402,38 @@ batch_rule_add(struct nft_handle *h, enum obj_update_type type,
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] = {
[NFT_TABLE_RAW] = {
.name = "raw",
......@@ -647,7 +664,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
if (t == NULL)
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;
......@@ -664,12 +681,12 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
if (c == NULL)
return NULL;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table->name);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain->name);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->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_PRIO, chain->prio);
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;
}
......@@ -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);
}
static const struct builtin_table *
__nft_table_builtin_find(const struct builtin_table *tables, const char *table)
/* find if built-in table already exists */
const struct builtin_table *
nft_table_builtin_find(struct nft_handle *h, const char *table)
{
int i;
bool found = false;
for (i = 0; i < NFT_TABLE_MAX; i++) {
if (tables[i].name == NULL)
if (h->tables[i].name == NULL)
continue;
if (strcmp(tables[i].name, table) != 0)
if (strcmp(h->tables[i].name, table) != 0)
continue;
found = true;
break;
}
return found ? &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);
return found ? &h->tables[i] : NULL;
}
/* find if built-in chain already exists */
......@@ -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,
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;
int i;
if (!list)
return;
/* Initialize built-in chains if they don't exist yet */
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);
if (c != NULL)
......@@ -757,6 +769,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
{
const struct builtin_table *t;
if (!h->cache_init)
return 0;
t = nft_table_builtin_find(h, table);
if (t == NULL)
return -1;
......@@ -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)
return -1;
if (h->cache_req.level < NFT_CL_CHAINS)
return 0;
nft_chain_builtin_init(h, t);
h->cache->table[t->type].initialized = true;
......@@ -782,7 +800,7 @@ static bool nft_chain_builtin(struct nftnl_chain *c)
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);
......@@ -794,13 +812,16 @@ static int nft_restart(struct nft_handle *h)
return -1;
h->portid = mnl_socket_get_portid(h->nl);
nlbuffsiz = 0;
h->nlsndbuffsiz = 0;
h->nlrcvbuffsiz = 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);
if (h->nl == NULL)
return -1;
......@@ -810,80 +831,37 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t)
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->tables = t;
h->cache = &h->__cache[0];
h->family = family;
INIT_LIST_HEAD(&h->obj_list);
INIT_LIST_HEAD(&h->err_list);
INIT_LIST_HEAD(&h->cmd_list);
INIT_LIST_HEAD(&h->cache_req.chain_list);
return 0;
}
static int __flush_rule_cache(struct nftnl_rule *r, void *data)
{
nftnl_rule_list_del(r);
nftnl_rule_free(r);
return 0;
}
static void flush_rule_cache(struct nftnl_chain *c)
void nft_fini(struct nft_handle *h)
{
nftnl_rule_foreach(c, __flush_rule_cache, NULL);
}
struct list_head *pos, *n;
static int __flush_chain_cache(struct nftnl_chain *c, void *data)
{
nftnl_chain_list_del(c);
nftnl_chain_free(c);
list_for_each_safe(pos, n, &h->cmd_list)
nft_cmd_free(list_entry(pos, struct nft_cmd, head));
return 0;
}
list_for_each_safe(pos, n, &h->obj_list)
batch_obj_del(h, list_entry(pos, struct obj_update, head));
static int flush_cache(struct nft_cache *c, const struct builtin_table *tables,
const char *tablename)
{
const struct builtin_table *table;
int i;
list_for_each_safe(pos, n, &h->err_list)
mnl_err_list_free(list_entry(pos, struct mnl_err, head));
if (tablename) {
table = __nft_table_builtin_find(tables, tablename);
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)
{
if (!h->have_cache)
return;
if (flush_cache(h->cache, h->tables, tablename))
h->have_cache = false;
}
void nft_fini(struct nft_handle *h)
{
flush_chain_cache(h, NULL);
nft_release_cache(h);
mnl_socket_close(h->nl);
}
......@@ -1015,13 +993,189 @@ static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
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;
int ret;
if (!strcmp(m->u.user.name, "limit"))
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");
if (expr == NULL)
......@@ -1223,7 +1377,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
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,
void *data)
{
......@@ -1234,10 +1388,10 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
return NULL;
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
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;
return r;
......@@ -1251,22 +1405,15 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
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 *r, struct nftnl_rule *ref, bool verbose)
{
struct nftnl_chain *c;
struct nftnl_rule *r;
int type;
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
nft_fn = nft_rule_append;
r = nft_rule_new(h, chain, table, data);
if (r == NULL)
return 0;
if (ref) {
nftnl_rule_set_u64(r, 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,
} else
type = NFT_COMPAT_RULE_APPEND;
if (batch_rule_add(h, type, r) == NULL) {
nftnl_rule_free(r);
if (batch_rule_add(h, type, r) == NULL)
return 0;
}
if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE);
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
if (ref) {
nftnl_chain_rule_insert_at(r, ref);
nftnl_chain_rule_del(r);
nftnl_chain_rule_del(ref);
nftnl_rule_free(ref);
} else {
c = nft_chain_find(h, table, chain);
if (!c) {
......@@ -1298,19 +1444,18 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
}
void
nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
unsigned int format)
nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
enum nft_rule_print type, unsigned int format)
{
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 nft_family_ops *ops;
struct nft_family_ops *ops = h->ops;
ops = nft_family_ops_lookup(family);
ops->rule_to_cs(r, &cs);
ops->rule_to_cs(h, r, &cs);
if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters)
ops->save_counters(&cs);
if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
(unsigned long long)cs.counters.bcnt);
/* print chain name */
switch(type) {
......@@ -1329,106 +1474,6 @@ nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
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)
{
const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
......@@ -1467,7 +1512,7 @@ static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
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_rule *last = nft_chain_last_rule(c);
......@@ -1500,147 +1545,15 @@ static void nft_bridge_chain_postprocess(struct nft_handle *h,
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;
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] = {
[NF_DROP] = "DROP",
[NF_ACCEPT] = "ACCEPT",
......@@ -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)
{
struct nft_family_ops *ops = h->ops;
struct nftnl_chain_list_iter *iter;
struct nft_family_ops *ops;
struct nftnl_chain *c;
ops = nft_family_ops_lookup(h->family);
iter = nftnl_chain_list_iter_create(list);
if (iter == NULL)
return 0;
......@@ -1702,7 +1613,7 @@ static int nft_chain_save_rules(struct nft_handle *h,
r = nftnl_rule_iter_next(iter);
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);
}
......@@ -1717,7 +1628,7 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
struct nftnl_chain *c;
int ret = 0;
list = nft_chain_list_get(h, table);
list = nft_chain_list_get(h, table, NULL);
if (!list)
return 0;
......@@ -1740,6 +1651,20 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
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
__nft_rule_flush(struct nft_handle *h, const char *table,
const char *chain, bool verbose, bool implicit)
......@@ -1747,15 +1672,16 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
struct obj_update *obj;
struct nftnl_rule *r;
if (verbose)
if (verbose && chain)
fprintf(stdout, "Flushing chain `%s'\n", chain);
r = nftnl_rule_alloc();
if (r == NULL)
return;
nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
if (chain)
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r);
if (!obj) {
......@@ -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,
bool verbose)
{
int ret = 0;
struct nftnl_chain_list *list;
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_fn = nft_rule_flush;
list = nft_chain_list_get(h, table);
if (chain || verbose) {
list = nft_chain_list_get(h, table, chain);
if (list == NULL) {
ret = 1;
goto err;
}
}
if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain);
if (!c)
if (!c) {
errno = ENOENT;
return 0;
}
}
if (chain || !verbose) {
batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(c);
flush_rule_cache(h, table, c);
return 1;
}
......@@ -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);
while (c != NULL) {
const char *chain_name =
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
__nft_rule_flush(h, table, chain_name, verbose, false);
flush_rule_cache(c);
batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(h, table, c);
c = nftnl_chain_list_iter_next(iter);
}
nftnl_chain_list_iter_destroy(iter);
......@@ -1824,8 +1756,6 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
nft_fn = nft_chain_user_add;
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
if (nft_chain_exists(h, table, chain)) {
......@@ -1837,14 +1767,14 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (c == NULL)
return 0;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
if (h->family == NFPROTO_BRIDGE)
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
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)
nftnl_chain_list_add(c, list);
......@@ -1869,10 +1799,10 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
} else {
c = nftnl_chain_alloc();
if (!c)
return -1;
return 0;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true;
}
......@@ -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);
if (!created)
return 0;
return 1;
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)
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 */
......@@ -1939,7 +1870,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
nft_fn = nft_chain_user_del;
list = nft_chain_list_get(h, table);
list = nft_chain_list_get(h, table, chain);
if (list == NULL)
return 0;
......@@ -1967,7 +1898,7 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
{
struct nftnl_chain_list *list;
list = nft_chain_list_get(h, table);
list = nft_chain_list_get(h, table, chain);
if (list == NULL)
return NULL;
......@@ -2003,8 +1934,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0;
}
/* If built-in chains don't exist for this table, create them */
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. */
......@@ -2023,8 +1952,8 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
if (c == NULL)
return 0;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)newname);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
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,
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)
{
struct nftnl_table_list_iter *iter;
......@@ -2075,8 +1997,8 @@ err:
}
int nft_for_each_table(struct nft_handle *h,
int (*func)(struct nft_handle *h, const char *tablename, bool counters),
bool counters)
int (*func)(struct nft_handle *h, const char *tablename, void *data),
void *data)
{
struct nftnl_table_list *list;
struct nftnl_table_list_iter *iter;
......@@ -2095,7 +2017,7 @@ int nft_for_each_table(struct nft_handle *h,
const char *tablename =
nftnl_table_get(t, NFTNL_TABLE_NAME);
func(h, tablename, counters);
func(h, tablename, data);
t = nftnl_table_list_iter_next(iter);
}
......@@ -2179,7 +2101,6 @@ err_out:
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);
}
......@@ -2189,6 +2110,9 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *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);
if (!obj) {
nftnl_rule_free(r);
......@@ -2197,8 +2121,48 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
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 *
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_iter *iter;
......@@ -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);
while (r != NULL) {
found = h->ops->rule_find(h->ops, r, data);
found = nft_rule_cmp(h, r, rule);
if (found)
break;
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
}
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_rule *r;
......@@ -2237,12 +2201,12 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
if (!c)
goto fail_enoent;
r = nft_rule_find(h, c, data, -1);
r = nft_rule_find(h, c, rule, -1);
if (r == NULL)
goto fail_enoent;
if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE);
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
return 1;
fail_enoent:
......@@ -2251,7 +2215,7 @@ fail_enoent:
}
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;
struct nftnl_chain *c;
......@@ -2265,13 +2229,13 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
return 0;
}
r = nft_rule_find(h, c, data, -1);
r = nft_rule_find(h, c, rule, -1);
if (r != NULL) {
ret =__nft_rule_del(h, r);
if (ret < 0)
errno = ENOMEM;
if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE);
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
} else
errno = ENOENT;
......@@ -2280,16 +2244,11 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
static struct nftnl_rule *
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 *r;
uint64_t ref_id;
r = nft_rule_new(h, chain, table, cs);
if (r == NULL)
return NULL;
if (ref) {
ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
if (ref_id > 0) {
......@@ -2306,25 +2265,22 @@ nft_rule_add(struct nft_handle *h, const char *chain,
}
}
if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) {
nftnl_rule_free(r);
if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r))
return NULL;
}
if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE);
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
return r;
}
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;
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
nft_fn = nft_rule_insert;
......@@ -2336,22 +2292,22 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
}
if (rulenum > 0) {
r = nft_rule_find(h, c, data, rulenum);
r = nft_rule_find(h, c, new_rule, rulenum);
if (r == NULL) {
/* special case: iptables allows to insert into
* 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)
return nft_rule_append(h, chain, table, data,
NULL, verbose);
return nft_rule_append(h, chain, table,
new_rule, NULL, verbose);
errno = E2BIG;
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)
goto err;
......@@ -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,
const char *table, void *data, int rulenum, bool verbose)
const char *table, struct nftnl_rule *rule,
int rulenum, bool verbose)
{
int ret = 0;
struct nftnl_chain *c;
......@@ -2407,13 +2364,13 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
return 0;
}
r = nft_rule_find(h, c, data, rulenum);
r = nft_rule_find(h, c, rule, rulenum);
if (r != NULL) {
DEBUGP("replacing rule with handle=%llu\n",
(unsigned long long)
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
errno = E2BIG;
......@@ -2423,8 +2380,8 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
static int
__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
int rulenum, unsigned int format,
void (*cb)(struct nftnl_rule *r, unsigned int num,
unsigned int format))
void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format))
{
struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
......@@ -2437,7 +2394,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
* valid chain but invalid rule number
*/
return 1;
cb(r, rulenum, format);
cb(h, r, rulenum, format);
return 1;
}
......@@ -2447,7 +2404,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
cb(r, ++rule_ctr, format);
cb(h, r, ++rule_ctr, format);
r = nftnl_rule_iter_next(iter);
}
......@@ -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,
const struct nft_family_ops *ops,
struct nftnl_chain *c, unsigned int format)
{
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,
if (nftnl_chain_is_set(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);
}
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
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_iter *iter;
struct nftnl_chain *c;
bool found = false;
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
nft_assert_table_compatible(h, table, chain);
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)
return 0;
......@@ -2528,7 +2476,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (!rulenum) {
if (ops->print_table_header)
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);
return 1;
......@@ -2546,7 +2494,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (found)
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);
found = true;
......@@ -2557,9 +2505,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
}
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)
......@@ -2612,16 +2561,10 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
struct nftnl_chain *c;
int ret = 0;
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
nft_assert_table_compatible(h, table, chain);
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)
return 0;
......@@ -2660,8 +2603,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
const char *table, int rulenum)
{
struct iptables_command_state cs = {};
struct nftnl_rule *r, *new_rule;
struct nftnl_chain *c;
struct nftnl_rule *r;
int ret = 0;
nft_fn = nft_rule_delete;
......@@ -2677,11 +2620,14 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
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;
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:
return ret;
......@@ -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);
}
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,
uint16_t flags, uint32_t seq,
struct nftnl_chain *chain)
......@@ -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_INSERT:
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
break;
case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
nftnl_rule_free(o->rule);
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--;
list_del(&o->head);
......@@ -2813,6 +2804,14 @@ static void nft_refresh_transaction(struct nft_handle *h)
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
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;
}
}
......@@ -2903,6 +2902,21 @@ retry:
nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
n->seq, n->rule);
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);
......@@ -2917,13 +2931,12 @@ retry:
}
errno = 0;
ret = mnl_batch_talk(h->nl, h->batch, &h->err_list);
ret = mnl_batch_talk(h, seq);
if (ret && errno == ERESTART) {
nft_rebuild_cache(h);
nft_refresh_transaction(h);
i=0;
list_for_each_entry_safe(err, ne, &h->err_list, head)
mnl_err_list_free(err);
......@@ -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),
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
ebt_cs_clean(&cs);
if (!r)
return -1;
udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udata)
return -1;
goto err_free_rule;
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_udata_buf_data(udata),
nftnl_udata_buf_len(udata));
nftnl_udata_buf_free(udata);
if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) {
nftnl_rule_free(r);
return -1;
}
if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r))
goto err_free_rule;
/* add the rule to chain so it is freed later */
nftnl_chain_rule_add_tail(r, c);
return 0;
err_free_rule:
nftnl_rule_free(r);
return -1;
}
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)
}
}
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)
nft_bridge_commit_prepare(h);
return nft_action(h, NFT_COMPAT_COMMIT);
if (chain && !nft_chain_exists(h, table, chain))
xtables_error(PARAMETER_PROBLEM,
"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) {
if (n->type != NFT_COMPAT_RULE_APPEND &&
n->type != NFT_COMPAT_RULE_DELETE)
continue;
return nft_action(h, NFT_COMPAT_COMMIT);
}
if (strcmp(table,
nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE)))
continue;
int nft_bridge_commit(struct nft_handle *h)
{
if (!nft_prepare(h))
return 0;
if (!nft_rule_is_policy_rule(n->rule))
continue;
nft_bridge_commit_prepare(h);
batch_obj_del(h, n);
}
return 0;
return nft_action(h, NFT_COMPAT_COMMIT);
}
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)
......@@ -3204,7 +3338,7 @@ const char *nft_strerror(int err)
{ 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)
&& table[i].err == err)
return table[i].message;
......@@ -3213,136 +3347,42 @@ const char *nft_strerror(int err)
return strerror(err);
}
static void xtables_config_perror(uint32_t flags, const char *fmt, ...)
{
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)
static int recover_rule_compat(struct nftnl_rule *r)
{
struct nftnl_table_list *table_list = NULL;
struct nftnl_chain_list *chain_list = NULL;
struct nftnl_table_list_iter *titer = NULL;
struct nftnl_chain_list_iter *citer = NULL;
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;
struct nftnl_expr_iter *iter;
struct nftnl_expr *e;
uint32_t reg;
int ret = -1;
return 0;
iter = nftnl_expr_iter_create(r);
if (!iter)
return -1;
err:
nftnl_table_list_free(table_list);
nftnl_chain_list_free(chain_list);
next_expr:
e = nftnl_expr_iter_next(iter);
if (!e)
goto out;
if (titer != NULL)
nftnl_table_list_iter_destroy(titer);
if (citer != NULL)
nftnl_chain_list_iter_destroy(citer);
if (strcmp("meta", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) != NFT_META_L4PROTO)
goto next_expr;
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,
uint32_t flags)
{
if (!h->config_done)
return __nft_xtables_config_load(h, filename, flags);
if (strcmp("cmp", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
reg != nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG))
goto next_expr;
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 {
......@@ -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
* rule based on its handle only.
*/
recover_rule_compat(r);
nftnl_rule_unset(r, NFTNL_RULE_POSITION);
if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) {
nftnl_rule_iter_destroy(iter);
......@@ -3431,7 +3472,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
struct nftnl_chain *c;
int ret = 0;
list = nft_chain_list_get(h, table);
list = nft_chain_list_get(h, table, chain);
if (list == NULL)
goto err;
......@@ -3460,9 +3501,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
return NFT_CMP_EQ;
}
#define NFT_COMPAT_EXPR_MAX 8
static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
static const char *supported_exprs[] = {
"match",
"target",
"payload",
......@@ -3470,7 +3509,8 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
"cmp",
"bitwise",
"counter",
"immediate"
"immediate",
"lookup",
};
......@@ -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);
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)
return 0;
}
......@@ -3533,11 +3573,12 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
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;
clist = nft_chain_list_get(h, tablename);
clist = nft_chain_list_get(h, table, chain);
if (clist == NULL)
return false;
......@@ -3546,3 +3587,22 @@ bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
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 @@
#include "xshared.h"
#include "nft-shared.h"
#include "nft-cache.h"
#include "nft-cmd.h"
#include <libiptc/linux_list.h>
enum nft_table_type {
......@@ -27,17 +29,65 @@ struct builtin_table {
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 nftnl_table_list *tables;
struct {
struct nftnl_chain_list *chains;
struct nftnl_set_list *sets;
bool initialized;
} 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 {
int family;
struct mnl_socket *nl;
int nlsndbuffsiz;
int nlrcvbuffsiz;
uint32_t portid;
uint32_t seq;
uint32_t nft_genid;
......@@ -51,10 +101,12 @@ struct nft_handle {
unsigned int cache_index;
struct nft_cache __cache[2];
struct nft_cache *cache;
bool have_cache;
struct nft_cache_req cache_req;
bool restore;
bool noflush;
int8_t config_done;
struct list_head cmd_list;
bool cache_init;
/* meta data, for error reporting */
struct {
......@@ -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 (*cb)(const struct nlmsghdr *nlh, 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_build_cache(struct nft_handle *h);
int nft_restart(struct nft_handle *h);
/*
* Operations with tables.
......@@ -79,7 +131,7 @@ void nft_build_cache(struct nft_handle *h);
struct nftnl_table;
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);
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);
......@@ -92,8 +144,6 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c
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);
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_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);
......@@ -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);
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);
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.
*/
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);
int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose);
int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose);
int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose);
struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
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_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, 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_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_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);
......@@ -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_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_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);
......@@ -136,8 +196,8 @@ enum nft_rule_print {
NFT_RULE_DEL,
};
void nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
unsigned int format);
void nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
enum nft_rule_print type, unsigned int format);
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
*/
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_policy_rule(struct nft_handle *h, const char *table);
/*
* revision compatibility.
......@@ -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);
/* For xtables-eb.c */
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 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
*/
......@@ -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);
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,
const char *chain, const char *policy);
......
......@@ -38,6 +38,18 @@ while [ -n "$1" ]; do
HOST=y
shift
;;
-l|--legacy)
LEGACY_ONLY=y
shift
;;
-n|--nft)
NFT_ONLY=y
shift
;;
-V|--valgrind)
VALGRIND=y
shift
;;
*${RETURNCODE_SEPARATOR}+([0-9]))
SINGLE+=" $1"
VERBOSE=y
......@@ -59,6 +71,49 @@ else
XTABLES_LEGACY_MULTI="xtables-legacy-multi"
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() {
if [ ! -z "$SINGLE" ] ; then
echo $SINGLE
......@@ -98,19 +153,23 @@ do_test() {
}
echo ""
for testfile in $(find_tests);do
if [ "$NFT_ONLY" != "y" ]; then
for testfile in $(find_tests);do
do_test "$testfile" "$XTABLES_LEGACY_MULTI"
done
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_fail=$failed
ok=0
failed=0
for testfile in $(find_tests);do
if [ "$LEGACY_ONLY" != "y" ]; then
for testfile in $(find_tests);do
do_test "$testfile" "$XTABLES_NFT_MULTI"
done
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))
failed=$((legacy_fail+failed))
......
......@@ -4,7 +4,7 @@ set -e
#set -x
# 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
......@@ -50,13 +50,12 @@ DUMP='*filter
-A foo -j MARK --set-mark 12345
-A foo -j ACCEPT --opcode 1
-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
$XT_MULTI arptables -F
$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 @@
set -e
# 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
# apply to consecutive rules using the same target/match as a previous one
......@@ -11,8 +11,7 @@ set -e
DUMP='*filter
:OUTPUT ACCEPT
-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
......@@ -20,8 +19,7 @@ EXPECT='*filter
:INPUT ACCEPT
:OUTPUT ACCEPT
-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-restore <<<$DUMP
......
......@@ -4,7 +4,7 @@ set -e
set -x
# 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
......@@ -58,7 +58,6 @@ EXPECT='*filter
-A INPUT -j MARK -i eth23 --set-mark 42
-A OUTPUT -j CLASSIFY -o eth23 --set-class 23:42
-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
set -x
case "$XT_MULTI" in
*/xtables-nft-multi)
for t in filter nat;do
*xtables-nft-multi)
;;
*)
echo "skip $XT_MULTI"
exit 0
;;
esac
get_entries_count() { # (chain)
$XT_MULTI ebtables -L $1 | sed -n 's/.*entries: \([0-9]*\).*/\1/p'
}
set -x
for t in filter nat;do
$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
done
for t in broute foobar ;do
for t in broute foobar ;do
$XT_MULTI ebtables -t $t -L &&
$XT_MULTI ebtables -t $t -X &&
$XT_MULTI ebtables -t $t -F
......@@ -17,66 +29,61 @@ case "$XT_MULTI" in
echo "Expect nonzero return for unsupported table"
exit 1
fi
done
done
$XT_MULTI ebtables -t filter -N FOO || exit 1
$XT_MULTI ebtables -t filter -N FOO
if [ $? -eq 0 ]; then
$XT_MULTI ebtables -t filter -N FOO || exit 1
$XT_MULTI ebtables -t filter -N FOO
if [ $? -eq 0 ]; then
echo "Duplicate chain FOO"
$XT_MULTI ebtables -t filter -L
exit 1
fi
fi
$XT_MULTI ebtables -L FOO | grep -q 'entries: 0'
if [ $? -ne 0 ]; then
echo "Unexpected entries count in empty unreferenced chain"
entries=$(get_entries_count FOO)
if [ $entries -ne 0 ]; then
echo "Unexpected entries count in empty unreferenced chain (expected 0, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
fi
$XT_MULTI ebtables -A FORWARD -j FOO
$XT_MULTI ebtables -L FORWARD | grep -q 'entries: 1'
if [ $? -ne 0 ]; then
echo "Unexpected entries count in FORWARD chain"
$XT_MULTI ebtables -A FORWARD -j FOO
entries=$(get_entries_count FORWARD)
if [ $entries -ne 1 ]; then
echo "Unexpected entries count in FORWARD chain (expected 1, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
fi
$XT_MULTI ebtables -L FOO | grep -q 'entries: 0'
if [ $? -ne 0 ]; then
echo "Unexpected entries count in empty referenced chain"
entries=$(get_entries_count FOO)
if [ $entries -ne 0 ]; then
echo "Unexpected entries count in empty referenced chain (expected 0, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
fi
$XT_MULTI ebtables -A FOO -j ACCEPT
$XT_MULTI ebtables -L FOO | grep -q 'entries: 1'
if [ $? -ne 0 ]; then
echo "Unexpected entries count in non-empty referenced chain"
$XT_MULTI ebtables -A FOO -j ACCEPT
entries=$(get_entries_count FOO)
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
fi
$XT_MULTI ebtables -t filter -N BAR || exit 1
$XT_MULTI ebtables -t filter -N BAZ || exit 1
$XT_MULTI ebtables -t filter -N BAR || exit 1
$XT_MULTI ebtables -t filter -N BAZ || exit 1
$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
$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
$XT_MULTI ebtables -t filter -L BAZ || exit 1
$XT_MULTI ebtables -t filter -X BAZ || exit 1
$XT_MULTI ebtables -t filter -L BAZ | grep -q BAZ
if [ $? -eq 0 ]; then
$XT_MULTI ebtables -t filter -L BAZ || exit 1
$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
fi
$XT_MULTI ebtables -t $t -F || exit 0
;;
*)
echo "skip $XT_MULTI"
;;
esac
$XT_MULTI ebtables -t $t -F || exit 0
......@@ -4,7 +4,7 @@ set -e
#set -x
# 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
......@@ -99,7 +99,6 @@ DUMP='*filter
-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 --limit 100/sec --limit-burst 5 -j ACCEPT
*nat
:PREROUTING ACCEPT
:OUTPUT DROP
......@@ -107,8 +106,7 @@ DUMP='*filter
:nat_foo DROP
-A PREROUTING -j redirect
-A OUTPUT -j ACCEPT
-A POSTROUTING -j ACCEPT
'
-A POSTROUTING -j ACCEPT'
diff -u <(echo -e "$DUMP") <($XT_MULTI ebtables-save | grep -v '^#')
......
......@@ -3,7 +3,7 @@
set -e
# 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
# apply to consecutive rules using the same target/match as a previous one
......@@ -13,8 +13,7 @@ DUMP='*filter
-A FORWARD --limit 100 --limit-burst 42 -j ACCEPT
-A FORWARD --limit 1000 -j ACCEPT
-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
......@@ -25,8 +24,7 @@ EXPECT='*filter
-A FORWARD --limit 100/sec --limit-burst 42 -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 "" -j CONTINUE
'
-A FORWARD --log-level notice --log-prefix "" -j CONTINUE'
$XT_MULTI ebtables --init-table
$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
done
case "$XT_MULTI" in
*/xtables-nft-multi)
*xtables-nft-multi)
# nft-multi displays chain names in different order, work around this for now
tmpfile2=$(mktemp)
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