diff options
Diffstat (limited to 'src/meta.c')
-rw-r--r-- | src/meta.c | 174 |
1 files changed, 107 insertions, 67 deletions
@@ -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); } @@ -340,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) @@ -361,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 = { @@ -385,21 +376,22 @@ 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; + tstamp64 /= 1000000000L; /* Obtain current tm, to add tm_gmtoff to the timestamp */ - cur_tm = localtime((time_t *) &tstamp); + tstamp = tstamp64; + if (localtime_r(&tstamp, &tm)) + tstamp64 += tm.tm_gmtoff; - if (cur_tm) - tstamp += cur_tm->tm_gmtoff; - - if ((tm = gmtime((time_t *) &tstamp)) != NULL && - strftime(timestr, sizeof(timestr) - 1, "%Y-%m-%d %T", tm)) + 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"); @@ -407,7 +399,8 @@ static void date_type_print(const struct expr *expr, struct output_ctx *octx) 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)); @@ -429,14 +422,15 @@ 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 */ - *tstamp = ts - cur_tm->tm_gmtoff; + *tstamp = ts - cur_tm.tm_gmtoff; return true; } @@ -491,16 +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; /* 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; @@ -517,10 +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; + 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)); @@ -534,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') @@ -698,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) @@ -717,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) @@ -734,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; } /** @@ -768,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; @@ -807,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; } @@ -825,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; @@ -839,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; @@ -852,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 = { @@ -901,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); } @@ -931,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; } @@ -960,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)) @@ -987,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; @@ -997,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); |