summaryrefslogtreecommitdiffstats
path: root/src/meta.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/meta.c')
-rw-r--r--src/meta.c238
1 files changed, 135 insertions, 103 deletions
diff --git a/src/meta.c b/src/meta.c
index 73d58b1f..a17bacf0 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -10,13 +10,12 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <errno.h>
#include <limits.h>
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <pwd.h>
@@ -25,6 +24,7 @@
#include <linux/netfilter.h>
#include <linux/pkt_sched.h>
#include <linux/if_packet.h>
+#include <time.h>
#include <nftables.h>
#include <expression.h>
@@ -37,10 +37,6 @@
#include <iface.h>
#include <json.h>
-#define _XOPEN_SOURCE
-#define __USE_XOPEN
-#include <time.h>
-
static void tchandle_type_print(const struct expr *expr,
struct output_ctx *octx)
{
@@ -66,50 +62,39 @@ static struct error_record *tchandle_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
uint32_t handle;
- char *str = NULL;
if (strcmp(sym->identifier, "root") == 0)
handle = TC_H_ROOT;
else if (strcmp(sym->identifier, "none") == 0)
handle = TC_H_UNSPEC;
else if (strchr(sym->identifier, ':')) {
+ char *colon, *end;
uint32_t tmp;
- char *colon;
-
- str = xstrdup(sym->identifier);
-
- colon = strchr(str, ':');
- if (!colon)
- goto err;
-
- *colon = '\0';
errno = 0;
- tmp = strtoull(str, NULL, 16);
- if (errno != 0)
+ tmp = strtoul(sym->identifier, &colon, 16);
+ if (errno != 0 || sym->identifier == colon)
goto err;
- handle = (tmp << 16);
- if (str[strlen(str) - 1] == ':')
- goto out;
+ if (*colon != ':')
+ goto err;
+ handle = tmp << 16;
errno = 0;
- tmp = strtoull(colon + 1, NULL, 16);
- if (errno != 0)
+ tmp = strtoul(colon + 1, &end, 16);
+ if (errno != 0 || *end)
goto err;
handle |= tmp;
} else {
handle = strtoull(sym->identifier, NULL, 0);
}
-out:
- xfree(str);
+
*res = constant_expr_alloc(&sym->location, sym->dtype,
BYTEORDER_HOST_ENDIAN,
sizeof(handle) * BITS_PER_BYTE, &handle);
return NULL;
err:
- xfree(str);
return error(&sym->location, "Could not parse %s", sym->dtype->desc);
}
@@ -220,18 +205,20 @@ static struct error_record *uid_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
struct passwd *pw;
- uint64_t uid;
+ uid_t uid;
char *endptr = NULL;
pw = getpwnam(sym->identifier);
if (pw != NULL)
uid = pw->pw_uid;
else {
- uid = strtoull(sym->identifier, &endptr, 10);
- if (uid > UINT32_MAX)
+ uint64_t _uid = strtoull(sym->identifier, &endptr, 10);
+
+ if (_uid > UINT32_MAX)
return error(&sym->location, "Value too large");
else if (*endptr)
return error(&sym->location, "User does not exist");
+ uid = _uid;
}
*res = constant_expr_alloc(&sym->location, sym->dtype,
@@ -274,18 +261,20 @@ static struct error_record *gid_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
struct group *gr;
- uint64_t gid;
+ gid_t gid;
char *endptr = NULL;
gr = getgrnam(sym->identifier);
if (gr != NULL)
gid = gr->gr_gid;
else {
- gid = strtoull(sym->identifier, &endptr, 0);
- if (gid > UINT32_MAX)
+ uint64_t _gid = strtoull(sym->identifier, &endptr, 0);
+
+ if (_gid > UINT32_MAX)
return error(&sym->location, "Value too large");
else if (*endptr)
return error(&sym->location, "Group does not exist");
+ gid = _gid;
}
*res = constant_expr_alloc(&sym->location, sym->dtype,
@@ -336,7 +325,7 @@ const struct datatype pkttype_type = {
void devgroup_table_init(struct nft_ctx *ctx)
{
- ctx->output.tbl.devgroup = rt_symbol_table_init("/etc/iproute2/group");
+ ctx->output.tbl.devgroup = rt_symbol_table_init("group");
}
void devgroup_table_exit(struct nft_ctx *ctx)
@@ -357,17 +346,23 @@ static struct error_record *devgroup_type_parse(struct parse_ctx *ctx,
return symbolic_constant_parse(ctx, sym, ctx->tbl->devgroup, res);
}
+static void devgroup_type_describe(struct output_ctx *octx)
+{
+ rt_symbol_table_describe(octx, "group",
+ octx->tbl.devgroup, &devgroup_type);
+}
+
const struct datatype devgroup_type = {
.type = TYPE_DEVGROUP,
.name = "devgroup",
.desc = "devgroup name",
+ .describe = devgroup_type_describe,
.byteorder = BYTEORDER_HOST_ENDIAN,
.size = 4 * BITS_PER_BYTE,
.basetype = &integer_type,
.print = devgroup_type_print,
.json = devgroup_type_json,
.parse = devgroup_type_parse,
- .flags = DTYPE_F_PREFIX,
};
const struct datatype ifname_type = {
@@ -381,51 +376,43 @@ const struct datatype ifname_type = {
static void date_type_print(const struct expr *expr, struct output_ctx *octx)
{
- uint64_t tstamp = mpz_get_uint64(expr->value);
- struct tm *tm, *cur_tm;
+ uint64_t tstamp64 = mpz_get_uint64(expr->value);
char timestr[21];
+ time_t tstamp;
+ struct tm tm;
/* Convert from nanoseconds to seconds */
- tstamp /= 1000000000L;
-
- if (!nft_output_seconds(octx)) {
- /* Obtain current tm, to add tm_gmtoff to the timestamp */
- cur_tm = localtime((time_t *) &tstamp);
-
- if (cur_tm)
- tstamp += cur_tm->tm_gmtoff;
+ tstamp64 /= 1000000000L;
- if ((tm = gmtime((time_t *) &tstamp)) != NULL &&
- strftime(timestr, sizeof(timestr) - 1, "%F %T", tm))
- nft_print(octx, "\"%s\"", timestr);
- else
- nft_print(octx, "Error converting timestamp to printed time");
-
- return;
- }
+ /* Obtain current tm, to add tm_gmtoff to the timestamp */
+ tstamp = tstamp64;
+ if (localtime_r(&tstamp, &tm))
+ tstamp64 += tm.tm_gmtoff;
- /*
- * Do our own printing. The default print function will print in
- * nanoseconds, which is ugly.
- */
- nft_print(octx, "%lu", tstamp);
+ tstamp = tstamp64;
+ if (gmtime_r(&tstamp, &tm) &&
+ strftime(timestr, sizeof(timestr) - 1, "%Y-%m-%d %T", &tm))
+ nft_print(octx, "\"%s\"", timestr);
+ else
+ nft_print(octx, "Error converting timestamp to printed time");
}
-static time_t parse_iso_date(const char *sym)
+static bool parse_iso_date(uint64_t *tstamp, const char *sym)
{
- struct tm tm, *cur_tm;
+ struct tm cur_tm;
+ struct tm tm;
time_t ts;
memset(&tm, 0, sizeof(struct tm));
- if (strptime(sym, "%F %T", &tm))
+ if (strptime(sym, "%Y-%m-%d %T", &tm))
goto success;
- if (strptime(sym, "%F %R", &tm))
+ if (strptime(sym, "%Y-%m-%d %R", &tm))
goto success;
- if (strptime(sym, "%F", &tm))
+ if (strptime(sym, "%Y-%m-%d", &tm))
goto success;
- return -1;
+ return false;
success:
/*
@@ -435,14 +422,17 @@ success:
*/
ts = timegm(&tm);
- /* Obtain current tm as well (at the specified time), so that we can substract tm_gmtoff */
- cur_tm = localtime(&ts);
+ if (ts == (time_t) -1)
+ return false;
- if (ts == (time_t) -1 || cur_tm == NULL)
- return ts;
+ /* Obtain current tm as well (at the specified time), so that we can substract tm_gmtoff */
+ if (!localtime_r(&ts, &cur_tm))
+ return false;
/* Substract tm_gmtoff to get the current time */
- return ts - cur_tm->tm_gmtoff;
+ *tstamp = ts - cur_tm.tm_gmtoff;
+
+ return true;
}
static struct error_record *date_type_parse(struct parse_ctx *ctx,
@@ -450,9 +440,9 @@ static struct error_record *date_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
const char *endptr = sym->identifier;
- time_t tstamp;
+ uint64_t tstamp;
- if ((tstamp = parse_iso_date(sym->identifier)) != -1)
+ if (parse_iso_date(&tstamp, sym->identifier))
goto success;
tstamp = strtoul(sym->identifier, (char **) &endptr, 10);
@@ -495,21 +485,21 @@ static void day_type_print(const struct expr *expr, struct output_ctx *octx)
static void hour_type_print(const struct expr *expr, struct output_ctx *octx)
{
uint32_t seconds = mpz_get_uint32(expr->value), minutes, hours;
- struct tm *cur_tm;
+ struct tm cur_tm;
time_t ts;
- if (nft_output_seconds(octx)) {
- expr_basetype(expr)->print(expr, octx);
- return;
- }
-
/* Obtain current tm, so that we can add tm_gmtoff */
ts = time(NULL);
- cur_tm = localtime(&ts);
+ if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm)) {
+ int32_t adj = seconds + cur_tm.tm_gmtoff;
- if (cur_tm)
- seconds = (seconds + cur_tm->tm_gmtoff) % SECONDS_PER_DAY;
+ if (adj < 0)
+ adj += SECONDS_PER_DAY;
+ else if (adj >= SECONDS_PER_DAY)
+ adj -= SECONDS_PER_DAY;
+ seconds = adj;
+ }
minutes = seconds / 60;
seconds %= 60;
hours = minutes / 60;
@@ -526,9 +516,12 @@ static struct error_record *hour_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
struct error_record *er;
- struct tm tm, *cur_tm;
- uint64_t result = 0;
+ struct tm cur_tm_data;
+ struct tm *cur_tm;
+ uint32_t result;
+ uint64_t tmp;
char *endptr;
+ struct tm tm;
time_t ts;
memset(&tm, 0, sizeof(struct tm));
@@ -542,7 +535,10 @@ static struct error_record *hour_type_parse(struct parse_ctx *ctx,
/* Obtain current tm, so that we can substract tm_gmtoff */
ts = time(NULL);
- cur_tm = localtime(&ts);
+ if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm_data))
+ cur_tm = &cur_tm_data;
+ else
+ cur_tm = NULL;
endptr = strptime(sym->identifier, "%T", &tm);
if (endptr && *endptr == '\0')
@@ -555,8 +551,8 @@ static struct error_record *hour_type_parse(struct parse_ctx *ctx,
if (endptr && *endptr)
return error(&sym->location, "Can't parse trailing input: \"%s\"\n", endptr);
- if ((er = time_parse(&sym->location, sym->identifier, &result)) == NULL) {
- result /= 1000;
+ if ((er = time_parse(&sym->location, sym->identifier, &tmp)) == NULL) {
+ result = tmp / 1000;
goto convert;
}
@@ -610,7 +606,7 @@ const struct datatype hour_type = {
.name = "hour",
.desc = "Hour of day of packet reception",
.byteorder = BYTEORDER_HOST_ENDIAN,
- .size = sizeof(uint64_t) * BITS_PER_BYTE,
+ .size = sizeof(uint32_t) * BITS_PER_BYTE,
.basetype = &integer_type,
.print = hour_type_print,
.parse = hour_type_parse,
@@ -706,6 +702,8 @@ const struct meta_template meta_templates[] = {
[NFT_META_SDIFNAME] = META_TEMPLATE("sdifname", &ifname_type,
IFNAMSIZ * BITS_PER_BYTE,
BYTEORDER_HOST_ENDIAN),
+ [NFT_META_BRI_BROUTE] = META_TEMPLATE("broute", &integer_type,
+ 1 , BYTEORDER_HOST_ENDIAN),
};
static bool meta_key_is_unqualified(enum nft_meta_keys key)
@@ -725,12 +723,16 @@ static bool meta_key_is_unqualified(enum nft_meta_keys key)
static void meta_expr_print(const struct expr *expr, struct output_ctx *octx)
{
- if (meta_key_is_unqualified(expr->meta.key))
- nft_print(octx, "%s",
- meta_templates[expr->meta.key].token);
+ const char *token = "unknown";
+ uint32_t key = expr->meta.key;
+
+ if (key < array_size(meta_templates))
+ token = meta_templates[key].token;
+
+ if (meta_key_is_unqualified(key))
+ nft_print(octx, "%s", token);
else
- nft_print(octx, "meta %s",
- meta_templates[expr->meta.key].token);
+ nft_print(octx, "meta %s", token);
}
static bool meta_expr_cmp(const struct expr *e1, const struct expr *e2)
@@ -742,6 +744,7 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr)
{
new->meta.key = expr->meta.key;
new->meta.base = expr->meta.base;
+ new->meta.inner_desc = expr->meta.inner_desc;
}
/**
@@ -776,6 +779,11 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
break;
case NFT_META_NFPROTO:
protonum = mpz_get_uint8(right->value);
+ if (protonum == NFPROTO_IPV4 && h->desc == &proto_ip)
+ break;
+ else if (protonum == NFPROTO_IPV6 && h->desc == &proto_ip6)
+ break;
+
desc = proto_find_upper(h->desc, protonum);
if (desc == NULL) {
desc = &proto_unknown;
@@ -815,13 +823,19 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
}
#define NFTNL_UDATA_META_KEY 0
-#define NFTNL_UDATA_META_MAX 1
+#define NFTNL_UDATA_META_INNER_DESC 1
+#define NFTNL_UDATA_META_MAX 2
static int meta_expr_build_udata(struct nftnl_udata_buf *udbuf,
const struct expr *expr)
{
nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_KEY, expr->meta.key);
+ if (expr->meta.inner_desc) {
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_INNER_DESC,
+ expr->meta.inner_desc->id);
+ }
+
return 0;
}
@@ -833,6 +847,7 @@ static int meta_parse_udata(const struct nftnl_udata *attr, void *data)
switch (type) {
case NFTNL_UDATA_META_KEY:
+ case NFTNL_UDATA_META_INNER_DESC:
if (len != sizeof(uint32_t))
return -1;
break;
@@ -847,6 +862,8 @@ static int meta_parse_udata(const struct nftnl_udata *attr, void *data)
static struct expr *meta_expr_parse_udata(const struct nftnl_udata *attr)
{
const struct nftnl_udata *ud[NFTNL_UDATA_META_MAX + 1] = {};
+ const struct proto_desc *desc;
+ struct expr *expr;
uint32_t key;
int err;
@@ -860,7 +877,14 @@ static struct expr *meta_expr_parse_udata(const struct nftnl_udata *attr)
key = nftnl_udata_get_u32(ud[NFTNL_UDATA_META_KEY]);
- return meta_expr_alloc(&internal_location, key);
+ expr = meta_expr_alloc(&internal_location, key);
+
+ if (ud[NFTNL_UDATA_META_INNER_DESC]) {
+ desc = find_proto_desc(ud[NFTNL_UDATA_META_INNER_DESC]);
+ expr->meta.inner_desc = desc;
+ }
+
+ return expr;
}
const struct expr_ops meta_expr_ops = {
@@ -909,12 +933,16 @@ struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key)
static void meta_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
+ const char *token = "unknown";
+ uint32_t key = stmt->meta.key;
+
+ if (key < array_size(meta_templates))
+ token = meta_templates[key].token;
+
if (meta_key_is_unqualified(stmt->meta.key))
- nft_print(octx, "%s set ",
- meta_templates[stmt->meta.key].token);
+ nft_print(octx, "%s set ", token);
else
- nft_print(octx, "meta %s set ",
- meta_templates[stmt->meta.key].token);
+ nft_print(octx, "meta %s set ", token);
expr_print(stmt->meta.expr, octx);
}
@@ -939,8 +967,11 @@ struct stmt *meta_stmt_alloc(const struct location *loc, enum nft_meta_keys key,
stmt = stmt_alloc(loc, &meta_stmt_ops);
stmt->meta.key = key;
- stmt->meta.tmpl = &meta_templates[key];
stmt->meta.expr = expr;
+
+ if (key < array_size(meta_templates))
+ stmt->meta.tmpl = &meta_templates[key];
+
return stmt;
}
@@ -968,11 +999,11 @@ struct error_record *meta_key_parse(const struct location *loc,
const char *str,
unsigned int *value)
{
- int ret, len, offset = 0;
const char *sep = "";
+ size_t offset = 0;
unsigned int i;
char buf[1024];
- size_t size;
+ size_t len;
for (i = 0; i < array_size(meta_templates); i++) {
if (!meta_templates[i].token || strcmp(meta_templates[i].token, str))
@@ -995,9 +1026,10 @@ struct error_record *meta_key_parse(const struct location *loc,
}
len = (int)sizeof(buf);
- size = sizeof(buf);
for (i = 0; i < array_size(meta_templates); i++) {
+ int ret;
+
if (!meta_templates[i].token)
continue;
@@ -1005,8 +1037,8 @@ struct error_record *meta_key_parse(const struct location *loc,
sep = ", ";
ret = snprintf(buf+offset, len, "%s%s", sep, meta_templates[i].token);
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
- assert(offset < (int)sizeof(buf));
+ SNPRINTF_BUFFER_SIZE(ret, &len, &offset);
+ assert(len > 0);
}
return error(loc, "syntax error, unexpected %s, known keys are %s", str, buf);