summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2019-10-26 13:15:10 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2019-10-30 09:29:05 +0100
commit3fdc7541fba079f9626bcb1605368a7da3a8d81a (patch)
tree8e83aa0d4ceb4f8f66325776b80301cf68afa42d /src
parent6b53baa89f5b6a0c1d2520820d9654418cda7105 (diff)
src: add multidevice support for netdev chain
This patch allows you to specify multiple netdevices to be bound to the netdev basechain, eg. # nft add chain netdev x y { \ type filter hook ingress devices = { eth0, eth1 } priority 0\; } json codebase has been updated to support for one single device with the existing representation, no support for multidevice is included in this patch. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/json.c17
-rw-r--r--src/mnl.c29
-rw-r--r--src/netlink.c20
-rw-r--r--src/parser_bison.y26
-rw-r--r--src/parser_json.c18
-rw-r--r--src/rule.c22
6 files changed, 106 insertions, 26 deletions
diff --git a/src/json.c b/src/json.c
index 13a06424..56b20549 100644
--- a/src/json.c
+++ b/src/json.c
@@ -222,9 +222,9 @@ static json_t *rule_print_json(struct output_ctx *octx,
static json_t *chain_print_json(const struct chain *chain)
{
+ int priority, policy, n = 0;
+ struct expr *dev, *expr;
json_t *root, *tmp;
- int priority;
- int policy;
root = json_pack("{s:s, s:s, s:s, s:I}",
"family", family2str(chain->handle.family),
@@ -243,8 +243,17 @@ static json_t *chain_print_json(const struct chain *chain)
chain->hooknum),
"prio", priority,
"policy", chain_policy2str(policy));
- if (chain->dev)
- json_object_set_new(tmp, "dev", json_string(chain->dev));
+ if (chain->dev_expr) {
+ list_for_each_entry(expr, &chain->dev_expr->expressions, list) {
+ dev = expr;
+ n++;
+ }
+ }
+
+ if (n == 1) {
+ json_object_set_new(tmp, "dev",
+ json_string(dev->identifier));
+ }
json_object_update(root, tmp);
json_decref(tmp);
}
diff --git a/src/mnl.c b/src/mnl.c
index 75ab07b0..492381da 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -526,10 +526,12 @@ err:
int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
unsigned int flags)
{
+ int priority, policy, i = 0;
struct nftnl_chain *nlc;
+ const char **dev_array;
struct nlmsghdr *nlh;
- int priority;
- int policy;
+ struct expr *expr;
+ int dev_array_len;
nlc = nftnl_chain_alloc();
if (nlc == NULL)
@@ -555,9 +557,26 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
BYTEORDER_HOST_ENDIAN, sizeof(int));
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, policy);
}
- if (cmd->chain->dev != NULL)
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV,
- cmd->chain->dev);
+ if (cmd->chain->dev_expr) {
+ dev_array = xmalloc(sizeof(char *) * 8);
+ dev_array_len = 8;
+ list_for_each_entry(expr, &cmd->chain->dev_expr->expressions, list) {
+ dev_array[i++] = expr->identifier;
+ if (i == dev_array_len) {
+ dev_array_len *= 2;
+ dev_array = xrealloc(dev_array,
+ dev_array_len * sizeof(char *));
+ }
+ }
+
+ dev_array[i] = NULL;
+ if (i == 1)
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV, dev_array[0]);
+ else if (i > 1)
+ nftnl_chain_set(nlc, NFTNL_CHAIN_DEVICES, dev_array);
+
+ xfree(dev_array);
+ }
}
netlink_dump_chain(nlc, ctx);
diff --git a/src/netlink.c b/src/netlink.c
index 1e669e5d..c47771d3 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -378,9 +378,9 @@ void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx)
struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
const struct nftnl_chain *nlc)
{
+ int priority, policy, len = 0, i;
+ const char * const *dev_array;
struct chain *chain;
- int priority;
- int policy;
chain = chain_alloc(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
chain->handle.family =
@@ -415,8 +415,22 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
&policy);
nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) {
- chain->dev =
+ chain->dev_array = xmalloc(sizeof(char *));
+ chain->dev_array_len = 1;
+ chain->dev_array[0] =
xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_DEV));
+ chain->dev_array[1] = NULL;
+ } else if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEVICES)) {
+ dev_array = nftnl_chain_get(nlc, NFTNL_CHAIN_DEVICES);
+ while (dev_array[len])
+ len++;
+
+ chain->dev_array = xmalloc(len * sizeof(char *));
+ for (i = 0; i < len; i++)
+ chain->dev_array[i] = xstrdup(dev_array[i]);
+
+ chain->dev_array[i] = NULL;
+ chain->dev_array_len = len;
}
chain->flags |= CHAIN_F_BASECHAIN;
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 11f0dc8b..7f9b1752 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -564,11 +564,11 @@ int nft_lex(void *, void *, void *);
%type <val> family_spec family_spec_explicit
%type <val32> int_num chain_policy
%type <prio_spec> extended_prio_spec prio_spec
-%type <string> extended_prio_name
-%destructor { xfree($$); } extended_prio_name
+%type <string> extended_prio_name quota_unit
+%destructor { xfree($$); } extended_prio_name quota_unit
-%type <string> dev_spec quota_unit
-%destructor { xfree($$); } dev_spec quota_unit
+%type <expr> dev_spec
+%destructor { xfree($$); } dev_spec
%type <table> table_block_alloc table_block
%destructor { close_scope(state); table_free($$); } table_block_alloc
@@ -1992,7 +1992,7 @@ hook_spec : TYPE STRING HOOK STRING dev_spec prio_spec
}
xfree($4);
- $<chain>0->dev = $5;
+ $<chain>0->dev_expr = $5;
$<chain>0->priority = $6;
$<chain>0->flags |= CHAIN_F_BASECHAIN;
}
@@ -2072,7 +2072,21 @@ int_num : NUM { $$ = $1; }
| DASH NUM { $$ = -$2; }
;
-dev_spec : DEVICE string { $$ = $2; }
+dev_spec : DEVICE string
+ {
+ struct expr *expr;
+
+ expr = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen($2) * BITS_PER_BYTE, $2);
+ $$ = compound_expr_alloc(&@$, EXPR_LIST);
+ compound_expr_add($$, expr);
+
+ }
+ | DEVICES '=' flowtable_expr
+ {
+ $$ = $3;
+ }
| /* empty */ { $$ = NULL; }
;
diff --git a/src/parser_json.c b/src/parser_json.c
index fe0c5df9..a9bcb84f 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -17,6 +17,7 @@
#include <netinet/icmp6.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
+#include <net/if.h>
#include <linux/xfrm.h>
#include <linux/netfilter.h>
@@ -2581,8 +2582,9 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
.table.location = *int_loc,
};
const char *family = "", *policy = "", *type, *hookstr;
- int prio;
+ const char name[IFNAMSIZ];
struct chain *chain;
+ int prio;
if (json_unpack_err(ctx, root, "{s:s, s:s}",
"family", &family,
@@ -2626,8 +2628,18 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
return NULL;
}
- if (!json_unpack(root, "{s:s}", "dev", &chain->dev))
- chain->dev = xstrdup(chain->dev);
+ if (!json_unpack(root, "{s:s}", "dev", &name)) {
+ struct expr *dev_expr, *expr;
+
+ dev_expr = compound_expr_alloc(int_loc, EXPR_LIST);
+ expr = constant_expr_alloc(int_loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(name) * BITS_PER_BYTE,
+ name);
+ compound_expr_add(dev_expr, expr);
+ chain->dev_expr = dev_expr;
+ }
+
if (!json_unpack(root, "{s:s}", "policy", &policy)) {
chain->policy = parse_policy(policy);
if (!chain->policy) {
diff --git a/src/rule.c b/src/rule.c
index 64756bce..c258f12e 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -814,6 +814,7 @@ struct chain *chain_get(struct chain *chain)
void chain_free(struct chain *chain)
{
struct rule *rule, *next;
+ int i;
if (--chain->refcnt > 0)
return;
@@ -822,8 +823,10 @@ void chain_free(struct chain *chain)
handle_free(&chain->handle);
scope_release(&chain->scope);
xfree(chain->type);
- if (chain->dev != NULL)
- xfree(chain->dev);
+ expr_free(chain->dev_expr);
+ for (i = 0; i < chain->dev_array_len; i++)
+ xfree(chain->dev_array[i]);
+ xfree(chain->dev_array);
expr_free(chain->priority.expr);
expr_free(chain->policy);
xfree(chain);
@@ -1102,7 +1105,7 @@ static void chain_print_declaration(const struct chain *chain,
struct output_ctx *octx)
{
char priobuf[STD_PRIO_BUFSIZE];
- int policy;
+ int policy, i;
nft_print(octx, "\tchain %s {", chain->handle.chain.name);
if (nft_output_handle(octx))
@@ -1111,8 +1114,17 @@ static void chain_print_declaration(const struct chain *chain,
if (chain->flags & CHAIN_F_BASECHAIN) {
nft_print(octx, "\t\ttype %s hook %s", chain->type,
hooknum2str(chain->handle.family, chain->hooknum));
- if (chain->dev != NULL)
- nft_print(octx, " device \"%s\"", chain->dev);
+ if (chain->dev_array_len == 1) {
+ nft_print(octx, " device \"%s\"", chain->dev_array[0]);
+ } else if (chain->dev_array_len > 1) {
+ nft_print(octx, " devices = { ");
+ for (i = 0; i < chain->dev_array_len; i++) {
+ nft_print(octx, "%s", chain->dev_array[i]);
+ if (i + 1 != chain->dev_array_len)
+ nft_print(octx, ", ");
+ }
+ nft_print(octx, " }");
+ }
nft_print(octx, " priority %s;",
prio2str(octx, priobuf, sizeof(priobuf),
chain->handle.family, chain->hooknum,