Commit 6343d369 authored by Arturo Borrero Gonzalez's avatar Arturo Borrero Gonzalez
Browse files

New upstream version 1.8.7

parent 9caffe92
#ifndef _NFT_CHAIN_H_
#define _NFT_CHAIN_H_
#include <libnftnl/chain.h>
#include <libiptc/linux_list.h>
struct nft_handle;
struct nft_chain {
struct list_head head;
struct hlist_node hnode;
struct nftnl_chain *nftnl;
};
#define CHAIN_NAME_HSIZE 512
struct nft_chain_list {
struct list_head list;
struct hlist_head names[CHAIN_NAME_HSIZE];
};
struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl);
void nft_chain_free(struct nft_chain *c);
struct nft_chain_list *nft_chain_list_alloc(void);
void nft_chain_list_free(struct nft_chain_list *list);
void nft_chain_list_del(struct nft_chain *c);
#endif /* _NFT_CHAIN_H_ */
...@@ -50,13 +50,15 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data) ...@@ -50,13 +50,15 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) { if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP); op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP);
add_addr(r, offsetof(struct iphdr, saddr), add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct iphdr, saddr),
&cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr, &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr,
sizeof(struct in_addr), op); sizeof(struct in_addr), op);
} }
if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) { if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP); op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP);
add_addr(r, offsetof(struct iphdr, daddr), add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct iphdr, daddr),
&cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr, &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr,
sizeof(struct in_addr), op); sizeof(struct in_addr), op);
} }
...@@ -199,7 +201,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, ...@@ -199,7 +201,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.smsk); parse_mask_ipv4(ctx, &cs->fw.ip.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE; ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else { } else {
cs->fw.ip.smsk.s_addr = 0xffffffff; memset(&cs->fw.ip.smsk, 0xff,
min(ctx->payload.len, sizeof(struct in_addr)));
} }
if (inv) if (inv)
...@@ -212,7 +215,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, ...@@ -212,7 +215,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.dmsk); parse_mask_ipv4(ctx, &cs->fw.ip.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE; ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else { } else {
cs->fw.ip.dmsk.s_addr = 0xffffffff; memset(&cs->fw.ip.dmsk, 0xff,
min(ctx->payload.len, sizeof(struct in_addr)));
} }
if (inv) if (inv)
......
...@@ -51,7 +51,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data) ...@@ -51,7 +51,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) { (cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_SRCIP); op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_SRCIP);
add_addr(r, offsetof(struct ip6_hdr, ip6_src), add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct ip6_hdr, ip6_src),
&cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
sizeof(struct in6_addr), op); sizeof(struct in6_addr), op);
} }
...@@ -59,7 +60,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data) ...@@ -59,7 +60,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) { (cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_DSTIP); op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_DSTIP);
add_addr(r, offsetof(struct ip6_hdr, ip6_dst), add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct ip6_hdr, ip6_dst),
&cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
sizeof(struct in6_addr), op); sizeof(struct in6_addr), op);
} }
...@@ -146,7 +148,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, ...@@ -146,7 +148,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk); parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE; ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else { } else {
memset(&cs->fw6.ipv6.smsk, 0xff, sizeof(struct in6_addr)); memset(&cs->fw6.ipv6.smsk, 0xff,
min(ctx->payload.len, sizeof(struct in6_addr)));
} }
if (inv) if (inv)
...@@ -159,7 +162,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, ...@@ -159,7 +162,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk); parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE; ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else { } else {
memset(&cs->fw6.ipv6.dmsk, 0xff, sizeof(struct in6_addr)); memset(&cs->fw6.ipv6.dmsk, 0xff,
min(ctx->payload.len, sizeof(struct in6_addr)));
} }
if (inv) if (inv)
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <xtables.h> #include <xtables.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/xt_comment.h> #include <linux/netfilter/xt_comment.h>
#include <linux/netfilter/xt_limit.h> #include <linux/netfilter/xt_limit.h>
...@@ -162,20 +161,26 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op) ...@@ -162,20 +161,26 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
add_cmp_ptr(r, op, iface, iface_len + 1); add_cmp_ptr(r, op, iface, iface_len + 1);
} }
void add_addr(struct nftnl_rule *r, int offset, void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op) void *data, void *mask, size_t len, uint32_t op)
{ {
const unsigned char *m = mask; const unsigned char *m = mask;
bool bitwise = false;
int i; int i;
add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (m[i] != 0xff) if (m[i] != 0xff) {
bitwise = m[i] != 0;
break; break;
}
} }
if (i != len) if (!bitwise)
len = i;
add_payload(r, offset, len, base);
if (bitwise)
add_bitwise(r, mask, len); add_bitwise(r, mask, len);
add_cmp_ptr(r, op, data, len); add_cmp_ptr(r, op, data, len);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <libnftnl/chain.h> #include <libnftnl/chain.h>
#include <linux/netfilter_arp/arp_tables.h> #include <linux/netfilter_arp/arp_tables.h>
#include <linux/netfilter/nf_tables.h>
#include "xshared.h" #include "xshared.h"
...@@ -121,7 +122,7 @@ void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op); ...@@ -121,7 +122,7 @@ void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op);
void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op); void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op);
void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op); void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op);
void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op); void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op);
void add_addr(struct nftnl_rule *r, int offset, void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op); void *data, void *mask, size_t len, uint32_t op);
void add_proto(struct nftnl_rule *r, int offset, size_t len, void add_proto(struct nftnl_rule *r, int offset, size_t len,
uint8_t proto, uint32_t op); uint8_t proto, uint32_t op);
...@@ -247,4 +248,8 @@ void xtables_restore_parse(struct nft_handle *h, ...@@ -247,4 +248,8 @@ void xtables_restore_parse(struct nft_handle *h,
const struct nft_xt_restore_parse *p); const struct nft_xt_restore_parse *p);
void nft_check_xt_legacy(int family, bool is_ipt_save); void nft_check_xt_legacy(int family, bool is_ipt_save);
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
#endif #endif
...@@ -688,7 +688,8 @@ nft_chain_builtin_alloc(const struct builtin_table *table, ...@@ -688,7 +688,8 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
static void nft_chain_builtin_add(struct nft_handle *h, static void nft_chain_builtin_add(struct nft_handle *h,
const struct builtin_table *table, const struct builtin_table *table,
const struct builtin_chain *chain) const struct builtin_chain *chain,
bool fake)
{ {
struct nftnl_chain *c; struct nftnl_chain *c;
...@@ -696,8 +697,9 @@ static void nft_chain_builtin_add(struct nft_handle *h, ...@@ -696,8 +697,9 @@ static void nft_chain_builtin_add(struct nft_handle *h,
if (c == NULL) if (c == NULL)
return; return;
batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c); if (!fake)
nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains); batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
nft_cache_add_chain(h, table, c);
} }
/* find if built-in table already exists */ /* find if built-in table already exists */
...@@ -738,9 +740,6 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain) ...@@ -738,9 +740,6 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
return found ? &t->chains[i] : NULL; return found ? &t->chains[i] : NULL;
} }
static struct nftnl_chain *
nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
static void nft_chain_builtin_init(struct nft_handle *h, static void nft_chain_builtin_init(struct nft_handle *h,
const struct builtin_table *table) const struct builtin_table *table)
{ {
...@@ -751,29 +750,57 @@ static void nft_chain_builtin_init(struct nft_handle *h, ...@@ -751,29 +750,57 @@ static void nft_chain_builtin_init(struct nft_handle *h,
if (nft_chain_find(h, table->name, table->chains[i].name)) if (nft_chain_find(h, table->name, table->chains[i].name))
continue; continue;
nft_chain_builtin_add(h, table, &table->chains[i]); nft_chain_builtin_add(h, table, &table->chains[i], false);
} }
} }
static int nft_xt_builtin_init(struct nft_handle *h, const char *table) static const struct builtin_table *
nft_xt_builtin_table_init(struct nft_handle *h, const char *table)
{ {
const struct builtin_table *t; const struct builtin_table *t;
if (!h->cache_init) if (!h->cache_init)
return 0; return NULL;
t = nft_table_builtin_find(h, table); t = nft_table_builtin_find(h, table);
if (t == NULL) if (t == NULL)
return -1; return NULL;
if (nft_table_builtin_add(h, t) < 0) if (nft_table_builtin_add(h, t) < 0)
return NULL;
return t;
}
static int nft_xt_builtin_init(struct nft_handle *h, const char *table,
const char *chain)
{
const struct builtin_table *t;
const struct builtin_chain *c;
if (!h->cache_init)
return 0;
t = nft_xt_builtin_table_init(h, table);
if (!t)
return -1; return -1;
if (h->cache_req.level < NFT_CL_CHAINS) if (h->cache_req.level < NFT_CL_CHAINS)
return 0; return 0;
nft_chain_builtin_init(h, t); if (!chain) {
nft_chain_builtin_init(h, t);
return 0;
}
c = nft_chain_builtin_find(t, chain);
if (!c)
return -1;
if (h->cache->table[t->type].base_chains[c->hook])
return 0;
nft_chain_builtin_add(h, t, c, false);
return 0; return 0;
} }
...@@ -785,6 +812,40 @@ static bool nft_chain_builtin(struct nftnl_chain *c) ...@@ -785,6 +812,40 @@ static bool nft_chain_builtin(struct nftnl_chain *c)
return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL; return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
} }
static int __nft_xt_fake_builtin_chains(struct nft_handle *h,
const char *table, void *data)
{
const char *chain = data ? *(const char **)data : NULL;
const struct builtin_table *t;
struct nft_chain **bcp;
int i;
t = nft_table_builtin_find(h, table);
if (!t)
return -1;
bcp = h->cache->table[t->type].base_chains;
for (i = 0; i < NF_INET_NUMHOOKS && t->chains[i].name; i++) {
if (bcp[t->chains[i].hook])
continue;
if (chain && strcmp(chain, t->chains[i].name))
continue;
nft_chain_builtin_add(h, t, &t->chains[i], true);
}
return 0;
}
int nft_xt_fake_builtin_chains(struct nft_handle *h,
const char *table, const char *chain)
{
if (table)
return __nft_xt_fake_builtin_chains(h, table, &chain);
return nft_for_each_table(h, __nft_xt_fake_builtin_chains, &chain);
}
int nft_restart(struct nft_handle *h) int nft_restart(struct nft_handle *h)
{ {
mnl_socket_close(h->nl); mnl_socket_close(h->nl);
...@@ -877,7 +938,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h, ...@@ -877,7 +938,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
} }
/* if this built-in table does not exists, create it */ /* if this built-in table does not exists, create it */
nft_xt_builtin_init(h, table); nft_xt_builtin_init(h, table, chain);
_c = nft_chain_builtin_find(_t, chain); _c = nft_chain_builtin_find(_t, chain);
if (_c != NULL) { if (_c != NULL) {
...@@ -1391,10 +1452,10 @@ int ...@@ -1391,10 +1452,10 @@ int
nft_rule_append(struct nft_handle *h, const char *chain, const char *table, nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose) struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
{ {
struct nftnl_chain *c; struct nft_chain *c;
int type; int type;
nft_xt_builtin_init(h, table); nft_xt_builtin_init(h, table, chain);
nft_fn = nft_rule_append; nft_fn = nft_rule_append;
...@@ -1421,7 +1482,7 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, ...@@ -1421,7 +1482,7 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
errno = ENOENT; errno = ENOENT;
return 0; return 0;
} }
nftnl_chain_rule_add_tail(r, c); nftnl_chain_rule_add_tail(r, c->nftnl);
} }
return 1; return 1;
...@@ -1543,8 +1604,9 @@ static const char *policy_name[NF_ACCEPT+1] = { ...@@ -1543,8 +1604,9 @@ static const char *policy_name[NF_ACCEPT+1] = {
[NF_ACCEPT] = "ACCEPT", [NF_ACCEPT] = "ACCEPT",
}; };
int nft_chain_save(struct nftnl_chain *c, void *data) int nft_chain_save(struct nft_chain *nc, void *data)
{ {
struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = data; struct nft_handle *h = data;
const char *policy = NULL; const char *policy = NULL;
...@@ -1567,13 +1629,13 @@ struct nft_rule_save_data { ...@@ -1567,13 +1629,13 @@ struct nft_rule_save_data {
unsigned int format; unsigned int format;
}; };
static int nft_rule_save_cb(struct nftnl_chain *c, void *data) static int nft_rule_save_cb(struct nft_chain *c, void *data)
{ {
struct nft_rule_save_data *d = data; struct nft_rule_save_data *d = data;
struct nftnl_rule_iter *iter; struct nftnl_rule_iter *iter;
struct nftnl_rule *r; struct nftnl_rule *r;
iter = nftnl_rule_iter_create(c); iter = nftnl_rule_iter_create(c->nftnl);
if (iter == NULL) if (iter == NULL)
return 1; return 1;
...@@ -1593,14 +1655,9 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) ...@@ -1593,14 +1655,9 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
.h = h, .h = h,
.format = format, .format = format,
}; };
struct nftnl_chain_list *list;
int ret; int ret;
list = nft_chain_list_get(h, table, NULL); ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d);
if (!list)
return 0;
ret = nftnl_chain_list_foreach(list, nft_rule_save_cb, &d);
/* the core expects 1 for success and 0 for error */ /* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0; return ret == 0 ? 1 : 0;
...@@ -1653,9 +1710,9 @@ struct nft_rule_flush_data { ...@@ -1653,9 +1710,9 @@ struct nft_rule_flush_data {
bool verbose; bool verbose;
}; };
static int nft_rule_flush_cb(struct nftnl_chain *c, void *data) static int nft_rule_flush_cb(struct nft_chain *c, void *data)
{ {
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); const char *chain = nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME);
struct nft_rule_flush_data *d = data; struct nft_rule_flush_data *d = data;
batch_chain_flush(d->h, d->table, chain); batch_chain_flush(d->h, d->table, chain);
...@@ -1672,14 +1729,13 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, ...@@ -1672,14 +1729,13 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
.table = table, .table = table,
.verbose = verbose, .verbose = verbose,
}; };
struct nftnl_chain_list *list; struct nft_chain *c = NULL;
struct nftnl_chain *c = NULL;
int ret = 0; int ret = 0;
nft_fn = nft_rule_flush; nft_fn = nft_rule_flush;
if (chain || verbose) if (chain || verbose)
nft_xt_builtin_init(h, table); nft_xt_builtin_init(h, table, chain);
else if (!nft_table_find(h, table)) else if (!nft_table_find(h, table))
return 1; return 1;
...@@ -1698,26 +1754,20 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, ...@@ -1698,26 +1754,20 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
return 1; return 1;
} }
list = nft_chain_list_get(h, table, chain); ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d);
if (list == NULL) {
ret = 1;
goto err;
}
ret = nftnl_chain_list_foreach(list, nft_rule_flush_cb, &d);
err:
/* the core expects 1 for success and 0 for error */ /* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0; return ret == 0 ? 1 : 0;
} }
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table) int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
{ {
struct nftnl_chain_list *list; const struct builtin_table *t;
struct nftnl_chain *c; struct nftnl_chain *c;
nft_fn = nft_chain_user_add; nft_fn = nft_chain_user_add;
nft_xt_builtin_init(h, table); t = nft_xt_builtin_table_init(h, table);
if (nft_chain_exists(h, table, chain)) { if (nft_chain_exists(h, table, chain)) {
errno = EEXIST; errno = EEXIST;
...@@ -1736,9 +1786,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl ...@@ -1736,9 +1786,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c)) if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
return 0; return 0;
list = nft_chain_list_get(h, table, chain); nft_cache_add_chain(h, t, c);
if (list)
nftnl_chain_list_add(c, list);
/* the core expects 1 for success and 0 for error */ /* the core expects 1 for success and 0 for error */
return 1; return 1;
...@@ -1746,15 +1794,16 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl ...@@ -1746,15 +1794,16 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table) int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
{ {
struct nftnl_chain_list *list; const struct builtin_table *t;
struct obj_update *obj; struct obj_update *obj;
struct nftnl_chain *c; struct nftnl_chain *c;
struct nft_chain *nc;
bool created = false; bool created = false;
nft_xt_builtin_init(h, table); t = nft_xt_builtin_table_init(h, table);
c = nft_chain_find(h, table, chain); nc = nft_chain_find(h, table, chain);
if (!c) { if (!nc) {
c = nftnl_chain_alloc(); c = nftnl_chain_alloc();
if (!c) if (!c)
return 0; return 0;
...@@ -1763,10 +1812,10 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table ...@@ -1763,10 +1812,10 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true; created = true;
list = nft_chain_list_get(h, table, chain); nft_cache_add_chain(h, t, c);
if (list)
nftnl_chain_list_add(c, list);
} else { } else {
c = nc->nftnl;
/* If the chain should vanish meanwhile, kernel genid changes /* If the chain should vanish meanwhile, kernel genid changes
* and the transaction is refreshed enabling the chain add * and the transaction is refreshed enabling the chain add
* object. With the handle still set, kernel interprets it as a * object. With the handle still set, kernel interprets it as a
...@@ -1798,9 +1847,10 @@ struct chain_user_del_data { ...@@ -1798,9 +1847,10 @@ struct chain_user_del_data {
int builtin_err; int builtin_err;
}; };
static int __nft_chain_user_del(struct nftnl_chain *c, void *data) static int __nft_chain_user_del(struct nft_chain *nc, void *data)
{ {
struct chain_user_del_data *d = data; struct chain_user_del_data *d = data;
struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = d->handle; struct nft_handle *h = d->handle;
/* don't delete built-in chain */ /* don't delete built-in chain */
...@@ -1811,12 +1861,17 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data) ...@@ -1811,12 +1861,17 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
fprintf(stdout, "Deleting chain `%s'\n", fprintf(stdout, "Deleting chain `%s'\n",
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
/* XXX This triggers a fast lookup from the kernel. */ /* XXX This triggers a fast lookup from the kernel. */
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c)) if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
return -1; return -1;
nftnl_chain_list_del(c); /* nftnl_chain is freed when deleting the batch object */
nc->nftnl = NULL;
nft_chain_list_del(nc);
nft_chain_free(nc);
return 0; return 0;
} }
...@@ -1827,18 +1882,13 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, ...@@ -1827,18 +1882,13 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
.handle = h, .handle = h,
.verbose = verbose, .verbose = verbose,
}; };
struct nftnl_chain_list *list; struct nft_chain *c;
struct nftnl_chain *c;
int ret = 0; int ret = 0;
nft_fn = nft_chain_user_del; nft_fn = nft_chain_user_del;
list = nft_chain_list_get(h, table, chain);
if (list == NULL)
return 0;
if (chain) { if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain); c = nft_chain_find(h, table, chain);
if (!c) { if (!c) {
errno = ENOENT; errno = ENOENT;
return 0; return 0;
...@@ -1850,24 +1900,12 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, ...@@ -1850,24 +1900,12 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
goto out; goto out;
} }
ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d); ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d);
out: out:
/* the core expects 1 for success and 0 for error */ /* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0; return ret == 0 ? 1 : 0;
} }
static struct nftnl_chain *
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, chain);
if (list == NULL)
return NULL;
return nftnl_chain_list_lookup_byname(list, chain);
}
bool nft_chain_exists(struct nft_handle *h, bool nft_chain_exists(struct nft_handle *h,
const char *table, const char *chain) const char *table, const char *chain)
{ {
...@@ -1887,6 +1925,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, ...@@ -1887,6 +1925,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
const char *table, const char *newname) const char *table, const char *newname)
{ {
struct nftnl_chain *c; struct nftnl_chain *c;
struct nft_chain *nc;
uint64_t handle; uint64_t handle;
nft_fn = nft_chain_user_rename; nft_fn = nft_chain_user_rename;
...@@ -1896,16 +1935,13 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, ...@@ -1896,16 +1935,13 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0; return 0;
} }
/* Config load changed errno. Ensure genuine info for our callers. */
errno = 0;
/* Find the old chain to be renamed */ /* Find the old chain to be renamed */
c = nft_chain_find(h, table, chain); nc = nft_chain_find(h, table, chain);
if (c == NULL) { if (nc == NULL) {
errno = ENOENT; errno = ENOENT;
return 0; return 0;
} }
handle = nftnl_chain_get_u64(c, NFTNL_CHAIN_HANDLE); handle = nftnl_chain_get_u64(nc->nftnl, NFTNL_CHAIN_HANDLE);
/* Now prepare the new name for the chain */ /* Now prepare the new name for the chain */
c = nftnl_chain_alloc(); c = nftnl_chain_alloc();
...@@ -2054,9 +2090,10 @@ out: ...@@ -2054,9 +2090,10 @@ out:
} }
static struct nftnl_rule * static struct nftnl_rule *
nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, nft_rule_find(struct nft_handle *h, struct nft_chain *nc,
struct nftnl_rule *rule, int rulenum) struct nftnl_rule *rule, int rulenum)
{ {
struct nftnl_chain *c = nc->nftnl;
struct nftnl_rule *r; struct nftnl_rule *r;
struct nftnl_rule_iter *iter; struct nftnl_rule_iter *iter;
bool found = false; bool found = false;
...@@ -2085,8 +2122,8 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, ...@@ -2085,8 +2122,8 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c,
int nft_rule_check(struct nft_handle *h, const char *chain, int nft_rule_check(struct nft_handle *h, const char *chain,
const char *table, struct nftnl_rule *rule, bool verbose) const char *table, struct nftnl_rule *rule, bool verbose)
{ {
struct nftnl_chain *c;
struct nftnl_rule *r; struct nftnl_rule *r;
struct nft_chain *c;
nft_fn = nft_rule_check; nft_fn = nft_rule_check;
...@@ -2111,8 +2148,8 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, ...@@ -2111,8 +2148,8 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
const char *table, struct nftnl_rule *rule, bool verbose) const char *table, struct nftnl_rule *rule, bool verbose)
{ {
int ret = 0; int ret = 0;
struct nftnl_chain *c;
struct nftnl_rule *r; struct nftnl_rule *r;
struct nft_chain *c;
nft_fn = nft_rule_delete; nft_fn = nft_rule_delete;
...@@ -2172,9 +2209,9 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, ...@@ -2172,9 +2209,9 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
bool verbose) bool verbose)
{ {
struct nftnl_rule *r = NULL; struct nftnl_rule *r = NULL;
struct nftnl_chain *c; struct nft_chain *c;
nft_xt_builtin_init(h, table); nft_xt_builtin_init(h, table, chain);
nft_fn = nft_rule_insert; nft_fn = nft_rule_insert;
...@@ -2207,7 +2244,7 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, ...@@ -2207,7 +2244,7 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
if (r) if (r)
nftnl_chain_rule_insert_at(new_rule, r); nftnl_chain_rule_insert_at(new_rule, r);
else else
nftnl_chain_rule_add(new_rule, c); nftnl_chain_rule_add(new_rule, c->nftnl);
return 1; return 1;
err: err:
...@@ -2218,8 +2255,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain, ...@@ -2218,8 +2255,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
const char *table, int rulenum, bool verbose) const char *table, int rulenum, bool verbose)
{ {
int ret = 0; int ret = 0;
struct nftnl_chain *c;
struct nftnl_rule *r; struct nftnl_rule *r;
struct nft_chain *c;
nft_fn = nft_rule_delete_num; nft_fn = nft_rule_delete_num;
...@@ -2246,8 +2283,8 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, ...@@ -2246,8 +2283,8 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
int rulenum, bool verbose) int rulenum, bool verbose)
{ {
int ret = 0; int ret = 0;
struct nftnl_chain *c;
struct nftnl_rule *r; struct nftnl_rule *r;
struct nft_chain *c;
nft_fn = nft_rule_replace; nft_fn = nft_rule_replace;
...@@ -2326,8 +2363,9 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c) ...@@ -2326,8 +2363,9 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
} }
static void __nft_print_header(struct nft_handle *h, static void __nft_print_header(struct nft_handle *h,
struct nftnl_chain *c, unsigned int format) struct nft_chain *nc, unsigned int format)
{ {
struct nftnl_chain *c = nc->nftnl;
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM); bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM);
uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE); uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
...@@ -2355,7 +2393,7 @@ struct nft_rule_list_cb_data { ...@@ -2355,7 +2393,7 @@ struct nft_rule_list_cb_data {
unsigned int num, unsigned int format); unsigned int num, unsigned int format);
}; };
static int nft_rule_list_cb(struct nftnl_chain *c, void *data) static int nft_rule_list_cb(struct nft_chain *c, void *data)
{ {
struct nft_rule_list_cb_data *d = data; struct nft_rule_list_cb_data *d = data;
...@@ -2367,7 +2405,7 @@ static int nft_rule_list_cb(struct nftnl_chain *c, void *data) ...@@ -2367,7 +2405,7 @@ static int nft_rule_list_cb(struct nftnl_chain *c, void *data)
__nft_print_header(d->h, c, d->format); __nft_print_header(d->h, c, d->format);
} }
return __nft_rule_list(d->h, c, d->rulenum, d->format, d->cb); return __nft_rule_list(d->h, c->nftnl, d->rulenum, d->format, d->cb);
} }
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
...@@ -2380,10 +2418,9 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, ...@@ -2380,10 +2418,9 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
.rulenum = rulenum, .rulenum = rulenum,
.cb = ops->print_rule, .cb = ops->print_rule,
}; };
struct nftnl_chain_list *list; struct nft_chain *c;
struct nftnl_chain *c;
nft_xt_builtin_init(h, table); nft_xt_fake_builtin_chains(h, table, chain);
nft_assert_table_compatible(h, table, chain); nft_assert_table_compatible(h, table, chain);
if (chain) { if (chain) {
...@@ -2400,14 +2437,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, ...@@ -2400,14 +2437,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
return 1; return 1;
} }
list = nft_chain_list_get(h, table, chain);
if (!list)
return 0;
if (ops->print_table_header) if (ops->print_table_header)
ops->print_table_header(table); ops->print_table_header(table);
nftnl_chain_list_foreach(list, nft_rule_list_cb, &d); nft_chain_foreach(h, table, nft_rule_list_cb, &d);
return 1; return 1;
} }
...@@ -2418,8 +2451,44 @@ list_save(struct nft_handle *h, struct nftnl_rule *r, ...@@ -2418,8 +2451,44 @@ list_save(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_print_save(h, r, NFT_RULE_APPEND, format); nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
} }
static int nft_rule_list_chain_save(struct nftnl_chain *c, void *data) int nft_chain_foreach(struct nft_handle *h, const char *table,
int (*cb)(struct nft_chain *c, void *data),
void *data)
{ {
const struct builtin_table *t;
struct nft_chain_list *list;
struct nft_chain *c, *c_bak;
int i, ret;
t = nft_table_builtin_find(h, table);
if (!t)
return -1;
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
c = h->cache->table[t->type].base_chains[i];
if (!c)
continue;
ret = cb(c, data);
if (ret < 0)
return ret;
}
list = h->cache->table[t->type].chains;
if (!list)
return -1;
list_for_each_entry_safe(c, c_bak, &list->list, head) {
ret = cb(c, data);
if (ret < 0)
return ret;
}
return 0;
}
static int nft_rule_list_chain_save(struct nft_chain *nc, void *data)
{
struct nftnl_chain *c = nc->nftnl;
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
int *counters = data; int *counters = data;
...@@ -2449,24 +2518,19 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, ...@@ -2449,24 +2518,19 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
.save_fmt = true, .save_fmt = true,
.cb = list_save, .cb = list_save,
}; };
struct nftnl_chain_list *list; struct nft_chain *c;
struct nftnl_chain *c;
int ret = 0; int ret = 0;
nft_xt_builtin_init(h, table); nft_xt_fake_builtin_chains(h, table, chain);
nft_assert_table_compatible(h, table, chain); nft_assert_table_compatible(h, table, chain);
list = nft_chain_list_get(h, table, chain);
if (!list)
return 0;
if (counters < 0) if (counters < 0)
d.format = FMT_C_COUNTS; d.format = FMT_C_COUNTS;
else if (counters == 0) else if (counters == 0)
d.format = FMT_NOCOUNTS; d.format = FMT_NOCOUNTS;
if (chain) { if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain); c = nft_chain_find(h, table, chain);
if (!c) if (!c)
return 0; return 0;
...@@ -2477,10 +2541,10 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, ...@@ -2477,10 +2541,10 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
} }
/* Dump policies and custom chains first */ /* Dump policies and custom chains first */
nftnl_chain_list_foreach(list, nft_rule_list_chain_save, &counters); nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters);
/* Now dump out rules in this table */ /* Now dump out rules in this table */
ret = nftnl_chain_list_foreach(list, nft_rule_list_cb, &d); ret = nft_chain_foreach(h, table, nft_rule_list_cb, &d);
return ret == 0 ? 1 : 0; return ret == 0 ? 1 : 0;
} }
...@@ -2489,7 +2553,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, ...@@ -2489,7 +2553,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
{ {
struct iptables_command_state cs = {}; struct iptables_command_state cs = {};
struct nftnl_rule *r, *new_rule; struct nftnl_rule *r, *new_rule;
struct nftnl_chain *c; struct nft_chain *c;
int ret = 0; int ret = 0;
nft_fn = nft_rule_delete; nft_fn = nft_rule_delete;
...@@ -2631,7 +2695,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) ...@@ -2631,7 +2695,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
static void nft_refresh_transaction(struct nft_handle *h) static void nft_refresh_transaction(struct nft_handle *h)
{ {
const char *tablename, *chainname; const char *tablename, *chainname;
const struct nftnl_chain *c; const struct nft_chain *c;
struct obj_update *n, *tmp; struct obj_update *n, *tmp;
bool exists; bool exists;
...@@ -2928,7 +2992,7 @@ err_free_rule: ...@@ -2928,7 +2992,7 @@ err_free_rule:
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy) const char *chain, const char *policy)
{ {
struct nftnl_chain *c = nft_chain_find(h, table, chain); struct nft_chain *c = nft_chain_find(h, table, chain);
int pval; int pval;
if (!c) if (!c)
...@@ -2943,14 +3007,15 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, ...@@ -2943,14 +3007,15 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
else else
return 0; return 0;
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval); nftnl_chain_set_u32(c->nftnl, NFTNL_CHAIN_POLICY, pval);
return 1; return 1;
} }
static void nft_bridge_commit_prepare(struct nft_handle *h) static void nft_bridge_commit_prepare(struct nft_handle *h)
{ {
const struct builtin_table *t; const struct builtin_table *t;
struct nftnl_chain_list *list; struct nft_chain_list *list;
struct nft_chain *c;
int i; int i;
for (i = 0; i < NFT_TABLE_MAX; i++) { for (i = 0; i < NFT_TABLE_MAX; i++) {
...@@ -2963,7 +3028,9 @@ static void nft_bridge_commit_prepare(struct nft_handle *h) ...@@ -2963,7 +3028,9 @@ static void nft_bridge_commit_prepare(struct nft_handle *h)
if (!list) if (!list)
continue; continue;
nftnl_chain_list_foreach(list, ebt_add_policy_rule, h); list_for_each_entry(c, &list->list, head) {
ebt_add_policy_rule(c->nftnl, h);
}
} }
} }
...@@ -3064,7 +3131,7 @@ static int nft_prepare(struct nft_handle *h) ...@@ -3064,7 +3131,7 @@ static int nft_prepare(struct nft_handle *h)
cmd->chain, cmd->policy); cmd->chain, cmd->policy);
break; break;
case NFT_COMPAT_SET_ADD: case NFT_COMPAT_SET_ADD:
nft_xt_builtin_init(h, cmd->table); nft_xt_builtin_table_init(h, cmd->table);
batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set); batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
ret = 1; ret = 1;
break; break;
...@@ -3271,8 +3338,9 @@ struct chain_zero_data { ...@@ -3271,8 +3338,9 @@ struct chain_zero_data {
bool verbose; bool verbose;
}; };
static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data) static int __nft_chain_zero_counters(struct nft_chain *nc, void *data)
{ {
struct nftnl_chain *c = nc->nftnl;
struct chain_zero_data *d = data; struct chain_zero_data *d = data;
struct nft_handle *h = d->handle; struct nft_handle *h = d->handle;
struct nftnl_rule_iter *iter; struct nftnl_rule_iter *iter;
...@@ -3280,7 +3348,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data) ...@@ -3280,7 +3348,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
if (d->verbose) if (d->verbose)
fprintf(stdout, "Zeroing chain `%s'\n", fprintf(stdout, "Zeroing chain `%s'\n",
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
/* zero base chain counters. */ /* zero base chain counters. */
...@@ -3345,20 +3413,15 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data) ...@@ -3345,20 +3413,15 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
int nft_chain_zero_counters(struct nft_handle *h, const char *chain, int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose) const char *table, bool verbose)
{ {
struct nftnl_chain_list *list;
struct chain_zero_data d = { struct chain_zero_data d = {
.handle = h, .handle = h,
.verbose = verbose, .verbose = verbose,
}; };
struct nftnl_chain *c; struct nft_chain *c;
int ret = 0; int ret = 0;
list = nft_chain_list_get(h, table, chain);
if (list == NULL)
goto err;
if (chain) { if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain); c = nft_chain_find(h, table, chain);
if (!c) { if (!c) {
errno = ENOENT; errno = ENOENT;
return 0; return 0;
...@@ -3368,7 +3431,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, ...@@ -3368,7 +3431,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
goto err; goto err;
} }
ret = nftnl_chain_list_foreach(list, __nft_chain_zero_counters, &d); ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d);
err: err:
/* the core expects 1 for success and 0 for error */ /* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0; return ret == 0 ? 1 : 0;
...@@ -3418,8 +3481,9 @@ static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data) ...@@ -3418,8 +3481,9 @@ static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL); return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
} }
static int nft_is_chain_compatible(struct nftnl_chain *c, void *data) static int nft_is_chain_compatible(struct nft_chain *nc, void *data)
{ {
struct nftnl_chain *c = nc->nftnl;
const struct builtin_table *table; const struct builtin_table *table;
const struct builtin_chain *chain; const struct builtin_chain *chain;
const char *tname, *cname, *type; const char *tname, *cname, *type;
...@@ -3457,16 +3521,13 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data) ...@@ -3457,16 +3521,13 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
bool nft_is_table_compatible(struct nft_handle *h, bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain) const char *table, const char *chain)
{ {
struct nftnl_chain_list *clist; if (chain) {
struct nft_chain *c = nft_chain_find(h, table, chain);
clist = nft_chain_list_get(h, table, chain);
if (clist == NULL)
return false;
if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h)) return c && !nft_is_chain_compatible(c, h);
return false; }
return true; return !nft_chain_foreach(h, table, nft_is_chain_compatible, h);
} }
void nft_assert_table_compatible(struct nft_handle *h, void nft_assert_table_compatible(struct nft_handle *h,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "xshared.h" #include "xshared.h"
#include "nft-shared.h" #include "nft-shared.h"
#include "nft-cache.h" #include "nft-cache.h"
#include "nft-chain.h"
#include "nft-cmd.h" #include "nft-cmd.h"
#include <libiptc/linux_list.h> #include <libiptc/linux_list.h>
...@@ -39,7 +40,8 @@ enum nft_cache_level { ...@@ -39,7 +40,8 @@ enum nft_cache_level {
struct nft_cache { struct nft_cache {
struct { struct {
struct nftnl_chain_list *chains; struct nft_chain *base_chains[NF_INET_NUMHOOKS];
struct nft_chain_list *chains;
struct nftnl_set_list *sets; struct nftnl_set_list *sets;
bool exists; bool exists;
} table[NFT_TABLE_MAX]; } table[NFT_TABLE_MAX];
...@@ -134,6 +136,7 @@ bool nft_table_find(struct nft_handle *h, const char *tablename); ...@@ -134,6 +136,7 @@ bool nft_table_find(struct nft_handle *h, const char *tablename);
int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list); int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list);
int nft_table_flush(struct nft_handle *h, const char *table); int nft_table_flush(struct nft_handle *h, const char *table);
const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table); const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table);
int nft_xt_fake_builtin_chains(struct nft_handle *h, const char *table, const char *chain);
/* /*
* Operations with chains. * Operations with chains.
...@@ -141,7 +144,7 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c ...@@ -141,7 +144,7 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c
struct nftnl_chain; struct nftnl_chain;
int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
int nft_chain_save(struct nftnl_chain *c, void *data); int nft_chain_save(struct nft_chain *c, void *data);
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table); int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table);
int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose); int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table); int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table);
...@@ -151,6 +154,9 @@ const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t ...@@ -151,6 +154,9 @@ const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t
bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain); bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain);
void nft_bridge_chain_postprocess(struct nft_handle *h, void nft_bridge_chain_postprocess(struct nft_handle *h,
struct nftnl_chain *c); struct nftnl_chain *c);
int nft_chain_foreach(struct nft_handle *h, const char *table,
int (*cb)(struct nft_chain *c, void *data),
void *data);
/* /*
......
...@@ -86,4 +86,8 @@ if [ $? -eq 0 ]; then ...@@ -86,4 +86,8 @@ if [ $? -eq 0 ]; then
exit 1 exit 1
fi fi
$XT_MULTI ebtables -t filter -E FOO BAZ || exit 1
$XT_MULTI ebtables -t filter -L | grep -q FOO && exit 1
$XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
$XT_MULTI ebtables -t $t -F || exit 0 $XT_MULTI ebtables -t $t -F || exit 0
...@@ -70,8 +70,8 @@ DUMP='*filter ...@@ -70,8 +70,8 @@ DUMP='*filter
:INPUT ACCEPT :INPUT ACCEPT
:FORWARD DROP :FORWARD DROP
:OUTPUT ACCEPT :OUTPUT ACCEPT
:foo ACCEPT
:bar RETURN :bar RETURN
:foo ACCEPT
-A INPUT -p IPv4 -i lo -j ACCEPT -A INPUT -p IPv4 -i lo -j ACCEPT
-A FORWARD -j foo -A FORWARD -j foo
-A OUTPUT -s Broadcast -j DROP -A OUTPUT -s Broadcast -j DROP
......
...@@ -230,21 +230,8 @@ for table in nat mangle raw filter;do ...@@ -230,21 +230,8 @@ for table in nat mangle raw filter;do
$XT_MULTI iptables-save -t $table | grep -v '^#' >> "$tmpfile" $XT_MULTI iptables-save -t $table | grep -v '^#' >> "$tmpfile"
done done
case "$XT_MULTI" in diff -u $tmpfile $(dirname "$0")/dumps/ipt-save-completed.txt
*xtables-nft-multi) RET=$?
# nft-multi displays chain names in different order, work around this for now
tmpfile2=$(mktemp)
sort "$tmpfile" > "$tmpfile2"
sort $(dirname "$0")/dumps/ipt-save-completed.txt > "$tmpfile"
diff -u $tmpfile $tmpfile2
RET=$?
rm -f "$tmpfile2"
;;
*)
diff -u $tmpfile $(dirname "$0")/dumps/ipt-save-completed.txt
RET=$?
;;
esac
rm -f "$tmpfile" rm -f "$tmpfile"
......
...@@ -18,7 +18,7 @@ EXPECT="*nat ...@@ -18,7 +18,7 @@ EXPECT="*nat
:POSTROUTING ACCEPT [0:0] :POSTROUTING ACCEPT [0:0]
-A POSTROUTING -j ACCEPT -A POSTROUTING -j ACCEPT
COMMIT" COMMIT"
diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort) diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save | grep -v '^#')
$XT_MULTI iptables-restore <<EOF $XT_MULTI iptables-restore <<EOF
*filter *filter
...@@ -39,4 +39,4 @@ COMMIT ...@@ -39,4 +39,4 @@ COMMIT
:POSTROUTING ACCEPT [0:0] :POSTROUTING ACCEPT [0:0]
-A POSTROUTING -j ACCEPT -A POSTROUTING -j ACCEPT
COMMIT" COMMIT"
diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort) diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save | grep -v '^#')
...@@ -59,7 +59,7 @@ Flushing chain \`secfoo' ...@@ -59,7 +59,7 @@ Flushing chain \`secfoo'
Deleting chain \`secfoo'" Deleting chain \`secfoo'"
for ipt in iptables-restore ip6tables-restore; do for ipt in iptables-restore ip6tables-restore; do
diff -u -Z <(sort <<< "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP" | sort) diff -u -Z <(echo "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP")
done done
DUMP="*filter DUMP="*filter
......
#!/bin/bash
# A bug in extension registration would leave unsupported older extension
# revisions in pending list and get compatibility checked again for each rule
# using them. With SELinux enabled, the resulting socket() call per rule leads
# to significant slowdown (~50% performance in worst cases).
set -e
strace --version >/dev/null || { echo "skip for missing strace"; exit 0; }
RULESET="$(
echo "*filter"
for ((i = 0; i < 100; i++)); do
echo "-A FORWARD -m conntrack --ctstate NEW"
done
echo "COMMIT"
)"
cmd="$XT_MULTI iptables-restore"
socketcount=$(strace -esocket $cmd <<< "$RULESET" 2>&1 | wc -l)
# unpatched iptables-restore would open 111 sockets,
# patched only 12 but keep a certain margin for future changes
[[ $socketcount -lt 20 ]]
...@@ -40,8 +40,8 @@ ...@@ -40,8 +40,8 @@
-A OUTPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -o lo -j ACCEPT -A OUTPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -o lo -j ACCEPT
-A OUTPUT -o wlan0 -j wlanout -A OUTPUT -o wlan0 -j wlanout
-A OUTPUT -j block -A OUTPUT -j block
-A WLAN -s 192.168.200.4/32 -m mac --mac-source 00:00:F1:05:A0:E0 -j RETURN -A WLAN -s 192.168.200.4/32 -m mac --mac-source 00:00:f1:05:a0:e0 -j RETURN
-A WLAN -s 192.168.200.9/32 -m mac --mac-source 00:00:F1:05:99:85 -j RETURN -A WLAN -s 192.168.200.9/32 -m mac --mac-source 00:00:f1:05:99:85 -j RETURN
-A WLAN -m limit --limit 12/min -j LOG --log-prefix "UNKNOWN WLAN dropped:" -A WLAN -m limit --limit 12/min -j LOG --log-prefix "UNKNOWN WLAN dropped:"
-A WLAN -j DROP -A WLAN -j DROP
-A accept_log -i ppp0 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 1/sec -j LOG --log-prefix "TCPConnect on ppp0:" -A accept_log -i ppp0 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 1/sec -j LOG --log-prefix "TCPConnect on ppp0:"
......
#!/bin/bash -x
[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
set -e
nft flush ruleset
(
echo "*filter"
for plen in "" 32 30 24 16 8 0; do
addr="10.1.2.3${plen:+/}$plen"
echo "-A OUTPUT -d $addr"
done
echo "COMMIT"
) | $XT_MULTI iptables-restore
(
echo "*filter"
for plen in "" 128 124 120 112 88 80 64 48 16 8 0; do
addr="feed:c0ff:ee00:0102:0304:0506:0708:090A${plen:+/}$plen"
echo "-A OUTPUT -d $addr"
done
echo "COMMIT"
) | $XT_MULTI ip6tables-restore
masks="
ff:ff:ff:ff:ff:ff
ff:ff:ff:ff:ff:f0
ff:ff:ff:ff:ff:00
ff:ff:ff:ff:00:00
ff:ff:ff:00:00:00
ff:ff:00:00:00:00
ff:00:00:00:00:00
"
(
echo "*filter"
for plen in "" 32 30 24 16 8 0; do
addr="10.1.2.3${plen:+/}$plen"
echo "-A OUTPUT -d $addr"
done
for mask in $masks; do
echo "-A OUTPUT --destination-mac fe:ed:00:c0:ff:ee/$mask"
done
echo "COMMIT"
) | $XT_MULTI arptables-restore
(
echo "*filter"
for mask in $masks; do
echo "-A OUTPUT -d fe:ed:00:c0:ff:ee/$mask"
done
echo "COMMIT"
) | $XT_MULTI ebtables-restore
EXPECT="ip filter OUTPUT 4
[ payload load 4b @ network header + 16 => reg 1 ]
[ cmp eq reg 1 0x0302010a ]
[ counter pkts 0 bytes 0 ]
ip filter OUTPUT 5 4
[ payload load 4b @ network header + 16 => reg 1 ]
[ cmp eq reg 1 0x0302010a ]
[ counter pkts 0 bytes 0 ]
ip filter OUTPUT 6 5
[ payload load 4b @ network header + 16 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0xfcffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0002010a ]
[ counter pkts 0 bytes 0 ]
ip filter OUTPUT 7 6
[ payload load 3b @ network header + 16 => reg 1 ]
[ cmp eq reg 1 0x0002010a ]
[ counter pkts 0 bytes 0 ]
ip filter OUTPUT 8 7
[ payload load 2b @ network header + 16 => reg 1 ]
[ cmp eq reg 1 0x0000010a ]
[ counter pkts 0 bytes 0 ]
ip filter OUTPUT 9 8
[ payload load 1b @ network header + 16 => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ counter pkts 0 bytes 0 ]
ip filter OUTPUT 10 9
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 4
[ payload load 16b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 5 4
[ payload load 16b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 6 5
[ payload load 16b @ network header + 24 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0xffffffff 0xffffffff 0xffffffff 0xf0ffffff ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 7 6
[ payload load 15b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 8 7
[ payload load 14b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00000807 ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 9 8
[ payload load 11b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00050403 ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 10 9
[ payload load 10b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00000403 ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 11 10
[ payload load 8b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x020100ee ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 12 11
[ payload load 6b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0xffc0edfe 0x000000ee ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 13 12
[ payload load 2b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0x0000edfe ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 14 13
[ payload load 1b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0x000000fe ]
[ counter pkts 0 bytes 0 ]
ip6 filter OUTPUT 15 14
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 3
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 4b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0x0302010a ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 4 3
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 4b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0x0302010a ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 5 4
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 4b @ network header + 24 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0xfcffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0002010a ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 6 5
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 3b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0x0002010a ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 7 6
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 2b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0x0000010a ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 8 7
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 1b @ network header + 24 => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 9 8
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 10 9
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 6b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0xc000edfe 0x0000eeff ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 11 10
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 6b @ network header + 18 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
[ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 12 11
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 5b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0xc000edfe 0x000000ff ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 13 12
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 4b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0xc000edfe ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 14 13
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 3b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0x0000edfe ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 15 14
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 2b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0x0000edfe ]
[ counter pkts 0 bytes 0 ]
arp filter OUTPUT 16 15
[ payload load 2b @ network header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 1b @ network header + 4 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ network header + 5 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ payload load 1b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0x000000fe ]
[ counter pkts 0 bytes 0 ]
bridge filter OUTPUT 4
[ payload load 6b @ link header + 0 => reg 1 ]
[ cmp eq reg 1 0xc000edfe 0x0000eeff ]
[ counter pkts 0 bytes 0 ]
bridge filter OUTPUT 5 4
[ payload load 6b @ link header + 0 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
[ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
[ counter pkts 0 bytes 0 ]
bridge filter OUTPUT 6 5
[ payload load 5b @ link header + 0 => reg 1 ]
[ cmp eq reg 1 0xc000edfe 0x000000ff ]
[ counter pkts 0 bytes 0 ]
bridge filter OUTPUT 7 6
[ payload load 4b @ link header + 0 => reg 1 ]
[ cmp eq reg 1 0xc000edfe ]
[ counter pkts 0 bytes 0 ]
bridge filter OUTPUT 8 7
[ payload load 3b @ link header + 0 => reg 1 ]
[ cmp eq reg 1 0x0000edfe ]
[ counter pkts 0 bytes 0 ]
bridge filter OUTPUT 9 8
[ payload load 2b @ link header + 0 => reg 1 ]
[ cmp eq reg 1 0x0000edfe ]
[ counter pkts 0 bytes 0 ]
bridge filter OUTPUT 10 9
[ payload load 1b @ link header + 0 => reg 1 ]
[ cmp eq reg 1 0x000000fe ]
[ counter pkts 0 bytes 0 ]
"
# print nothing but:
# - lines with bytecode (starting with ' [')
# - empty lines (so printed diff is not a complete mess)
filter() {
awk '/^( \[|$)/{print}'
}
diff -u -Z <(filter <<< "$EXPECT") <(nft --debug=netlink list ruleset | filter)
...@@ -779,3 +779,77 @@ int parse_rulenumber(const char *rule) ...@@ -779,3 +779,77 @@ int parse_rulenumber(const char *rule)
return rulenum; return rulenum;
} }
/* Table of legal combinations of commands and options. If any of the
* given commands make an option legal, that option is legal (applies to
* CMD_LIST and CMD_ZERO only).
* Key:
* + compulsory
* x illegal
* optional
*/
static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
/* Well, it's better than "Re: Linux vs FreeBSD" */
{
/* -n -s -d -p -j -v -x -i -o --line -c -f 2 3 l 4 5 6 */
/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x','x','x','x','x','x','x'},
/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x','x','x','x','x','x','x'},
/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
};
void generic_opt_check(int command, int options)
{
int i, j, legal = 0;
/* Check that commands are valid with options. Complicated by the
* fact that if an option is legal with *any* command given, it is
* legal overall (ie. -z and -l).
*/
for (i = 0; i < NUMBER_OF_OPT; i++) {
legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
for (j = 0; j < NUMBER_OF_CMD; j++) {
if (!(command & (1<<j)))
continue;
if (!(options & (1<<i))) {
if (commands_v_options[j][i] == '+')
xtables_error(PARAMETER_PROBLEM,
"You need to supply the `-%c' "
"option for this command\n",
optflags[i]);
} else {
if (commands_v_options[j][i] != 'x')
legal = 1;
else if (legal == 0)
legal = -1;
}
}
if (legal == -1)
xtables_error(PARAMETER_PROBLEM,
"Illegal option `-%c' with this command\n",
optflags[i]);
}
}
char opt2char(int option)
{
const char *ptr;
for (ptr = optflags; option > 1; option >>= 1, ptr++)
;
return *ptr;
}
...@@ -30,15 +30,20 @@ enum { ...@@ -30,15 +30,20 @@ enum {
OPT_VIANAMEOUT = 1 << 8, OPT_VIANAMEOUT = 1 << 8,
OPT_LINENUMBERS = 1 << 9, OPT_LINENUMBERS = 1 << 9,
OPT_COUNTERS = 1 << 10, OPT_COUNTERS = 1 << 10,
OPT_FRAGMENT = 1 << 11,
/* below are for arptables only */ /* below are for arptables only */
OPT_S_MAC = 1 << 11, OPT_S_MAC = 1 << 12,
OPT_D_MAC = 1 << 12, OPT_D_MAC = 1 << 13,
OPT_H_LENGTH = 1 << 13, OPT_H_LENGTH = 1 << 14,
OPT_OPCODE = 1 << 14, OPT_OPCODE = 1 << 15,
OPT_H_TYPE = 1 << 15, OPT_H_TYPE = 1 << 16,
OPT_P_TYPE = 1 << 16, OPT_P_TYPE = 1 << 17,
}; };
#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
static const char optflags[]
= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f', 2, 3, 'l', 4, 5, 6 };
enum { enum {
CMD_NONE = 0, CMD_NONE = 0,
CMD_INSERT = 1 << 0, CMD_INSERT = 1 << 0,
...@@ -216,4 +221,7 @@ void add_command(unsigned int *cmd, const int newcmd, ...@@ -216,4 +221,7 @@ void add_command(unsigned int *cmd, const int newcmd,
const int othercmds, int invert); const int othercmds, int invert);
int parse_rulenumber(const char *rule); int parse_rulenumber(const char *rule);
void generic_opt_check(int command, int options);
char opt2char(int option);
#endif /* IPTABLES_XSHARED_H */ #endif /* IPTABLES_XSHARED_H */
...@@ -53,10 +53,6 @@ ...@@ -53,10 +53,6 @@
#include "nft-arp.h" #include "nft-arp.h"
#include <linux/netfilter_arp/arp_tables.h> #include <linux/netfilter_arp/arp_tables.h>
#define NUMBER_OF_OPT 16
static const char optflags[NUMBER_OF_OPT]
= { 'n', 's', 'd', 2, 3, 7, 8, 4, 5, 6, 'j', 'v', 'i', 'o', '0', 'c'};
static struct option original_opts[] = { static struct option original_opts[] = {
{ "append", 1, 0, 'A' }, { "append", 1, 0, 'A' },
{ "delete", 1, 0, 'D' }, { "delete", 1, 0, 'D' },
...@@ -113,74 +109,29 @@ struct xtables_globals arptables_globals = { ...@@ -113,74 +109,29 @@ struct xtables_globals arptables_globals = {
static int inverse_for_options[] = static int inverse_for_options[] =
{ {
/* -n */ 0, /* -n */ 0,
/* -s */ ARPT_INV_SRCIP, /* -s */ IPT_INV_SRCIP,
/* -d */ ARPT_INV_TGTIP, /* -d */ IPT_INV_DSTIP,
/* -p */ 0, /* -p */ 0,
/* -j */ 0, /* -j */ 0,
/* -v */ 0, /* -v */ 0,
/* -x */ 0, /* -x */ 0,
/* -i */ ARPT_INV_VIA_IN, /* -i */ IPT_INV_VIA_IN,
/* -o */ ARPT_INV_VIA_OUT, /* -o */ IPT_INV_VIA_OUT,
/*--line*/ 0, /*--line*/ 0,
/* -c */ 0, /* -c */ 0,
/* 2 */ ARPT_INV_SRCDEVADDR, /* -f */ 0,
/* 3 */ ARPT_INV_TGTDEVADDR, /* 2 */ IPT_INV_SRCDEVADDR,
/* -l */ ARPT_INV_ARPHLN, /* 3 */ IPT_INV_TGTDEVADDR,
/* 4 */ ARPT_INV_ARPOP, /* -l */ IPT_INV_ARPHLN,
/* 5 */ ARPT_INV_ARPHRD, /* 4 */ IPT_INV_ARPOP,
/* 6 */ ARPT_INV_ARPPRO, /* 5 */ IPT_INV_ARPHRD,
/* 6 */ IPT_INV_PROTO,
}; };
/***********************************************/ /***********************************************/
/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */ /* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
/***********************************************/ /***********************************************/
static unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
static unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
static unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
static unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
static unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
static unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
/*
* put the mac address into 6 (ETH_ALEN) bytes
*/
static int getmac_and_mask(char *from, char *to, char *mask)
{
char *p;
int i;
struct ether_addr *addr;
if (strcasecmp(from, "Unicast") == 0) {
memcpy(to, mac_type_unicast, ETH_ALEN);
memcpy(mask, msk_type_unicast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "Multicast") == 0) {
memcpy(to, mac_type_multicast, ETH_ALEN);
memcpy(mask, msk_type_multicast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "Broadcast") == 0) {
memcpy(to, mac_type_broadcast, ETH_ALEN);
memcpy(mask, msk_type_broadcast, ETH_ALEN);
return 0;
}
if ( (p = strrchr(from, '/')) != NULL) {
*p = '\0';
if (!(addr = ether_aton(p + 1)))
return -1;
memcpy(mask, addr, ETH_ALEN);
} else
memset(mask, 0xff, ETH_ALEN);
if (!(addr = ether_aton(from)))
return -1;
memcpy(to, addr, ETH_ALEN);
for (i = 0; i < ETH_ALEN; i++)
to[i] &= mask[i];
return 0;
}
static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask) static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
{ {
char *p, *buffer; char *p, *buffer;
...@@ -327,15 +278,6 @@ printhelp(void) ...@@ -327,15 +278,6 @@ printhelp(void)
} }
} }
static char
opt2char(int option)
{
const char *ptr;
for (ptr = optflags; option > 1; option >>= 1, ptr++);
return *ptr;
}
static int static int
check_inverse(const char option[], int *invert, int *optidx, int argc) check_inverse(const char option[], int *invert, int *optidx, int argc)
{ {
...@@ -686,7 +628,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, ...@@ -686,7 +628,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
check_inverse(optarg, &invert, &optind, argc); check_inverse(optarg, &invert, &optind, argc);
set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags, set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags,
invert); invert);
if (getmac_and_mask(argv[optind - 1], if (xtables_parse_mac_and_mask(argv[optind - 1],
cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask)) cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified " xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"source mac"); "source mac");
...@@ -697,7 +639,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, ...@@ -697,7 +639,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags, set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags,
invert); invert);
if (getmac_and_mask(argv[optind - 1], if (xtables_parse_mac_and_mask(argv[optind - 1],
cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask)) cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified " xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"destination mac"); "destination mac");
...@@ -901,7 +843,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, ...@@ -901,7 +843,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
&dmasks, &ndaddrs); &dmasks, &ndaddrs);
if ((nsaddrs > 1 || ndaddrs > 1) && if ((nsaddrs > 1 || ndaddrs > 1) &&
(cs.arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
" source or destination IP addresses"); " source or destination IP addresses");
......
...@@ -397,7 +397,9 @@ print_zero: ...@@ -397,7 +397,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv)) if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_ISOURCE; cs.eb.invflags |= EBT_ISOURCE;
if (ebt_get_mac_and_mask(optarg, cs.eb.sourcemac, cs.eb.sourcemsk)) if (xtables_parse_mac_and_mask(optarg,
cs.eb.sourcemac,
cs.eb.sourcemsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg); xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
cs.eb.bitmask |= EBT_SOURCEMAC; cs.eb.bitmask |= EBT_SOURCEMAC;
break; break;
...@@ -406,7 +408,9 @@ print_zero: ...@@ -406,7 +408,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv)) if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_IDEST; cs.eb.invflags |= EBT_IDEST;
if (ebt_get_mac_and_mask(optarg, cs.eb.destmac, cs.eb.destmsk)) if (xtables_parse_mac_and_mask(optarg,
cs.eb.destmac,
cs.eb.destmsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg); xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
cs.eb.bitmask |= EBT_DESTMAC; cs.eb.bitmask |= EBT_DESTMAC;
break; break;
......
...@@ -55,57 +55,6 @@ ...@@ -55,57 +55,6 @@
* 1: the inverse '!' of the option has already been specified */ * 1: the inverse '!' of the option has already been specified */
int ebt_invert = 0; int ebt_invert = 0;
unsigned char eb_mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
unsigned char eb_msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
unsigned char eb_mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
unsigned char eb_msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
unsigned char eb_mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
unsigned char eb_msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
unsigned char eb_mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
unsigned char eb_msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
int ebt_get_mac_and_mask(const char *from, unsigned char *to,
unsigned char *mask)
{
char *p;
int i;
struct ether_addr *addr = NULL;
if (strcasecmp(from, "Unicast") == 0) {
memcpy(to, eb_mac_type_unicast, ETH_ALEN);
memcpy(mask, eb_msk_type_unicast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "Multicast") == 0) {
memcpy(to, eb_mac_type_multicast, ETH_ALEN);
memcpy(mask, eb_msk_type_multicast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "Broadcast") == 0) {
memcpy(to, eb_mac_type_broadcast, ETH_ALEN);
memcpy(mask, eb_msk_type_broadcast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "BGA") == 0) {
memcpy(to, eb_mac_type_bridge_group, ETH_ALEN);
memcpy(mask, eb_msk_type_bridge_group, ETH_ALEN);
return 0;
}
if ( (p = strrchr(from, '/')) != NULL) {
*p = '\0';
if (!(addr = ether_aton(p + 1)))
return -1;
memcpy(mask, addr, ETH_ALEN);
} else
memset(mask, 0xff, ETH_ALEN);
if (!(addr = ether_aton(from)))
return -1;
memcpy(to, addr, ETH_ALEN);
for (i = 0; i < ETH_ALEN; i++)
to[i] &= mask[i];
return 0;
}
static int ebt_check_inverse2(const char option[], int argc, char **argv) static int ebt_check_inverse2(const char option[], int argc, char **argv)
{ {
if (!option) if (!option)
...@@ -853,6 +802,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, ...@@ -853,6 +802,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
else if (strchr(argv[optind], ' ') != NULL) else if (strchr(argv[optind], ' ') != NULL)
xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names"); xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");
errno = 0;
ret = nft_cmd_chain_user_rename(h, chain, *table, ret = nft_cmd_chain_user_rename(h, chain, *table,
argv[optind]); argv[optind]);
if (ret != 0 && errno == ENOENT) if (ret != 0 && errno == ENOENT)
...@@ -1037,7 +987,9 @@ print_zero: ...@@ -1037,7 +987,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv)) if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_ISOURCE; cs.eb.invflags |= EBT_ISOURCE;
if (ebt_get_mac_and_mask(optarg, cs.eb.sourcemac, cs.eb.sourcemsk)) if (xtables_parse_mac_and_mask(optarg,
cs.eb.sourcemac,
cs.eb.sourcemsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg); xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
cs.eb.bitmask |= EBT_SOURCEMAC; cs.eb.bitmask |= EBT_SOURCEMAC;
break; break;
...@@ -1046,7 +998,9 @@ print_zero: ...@@ -1046,7 +998,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv)) if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_IDEST; cs.eb.invflags |= EBT_IDEST;
if (ebt_get_mac_and_mask(optarg, cs.eb.destmac, cs.eb.destmsk)) if (xtables_parse_mac_and_mask(optarg,
cs.eb.destmac,
cs.eb.destmsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg); xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
cs.eb.bitmask |= EBT_DESTMAC; cs.eb.bitmask |= EBT_DESTMAC;
break; break;
......
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