diff options
Diffstat (limited to 'src/obj')
| -rw-r--r-- | src/obj/counter.c | 42 | ||||
| -rw-r--r-- | src/obj/ct_expect.c | 69 | ||||
| -rw-r--r-- | src/obj/ct_helper.c | 45 | ||||
| -rw-r--r-- | src/obj/ct_timeout.c | 67 | ||||
| -rw-r--r-- | src/obj/limit.c | 52 | ||||
| -rw-r--r-- | src/obj/quota.c | 46 | ||||
| -rw-r--r-- | src/obj/secmark.c | 38 | ||||
| -rw-r--r-- | src/obj/synproxy.c | 39 | ||||
| -rw-r--r-- | src/obj/tunnel.c | 680 |
9 files changed, 708 insertions, 370 deletions
diff --git a/src/obj/counter.c b/src/obj/counter.c index 1baba4e..c9462cd 100644 --- a/src/obj/counter.c +++ b/src/obj/counter.c @@ -1,10 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * (C) 2012-2016 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. */ #include <stdio.h> @@ -29,13 +25,11 @@ nftnl_obj_counter_set(struct nftnl_obj *e, uint16_t type, switch(type) { case NFTNL_OBJ_CTR_BYTES: - memcpy(&ctr->bytes, data, sizeof(ctr->bytes)); + memcpy(&ctr->bytes, data, data_len); break; case NFTNL_OBJ_CTR_PKTS: - memcpy(&ctr->pkts, data, sizeof(ctr->pkts)); + memcpy(&ctr->pkts, data, data_len); break; - default: - return -1; } return 0; } @@ -109,8 +103,8 @@ nftnl_obj_counter_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_counter_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_counter_snprintf(char *buf, size_t len, uint32_t flags, + const struct nftnl_obj *e) { struct nftnl_obj_counter *ctr = nftnl_obj_data(e); @@ -118,32 +112,20 @@ static int nftnl_obj_counter_snprintf_default(char *buf, size_t len, ctr->pkts, ctr->bytes); } -static int nftnl_obj_counter_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - if (len) - buf[0] = '\0'; - - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_counter_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_XML: - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy obj_ctr_attr_policy[__NFTNL_OBJ_CTR_MAX] = { + [NFTNL_OBJ_CTR_BYTES] = { .maxlen = sizeof(uint64_t) }, + [NFTNL_OBJ_CTR_PKTS] = { .maxlen = sizeof(uint64_t) }, +}; struct obj_ops obj_ops_counter = { .name = "counter", .type = NFT_OBJECT_COUNTER, .alloc_len = sizeof(struct nftnl_obj_counter), - .max_attr = NFTA_COUNTER_MAX, + .nftnl_max_attr = __NFTNL_OBJ_CTR_MAX - 1, + .attr_policy = obj_ctr_attr_policy, .set = nftnl_obj_counter_set, .get = nftnl_obj_counter_get, .parse = nftnl_obj_counter_parse, .build = nftnl_obj_counter_build, - .snprintf = nftnl_obj_counter_snprintf, + .output = nftnl_obj_counter_snprintf, }; diff --git a/src/obj/ct_expect.c b/src/obj/ct_expect.c index c0bb5ba..65c6d08 100644 --- a/src/obj/ct_expect.c +++ b/src/obj/ct_expect.c @@ -1,10 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * (C) 2019 by Stéphane Veyret <sveyret@gmail.com> - * - * 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. */ #include <arpa/inet.h> @@ -21,22 +17,20 @@ static int nftnl_obj_ct_expect_set(struct nftnl_obj *e, uint16_t type, switch (type) { case NFTNL_OBJ_CT_EXPECT_L3PROTO: - memcpy(&exp->l3proto, data, sizeof(exp->l3proto)); + memcpy(&exp->l3proto, data, data_len); break; case NFTNL_OBJ_CT_EXPECT_L4PROTO: - memcpy(&exp->l4proto, data, sizeof(exp->l4proto)); + memcpy(&exp->l4proto, data, data_len); break; case NFTNL_OBJ_CT_EXPECT_DPORT: - memcpy(&exp->dport, data, sizeof(exp->dport)); + memcpy(&exp->dport, data, data_len); break; case NFTNL_OBJ_CT_EXPECT_TIMEOUT: - memcpy(&exp->timeout, data, sizeof(exp->timeout)); + memcpy(&exp->timeout, data, data_len); break; case NFTNL_OBJ_CT_EXPECT_SIZE: - memcpy(&exp->size, data, sizeof(exp->size)); + memcpy(&exp->size, data, data_len); break; - default: - return -1; } return 0; } @@ -151,31 +145,35 @@ nftnl_obj_ct_expect_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_ct_expect_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_ct_expect_snprintf(char *buf, size_t remain, + uint32_t flags, + const struct nftnl_obj *e) { - int ret = 0; - int offset = 0, remain = len; struct nftnl_obj_ct_expect *exp = nftnl_obj_data(e); + int ret = 0, offset = 0; if (e->flags & (1 << NFTNL_OBJ_CT_EXPECT_L3PROTO)) { - ret = snprintf(buf + offset, len, "family %d ", exp->l3proto); + ret = snprintf(buf + offset, remain, + "family %d ", exp->l3proto); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } if (e->flags & (1 << NFTNL_OBJ_CT_EXPECT_L4PROTO)) { - ret = snprintf(buf + offset, len, "protocol %d ", exp->l4proto); + ret = snprintf(buf + offset, remain, + "protocol %d ", exp->l4proto); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } if (e->flags & (1 << NFTNL_OBJ_CT_EXPECT_DPORT)) { - ret = snprintf(buf + offset, len, "dport %d ", exp->dport); + ret = snprintf(buf + offset, remain, + "dport %d ", exp->dport); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } if (e->flags & (1 << NFTNL_OBJ_CT_EXPECT_TIMEOUT)) { - ret = snprintf(buf + offset, len, "timeout %d ", exp->timeout); + ret = snprintf(buf + offset, remain, + "timeout %d ", exp->timeout); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } if (e->flags & (1 << NFTNL_OBJ_CT_EXPECT_SIZE)) { - ret = snprintf(buf + offset, len, "size %d ", exp->size); + ret = snprintf(buf + offset, remain, "size %d ", exp->size); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } @@ -183,31 +181,24 @@ static int nftnl_obj_ct_expect_snprintf_default(char *buf, size_t len, return offset; } -static int nftnl_obj_ct_expect_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - if (len) - buf[0] = '\0'; - - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_ct_expect_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy +obj_ct_expect_attr_policy[__NFTNL_OBJ_CT_EXPECT_MAX] = { + [NFTNL_OBJ_CT_EXPECT_L3PROTO] = { .maxlen = sizeof(uint16_t) }, + [NFTNL_OBJ_CT_EXPECT_L4PROTO] = { .maxlen = sizeof(uint8_t) }, + [NFTNL_OBJ_CT_EXPECT_DPORT] = { .maxlen = sizeof(uint16_t) }, + [NFTNL_OBJ_CT_EXPECT_TIMEOUT] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_CT_EXPECT_SIZE] = { .maxlen = sizeof(uint8_t) }, +}; struct obj_ops obj_ops_ct_expect = { .name = "ct_expect", .type = NFT_OBJECT_CT_EXPECT, .alloc_len = sizeof(struct nftnl_obj_ct_expect), - .max_attr = NFTA_CT_EXPECT_MAX, + .nftnl_max_attr = __NFTNL_OBJ_CT_EXPECT_MAX - 1, + .attr_policy = obj_ct_expect_attr_policy, .set = nftnl_obj_ct_expect_set, .get = nftnl_obj_ct_expect_get, .parse = nftnl_obj_ct_expect_parse, .build = nftnl_obj_ct_expect_build, - .snprintf = nftnl_obj_ct_expect_snprintf, + .output = nftnl_obj_ct_expect_snprintf, }; diff --git a/src/obj/ct_helper.c b/src/obj/ct_helper.c index d91f636..6e16f08 100644 --- a/src/obj/ct_helper.c +++ b/src/obj/ct_helper.c @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * (C) 2017 Red Hat GmbH * Author: Florian Westphal <fw@strlen.de> - * - * 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. */ #include <stdio.h> @@ -32,13 +28,11 @@ static int nftnl_obj_ct_helper_set(struct nftnl_obj *e, uint16_t type, snprintf(helper->name, sizeof(helper->name), "%s", (const char *)data); break; case NFTNL_OBJ_CT_HELPER_L3PROTO: - memcpy(&helper->l3proto, data, sizeof(helper->l3proto)); + memcpy(&helper->l3proto, data, data_len); break; case NFTNL_OBJ_CT_HELPER_L4PROTO: - memcpy(&helper->l4proto, data, sizeof(helper->l4proto)); + memcpy(&helper->l4proto, data, data_len); break; - default: - return -1; } return 0; } @@ -131,8 +125,9 @@ nftnl_obj_ct_helper_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_ct_helper_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_ct_helper_snprintf(char *buf, size_t len, + uint32_t flags, + const struct nftnl_obj *e) { struct nftnl_obj_ct_helper *helper = nftnl_obj_data(e); @@ -140,31 +135,25 @@ static int nftnl_obj_ct_helper_snprintf_default(char *buf, size_t len, helper->name, helper->l3proto, helper->l4proto); } -static int nftnl_obj_ct_helper_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - if (len) - buf[0] = '\0'; +/* from kernel's include/net/netfilter/nf_conntrack_helper.h */ +#define NF_CT_HELPER_NAME_LEN 16 - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_ct_helper_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy +obj_ct_helper_attr_policy[__NFTNL_OBJ_CT_HELPER_MAX] = { + [NFTNL_OBJ_CT_HELPER_NAME] = { .maxlen = NF_CT_HELPER_NAME_LEN }, + [NFTNL_OBJ_CT_HELPER_L3PROTO] = { .maxlen = sizeof(uint16_t) }, + [NFTNL_OBJ_CT_HELPER_L4PROTO] = { .maxlen = sizeof(uint8_t) }, +}; struct obj_ops obj_ops_ct_helper = { .name = "ct_helper", .type = NFT_OBJECT_CT_HELPER, .alloc_len = sizeof(struct nftnl_obj_ct_helper), - .max_attr = NFTA_CT_HELPER_MAX, + .nftnl_max_attr = __NFTNL_OBJ_CT_HELPER_MAX - 1, + .attr_policy = obj_ct_helper_attr_policy, .set = nftnl_obj_ct_helper_set, .get = nftnl_obj_ct_helper_get, .parse = nftnl_obj_ct_helper_parse, .build = nftnl_obj_ct_helper_build, - .snprintf = nftnl_obj_ct_helper_snprintf, + .output = nftnl_obj_ct_helper_snprintf, }; diff --git a/src/obj/ct_timeout.c b/src/obj/ct_timeout.c index 2662cac..22ce918 100644 --- a/src/obj/ct_timeout.c +++ b/src/obj/ct_timeout.c @@ -1,10 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * (C) 2018 by Harsha Sharma <harshasharmaiitr@gmail.com> - * - * 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. */ #include <stdio.h> @@ -21,7 +17,7 @@ #include "obj.h" -static const char *const tcp_state_to_name[] = { +static const char *const tcp_state_to_name[NFTNL_CTTIMEOUT_TCP_MAX] = { [NFTNL_CTTIMEOUT_TCP_SYN_SENT] = "SYN_SENT", [NFTNL_CTTIMEOUT_TCP_SYN_RECV] = "SYN_RECV", [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] = "ESTABLISHED", @@ -35,7 +31,7 @@ static const char *const tcp_state_to_name[] = { [NFTNL_CTTIMEOUT_TCP_UNACK] = "UNACKNOWLEDGED", }; -static uint32_t tcp_dflt_timeout[] = { +static uint32_t tcp_dflt_timeout[NFTNL_CTTIMEOUT_TCP_MAX] = { [NFTNL_CTTIMEOUT_TCP_SYN_SENT] = 120, [NFTNL_CTTIMEOUT_TCP_SYN_RECV] = 60, [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] = 432000, @@ -49,12 +45,12 @@ static uint32_t tcp_dflt_timeout[] = { [NFTNL_CTTIMEOUT_TCP_UNACK] = 300, }; -static const char *const udp_state_to_name[] = { +static const char *const udp_state_to_name[NFTNL_CTTIMEOUT_UDP_MAX] = { [NFTNL_CTTIMEOUT_UDP_UNREPLIED] = "UNREPLIED", [NFTNL_CTTIMEOUT_UDP_REPLIED] = "REPLIED", }; -static uint32_t udp_dflt_timeout[] = { +static uint32_t udp_dflt_timeout[NFTNL_CTTIMEOUT_UDP_MAX] = { [NFTNL_CTTIMEOUT_UDP_UNREPLIED] = 30, [NFTNL_CTTIMEOUT_UDP_REPLIED] = 180, }; @@ -150,17 +146,18 @@ static int nftnl_obj_ct_timeout_set(struct nftnl_obj *e, uint16_t type, switch (type) { case NFTNL_OBJ_CT_TIMEOUT_L3PROTO: - memcpy(&timeout->l3proto, data, sizeof(timeout->l3proto)); + memcpy(&timeout->l3proto, data, data_len); break; case NFTNL_OBJ_CT_TIMEOUT_L4PROTO: - memcpy(&timeout->l4proto, data, sizeof(timeout->l4proto)); + memcpy(&timeout->l4proto, data, data_len); break; case NFTNL_OBJ_CT_TIMEOUT_ARRAY: + if (data_len < sizeof(uint32_t) * NFTNL_CTTIMEOUT_ARRAY_MAX) + return -1; + memcpy(timeout->timeout, data, sizeof(uint32_t) * NFTNL_CTTIMEOUT_ARRAY_MAX); break; - default: - return -1; } return 0; } @@ -257,21 +254,21 @@ nftnl_obj_ct_timeout_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_ct_timeout_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_ct_timeout_snprintf(char *buf, size_t remain, + uint32_t flags, + const struct nftnl_obj *e) { - int ret = 0; - int offset = 0, remain = len; + int ret = 0, offset = 0; struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e); if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO)) { - ret = snprintf(buf + offset, len, "family %d ", + ret = snprintf(buf + offset, remain, "family %d ", timeout->l3proto); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO)) { - ret = snprintf(buf + offset, len, "protocol %d ", + ret = snprintf(buf + offset, remain, "protocol %d ", timeout->l4proto); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } @@ -283,7 +280,7 @@ static int nftnl_obj_ct_timeout_snprintf_default(char *buf, size_t len, if (timeout_protocol[timeout->l4proto].attr_max == 0) l4num = IPPROTO_RAW; - ret = snprintf(buf + offset, len, "policy = {"); + ret = snprintf(buf + offset, remain, "policy = {"); SNPRINTF_BUFFER_SIZE(ret, remain, offset); for (i = 0; i < timeout_protocol[l4num].attr_max; i++) { @@ -293,13 +290,13 @@ static int nftnl_obj_ct_timeout_snprintf_default(char *buf, size_t len, "UNKNOWN"; if (timeout->timeout[i] != timeout_protocol[l4num].dflt_timeout[i]) { - ret = snprintf(buf + offset, len, + ret = snprintf(buf + offset, remain, "%s = %u,", state_name, timeout->timeout[i]); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } } - ret = snprintf(buf + offset, len, "}"); + ret = snprintf(buf + offset, remain, "}"); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } buf[offset] = '\0'; @@ -307,31 +304,21 @@ static int nftnl_obj_ct_timeout_snprintf_default(char *buf, size_t len, return offset; } -static int nftnl_obj_ct_timeout_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - if (len) - buf[0] = '\0'; - - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_ct_timeout_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy +obj_ct_timeout_attr_policy[__NFTNL_OBJ_CT_TIMEOUT_MAX] = { + [NFTNL_OBJ_CT_TIMEOUT_L3PROTO] = { .maxlen = sizeof(uint16_t) }, + [NFTNL_OBJ_CT_TIMEOUT_L4PROTO] = { .maxlen = sizeof(uint8_t) }, +}; struct obj_ops obj_ops_ct_timeout = { .name = "ct_timeout", .type = NFT_OBJECT_CT_TIMEOUT, .alloc_len = sizeof(struct nftnl_obj_ct_timeout), - .max_attr = NFTA_CT_TIMEOUT_MAX, + .nftnl_max_attr = __NFTNL_OBJ_CT_TIMEOUT_MAX - 1, + .attr_policy = obj_ct_timeout_attr_policy, .set = nftnl_obj_ct_timeout_set, .get = nftnl_obj_ct_timeout_get, .parse = nftnl_obj_ct_timeout_parse, .build = nftnl_obj_ct_timeout_build, - .snprintf = nftnl_obj_ct_timeout_snprintf, + .output = nftnl_obj_ct_timeout_snprintf, }; diff --git a/src/obj/limit.c b/src/obj/limit.c index 60b0159..fe1a88f 100644 --- a/src/obj/limit.c +++ b/src/obj/limit.c @@ -1,10 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2017 Pablo M. Bermudo Garay <pablombg@gmail.com> - * - * 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. */ #include <stdio.h> @@ -28,22 +24,20 @@ static int nftnl_obj_limit_set(struct nftnl_obj *e, uint16_t type, switch (type) { case NFTNL_OBJ_LIMIT_RATE: - memcpy(&limit->rate, data, sizeof(limit->rate)); + memcpy(&limit->rate, data, data_len); break; case NFTNL_OBJ_LIMIT_UNIT: - memcpy(&limit->unit, data, sizeof(limit->unit)); + memcpy(&limit->unit, data, data_len); break; case NFTNL_OBJ_LIMIT_BURST: - memcpy(&limit->burst, data, sizeof(limit->burst)); + memcpy(&limit->burst, data, data_len); break; case NFTNL_OBJ_LIMIT_TYPE: - memcpy(&limit->type, data, sizeof(limit->type)); + memcpy(&limit->type, data, data_len); break; case NFTNL_OBJ_LIMIT_FLAGS: - memcpy(&limit->flags, data, sizeof(limit->flags)); + memcpy(&limit->flags, data, data_len); break; - default: - return -1; } return 0; } @@ -148,8 +142,9 @@ static int nftnl_obj_limit_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_limit_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_limit_snprintf(char *buf, size_t len, + uint32_t flags, + const struct nftnl_obj *e) { struct nftnl_obj_limit *limit = nftnl_obj_data(e); @@ -158,32 +153,23 @@ static int nftnl_obj_limit_snprintf_default(char *buf, size_t len, limit->burst, limit->type, limit->flags); } -static int nftnl_obj_limit_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - if (len) - buf[0] = '\0'; - - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_limit_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_XML: - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy obj_limit_attr_policy[__NFTNL_OBJ_LIMIT_MAX] = { + [NFTNL_OBJ_LIMIT_RATE] = { .maxlen = sizeof(uint64_t) }, + [NFTNL_OBJ_LIMIT_UNIT] = { .maxlen = sizeof(uint64_t) }, + [NFTNL_OBJ_LIMIT_BURST] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_LIMIT_TYPE] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_LIMIT_FLAGS] = { .maxlen = sizeof(uint32_t) }, +}; struct obj_ops obj_ops_limit = { .name = "limit", .type = NFT_OBJECT_LIMIT, .alloc_len = sizeof(struct nftnl_obj_limit), - .max_attr = NFTA_LIMIT_MAX, + .nftnl_max_attr = __NFTNL_OBJ_LIMIT_MAX - 1, + .attr_policy = obj_limit_attr_policy, .set = nftnl_obj_limit_set, .get = nftnl_obj_limit_get, .parse = nftnl_obj_limit_parse, .build = nftnl_obj_limit_build, - .snprintf = nftnl_obj_limit_snprintf, + .output = nftnl_obj_limit_snprintf, }; diff --git a/src/obj/quota.c b/src/obj/quota.c index 1914037..0eda0a5 100644 --- a/src/obj/quota.c +++ b/src/obj/quota.c @@ -1,10 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * (C) 2012-2016 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. */ #include <stdio.h> @@ -28,16 +24,14 @@ static int nftnl_obj_quota_set(struct nftnl_obj *e, uint16_t type, switch (type) { case NFTNL_OBJ_QUOTA_BYTES: - memcpy("a->bytes, data, sizeof(quota->bytes)); + memcpy("a->bytes, data, data_len); break; case NFTNL_OBJ_QUOTA_CONSUMED: - memcpy("a->consumed, data, sizeof(quota->consumed)); + memcpy("a->consumed, data, data_len); break; case NFTNL_OBJ_QUOTA_FLAGS: - memcpy("a->flags, data, sizeof(quota->flags)); + memcpy("a->flags, data, data_len); break; - default: - return -1; } return 0; } @@ -125,8 +119,9 @@ nftnl_obj_quota_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_quota_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_quota_snprintf(char *buf, size_t len, + uint32_t flags, + const struct nftnl_obj *e) { struct nftnl_obj_quota *quota = nftnl_obj_data(e); @@ -134,32 +129,21 @@ static int nftnl_obj_quota_snprintf_default(char *buf, size_t len, quota->bytes, quota->flags); } -static int nftnl_obj_quota_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - if (len) - buf[0] = '\0'; - - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_quota_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_XML: - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy obj_quota_attr_policy[__NFTNL_OBJ_QUOTA_MAX] = { + [NFTNL_OBJ_QUOTA_BYTES] = { .maxlen = sizeof(uint64_t) }, + [NFTNL_OBJ_QUOTA_CONSUMED] = { .maxlen = sizeof(uint64_t) }, + [NFTNL_OBJ_QUOTA_FLAGS] = { .maxlen = sizeof(uint32_t) }, +}; struct obj_ops obj_ops_quota = { .name = "quota", .type = NFT_OBJECT_QUOTA, .alloc_len = sizeof(struct nftnl_obj_quota), - .max_attr = NFTA_QUOTA_MAX, + .nftnl_max_attr = __NFTNL_OBJ_QUOTA_MAX - 1, + .attr_policy = obj_quota_attr_policy, .set = nftnl_obj_quota_set, .get = nftnl_obj_quota_get, .parse = nftnl_obj_quota_parse, .build = nftnl_obj_quota_build, - .snprintf = nftnl_obj_quota_snprintf, + .output = nftnl_obj_quota_snprintf, }; diff --git a/src/obj/secmark.c b/src/obj/secmark.c index e27b5fa..25b04e2 100644 --- a/src/obj/secmark.c +++ b/src/obj/secmark.c @@ -1,10 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * (C) 2012-2016 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. */ #include <stdio.h> @@ -30,8 +26,6 @@ static int nftnl_obj_secmark_set(struct nftnl_obj *e, uint16_t type, case NFTNL_OBJ_SECMARK_CTX: snprintf(secmark->ctx, sizeof(secmark->ctx), "%s", (const char *)data); break; - default: - return -1; } return 0; } @@ -98,40 +92,28 @@ nftnl_obj_secmark_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_secmark_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_secmark_snprintf(char *buf, size_t len, + uint32_t flags, + const struct nftnl_obj *e) { struct nftnl_obj_secmark *secmark = nftnl_obj_data(e); return snprintf(buf, len, "context %s ", secmark->ctx); } -static int nftnl_obj_secmark_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - if (len) - buf[0] = '\0'; - - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_secmark_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_XML: - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy obj_secmark_attr_policy[__NFTNL_OBJ_SECMARK_MAX] = { + [NFTNL_OBJ_SECMARK_CTX] = { .maxlen = NFT_SECMARK_CTX_MAXLEN }, +}; struct obj_ops obj_ops_secmark = { .name = "secmark", .type = NFT_OBJECT_SECMARK, .alloc_len = sizeof(struct nftnl_obj_secmark), - .max_attr = NFTA_SECMARK_MAX, + .nftnl_max_attr = __NFTNL_OBJ_SECMARK_MAX - 1, + .attr_policy = obj_secmark_attr_policy, .set = nftnl_obj_secmark_set, .get = nftnl_obj_secmark_get, .parse = nftnl_obj_secmark_parse, .build = nftnl_obj_secmark_build, - .snprintf = nftnl_obj_secmark_snprintf, + .output = nftnl_obj_secmark_snprintf, }; diff --git a/src/obj/synproxy.c b/src/obj/synproxy.c index 56ebc85..65fbcf7 100644 --- a/src/obj/synproxy.c +++ b/src/obj/synproxy.c @@ -19,16 +19,14 @@ static int nftnl_obj_synproxy_set(struct nftnl_obj *e, uint16_t type, switch (type) { case NFTNL_OBJ_SYNPROXY_MSS: - synproxy->mss = *((uint16_t *)data); + memcpy(&synproxy->mss, data, data_len); break; case NFTNL_OBJ_SYNPROXY_WSCALE: - synproxy->wscale = *((uint8_t *)data); + memcpy(&synproxy->wscale, data, data_len); break; case NFTNL_OBJ_SYNPROXY_FLAGS: - synproxy->flags = *((uint32_t *)data); + memcpy(&synproxy->flags, data, data_len); break; - default: - return -1; } return 0; } @@ -117,11 +115,12 @@ static int nftnl_obj_synproxy_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_synproxy_snprintf_default(char *buf, size_t size, - const struct nftnl_obj *e) +static int nftnl_obj_synproxy_snprintf(char *buf, size_t len, + uint32_t flags, + const struct nftnl_obj *e) { struct nftnl_obj_synproxy *synproxy = nftnl_obj_data(e); - int ret, offset = 0, len = size; + int ret, offset = 0; if (e->flags & (1 << NFTNL_OBJ_SYNPROXY_MSS) && e->flags & (1 << NFTNL_OBJ_SYNPROXY_WSCALE)) { @@ -133,29 +132,21 @@ static int nftnl_obj_synproxy_snprintf_default(char *buf, size_t size, return offset; } -static int nftnl_obj_synproxy_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, - const struct nftnl_obj *e) -{ - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_synproxy_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_XML: - case NFTNL_OUTPUT_JSON: - default: - break; - } - return -1; -} +static struct attr_policy obj_synproxy_attr_policy[__NFTNL_OBJ_SYNPROXY_MAX] = { + [NFTNL_OBJ_SYNPROXY_MSS] = { .maxlen = sizeof(uint16_t) }, + [NFTNL_OBJ_SYNPROXY_WSCALE] = { .maxlen = sizeof(uint8_t) }, + [NFTNL_OBJ_SYNPROXY_FLAGS] = { .maxlen = sizeof(uint32_t) }, +}; struct obj_ops obj_ops_synproxy = { .name = "synproxy", .type = NFT_OBJECT_SYNPROXY, .alloc_len = sizeof(struct nftnl_obj_synproxy), - .max_attr = NFTA_SYNPROXY_MAX, + .nftnl_max_attr = __NFTNL_OBJ_SYNPROXY_MAX - 1, + .attr_policy = obj_synproxy_attr_policy, .set = nftnl_obj_synproxy_set, .get = nftnl_obj_synproxy_get, .parse = nftnl_obj_synproxy_parse, .build = nftnl_obj_synproxy_build, - .snprintf = nftnl_obj_synproxy_snprintf, + .output = nftnl_obj_synproxy_snprintf, }; diff --git a/src/obj/tunnel.c b/src/obj/tunnel.c index 100aa09..ea9cb02 100644 --- a/src/obj/tunnel.c +++ b/src/obj/tunnel.c @@ -1,10 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * (C) 2018 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. */ #include <stdio.h> @@ -29,55 +25,41 @@ nftnl_obj_tunnel_set(struct nftnl_obj *e, uint16_t type, switch (type) { case NFTNL_OBJ_TUNNEL_ID: - memcpy(&tun->id, data, sizeof(tun->id)); + memcpy(&tun->id, data, data_len); break; case NFTNL_OBJ_TUNNEL_IPV4_SRC: - memcpy(&tun->src_v4, data, sizeof(tun->src_v4)); + memcpy(&tun->src_v4, data, data_len); break; case NFTNL_OBJ_TUNNEL_IPV4_DST: - memcpy(&tun->dst_v4, data, sizeof(tun->dst_v4)); + memcpy(&tun->dst_v4, data, data_len); break; case NFTNL_OBJ_TUNNEL_IPV6_SRC: - memcpy(&tun->src_v6, data, sizeof(struct in6_addr)); + memcpy(&tun->src_v6, data, data_len); break; case NFTNL_OBJ_TUNNEL_IPV6_DST: - memcpy(&tun->dst_v6, data, sizeof(struct in6_addr)); + memcpy(&tun->dst_v6, data, data_len); break; case NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL: - memcpy(&tun->flowlabel, data, sizeof(tun->flowlabel)); + memcpy(&tun->flowlabel, data, data_len); break; case NFTNL_OBJ_TUNNEL_SPORT: - memcpy(&tun->sport, data, sizeof(tun->sport)); + memcpy(&tun->sport, data, data_len); break; case NFTNL_OBJ_TUNNEL_DPORT: - memcpy(&tun->dport, data, sizeof(tun->dport)); + memcpy(&tun->dport, data, data_len); break; case NFTNL_OBJ_TUNNEL_FLAGS: - memcpy(&tun->tun_flags, data, sizeof(tun->tun_flags)); + memcpy(&tun->tun_flags, data, data_len); break; case NFTNL_OBJ_TUNNEL_TOS: - memcpy(&tun->tun_tos, data, sizeof(tun->tun_tos)); + memcpy(&tun->tun_tos, data, data_len); break; case NFTNL_OBJ_TUNNEL_TTL: - memcpy(&tun->tun_ttl, data, sizeof(tun->tun_ttl)); + memcpy(&tun->tun_ttl, data, data_len); break; - case NFTNL_OBJ_TUNNEL_VXLAN_GBP: - memcpy(&tun->u.tun_vxlan.gbp, data, sizeof(tun->u.tun_vxlan.gbp)); + case NFTNL_OBJ_TUNNEL_OPTS: + memcpy(&tun->tun_opts, data, data_len); break; - case NFTNL_OBJ_TUNNEL_ERSPAN_VERSION: - memcpy(&tun->u.tun_erspan.version, data, sizeof(tun->u.tun_erspan.version)); - break; - case NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX: - memcpy(&tun->u.tun_erspan.u.v1_index, data, sizeof(tun->u.tun_erspan.u.v1_index)); - break; - case NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID: - memcpy(&tun->u.tun_erspan.u.v2.hwid, data, sizeof(tun->u.tun_erspan.u.v2.hwid)); - break; - case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR: - memcpy(&tun->u.tun_erspan.u.v2.dir, data, sizeof(tun->u.tun_erspan.u.v2.dir)); - break; - default: - return -1; } return 0; } @@ -122,21 +104,9 @@ nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type, case NFTNL_OBJ_TUNNEL_TTL: *data_len = sizeof(tun->tun_ttl); return &tun->tun_ttl; - case NFTNL_OBJ_TUNNEL_VXLAN_GBP: - *data_len = sizeof(tun->u.tun_vxlan.gbp); - return &tun->u.tun_vxlan.gbp; - case NFTNL_OBJ_TUNNEL_ERSPAN_VERSION: - *data_len = sizeof(tun->u.tun_erspan.version); - return &tun->u.tun_erspan.version; - case NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX: - *data_len = sizeof(tun->u.tun_erspan.u.v1_index); - return &tun->u.tun_erspan.u.v1_index; - case NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID: - *data_len = sizeof(tun->u.tun_erspan.u.v2.hwid); - return &tun->u.tun_erspan.u.v2.hwid; - case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR: - *data_len = sizeof(tun->u.tun_erspan.u.v2.dir); - return &tun->u.tun_erspan.u.v2.dir; + case NFTNL_OBJ_TUNNEL_OPTS: + *data_len = sizeof(tun->tun_opts); + return &tun->tun_opts; } return NULL; } @@ -177,6 +147,9 @@ static int nftnl_obj_tunnel_cb(const struct nlattr *attr, void *data) return MNL_CB_OK; } +static void nftnl_tunnel_opts_build(struct nlmsghdr *nlh, + struct nftnl_tunnel_opts *opts); + static void nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e) { @@ -218,34 +191,8 @@ nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e) mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TTL, tun->tun_ttl); if (e->flags & (1 << NFTNL_OBJ_TUNNEL_FLAGS)) mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_FLAGS, htonl(tun->tun_flags)); - if (e->flags & (1 << NFTNL_OBJ_TUNNEL_VXLAN_GBP)) { - nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS); - mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP, - htonl(tun->u.tun_vxlan.gbp)); - mnl_attr_nest_end(nlh, nest); - } - if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_VERSION) && - (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX) || - (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID) && - e->flags & (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR)))) { - struct nlattr *nest_inner; - - nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS); - nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN); - mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION, - htonl(tun->u.tun_erspan.version)); - if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX)) - mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, - htonl(tun->u.tun_erspan.u.v1_index)); - if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID)) - mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, - tun->u.tun_erspan.u.v2.hwid); - if (e->flags & (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR)) - mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, - tun->u.tun_erspan.u.v2.dir); - mnl_attr_nest_end(nlh, nest_inner); - mnl_attr_nest_end(nlh, nest); - } + if (e->flags & (1 << NFTNL_OBJ_TUNNEL_OPTS)) + nftnl_tunnel_opts_build(nlh, tun->tun_opts); } static int nftnl_obj_tunnel_ip_cb(const struct nlattr *attr, void *data) @@ -341,6 +288,150 @@ static int nftnl_obj_tunnel_parse_ip6(struct nftnl_obj *e, struct nlattr *attr, return 0; } +struct nftnl_tunnel_opt { + struct list_head list; + + enum nftnl_tunnel_type type; + uint32_t flags; + + union { + struct { + uint32_t gbp; + } vxlan; + struct { + uint32_t version; + struct { + uint32_t index; + } v1; + struct { + uint8_t hwid; + uint8_t dir; + } v2; + } erspan; + struct { + uint16_t geneve_class; + uint8_t type; + uint8_t data[NFTNL_TUNNEL_GENEVE_DATA_MAXLEN]; + uint32_t data_len; + } geneve; + }; +}; + +struct nftnl_tunnel_opts { + enum nftnl_tunnel_type type; + uint32_t num; + struct list_head opts_list; +}; + +EXPORT_SYMBOL(nftnl_tunnel_opt_get_data); +const void *nftnl_tunnel_opt_get_data(const struct nftnl_tunnel_opt *ne, + uint16_t attr, uint32_t *data_len) +{ + if (!(ne->flags & (1 << attr))) + return NULL; + + switch (ne->type) { + case NFTNL_TUNNEL_TYPE_ERSPAN: + switch (attr) { + case NFTNL_TUNNEL_ERSPAN_VERSION: + *data_len = sizeof(uint32_t); + return &ne->erspan.version; + case NFTNL_TUNNEL_ERSPAN_V1_INDEX: + *data_len = sizeof(uint32_t); + return &ne->erspan.v1.index; + case NFTNL_TUNNEL_ERSPAN_V2_HWID: + *data_len = sizeof(uint8_t); + return &ne->erspan.v2.hwid; + case NFTNL_TUNNEL_ERSPAN_V2_DIR: + *data_len = sizeof(uint8_t); + return &ne->erspan.v2.dir; + } + break; + case NFTNL_TUNNEL_TYPE_VXLAN: + switch (attr) { + case NFTNL_TUNNEL_VXLAN_GBP: + *data_len = sizeof(uint32_t); + return &ne->vxlan.gbp; + } + break; + case NFTNL_TUNNEL_TYPE_GENEVE: + switch (attr) { + case NFTNL_TUNNEL_GENEVE_CLASS: + *data_len = sizeof(uint16_t); + return &ne->geneve.geneve_class; + case NFTNL_TUNNEL_GENEVE_TYPE: + *data_len = sizeof(uint8_t); + return &ne->geneve.type; + case NFTNL_TUNNEL_GENEVE_DATA: + *data_len = ne->geneve.data_len; + return &ne->geneve.data; + } + break; + } + + errno = EOPNOTSUPP; + return NULL; +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_get); +const void * +nftnl_tunnel_opt_get(const struct nftnl_tunnel_opt *ne, uint16_t attr) +{ + uint32_t data_len; + return nftnl_tunnel_opt_get_data(ne, attr, &data_len); +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_get_u8); +uint8_t nftnl_tunnel_opt_get_u8(const struct nftnl_tunnel_opt *ne, uint16_t attr) +{ + const void *ret = nftnl_tunnel_opt_get(ne, attr); + return ret == NULL ? 0 : *((uint8_t *)ret); +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_get_u16); +uint16_t nftnl_tunnel_opt_get_u16(const struct nftnl_tunnel_opt *ne, uint16_t attr) +{ + const void *ret = nftnl_tunnel_opt_get(ne, attr); + return ret == NULL ? 0 : *((uint16_t *)ret); +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_get_u32); +uint32_t nftnl_tunnel_opt_get_u32(const struct nftnl_tunnel_opt *ne, uint16_t attr) +{ + const void *ret = nftnl_tunnel_opt_get(ne, attr); + return ret == NULL ? 0 : *((uint32_t *)ret); +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_get_type); +enum nftnl_tunnel_type nftnl_tunnel_opt_get_type(const struct nftnl_tunnel_opt *ne) +{ + return ne->type; +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_get_flags); +uint32_t nftnl_tunnel_opt_get_flags(const struct nftnl_tunnel_opt *ne) +{ + return ne->flags; +} + +EXPORT_SYMBOL(nftnl_obj_tunnel_opts_foreach); +int nftnl_obj_tunnel_opts_foreach(const struct nftnl_obj *ne, + int (*cb)(struct nftnl_tunnel_opt *opt, void *data), + void *data) +{ + struct nftnl_obj_tunnel *tun = nftnl_obj_data(ne); + struct nftnl_tunnel_opt *cur, *tmp; + int ret; + + list_for_each_entry_safe(cur, tmp, &tun->tun_opts->opts_list, list) { + ret = cb(cur, data); + if (ret < 0) + return ret; + } + + return 0; +} + static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -360,21 +451,29 @@ static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data) return MNL_CB_OK; } +struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type); + static int -nftnl_obj_tunnel_parse_vxlan(struct nftnl_obj *e, struct nlattr *attr, - struct nftnl_obj_tunnel *tun) +nftnl_obj_tunnel_parse_vxlan(struct nftnl_tunnel_opts *opts, struct nlattr *attr) { struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = {}; + struct nftnl_tunnel_opt *opt; if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_vxlan_cb, tb) < 0) return -1; + opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_VXLAN); + if (!opt) + return -1; + if (tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) { - tun->u.tun_vxlan.gbp = + opt->vxlan.gbp = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP])); - e->flags |= (1 << NFTNL_OBJ_TUNNEL_VXLAN_GBP); + opt->flags |= (1 << NFTNL_TUNNEL_VXLAN_GBP); } + list_add_tail(&opt->list, &opts->opts_list); + return 0; } @@ -404,50 +503,63 @@ static int nftnl_obj_tunnel_erspan_cb(const struct nlattr *attr, void *data) } static int -nftnl_obj_tunnel_parse_erspan(struct nftnl_obj *e, struct nlattr *attr, - struct nftnl_obj_tunnel *tun) +nftnl_obj_tunnel_parse_erspan(struct nftnl_tunnel_opts *opts, struct nlattr *attr) { struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = {}; + struct nftnl_tunnel_opt *opt; if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_erspan_cb, tb) < 0) return -1; + opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_ERSPAN); + if (!opt) + return -1; + if (tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]) { - tun->u.tun_erspan.version = + opt->erspan.version = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION])); - e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_VERSION); + opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_VERSION); } if (tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) { - tun->u.tun_erspan.u.v1_index = + opt->erspan.v1.index = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX])); - e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX); + opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX); } if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) { - tun->u.tun_erspan.u.v2.hwid = + opt->erspan.v2.hwid = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]); - e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID); + opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID); } if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]) { - tun->u.tun_erspan.u.v2.dir = + opt->erspan.v2.dir = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]); - e->flags |= (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR); + opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR); } + list_add_tail(&opt->list, &opts->opts_list); + return 0; } -static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data) +static int nftnl_obj_tunnel_geneve_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; int type = mnl_attr_get_type(attr); - if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_OPTS_MAX) < 0) + if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_GENEVE_MAX) < 0) return MNL_CB_OK; switch (type) { - case NFTA_TUNNEL_KEY_OPTS_VXLAN: - case NFTA_TUNNEL_KEY_OPTS_ERSPAN: - if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) + case NFTA_TUNNEL_KEY_GENEVE_CLASS: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + abi_breakage(); + break; + case NFTA_TUNNEL_KEY_GENEVE_TYPE: + if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + abi_breakage(); + break; + case NFTA_TUNNEL_KEY_GENEVE_DATA: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) abi_breakage(); break; } @@ -457,21 +569,89 @@ static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data) } static int -nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *attr, +nftnl_obj_tunnel_parse_geneve(struct nftnl_tunnel_opts *opts, struct nlattr *attr) +{ + struct nlattr *tb[NFTA_TUNNEL_KEY_GENEVE_MAX + 1] = {}; + struct nftnl_tunnel_opt *opt; + + if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_geneve_cb, tb) < 0) + return -1; + + opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_GENEVE); + if (!opt) + return -1; + + if (tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]) { + opt->geneve.geneve_class = + ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_GENEVE_CLASS])); + opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_CLASS); + } + + if (tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]) { + opt->geneve.type = + mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]); + opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_TYPE); + } + + if (tb[NFTA_TUNNEL_KEY_GENEVE_DATA]) { + uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]); + + memcpy(opt->geneve.data, + mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]), + len); + opt->geneve.data_len = len; + opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_DATA); + } + + list_add_tail(&opt->list, &opts->opts_list); + + return 0; +} + +struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type); + +static int +nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *nest, struct nftnl_obj_tunnel *tun) { - struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = {}; + struct nlattr *attr; + struct nftnl_tunnel_opts *opts = NULL; int err = 0; - if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_opts_cb, tb) < 0) - return -1; + mnl_attr_for_each_nested(attr, nest) { + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) + abi_breakage(); + + switch(mnl_attr_get_type(attr)) { + case NFTA_TUNNEL_KEY_OPTS_VXLAN: + opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_VXLAN); + if (!opts) + return -1; + + err = nftnl_obj_tunnel_parse_vxlan(opts, attr); + break; + case NFTA_TUNNEL_KEY_OPTS_ERSPAN: + opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN); + if (!opts) + return -1; + + err = nftnl_obj_tunnel_parse_erspan(opts, attr); + break; + case NFTA_TUNNEL_KEY_OPTS_GENEVE: + if (!opts) + opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE); + + if (!opts) + return -1; + + err = nftnl_obj_tunnel_parse_geneve(opts, attr); + break; + } + } - if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) { - err = nftnl_obj_tunnel_parse_vxlan(e, tb[NFTA_TUNNEL_KEY_OPTS_VXLAN], - tun); - } else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) { - err = nftnl_obj_tunnel_parse_erspan(e, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN], - tun); + if (opts) { + tun->tun_opts = opts; + e->flags |= (1 << NFTNL_OBJ_TUNNEL_OPTS); } return err; @@ -530,39 +710,305 @@ nftnl_obj_tunnel_parse(struct nftnl_obj *e, struct nlattr *attr) return 0; } -static int nftnl_obj_tunnel_snprintf_default(char *buf, size_t len, - const struct nftnl_obj *e) +static int nftnl_obj_tunnel_snprintf(char *buf, size_t len, + uint32_t flags, const struct nftnl_obj *e) { struct nftnl_obj_tunnel *tun = nftnl_obj_data(e); return snprintf(buf, len, "id %u ", tun->id); } -static int nftnl_obj_tunnel_snprintf(char *buf, size_t len, uint32_t type, - uint32_t flags, const struct nftnl_obj *e) +EXPORT_SYMBOL(nftnl_tunnel_opts_alloc); +struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type) +{ + struct nftnl_tunnel_opts *opts; + + switch (type) { + case NFTNL_TUNNEL_TYPE_VXLAN: + case NFTNL_TUNNEL_TYPE_ERSPAN: + case NFTNL_TUNNEL_TYPE_GENEVE: + break; + default: + errno = EOPNOTSUPP; + return NULL; + } + + opts = calloc(1, sizeof(struct nftnl_tunnel_opts)); + if (!opts) + return NULL; + + opts->type = type; + INIT_LIST_HEAD(&opts->opts_list); + + return opts; +} + +EXPORT_SYMBOL(nftnl_tunnel_opts_add); +int nftnl_tunnel_opts_add(struct nftnl_tunnel_opts *opts, + struct nftnl_tunnel_opt *opt) +{ + if (opt->type != opts->type) { + errno = EOPNOTSUPP; + return -1; + } + + switch (opts->type) { + case NFTNL_TUNNEL_TYPE_VXLAN: + case NFTNL_TUNNEL_TYPE_ERSPAN: + if (opts->num > 0) { + errno = EEXIST; + return -1; + } + break; + case NFTNL_TUNNEL_TYPE_GENEVE: + break; + default: + errno = EOPNOTSUPP; + return -1; + } + + list_add_tail(&opt->list, &opts->opts_list); + + return 0; +} + +EXPORT_SYMBOL(nftnl_tunnel_opts_free); +void nftnl_tunnel_opts_free(struct nftnl_tunnel_opts *opts) +{ + struct nftnl_tunnel_opt *opt, *next; + + list_for_each_entry_safe(opt, next, &opts->opts_list, list) { + switch(opts->type) { + case NFTNL_TUNNEL_TYPE_VXLAN: + case NFTNL_TUNNEL_TYPE_ERSPAN: + case NFTNL_TUNNEL_TYPE_GENEVE: + list_del(&opt->list); + xfree(opt); + break; + } + } +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_alloc); +struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type) +{ + struct nftnl_tunnel_opt *opt; + + switch (type) { + case NFTNL_TUNNEL_TYPE_VXLAN: + case NFTNL_TUNNEL_TYPE_ERSPAN: + case NFTNL_TUNNEL_TYPE_GENEVE: + break; + default: + errno = EOPNOTSUPP; + return NULL; + } + + opt = calloc(1, sizeof(struct nftnl_tunnel_opt)); + if (!opt) + return NULL; + + opt->type = type; + + return opt; +} + +static int nftnl_tunnel_opt_vxlan_set(struct nftnl_tunnel_opt *opt, uint16_t type, + const void *data, uint32_t data_len) { - if (len) - buf[0] = '\0'; + switch (type) { + case NFTNL_TUNNEL_VXLAN_GBP: + memcpy(&opt->vxlan.gbp, data, data_len); + break; + default: + errno = EOPNOTSUPP; + return -1; + } + opt->flags |= (1 << type); + + return 0; +} + +static int nftnl_tunnel_opt_erspan_set(struct nftnl_tunnel_opt *opt, uint16_t type, + const void *data, uint32_t data_len) +{ switch (type) { - case NFTNL_OUTPUT_DEFAULT: - return nftnl_obj_tunnel_snprintf_default(buf, len, e); - case NFTNL_OUTPUT_XML: - case NFTNL_OUTPUT_JSON: + case NFTNL_TUNNEL_ERSPAN_VERSION: + memcpy(&opt->erspan.version, data, data_len); + break; + case NFTNL_TUNNEL_ERSPAN_V1_INDEX: + memcpy(&opt->erspan.v1.index, data, data_len); + break; + case NFTNL_TUNNEL_ERSPAN_V2_HWID: + memcpy(&opt->erspan.v2.hwid, data, data_len); + break; + case NFTNL_TUNNEL_ERSPAN_V2_DIR: + memcpy(&opt->erspan.v2.dir, data, data_len); + break; default: + errno = EOPNOTSUPP; + return -1; + } + + opt->flags |= (1 << type); + + return 0; +} + +static int nftnl_tunnel_opt_geneve_set(struct nftnl_tunnel_opt *opt, uint16_t type, + const void *data, uint32_t data_len) +{ + switch(type) { + case NFTNL_TUNNEL_GENEVE_CLASS: + memcpy(&opt->geneve.geneve_class, data, data_len); break; + case NFTNL_TUNNEL_GENEVE_TYPE: + memcpy(&opt->geneve.type, data, data_len); + break; + case NFTNL_TUNNEL_GENEVE_DATA: + if (data_len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) { + errno = EINVAL; + return -1; + } + memcpy(&opt->geneve.data, data, data_len); + opt->geneve.data_len = data_len; + break; + default: + errno = EOPNOTSUPP; + return -1; + } + + opt->flags |= (1 << type); + + return 0; +} + +EXPORT_SYMBOL(nftnl_tunnel_opt_set); +int nftnl_tunnel_opt_set(struct nftnl_tunnel_opt *opt, uint16_t type, + const void *data, uint32_t data_len) +{ + switch (opt->type) { + case NFTNL_TUNNEL_TYPE_VXLAN: + return nftnl_tunnel_opt_vxlan_set(opt, type, data, data_len); + case NFTNL_TUNNEL_TYPE_ERSPAN: + return nftnl_tunnel_opt_erspan_set(opt, type, data, data_len); + case NFTNL_TUNNEL_TYPE_GENEVE: + return nftnl_tunnel_opt_geneve_set(opt, type, data, data_len); + default: + errno = EOPNOTSUPP; + return -1; + } + + return 0; +} + +static void nftnl_tunnel_opt_build_vxlan(struct nlmsghdr *nlh, + const struct nftnl_tunnel_opt *opt) +{ + struct nlattr *nest_inner; + + if (opt->flags & (1 << NFTNL_TUNNEL_VXLAN_GBP)) { + nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN); + mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP, + htonl(opt->vxlan.gbp)); + mnl_attr_nest_end(nlh, nest_inner); + } +} + +static void nftnl_tunnel_opt_build_erspan(struct nlmsghdr *nlh, + const struct nftnl_tunnel_opt *opt) +{ + struct nlattr *nest_inner; + + if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_VERSION) && + (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX) || + (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID) && + opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)))) { + nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN); + mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION, + htonl(opt->erspan.version)); + if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX)) + mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, + htonl(opt->erspan.v1.index)); + if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID)) + mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, + opt->erspan.v2.hwid); + if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)) + mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, + opt->erspan.v2.dir); + mnl_attr_nest_end(nlh, nest_inner); } - return -1; } +static void nftnl_tunnel_opt_build_geneve(struct nlmsghdr *nlh, + const struct nftnl_tunnel_opt *opt) +{ + struct nlattr *nest_inner; + + if (opt->flags & (1 << NFTNL_TUNNEL_GENEVE_CLASS) && + opt->flags & (1 << NFTNL_TUNNEL_GENEVE_TYPE) && + opt->flags & (1 << NFTNL_TUNNEL_GENEVE_DATA)) { + nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE); + mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS, + htons(opt->geneve.geneve_class)); + mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE, + opt->geneve.type); + mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA, + opt->geneve.data_len, + opt->geneve.data); + mnl_attr_nest_end(nlh, nest_inner); + } +} + +void nftnl_tunnel_opts_build(struct nlmsghdr *nlh, + struct nftnl_tunnel_opts *opts) +{ + const struct nftnl_tunnel_opt *opt; + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS); + + list_for_each_entry(opt, &opts->opts_list, list) { + switch (opts->type) { + case NFTNL_TUNNEL_TYPE_VXLAN: + nftnl_tunnel_opt_build_vxlan(nlh, opt); + break; + case NFTNL_TUNNEL_TYPE_ERSPAN: + nftnl_tunnel_opt_build_erspan(nlh, opt); + break; + case NFTNL_TUNNEL_TYPE_GENEVE: + nftnl_tunnel_opt_build_geneve(nlh, opt); + break; + } + } + mnl_attr_nest_end(nlh, nest); +} + +static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = { + [NFTNL_OBJ_TUNNEL_ID] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_TUNNEL_IPV4_SRC] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_TUNNEL_IPV4_DST] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_TUNNEL_IPV6_SRC] = { .maxlen = sizeof(struct in6_addr) }, + [NFTNL_OBJ_TUNNEL_IPV6_DST] = { .maxlen = sizeof(struct in6_addr) }, + [NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_TUNNEL_SPORT] = { .maxlen = sizeof(uint16_t) }, + [NFTNL_OBJ_TUNNEL_DPORT] = { .maxlen = sizeof(uint16_t) }, + [NFTNL_OBJ_TUNNEL_FLAGS] = { .maxlen = sizeof(uint32_t) }, + [NFTNL_OBJ_TUNNEL_TOS] = { .maxlen = sizeof(uint8_t) }, + [NFTNL_OBJ_TUNNEL_TTL] = { .maxlen = sizeof(uint8_t) }, + [NFTNL_OBJ_TUNNEL_OPTS] = { .maxlen = sizeof(struct nftnl_tunnel_opts *) }, +}; + struct obj_ops obj_ops_tunnel = { .name = "tunnel", .type = NFT_OBJECT_TUNNEL, .alloc_len = sizeof(struct nftnl_obj_tunnel), - .max_attr = NFTA_TUNNEL_KEY_MAX, + .nftnl_max_attr = __NFTNL_OBJ_TUNNEL_MAX - 1, + .attr_policy = obj_tunnel_attr_policy, .set = nftnl_obj_tunnel_set, .get = nftnl_obj_tunnel_get, .parse = nftnl_obj_tunnel_parse, .build = nftnl_obj_tunnel_build, - .snprintf = nftnl_obj_tunnel_snprintf, + .output = nftnl_obj_tunnel_snprintf, }; |
