diff options
Diffstat (limited to 'src/datatype.c')
-rw-r--r-- | src/datatype.c | 453 |
1 files changed, 349 insertions, 104 deletions
diff --git a/src/datatype.c b/src/datatype.c index 2e31c858..d398a9c8 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -8,8 +8,8 @@ * Development of this code funded by Astaro AG (http://www.astaro.com/) */ -#include <stdlib.h> -#include <string.h> +#include <nft.h> + #include <inttypes.h> #include <ctype.h> /* isdigit */ #include <errno.h> @@ -28,6 +28,8 @@ #include <erec.h> #include <netlink.h> #include <json.h> +#include <misspell.h> +#include "nftutils.h" #include <netinet/ip_icmp.h> @@ -62,6 +64,7 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = { [TYPE_CT_DIR] = &ct_dir_type, [TYPE_CT_STATUS] = &ct_status_type, [TYPE_ICMP6_TYPE] = &icmp6_type_type, + [TYPE_CT_LABEL] = &ct_label_type, [TYPE_PKTTYPE] = &pkttype_type, [TYPE_ICMP_CODE] = &icmp_code_type, [TYPE_ICMPV6_CODE] = &icmpv6_code_type, @@ -71,6 +74,7 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = { [TYPE_ECN] = &ecn_type, [TYPE_FIB_ADDR] = &fib_addr_type, [TYPE_BOOLEAN] = &boolean_type, + [TYPE_CT_EVENTBIT] = &ct_event_type, [TYPE_IFNAME] = &ifname_type, [TYPE_IGMP_TYPE] = &igmp_type_type, [TYPE_TIME_DATE] = &date_type, @@ -123,6 +127,7 @@ struct error_record *symbol_parse(struct parse_ctx *ctx, const struct expr *sym, struct expr **res) { const struct datatype *dtype = sym->dtype; + struct error_record *erec; assert(sym->etype == EXPR_SYMBOL); @@ -136,11 +141,54 @@ struct error_record *symbol_parse(struct parse_ctx *ctx, const struct expr *sym, res); } while ((dtype = dtype->basetype)); - return error(&sym->location, - "Can't parse symbolic %s expressions", + dtype = sym->dtype; + if (dtype->err) { + erec = dtype->err(sym); + if (erec) + return erec; + } + + return error(&sym->location, "Could not parse symbolic %s expression", sym->dtype->desc); } +static struct error_record *__symbol_parse_fuzzy(const struct expr *sym, + const struct symbol_table *tbl) +{ + const struct symbolic_constant *s; + struct string_misspell_state st; + + string_misspell_init(&st); + + for (s = tbl->symbols; s->identifier != NULL; s++) { + string_misspell_update(sym->identifier, s->identifier, + (void *)s->identifier, &st); + } + + if (st.obj) { + return error(&sym->location, + "Could not parse %s expression; did you you mean `%s`?", + sym->dtype->desc, st.obj); + } + + return NULL; +} + +static struct error_record *symbol_parse_fuzzy(const struct expr *sym, + const struct symbol_table *tbl) +{ + struct error_record *erec; + + if (!tbl) + return NULL; + + erec = __symbol_parse_fuzzy(sym, tbl); + if (erec) + return erec; + + return NULL; +} + struct error_record *symbolic_constant_parse(struct parse_ctx *ctx, const struct expr *sym, const struct symbol_table *tbl, @@ -163,8 +211,16 @@ struct error_record *symbolic_constant_parse(struct parse_ctx *ctx, do { if (dtype->basetype->parse) { erec = dtype->basetype->parse(ctx, sym, res); - if (erec != NULL) - return erec; + if (erec != NULL) { + struct error_record *fuzzy_erec; + + fuzzy_erec = symbol_parse_fuzzy(sym, tbl); + if (!fuzzy_erec) + return erec; + + erec_destroy(erec); + return fuzzy_erec; + } if (*res) return NULL; goto out; @@ -321,15 +377,33 @@ static void verdict_type_print(const struct expr *expr, struct output_ctx *octx) } } -static struct error_record *verdict_type_parse(struct parse_ctx *ctx, - const struct expr *sym, - struct expr **res) +static struct error_record *verdict_type_error(const struct expr *sym) { - *res = constant_expr_alloc(&sym->location, &string_type, - BYTEORDER_HOST_ENDIAN, - (strlen(sym->identifier) + 1) * BITS_PER_BYTE, - sym->identifier); - return NULL; + /* Skip jump and goto from fuzzy match to provide better error + * reporting, fall back to `jump chain' if no clue. + */ + static const char *verdict_array[] = { + "continue", "break", "return", "accept", "drop", "queue", + "stolen", NULL, + }; + struct string_misspell_state st; + int i; + + string_misspell_init(&st); + + for (i = 0; verdict_array[i] != NULL; i++) { + string_misspell_update(sym->identifier, verdict_array[i], + (void *)verdict_array[i], &st); + } + + if (st.obj) { + return error(&sym->location, "Could not parse %s; did you mean `%s'?", + sym->dtype->desc, st.obj); + } + + /* assume user would like to jump to chain as a hint. */ + return error(&sym->location, "Could not parse %s; did you mean `jump %s'?", + sym->dtype->desc, sym->identifier); } const struct datatype verdict_type = { @@ -337,7 +411,7 @@ const struct datatype verdict_type = { .name = "verdict", .desc = "netfilter verdict", .print = verdict_type_print, - .parse = verdict_type_parse, + .err = verdict_type_error, }; static const struct symbol_table nfproto_tbl = { @@ -528,27 +602,34 @@ static struct error_record *ipaddr_type_parse(struct parse_ctx *ctx, const struct expr *sym, struct expr **res) { - struct addrinfo *ai, hints = { .ai_family = AF_INET, - .ai_socktype = SOCK_DGRAM}; - struct in_addr *addr; - int err; + struct in_addr addr; + + if (nft_input_no_dns(ctx->input)) { + if (inet_pton(AF_INET, sym->identifier, &addr) != 1) + return error(&sym->location, "Invalid IPv4 address"); + } else { + struct addrinfo *ai, hints = { .ai_family = AF_INET, + .ai_socktype = SOCK_DGRAM}; + int err; - err = getaddrinfo(sym->identifier, NULL, &hints, &ai); - if (err != 0) - return error(&sym->location, "Could not resolve hostname: %s", - gai_strerror(err)); + err = getaddrinfo(sym->identifier, NULL, &hints, &ai); + if (err != 0) + return error(&sym->location, "Could not resolve hostname: %s", + gai_strerror(err)); - if (ai->ai_next != NULL) { + if (ai->ai_next != NULL) { + freeaddrinfo(ai); + return error(&sym->location, + "Hostname resolves to multiple addresses"); + } + assert(ai->ai_addr->sa_family == AF_INET); + addr = ((struct sockaddr_in *) (void *) ai->ai_addr)->sin_addr; freeaddrinfo(ai); - return error(&sym->location, - "Hostname resolves to multiple addresses"); } - addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr; *res = constant_expr_alloc(&sym->location, &ipaddr_type, BYTEORDER_BIG_ENDIAN, - sizeof(*addr) * BITS_PER_BYTE, addr); - freeaddrinfo(ai); + sizeof(addr) * BITS_PER_BYTE, &addr); return NULL; } @@ -587,27 +668,35 @@ static struct error_record *ip6addr_type_parse(struct parse_ctx *ctx, const struct expr *sym, struct expr **res) { - struct addrinfo *ai, hints = { .ai_family = AF_INET6, - .ai_socktype = SOCK_DGRAM}; - struct in6_addr *addr; - int err; + struct in6_addr addr; + + if (nft_input_no_dns(ctx->input)) { + if (inet_pton(AF_INET6, sym->identifier, &addr) != 1) + return error(&sym->location, "Invalid IPv6 address"); + } else { + struct addrinfo *ai, hints = { .ai_family = AF_INET6, + .ai_socktype = SOCK_DGRAM}; + int err; - err = getaddrinfo(sym->identifier, NULL, &hints, &ai); - if (err != 0) - return error(&sym->location, "Could not resolve hostname: %s", - gai_strerror(err)); + err = getaddrinfo(sym->identifier, NULL, &hints, &ai); + if (err != 0) + return error(&sym->location, "Could not resolve hostname: %s", + gai_strerror(err)); + + if (ai->ai_next != NULL) { + freeaddrinfo(ai); + return error(&sym->location, + "Hostname resolves to multiple addresses"); + } - if (ai->ai_next != NULL) { + assert(ai->ai_addr->sa_family == AF_INET6); + addr = ((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_addr; freeaddrinfo(ai); - return error(&sym->location, - "Hostname resolves to multiple addresses"); } - addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; *res = constant_expr_alloc(&sym->location, &ip6addr_type, BYTEORDER_BIG_ENDIAN, - sizeof(*addr) * BITS_PER_BYTE, addr); - freeaddrinfo(ai); + sizeof(addr) * BITS_PER_BYTE, &addr); return NULL; } @@ -626,12 +715,12 @@ const struct datatype ip6addr_type = { static void inet_protocol_type_print(const struct expr *expr, struct output_ctx *octx) { - struct protoent *p; + if (!nft_output_numeric_proto(octx) && + mpz_cmp_ui(expr->value, UINT8_MAX) <= 0) { + char name[NFT_PROTONAME_MAXSIZE]; - if (!nft_output_numeric_proto(octx)) { - p = getprotobynumber(mpz_get_uint8(expr->value)); - if (p != NULL) { - nft_print(octx, "%s", p->p_name); + if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name))) { + nft_print(octx, "%s", name); return; } } @@ -640,15 +729,15 @@ static void inet_protocol_type_print(const struct expr *expr, static void inet_protocol_type_describe(struct output_ctx *octx) { - struct protoent *p; uint8_t protonum; for (protonum = 0; protonum < UINT8_MAX; protonum++) { - p = getprotobynumber(protonum); - if (!p) + char name[NFT_PROTONAME_MAXSIZE]; + + if (!nft_getprotobynumber(protonum, name, sizeof(name))) continue; - nft_print(octx, "\t%-30s\t%u\n", p->p_name, protonum); + nft_print(octx, "\t%-30s\t%u\n", name, protonum); } } @@ -656,7 +745,6 @@ static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx, const struct expr *sym, struct expr **res) { - struct protoent *p; uint8_t proto; uintmax_t i; char *end; @@ -669,11 +757,13 @@ static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx, proto = i; } else { - p = getprotobyname(sym->identifier); - if (p == NULL) + int r; + + r = nft_getprotobyname(sym->identifier); + if (r < 0) return error(&sym->location, "Could not resolve protocol name"); - proto = p->p_proto; + proto = r; } *res = constant_expr_alloc(&sym->location, &inet_protocol_type, @@ -697,17 +787,18 @@ const struct datatype inet_protocol_type = { static void inet_service_print(const struct expr *expr, struct output_ctx *octx) { uint16_t port = mpz_get_be16(expr->value); - const struct servent *s = getservbyport(port, NULL); + char name[NFT_SERVNAME_MAXSIZE]; - if (s == NULL) + if (!nft_getservbyport(port, NULL, name, sizeof(name))) nft_print(octx, "%hu", ntohs(port)); else - nft_print(octx, "\"%s\"", s->s_name); + nft_print(octx, "\"%s\"", name); } void inet_service_type_print(const struct expr *expr, struct output_ctx *octx) { - if (nft_output_service(octx)) { + if (nft_output_service(octx) && + mpz_cmp_ui(expr->value, UINT16_MAX) <= 0) { inet_service_print(expr, octx); return; } @@ -737,7 +828,12 @@ static struct error_record *inet_service_type_parse(struct parse_ctx *ctx, return error(&sym->location, "Could not resolve service: %s", gai_strerror(err)); - port = ((struct sockaddr_in *)ai->ai_addr)->sin_port; + if (ai->ai_addr->sa_family == AF_INET) { + port = ((struct sockaddr_in *)(void *)ai->ai_addr)->sin_port; + } else { + assert(ai->ai_addr->sa_family == AF_INET6); + port = ((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_port; + } freeaddrinfo(ai); } @@ -761,19 +857,48 @@ const struct datatype inet_service_type = { #define RT_SYM_TAB_INITIAL_SIZE 16 +static FILE *open_iproute2_db(const char *filename, char **path) +{ + FILE *ret; + + if (filename[0] == '/') + return fopen(filename, "r"); + + if (asprintf(path, "/etc/iproute2/%s", filename) == -1) + goto fail; + + ret = fopen(*path, "r"); + if (ret) + return ret; + + free(*path); + if (asprintf(path, "/usr/share/iproute2/%s", filename) == -1) + goto fail; + + ret = fopen(*path, "r"); + if (ret) + return ret; + + free(*path); +fail: + *path = NULL; + return NULL; +} + struct symbol_table *rt_symbol_table_init(const char *filename) { + char buf[512], namebuf[512], *p, *path = NULL; struct symbolic_constant s; struct symbol_table *tbl; unsigned int size, nelems, val; - char buf[512], namebuf[512], *p; FILE *f; size = RT_SYM_TAB_INITIAL_SIZE; tbl = xmalloc(sizeof(*tbl) + size * sizeof(s)); + tbl->base = BASE_DECIMAL; nelems = 0; - f = fopen(filename, "r"); + f = open_iproute2_db(filename, &path); if (f == NULL) goto out; @@ -783,12 +908,15 @@ struct symbol_table *rt_symbol_table_init(const char *filename) p++; if (*p == '#' || *p == '\n' || *p == '\0') continue; - if (sscanf(p, "0x%x %511s\n", &val, namebuf) != 2 && - sscanf(p, "0x%x %511s #", &val, namebuf) != 2 && - sscanf(p, "%u %511s\n", &val, namebuf) != 2 && - sscanf(p, "%u %511s #", &val, namebuf) != 2) { + if (sscanf(p, "0x%x %511s\n", &val, namebuf) == 2 || + sscanf(p, "0x%x %511s #", &val, namebuf) == 2) { + tbl->base = BASE_HEXADECIMAL; + } else if (sscanf(p, "%u %511s\n", &val, namebuf) == 2 || + sscanf(p, "%u %511s #", &val, namebuf) == 2) { + tbl->base = BASE_DECIMAL; + } else { fprintf(stderr, "iproute database '%s' corrupted\n", - filename); + path ?: filename); break; } @@ -805,6 +933,8 @@ struct symbol_table *rt_symbol_table_init(const char *filename) fclose(f); out: + if (path) + free(path); tbl->symbols[nelems] = SYMBOL_LIST_END; return tbl; } @@ -814,13 +944,40 @@ void rt_symbol_table_free(const struct symbol_table *tbl) const struct symbolic_constant *s; for (s = tbl->symbols; s->identifier != NULL; s++) - xfree(s->identifier); - xfree(tbl); + free_const(s->identifier); + free_const(tbl); +} + +void rt_symbol_table_describe(struct output_ctx *octx, const char *name, + const struct symbol_table *tbl, + const struct datatype *type) +{ + char *path = NULL; + FILE *f; + + if (!tbl || !tbl->symbols[0].identifier) + return; + + f = open_iproute2_db(name, &path); + if (f) + fclose(f); + if (!path && asprintf(&path, "%s%s", + name[0] == '/' ? "" : "unknown location of ", + name) < 0) + return; + + nft_print(octx, "\npre-defined symbolic constants from %s ", path); + if (tbl->base == BASE_DECIMAL) + nft_print(octx, "(in decimal):\n"); + else + nft_print(octx, "(in hexadecimal):\n"); + symbol_table_print(tbl, type, type->byteorder, octx); + free(path); } void mark_table_init(struct nft_ctx *ctx) { - ctx->output.tbl.mark = rt_symbol_table_init("/etc/iproute2/rt_marks"); + ctx->output.tbl.mark = rt_symbol_table_init("rt_marks"); } void mark_table_exit(struct nft_ctx *ctx) @@ -840,10 +997,17 @@ static struct error_record *mark_type_parse(struct parse_ctx *ctx, return symbolic_constant_parse(ctx, sym, ctx->tbl->mark, res); } +static void mark_type_describe(struct output_ctx *octx) +{ + rt_symbol_table_describe(octx, "rt_marks", + octx->tbl.mark, &mark_type); +} + const struct datatype mark_type = { .type = TYPE_MARK, .name = "mark", .desc = "packet mark", + .describe = mark_type_describe, .size = 4 * BITS_PER_BYTE, .byteorder = BYTEORDER_HOST_ENDIAN, .basetype = &integer_type, @@ -851,9 +1015,9 @@ const struct datatype mark_type = { .print = mark_type_print, .json = mark_type_json, .parse = mark_type_parse, - .flags = DTYPE_F_PREFIX, }; +/* symbol table for private datatypes for reject statement. */ static const struct symbol_table icmp_code_tbl = { .base = BASE_DECIMAL, .symbols = { @@ -869,16 +1033,17 @@ static const struct symbol_table icmp_code_tbl = { }, }; -const struct datatype icmp_code_type = { - .type = TYPE_ICMP_CODE, +/* private datatype for reject statement. */ +const struct datatype reject_icmp_code_type = { .name = "icmp_code", - .desc = "icmp code", + .desc = "reject icmp code", .size = BITS_PER_BYTE, .byteorder = BYTEORDER_BIG_ENDIAN, .basetype = &integer_type, .sym_tbl = &icmp_code_tbl, }; +/* symbol table for private datatypes for reject statement. */ static const struct symbol_table icmpv6_code_tbl = { .base = BASE_DECIMAL, .symbols = { @@ -892,16 +1057,17 @@ static const struct symbol_table icmpv6_code_tbl = { }, }; -const struct datatype icmpv6_code_type = { - .type = TYPE_ICMPV6_CODE, +/* private datatype for reject statement. */ +const struct datatype reject_icmpv6_code_type = { .name = "icmpv6_code", - .desc = "icmpv6 code", + .desc = "reject icmpv6 code", .size = BITS_PER_BYTE, .byteorder = BYTEORDER_BIG_ENDIAN, .basetype = &integer_type, .sym_tbl = &icmpv6_code_tbl, }; +/* symbol table for private datatypes for reject statement. */ static const struct symbol_table icmpx_code_tbl = { .base = BASE_DECIMAL, .symbols = { @@ -913,6 +1079,60 @@ static const struct symbol_table icmpx_code_tbl = { }, }; +/* private datatype for reject statement. */ +const struct datatype reject_icmpx_code_type = { + .name = "icmpx_code", + .desc = "reject icmpx code", + .size = BITS_PER_BYTE, + .byteorder = BYTEORDER_BIG_ENDIAN, + .basetype = &integer_type, + .sym_tbl = &icmpx_code_tbl, +}; + +/* Backward compatible parser for the reject statement. */ +static struct error_record *icmp_code_parse(struct parse_ctx *ctx, + const struct expr *sym, + struct expr **res) +{ + return symbolic_constant_parse(ctx, sym, &icmp_code_tbl, res); +} + +const struct datatype icmp_code_type = { + .type = TYPE_ICMP_CODE, + .name = "icmp_code", + .desc = "icmp code", + .size = BITS_PER_BYTE, + .byteorder = BYTEORDER_BIG_ENDIAN, + .basetype = &integer_type, + .parse = icmp_code_parse, +}; + +/* Backward compatible parser for the reject statement. */ +static struct error_record *icmpv6_code_parse(struct parse_ctx *ctx, + const struct expr *sym, + struct expr **res) +{ + return symbolic_constant_parse(ctx, sym, &icmpv6_code_tbl, res); +} + +const struct datatype icmpv6_code_type = { + .type = TYPE_ICMPV6_CODE, + .name = "icmpv6_code", + .desc = "icmpv6 code", + .size = BITS_PER_BYTE, + .byteorder = BYTEORDER_BIG_ENDIAN, + .basetype = &integer_type, + .parse = icmpv6_code_parse, +}; + +/* Backward compatible parser for the reject statement. */ +static struct error_record *icmpx_code_parse(struct parse_ctx *ctx, + const struct expr *sym, + struct expr **res) +{ + return symbolic_constant_parse(ctx, sym, &icmpx_code_tbl, res); +} + const struct datatype icmpx_code_type = { .type = TYPE_ICMPX_CODE, .name = "icmpx_code", @@ -920,12 +1140,13 @@ const struct datatype icmpx_code_type = { .size = BITS_PER_BYTE, .byteorder = BYTEORDER_BIG_ENDIAN, .basetype = &integer_type, - .sym_tbl = &icmpx_code_tbl, + .parse = icmpx_code_parse, }; void time_print(uint64_t ms, struct output_ctx *octx) { uint64_t days, hours, minutes, seconds; + bool printed = false; if (nft_output_seconds(octx)) { nft_print(octx, "%" PRIu64 "s", ms / 1000); @@ -944,16 +1165,29 @@ void time_print(uint64_t ms, struct output_ctx *octx) seconds = ms / 1000; ms %= 1000; - if (days > 0) + if (days > 0) { nft_print(octx, "%" PRIu64 "d", days); - if (hours > 0) + printed = true; + } + if (hours > 0) { nft_print(octx, "%" PRIu64 "h", hours); - if (minutes > 0) + printed = true; + } + if (minutes > 0) { nft_print(octx, "%" PRIu64 "m", minutes); - if (seconds > 0) + printed = true; + } + if (seconds > 0) { nft_print(octx, "%" PRIu64 "s", seconds); - if (ms > 0) + printed = true; + } + if (ms > 0) { nft_print(octx, "%" PRIu64 "ms", ms); + printed = true; + } + + if (!printed) + nft_print(octx, "0s"); } enum { @@ -1105,17 +1339,18 @@ static struct error_record *concat_type_parse(struct parse_ctx *ctx, sym->dtype->desc); } -static struct datatype *dtype_alloc(void) +static struct datatype *datatype_alloc(void) { struct datatype *dtype; dtype = xzalloc(sizeof(*dtype)); dtype->flags = DTYPE_F_ALLOC; + dtype->refcnt = 1; return dtype; } -struct datatype *datatype_get(const struct datatype *ptr) +const struct datatype *datatype_get(const struct datatype *ptr) { struct datatype *dtype = (struct datatype *)ptr; @@ -1128,24 +1363,31 @@ struct datatype *datatype_get(const struct datatype *ptr) return dtype; } +void __datatype_set(struct expr *expr, const struct datatype *dtype) +{ + const struct datatype *dtype_free; + + dtype_free = expr->dtype; + expr->dtype = dtype; + datatype_free(dtype_free); +} + void datatype_set(struct expr *expr, const struct datatype *dtype) { - if (dtype == expr->dtype) - return; - datatype_free(expr->dtype); - expr->dtype = datatype_get(dtype); + if (dtype != expr->dtype) + __datatype_set(expr, datatype_get(dtype)); } -struct datatype *dtype_clone(const struct datatype *orig_dtype) +struct datatype *datatype_clone(const struct datatype *orig_dtype) { struct datatype *dtype; - dtype = xzalloc(sizeof(*dtype)); + dtype = xmalloc(sizeof(*dtype)); *dtype = *orig_dtype; dtype->name = xstrdup(orig_dtype->name); dtype->desc = xstrdup(orig_dtype->desc); dtype->flags = DTYPE_F_ALLOC | orig_dtype->flags; - dtype->refcnt = 0; + dtype->refcnt = 1; return dtype; } @@ -1158,12 +1400,15 @@ void datatype_free(const struct datatype *ptr) return; if (!(dtype->flags & DTYPE_F_ALLOC)) return; + + assert(dtype->refcnt != 0); + if (--dtype->refcnt > 0) return; - xfree(dtype->name); - xfree(dtype->desc); - xfree(dtype); + free_const(dtype->name); + free_const(dtype->desc); + free(dtype); } const struct datatype *concat_type_alloc(uint32_t type) @@ -1192,7 +1437,7 @@ const struct datatype *concat_type_alloc(uint32_t type) } strncat(desc, ")", sizeof(desc) - strlen(desc) - 1); - dtype = dtype_alloc(); + dtype = datatype_alloc(); dtype->type = type; dtype->size = size; dtype->subtypes = subtypes; @@ -1204,15 +1449,15 @@ const struct datatype *concat_type_alloc(uint32_t type) } const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype, - unsigned int byteorder) + enum byteorder byteorder) { struct datatype *dtype; /* Restrict dynamic datatype allocation to generic integer datatype. */ if (orig_dtype != &integer_type) - return orig_dtype; + return datatype_get(orig_dtype); - dtype = dtype_clone(orig_dtype); + dtype = datatype_clone(orig_dtype); dtype->byteorder = byteorder; return dtype; @@ -1360,10 +1605,10 @@ const struct datatype policy_type = { #define SYSFS_CGROUPSV2_PATH "/sys/fs/cgroup" -static const char *cgroupv2_get_path(const char *path, uint64_t id) +static char *cgroupv2_get_path(const char *path, uint64_t id) { - const char *cgroup_path = NULL; char dent_name[PATH_MAX + 1]; + char *cgroup_path = NULL; struct dirent *dent; struct stat st; DIR *d; @@ -1401,7 +1646,7 @@ static void cgroupv2_type_print(const struct expr *expr, struct output_ctx *octx) { uint64_t id = mpz_get_uint64(expr->value); - const char *cgroup_path; + char *cgroup_path; cgroup_path = cgroupv2_get_path(SYSFS_CGROUPSV2_PATH, id); if (cgroup_path) @@ -1410,7 +1655,7 @@ static void cgroupv2_type_print(const struct expr *expr, else nft_print(octx, "%" PRIu64, id); - xfree(cgroup_path); + free(cgroup_path); } static struct error_record *cgroupv2_type_parse(struct parse_ctx *ctx, |