|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <inttypes.h>
|
|
Packit |
c5a612 |
#include <ctype.h> /* isdigit */
|
|
Packit |
c5a612 |
#include <errno.h>
|
|
Packit |
c5a612 |
#include <netdb.h>
|
|
Packit |
c5a612 |
#include <arpa/inet.h>
|
|
Packit |
c5a612 |
#include <linux/types.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter.h>
|
|
Packit |
c5a612 |
#include <linux/icmpv6.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <nftables.h>
|
|
Packit |
c5a612 |
#include <datatype.h>
|
|
Packit |
c5a612 |
#include <expression.h>
|
|
Packit |
c5a612 |
#include <gmputil.h>
|
|
Packit |
c5a612 |
#include <erec.h>
|
|
Packit |
c5a612 |
#include <netlink.h>
|
|
Packit |
c5a612 |
#include <json.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <netinet/ip_icmp.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct datatype *datatypes[TYPE_MAX + 1] = {
|
|
Packit |
c5a612 |
[TYPE_INVALID] = &invalid_type,
|
|
Packit |
c5a612 |
[TYPE_VERDICT] = &verdict_type,
|
|
Packit |
c5a612 |
[TYPE_NFPROTO] = &nfproto_type,
|
|
Packit |
c5a612 |
[TYPE_BITMASK] = &bitmask_type,
|
|
Packit |
c5a612 |
[TYPE_INTEGER] = &integer_type,
|
|
Packit |
c5a612 |
[TYPE_STRING] = &string_type,
|
|
Packit |
c5a612 |
[TYPE_LLADDR] = &lladdr_type,
|
|
Packit |
c5a612 |
[TYPE_IPADDR] = &ipaddr_type,
|
|
Packit |
c5a612 |
[TYPE_IP6ADDR] = &ip6addr_type,
|
|
Packit |
c5a612 |
[TYPE_ETHERADDR] = ðeraddr_type,
|
|
Packit |
c5a612 |
[TYPE_ETHERTYPE] = ðertype_type,
|
|
Packit |
c5a612 |
[TYPE_ARPOP] = &arpop_type,
|
|
Packit |
c5a612 |
[TYPE_INET_PROTOCOL] = &inet_protocol_type,
|
|
Packit |
c5a612 |
[TYPE_INET_SERVICE] = &inet_service_type,
|
|
Packit |
c5a612 |
[TYPE_ICMP_TYPE] = &icmp_type_type,
|
|
Packit |
c5a612 |
[TYPE_TCP_FLAG] = &tcp_flag_type,
|
|
Packit |
c5a612 |
[TYPE_DCCP_PKTTYPE] = &dccp_pkttype_type,
|
|
Packit |
c5a612 |
[TYPE_MH_TYPE] = &mh_type_type,
|
|
Packit |
c5a612 |
[TYPE_TIME] = &time_type,
|
|
Packit |
c5a612 |
[TYPE_MARK] = &mark_type,
|
|
Packit |
c5a612 |
[TYPE_IFINDEX] = &ifindex_type,
|
|
Packit |
c5a612 |
[TYPE_ARPHRD] = &arphrd_type,
|
|
Packit |
c5a612 |
[TYPE_REALM] = &realm_type,
|
|
Packit |
c5a612 |
[TYPE_CLASSID] = &tchandle_type,
|
|
Packit |
c5a612 |
[TYPE_UID] = &uid_type,
|
|
Packit |
c5a612 |
[TYPE_GID] = &gid_type,
|
|
Packit |
c5a612 |
[TYPE_CT_STATE] = &ct_state_type,
|
|
Packit |
c5a612 |
[TYPE_CT_DIR] = &ct_dir_type,
|
|
Packit |
c5a612 |
[TYPE_CT_STATUS] = &ct_status_type,
|
|
Packit |
c5a612 |
[TYPE_ICMP6_TYPE] = &icmp6_type_type,
|
|
Packit |
c5a612 |
[TYPE_PKTTYPE] = &pkttype_type,
|
|
Packit |
c5a612 |
[TYPE_ICMP_CODE] = &icmp_code_type,
|
|
Packit |
c5a612 |
[TYPE_ICMPV6_CODE] = &icmpv6_code_type,
|
|
Packit |
c5a612 |
[TYPE_ICMPX_CODE] = &icmpx_code_type,
|
|
Packit |
c5a612 |
[TYPE_DEVGROUP] = &devgroup_type,
|
|
Packit |
c5a612 |
[TYPE_DSCP] = &dscp_type,
|
|
Packit |
c5a612 |
[TYPE_ECN] = &ecn_type,
|
|
Packit |
c5a612 |
[TYPE_FIB_ADDR] = &fib_addr_type,
|
|
Packit |
c5a612 |
[TYPE_BOOLEAN] = &boolean_type,
|
|
Packit |
c5a612 |
[TYPE_IFNAME] = &ifname_type,
|
|
Packit |
c5a612 |
[TYPE_IGMP_TYPE] = &igmp_type_type,
|
|
Packit |
c5a612 |
[TYPE_TIME_DATE] = &date_type,
|
|
Packit |
c5a612 |
[TYPE_TIME_HOUR] = &hour_type,
|
|
Packit |
c5a612 |
[TYPE_TIME_DAY] = &day_type,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype *datatype_lookup(enum datatypes type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
BUILD_BUG_ON(TYPE_MAX & ~TYPE_MASK);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (type > TYPE_MAX)
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
return datatypes[type];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype *datatype_lookup_byname(const char *name)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct datatype *dtype;
|
|
Packit |
c5a612 |
enum datatypes type;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (type = TYPE_INVALID; type <= TYPE_MAX; type++) {
|
|
Packit |
c5a612 |
dtype = datatypes[type];
|
|
Packit |
c5a612 |
if (dtype == NULL)
|
|
Packit |
c5a612 |
continue;
|
|
Packit |
c5a612 |
if (!strcmp(dtype->name, name))
|
|
Packit |
c5a612 |
return dtype;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void datatype_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct datatype *dtype = expr->dtype;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
do {
|
|
Packit |
c5a612 |
if (dtype->print != NULL)
|
|
Packit |
c5a612 |
return dtype->print(expr, octx);
|
|
Packit |
c5a612 |
if (dtype->sym_tbl != NULL)
|
|
Packit |
c5a612 |
return symbolic_constant_print(dtype->sym_tbl, expr,
|
|
Packit |
c5a612 |
false, octx);
|
|
Packit |
c5a612 |
} while ((dtype = dtype->basetype));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
BUG("datatype %s has no print method or symbol table\n",
|
|
Packit |
c5a612 |
expr->dtype->name);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct error_record *symbol_parse(struct parse_ctx *ctx, const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct datatype *dtype = sym->dtype;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
assert(sym->etype == EXPR_SYMBOL);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (dtype == NULL)
|
|
Packit |
c5a612 |
return error(&sym->location, "No symbol type information");
|
|
Packit |
c5a612 |
do {
|
|
Packit |
c5a612 |
if (dtype->parse != NULL)
|
|
Packit |
c5a612 |
return dtype->parse(ctx, sym, res);
|
|
Packit |
c5a612 |
if (dtype->sym_tbl != NULL)
|
|
Packit |
c5a612 |
return symbolic_constant_parse(ctx, sym, dtype->sym_tbl,
|
|
Packit |
c5a612 |
res);
|
|
Packit |
c5a612 |
} while ((dtype = dtype->basetype));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return error(&sym->location,
|
|
Packit |
c5a612 |
"Can't parse symbolic %s expressions",
|
|
Packit |
c5a612 |
sym->dtype->desc);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct error_record *symbolic_constant_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
const struct symbol_table *tbl,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct symbolic_constant *s;
|
|
Packit |
c5a612 |
const struct datatype *dtype;
|
|
Packit |
c5a612 |
struct error_record *erec;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (s = tbl->symbols; s->identifier != NULL; s++) {
|
|
Packit |
c5a612 |
if (!strcmp(sym->identifier, s->identifier))
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (s->identifier != NULL)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dtype = sym->dtype;
|
|
Packit |
c5a612 |
*res = NULL;
|
|
Packit |
c5a612 |
do {
|
|
Packit |
c5a612 |
if (dtype->basetype->parse) {
|
|
Packit |
c5a612 |
erec = dtype->basetype->parse(ctx, sym, res);
|
|
Packit |
c5a612 |
if (erec != NULL)
|
|
Packit |
c5a612 |
return erec;
|
|
Packit |
c5a612 |
if (*res)
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
} while ((dtype = dtype->basetype));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return error(&sym->location, "Could not parse %s", sym->dtype->desc);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, sym->dtype,
|
|
Packit |
c5a612 |
sym->dtype->byteorder, sym->dtype->size,
|
|
Packit |
c5a612 |
constant_data_ptr(s->value,
|
|
Packit |
c5a612 |
sym->dtype->size));
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void symbolic_constant_print(const struct symbol_table *tbl,
|
|
Packit |
c5a612 |
const struct expr *expr, bool quotes,
|
|
Packit |
c5a612 |
struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
const struct symbolic_constant *s;
|
|
Packit |
c5a612 |
uint64_t val = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* Export the data in the correct byteorder for comparison */
|
|
Packit |
c5a612 |
assert(expr->len / BITS_PER_BYTE <= sizeof(val));
|
|
Packit |
c5a612 |
mpz_export_data(constant_data_ptr(val, expr->len), expr->value,
|
|
Packit |
c5a612 |
expr->byteorder, len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (s = tbl->symbols; s->identifier != NULL; s++) {
|
|
Packit |
c5a612 |
if (val == s->value)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (s->identifier == NULL || nft_output_numeric_symbol(octx))
|
|
Packit |
c5a612 |
return expr_basetype(expr)->print(expr, octx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_print(octx, quotes ? "\"%s\"" : "%s", s->identifier);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void switch_byteorder(void *data, unsigned int len)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
mpz_t op;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_init(op);
|
|
Packit |
c5a612 |
mpz_import_data(op, data, BYTEORDER_BIG_ENDIAN, len);
|
|
Packit |
c5a612 |
mpz_export_data(data, op, BYTEORDER_HOST_ENDIAN, len);
|
|
Packit |
c5a612 |
mpz_clear(op);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void symbol_table_print(const struct symbol_table *tbl,
|
|
Packit |
c5a612 |
const struct datatype *dtype,
|
|
Packit |
c5a612 |
enum byteorder byteorder,
|
|
Packit |
c5a612 |
struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int len = div_round_up(dtype->size, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
const struct symbolic_constant *s;
|
|
Packit |
c5a612 |
uint64_t value;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (s = tbl->symbols; s->identifier != NULL; s++) {
|
|
Packit |
c5a612 |
value = s->value;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (byteorder == BYTEORDER_BIG_ENDIAN)
|
|
Packit |
c5a612 |
switch_byteorder(&value, len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (tbl->base == BASE_DECIMAL)
|
|
Packit |
c5a612 |
nft_print(octx, "\t%-30s\t%20" PRIu64 "\n",
|
|
Packit |
c5a612 |
s->identifier, value);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
nft_print(octx, "\t%-30s\t0x%.*" PRIx64 "\n",
|
|
Packit |
c5a612 |
s->identifier, 2 * len, value);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void invalid_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nft_gmp_print(octx, "0x%Zx [invalid type]", expr->value);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype invalid_type = {
|
|
Packit |
c5a612 |
.type = TYPE_INVALID,
|
|
Packit |
c5a612 |
.name = "invalid",
|
|
Packit |
c5a612 |
.desc = "invalid",
|
|
Packit |
c5a612 |
.print = invalid_type_print,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void verdict_jump_chain_print(const char *what, const struct expr *e,
|
|
Packit |
c5a612 |
struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char chain[NFT_CHAIN_MAXNAMELEN];
|
|
Packit |
c5a612 |
unsigned int len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
memset(chain, 0, sizeof(chain));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
len = e->len / BITS_PER_BYTE;
|
|
Packit |
c5a612 |
if (len >= sizeof(chain))
|
|
Packit |
c5a612 |
BUG("verdict expression length %u is too large (%lu bits max)",
|
|
Packit |
c5a612 |
e->len, (unsigned long)sizeof(chain) * BITS_PER_BYTE);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_export_data(chain, e->value, BYTEORDER_HOST_ENDIAN, len);
|
|
Packit |
c5a612 |
nft_print(octx, "%s %s", what, chain);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void verdict_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (expr->verdict) {
|
|
Packit |
c5a612 |
case NFT_CONTINUE:
|
|
Packit |
c5a612 |
nft_print(octx, "continue");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_BREAK:
|
|
Packit |
c5a612 |
nft_print(octx, "break");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_JUMP:
|
|
Packit |
c5a612 |
if (expr->chain->etype == EXPR_VALUE) {
|
|
Packit |
c5a612 |
verdict_jump_chain_print("jump", expr->chain, octx);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
nft_print(octx, "jump ");
|
|
Packit |
c5a612 |
expr_print(expr->chain, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_GOTO:
|
|
Packit |
c5a612 |
if (expr->chain->etype == EXPR_VALUE) {
|
|
Packit |
c5a612 |
verdict_jump_chain_print("goto", expr->chain, octx);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
nft_print(octx, "goto ");
|
|
Packit |
c5a612 |
expr_print(expr->chain, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_RETURN:
|
|
Packit |
c5a612 |
nft_print(octx, "return");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
switch (expr->verdict & NF_VERDICT_MASK) {
|
|
Packit |
c5a612 |
case NF_ACCEPT:
|
|
Packit |
c5a612 |
nft_print(octx, "accept");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NF_DROP:
|
|
Packit |
c5a612 |
nft_print(octx, "drop");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NF_QUEUE:
|
|
Packit |
c5a612 |
nft_print(octx, "queue");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NF_STOLEN:
|
|
Packit |
c5a612 |
nft_print(octx, "stolen");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
nft_print(octx, "unknown verdict value %u", expr->verdict);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *verdict_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &string_type,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
(strlen(sym->identifier) + 1) * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
sym->identifier);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype verdict_type = {
|
|
Packit |
c5a612 |
.type = TYPE_VERDICT,
|
|
Packit |
c5a612 |
.name = "verdict",
|
|
Packit |
c5a612 |
.desc = "netfilter verdict",
|
|
Packit |
c5a612 |
.print = verdict_type_print,
|
|
Packit |
c5a612 |
.parse = verdict_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct symbol_table nfproto_tbl = {
|
|
Packit |
c5a612 |
.base = BASE_DECIMAL,
|
|
Packit |
c5a612 |
.symbols = {
|
|
Packit |
c5a612 |
SYMBOL("ipv4", NFPROTO_IPV4),
|
|
Packit |
c5a612 |
SYMBOL("ipv6", NFPROTO_IPV6),
|
|
Packit |
c5a612 |
SYMBOL_LIST_END
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype nfproto_type = {
|
|
Packit |
c5a612 |
.type = TYPE_NFPROTO,
|
|
Packit |
c5a612 |
.name = "nf_proto",
|
|
Packit |
c5a612 |
.desc = "netfilter protocol",
|
|
Packit |
c5a612 |
.size = 1 * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.sym_tbl = &nfproto_tbl,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype bitmask_type = {
|
|
Packit |
c5a612 |
.type = TYPE_BITMASK,
|
|
Packit |
c5a612 |
.name = "bitmask",
|
|
Packit |
c5a612 |
.desc = "bitmask",
|
|
Packit |
c5a612 |
.basefmt = "0x%Zx",
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void integer_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct datatype *dtype = expr->dtype;
|
|
Packit |
c5a612 |
const char *fmt = "%Zu";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
do {
|
|
Packit |
c5a612 |
if (dtype->basefmt != NULL) {
|
|
Packit |
c5a612 |
fmt = dtype->basefmt;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
} while ((dtype = dtype->basetype));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_gmp_print(octx, fmt, expr->value);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *integer_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
mpz_t v;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_init(v);
|
|
Packit |
c5a612 |
if (mpz_set_str(v, sym->identifier, 0)) {
|
|
Packit |
c5a612 |
mpz_clear(v);
|
|
Packit |
c5a612 |
return error(&sym->location, "Could not parse %s",
|
|
Packit |
c5a612 |
sym->dtype->desc);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, sym->dtype,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN, 1, NULL);
|
|
Packit |
c5a612 |
mpz_set((*res)->value, v);
|
|
Packit |
c5a612 |
mpz_clear(v);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype integer_type = {
|
|
Packit |
c5a612 |
.type = TYPE_INTEGER,
|
|
Packit |
c5a612 |
.name = "integer",
|
|
Packit |
c5a612 |
.desc = "integer",
|
|
Packit |
c5a612 |
.print = integer_type_print,
|
|
Packit |
c5a612 |
.json = integer_type_json,
|
|
Packit |
c5a612 |
.parse = integer_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void string_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
char data[len+1];
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
|
|
Packit |
c5a612 |
data[len] = '\0';
|
|
Packit |
c5a612 |
nft_print(octx, "\"%s\"", data);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *string_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &string_type,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
(strlen(sym->identifier) + 1) * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
sym->identifier);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype string_type = {
|
|
Packit |
c5a612 |
.type = TYPE_STRING,
|
|
Packit |
c5a612 |
.name = "string",
|
|
Packit |
c5a612 |
.desc = "string",
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
.print = string_type_print,
|
|
Packit |
c5a612 |
.json = string_type_json,
|
|
Packit |
c5a612 |
.parse = string_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void lladdr_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
const char *delim = "";
|
|
Packit |
c5a612 |
uint8_t data[len];
|
|
Packit |
c5a612 |
unsigned int i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_export_data(data, expr->value, BYTEORDER_BIG_ENDIAN, len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; i < len; i++) {
|
|
Packit |
c5a612 |
nft_print(octx, "%s%.2x", delim, data[i]);
|
|
Packit |
c5a612 |
delim = ":";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *lladdr_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[strlen(sym->identifier) + 1], *p;
|
|
Packit |
c5a612 |
const char *s = sym->identifier;
|
|
Packit |
c5a612 |
unsigned int len, n;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (len = 0;;) {
|
|
Packit |
c5a612 |
n = strtoul(s, &p, 16);
|
|
Packit |
c5a612 |
if (s == p || n > 0xff)
|
|
Packit |
c5a612 |
return erec_create(EREC_ERROR, &sym->location,
|
|
Packit |
c5a612 |
"Invalid LL address");
|
|
Packit |
c5a612 |
buf[len++] = n;
|
|
Packit |
c5a612 |
if (*p == '\0')
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
s = ++p;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, sym->dtype,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN, len * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
buf);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype lladdr_type = {
|
|
Packit |
c5a612 |
.type = TYPE_LLADDR,
|
|
Packit |
c5a612 |
.name = "ll_addr",
|
|
Packit |
c5a612 |
.desc = "link layer address",
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.print = lladdr_type_print,
|
|
Packit |
c5a612 |
.parse = lladdr_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void ipaddr_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct sockaddr_in sin = { .sin_family = AF_INET, };
|
|
Packit |
c5a612 |
char buf[NI_MAXHOST];
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sin.sin_addr.s_addr = mpz_get_be32(expr->value);
|
|
Packit |
c5a612 |
err = getnameinfo((struct sockaddr *)&sin, sizeof(sin), buf,
|
|
Packit |
c5a612 |
sizeof(buf), NULL, 0,
|
|
Packit |
c5a612 |
nft_output_reversedns(octx) ? 0 : NI_NUMERICHOST);
|
|
Packit |
c5a612 |
if (err != 0) {
|
|
Packit |
c5a612 |
getnameinfo((struct sockaddr *)&sin, sizeof(sin), buf,
|
|
Packit |
c5a612 |
sizeof(buf), NULL, 0, NI_NUMERICHOST);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_print(octx, "%s", buf);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *ipaddr_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct addrinfo *ai, hints = { .ai_family = AF_INET,
|
|
Packit |
c5a612 |
.ai_socktype = SOCK_DGRAM};
|
|
Packit |
c5a612 |
struct in_addr *addr;
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err = getaddrinfo(sym->identifier, NULL, &hints, &ai;;
|
|
Packit |
c5a612 |
if (err != 0)
|
|
Packit |
c5a612 |
return error(&sym->location, "Could not resolve hostname: %s",
|
|
Packit |
c5a612 |
gai_strerror(err));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (ai->ai_next != NULL) {
|
|
Packit |
c5a612 |
freeaddrinfo(ai);
|
|
Packit |
c5a612 |
return error(&sym->location,
|
|
Packit |
c5a612 |
"Hostname resolves to multiple addresses");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &ipaddr_type,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
sizeof(*addr) * BITS_PER_BYTE, addr);
|
|
Packit |
c5a612 |
freeaddrinfo(ai);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype ipaddr_type = {
|
|
Packit |
c5a612 |
.type = TYPE_IPADDR,
|
|
Packit |
c5a612 |
.name = "ipv4_addr",
|
|
Packit |
c5a612 |
.desc = "IPv4 address",
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.size = 4 * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.print = ipaddr_type_print,
|
|
Packit |
c5a612 |
.parse = ipaddr_type_parse,
|
|
Packit |
c5a612 |
.flags = DTYPE_F_PREFIX,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void ip6addr_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
|
|
Packit |
c5a612 |
char buf[NI_MAXHOST];
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_export_data(&sin6.sin6_addr, expr->value, BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
sizeof(sin6.sin6_addr));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), buf,
|
|
Packit |
c5a612 |
sizeof(buf), NULL, 0,
|
|
Packit |
c5a612 |
nft_output_reversedns(octx) ? 0 : NI_NUMERICHOST);
|
|
Packit |
c5a612 |
if (err != 0) {
|
|
Packit |
c5a612 |
getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), buf,
|
|
Packit |
c5a612 |
sizeof(buf), NULL, 0, NI_NUMERICHOST);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_print(octx, "%s", buf);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *ip6addr_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct addrinfo *ai, hints = { .ai_family = AF_INET6,
|
|
Packit |
c5a612 |
.ai_socktype = SOCK_DGRAM};
|
|
Packit |
c5a612 |
struct in6_addr *addr;
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err = getaddrinfo(sym->identifier, NULL, &hints, &ai;;
|
|
Packit |
c5a612 |
if (err != 0)
|
|
Packit |
c5a612 |
return error(&sym->location, "Could not resolve hostname: %s",
|
|
Packit |
c5a612 |
gai_strerror(err));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (ai->ai_next != NULL) {
|
|
Packit |
c5a612 |
freeaddrinfo(ai);
|
|
Packit |
c5a612 |
return error(&sym->location,
|
|
Packit |
c5a612 |
"Hostname resolves to multiple addresses");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &ip6addr_type,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
sizeof(*addr) * BITS_PER_BYTE, addr);
|
|
Packit |
c5a612 |
freeaddrinfo(ai);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype ip6addr_type = {
|
|
Packit |
c5a612 |
.type = TYPE_IP6ADDR,
|
|
Packit |
c5a612 |
.name = "ipv6_addr",
|
|
Packit |
c5a612 |
.desc = "IPv6 address",
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.size = 16 * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.print = ip6addr_type_print,
|
|
Packit |
c5a612 |
.parse = ip6addr_type_parse,
|
|
Packit |
c5a612 |
.flags = DTYPE_F_PREFIX,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void inet_protocol_type_print(const struct expr *expr,
|
|
Packit |
c5a612 |
struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct protoent *p;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!nft_output_numeric_proto(octx)) {
|
|
Packit |
c5a612 |
p = getprotobynumber(mpz_get_uint8(expr->value));
|
|
Packit |
c5a612 |
if (p != NULL) {
|
|
Packit |
c5a612 |
nft_print(octx, "%s", p->p_name);
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
integer_type_print(expr, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct protoent *p;
|
|
Packit |
c5a612 |
uint8_t proto;
|
|
Packit |
c5a612 |
uintmax_t i;
|
|
Packit |
c5a612 |
char *end;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
errno = 0;
|
|
Packit |
c5a612 |
i = strtoumax(sym->identifier, &end, 0);
|
|
Packit |
c5a612 |
if (sym->identifier != end && *end == '\0') {
|
|
Packit |
c5a612 |
if (errno == ERANGE || i > UINT8_MAX)
|
|
Packit |
c5a612 |
return error(&sym->location, "Protocol out of range");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
proto = i;
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
p = getprotobyname(sym->identifier);
|
|
Packit |
c5a612 |
if (p == NULL)
|
|
Packit |
c5a612 |
return error(&sym->location, "Could not resolve protocol name");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
proto = p->p_proto;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &inet_protocol_type,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN, BITS_PER_BYTE,
|
|
Packit |
c5a612 |
&proto);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype inet_protocol_type = {
|
|
Packit |
c5a612 |
.type = TYPE_INET_PROTOCOL,
|
|
Packit |
c5a612 |
.name = "inet_proto",
|
|
Packit |
c5a612 |
.desc = "Internet protocol",
|
|
Packit |
c5a612 |
.size = BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.print = inet_protocol_type_print,
|
|
Packit |
c5a612 |
.json = inet_protocol_type_json,
|
|
Packit |
c5a612 |
.parse = inet_protocol_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void inet_service_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct sockaddr_in sin = { .sin_family = AF_INET };
|
|
Packit |
c5a612 |
char buf[NI_MAXSERV];
|
|
Packit |
c5a612 |
uint16_t port;
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sin.sin_port = mpz_get_be16(expr->value);
|
|
Packit |
c5a612 |
err = getnameinfo((struct sockaddr *)&sin, sizeof(sin), NULL, 0,
|
|
Packit |
c5a612 |
buf, sizeof(buf), 0);
|
|
Packit |
c5a612 |
if (err != 0) {
|
|
Packit |
c5a612 |
nft_print(octx, "%u", ntohs(sin.sin_port));
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
port = atoi(buf);
|
|
Packit |
c5a612 |
/* We got a TCP service name string, display it... */
|
|
Packit |
c5a612 |
if (htons(port) != sin.sin_port) {
|
|
Packit |
c5a612 |
nft_print(octx, "\"%s\"", buf);
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* ...otherwise, this might be a UDP service name. */
|
|
Packit |
c5a612 |
err = getnameinfo((struct sockaddr *)&sin, sizeof(sin), NULL, 0,
|
|
Packit |
c5a612 |
buf, sizeof(buf), NI_DGRAM);
|
|
Packit |
c5a612 |
if (err != 0) {
|
|
Packit |
c5a612 |
/* No service name, display numeric value. */
|
|
Packit |
c5a612 |
nft_print(octx, "%u", ntohs(sin.sin_port));
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_print(octx, "\"%s\"", buf);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void inet_service_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (nft_output_service(octx)) {
|
|
Packit |
c5a612 |
inet_service_print(expr, octx);
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
integer_type_print(expr, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *inet_service_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct addrinfo *ai;
|
|
Packit |
c5a612 |
uint16_t port;
|
|
Packit |
c5a612 |
uintmax_t i;
|
|
Packit |
c5a612 |
char *end;
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
errno = 0;
|
|
Packit |
c5a612 |
i = strtoumax(sym->identifier, &end, 0);
|
|
Packit |
c5a612 |
if (sym->identifier != end && *end == '\0') {
|
|
Packit |
c5a612 |
if (errno == ERANGE || i > UINT16_MAX)
|
|
Packit |
c5a612 |
return error(&sym->location, "Service out of range");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
port = htons(i);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
err = getaddrinfo(NULL, sym->identifier, NULL, &ai;;
|
|
Packit |
c5a612 |
if (err != 0)
|
|
Packit |
c5a612 |
return error(&sym->location, "Could not resolve service: %s",
|
|
Packit |
c5a612 |
gai_strerror(err));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
|
|
Packit |
c5a612 |
freeaddrinfo(ai);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &inet_service_type,
|
|
Packit |
c5a612 |
BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
sizeof(port) * BITS_PER_BYTE, &port);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype inet_service_type = {
|
|
Packit |
c5a612 |
.type = TYPE_INET_SERVICE,
|
|
Packit |
c5a612 |
.name = "inet_service",
|
|
Packit |
c5a612 |
.desc = "internet network service",
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.size = 2 * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.print = inet_service_type_print,
|
|
Packit |
c5a612 |
.json = inet_service_type_json,
|
|
Packit |
c5a612 |
.parse = inet_service_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define RT_SYM_TAB_INITIAL_SIZE 16
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct symbol_table *rt_symbol_table_init(const char *filename)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct symbolic_constant s;
|
|
Packit |
c5a612 |
struct symbol_table *tbl;
|
|
Packit |
c5a612 |
unsigned int size, nelems, val;
|
|
Packit |
c5a612 |
char buf[512], namebuf[512], *p;
|
|
Packit |
c5a612 |
FILE *f;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
size = RT_SYM_TAB_INITIAL_SIZE;
|
|
Packit |
c5a612 |
tbl = xmalloc(sizeof(*tbl) + size * sizeof(s));
|
|
Packit |
c5a612 |
nelems = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
f = fopen(filename, "r");
|
|
Packit |
c5a612 |
if (f == NULL)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
while (fgets(buf, sizeof(buf), f)) {
|
|
Packit |
c5a612 |
p = buf;
|
|
Packit |
c5a612 |
while (*p == ' ' || *p == '\t')
|
|
Packit |
c5a612 |
p++;
|
|
Packit |
c5a612 |
if (*p == '#' || *p == '\n' || *p == '\0')
|
|
Packit |
c5a612 |
continue;
|
|
Packit |
c5a612 |
if (sscanf(p, "0x%x %511s\n", &val, namebuf) != 2 &&
|
|
Packit |
c5a612 |
sscanf(p, "0x%x %511s #", &val, namebuf) != 2 &&
|
|
Packit |
c5a612 |
sscanf(p, "%u %511s\n", &val, namebuf) != 2 &&
|
|
Packit |
c5a612 |
sscanf(p, "%u %511s #", &val, namebuf) != 2) {
|
|
Packit |
c5a612 |
fprintf(stderr, "iproute database '%s' corrupted\n",
|
|
Packit |
c5a612 |
filename);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* One element is reserved for list terminator */
|
|
Packit |
c5a612 |
if (nelems == size - 2) {
|
|
Packit |
c5a612 |
size *= 2;
|
|
Packit |
c5a612 |
tbl = xrealloc(tbl, sizeof(*tbl) + size * sizeof(s));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
tbl->symbols[nelems].identifier = xstrdup(namebuf);
|
|
Packit |
c5a612 |
tbl->symbols[nelems].value = val;
|
|
Packit |
c5a612 |
nelems++;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
fclose(f);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
tbl->symbols[nelems] = SYMBOL_LIST_END;
|
|
Packit |
c5a612 |
return tbl;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void rt_symbol_table_free(const struct symbol_table *tbl)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct symbolic_constant *s;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (s = tbl->symbols; s->identifier != NULL; s++)
|
|
Packit |
c5a612 |
xfree(s->identifier);
|
|
Packit |
c5a612 |
xfree(tbl);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void mark_table_init(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
ctx->output.tbl.mark = rt_symbol_table_init("/etc/iproute2/rt_marks");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void mark_table_exit(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
rt_symbol_table_free(ctx->output.tbl.mark);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void mark_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return symbolic_constant_print(octx->tbl.mark, expr, true, octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *mark_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return symbolic_constant_parse(ctx, sym, ctx->tbl->mark, res);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype mark_type = {
|
|
Packit |
c5a612 |
.type = TYPE_MARK,
|
|
Packit |
c5a612 |
.name = "mark",
|
|
Packit |
c5a612 |
.desc = "packet mark",
|
|
Packit |
c5a612 |
.size = 4 * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.basefmt = "0x%.8Zx",
|
|
Packit |
c5a612 |
.print = mark_type_print,
|
|
Packit |
c5a612 |
.json = mark_type_json,
|
|
Packit |
c5a612 |
.parse = mark_type_parse,
|
|
Packit |
c5a612 |
.flags = DTYPE_F_PREFIX,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct symbol_table icmp_code_tbl = {
|
|
Packit |
c5a612 |
.base = BASE_DECIMAL,
|
|
Packit |
c5a612 |
.symbols = {
|
|
Packit |
c5a612 |
SYMBOL("net-unreachable", ICMP_NET_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL("host-unreachable", ICMP_HOST_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL("prot-unreachable", ICMP_PROT_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL("port-unreachable", ICMP_PORT_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL("net-prohibited", ICMP_NET_ANO),
|
|
Packit |
c5a612 |
SYMBOL("host-prohibited", ICMP_HOST_ANO),
|
|
Packit |
c5a612 |
SYMBOL("admin-prohibited", ICMP_PKT_FILTERED),
|
|
Packit |
c5a612 |
SYMBOL_LIST_END
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype icmp_code_type = {
|
|
Packit |
c5a612 |
.type = TYPE_ICMP_CODE,
|
|
Packit |
c5a612 |
.name = "icmp_code",
|
|
Packit |
c5a612 |
.desc = "icmp code",
|
|
Packit |
c5a612 |
.size = BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.sym_tbl = &icmp_code_tbl,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct symbol_table icmpv6_code_tbl = {
|
|
Packit |
c5a612 |
.base = BASE_DECIMAL,
|
|
Packit |
c5a612 |
.symbols = {
|
|
Packit |
c5a612 |
SYMBOL("no-route", ICMPV6_NOROUTE),
|
|
Packit |
c5a612 |
SYMBOL("admin-prohibited", ICMPV6_ADM_PROHIBITED),
|
|
Packit |
c5a612 |
SYMBOL("addr-unreachable", ICMPV6_ADDR_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL("port-unreachable", ICMPV6_PORT_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL("policy-fail", ICMPV6_POLICY_FAIL),
|
|
Packit |
c5a612 |
SYMBOL("reject-route", ICMPV6_REJECT_ROUTE),
|
|
Packit |
c5a612 |
SYMBOL_LIST_END
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype icmpv6_code_type = {
|
|
Packit |
c5a612 |
.type = TYPE_ICMPV6_CODE,
|
|
Packit |
c5a612 |
.name = "icmpv6_code",
|
|
Packit |
c5a612 |
.desc = "icmpv6 code",
|
|
Packit |
c5a612 |
.size = BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.sym_tbl = &icmpv6_code_tbl,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct symbol_table icmpx_code_tbl = {
|
|
Packit |
c5a612 |
.base = BASE_DECIMAL,
|
|
Packit |
c5a612 |
.symbols = {
|
|
Packit |
c5a612 |
SYMBOL("port-unreachable", NFT_REJECT_ICMPX_PORT_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL("admin-prohibited", NFT_REJECT_ICMPX_ADMIN_PROHIBITED),
|
|
Packit |
c5a612 |
SYMBOL("no-route", NFT_REJECT_ICMPX_NO_ROUTE),
|
|
Packit |
c5a612 |
SYMBOL("host-unreachable", NFT_REJECT_ICMPX_HOST_UNREACH),
|
|
Packit |
c5a612 |
SYMBOL_LIST_END
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype icmpx_code_type = {
|
|
Packit |
c5a612 |
.type = TYPE_ICMPX_CODE,
|
|
Packit |
c5a612 |
.name = "icmpx_code",
|
|
Packit |
c5a612 |
.desc = "icmpx code",
|
|
Packit |
c5a612 |
.size = BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_BIG_ENDIAN,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.sym_tbl = &icmpx_code_tbl,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void time_print(uint64_t ms, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
uint64_t days, hours, minutes, seconds;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
days = ms / 86400000;
|
|
Packit |
c5a612 |
ms %= 86400000;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
hours = ms / 3600000;
|
|
Packit |
c5a612 |
ms %= 3600000;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
minutes = ms / 60000;
|
|
Packit |
c5a612 |
ms %= 60000;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
seconds = ms / 1000;
|
|
Packit |
c5a612 |
ms %= 1000;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (days > 0)
|
|
Packit |
c5a612 |
nft_print(octx, "%" PRIu64 "d", days);
|
|
Packit |
c5a612 |
if (hours > 0)
|
|
Packit |
c5a612 |
nft_print(octx, "%" PRIu64 "h", hours);
|
|
Packit |
c5a612 |
if (minutes > 0)
|
|
Packit |
c5a612 |
nft_print(octx, "%" PRIu64 "m", minutes);
|
|
Packit |
c5a612 |
if (seconds > 0)
|
|
Packit |
c5a612 |
nft_print(octx, "%" PRIu64 "s", seconds);
|
|
Packit |
c5a612 |
if (ms > 0)
|
|
Packit |
c5a612 |
nft_print(octx, "%" PRIu64 "ms", ms);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
enum {
|
|
Packit |
c5a612 |
DAY = (1 << 0),
|
|
Packit |
c5a612 |
HOUR = (1 << 1),
|
|
Packit |
c5a612 |
MIN = (1 << 2),
|
|
Packit |
c5a612 |
SECS = (1 << 3),
|
|
Packit |
c5a612 |
MSECS = (1 << 4),
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static uint32_t str2int(const char *str)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int ret, number;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = sscanf(str, "%d", &number);
|
|
Packit |
c5a612 |
return ret == 1 ? number : 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct error_record *time_parse(const struct location *loc, const char *str,
|
|
Packit |
c5a612 |
uint64_t *res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int max_digits = strlen("12345678");
|
|
Packit |
c5a612 |
int i, len;
|
|
Packit |
c5a612 |
unsigned int k = 0;
|
|
Packit |
c5a612 |
const char *c;
|
|
Packit |
c5a612 |
uint64_t d = 0, h = 0, m = 0, s = 0, ms = 0;
|
|
Packit |
c5a612 |
uint32_t mask = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
c = str;
|
|
Packit |
c5a612 |
len = strlen(c);
|
|
Packit |
c5a612 |
for (i = 0; i < len; i++, c++) {
|
|
Packit |
c5a612 |
switch (*c) {
|
|
Packit |
c5a612 |
case 'd':
|
|
Packit |
c5a612 |
if (mask & DAY)
|
|
Packit |
c5a612 |
return error(loc,
|
|
Packit |
c5a612 |
"Day has been specified twice");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
d = str2int(c - k);
|
|
Packit |
c5a612 |
k = 0;
|
|
Packit |
c5a612 |
mask |= DAY;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case 'h':
|
|
Packit |
c5a612 |
if (mask & HOUR)
|
|
Packit |
c5a612 |
return error(loc,
|
|
Packit |
c5a612 |
"Hour has been specified twice");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
h = str2int(c - k);
|
|
Packit |
c5a612 |
k = 0;
|
|
Packit |
c5a612 |
mask |= HOUR;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case 'm':
|
|
Packit |
c5a612 |
if (strcmp(c, "ms") == 0) {
|
|
Packit |
c5a612 |
if (mask & MSECS)
|
|
Packit |
c5a612 |
return error(loc,
|
|
Packit |
c5a612 |
"Millisecond has been specified twice");
|
|
Packit |
c5a612 |
ms = str2int(c - k);
|
|
Packit |
c5a612 |
c++;
|
|
Packit |
c5a612 |
i++;
|
|
Packit |
c5a612 |
k = 0;
|
|
Packit |
c5a612 |
mask |= MSECS;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (mask & MIN)
|
|
Packit |
c5a612 |
return error(loc,
|
|
Packit |
c5a612 |
"Minute has been specified twice");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
m = str2int(c - k);
|
|
Packit |
c5a612 |
k = 0;
|
|
Packit |
c5a612 |
mask |= MIN;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case 's':
|
|
Packit |
c5a612 |
if (mask & SECS)
|
|
Packit |
c5a612 |
return error(loc,
|
|
Packit |
c5a612 |
"Second has been specified twice");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
s = str2int(c - k);
|
|
Packit |
c5a612 |
k = 0;
|
|
Packit |
c5a612 |
mask |= SECS;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
if (!isdigit(*c))
|
|
Packit |
c5a612 |
return error(loc, "wrong time format");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (k++ >= max_digits)
|
|
Packit |
c5a612 |
return error(loc, "value too large");
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* default to seconds if no unit was specified */
|
|
Packit |
c5a612 |
if (!mask)
|
|
Packit |
c5a612 |
ms = atoi(str) * MSEC_PER_SEC;
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
ms = 24*60*60*MSEC_PER_SEC * d +
|
|
Packit |
c5a612 |
60*60*MSEC_PER_SEC * h +
|
|
Packit |
c5a612 |
60*MSEC_PER_SEC * m +
|
|
Packit |
c5a612 |
MSEC_PER_SEC * s + ms;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*res = ms;
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void time_type_print(const struct expr *expr, struct output_ctx *octx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
time_print(mpz_get_uint64(expr->value), octx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *time_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct error_record *erec;
|
|
Packit |
c5a612 |
uint64_t s;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
erec = time_parse(&sym->location, sym->identifier, &s);
|
|
Packit |
c5a612 |
if (erec != NULL)
|
|
Packit |
c5a612 |
return erec;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (s > UINT32_MAX)
|
|
Packit |
c5a612 |
return error(&sym->location, "value too large");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &time_type,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
sizeof(uint32_t) * BITS_PER_BYTE, &s);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype time_type = {
|
|
Packit |
c5a612 |
.type = TYPE_TIME,
|
|
Packit |
c5a612 |
.name = "time",
|
|
Packit |
c5a612 |
.desc = "relative time",
|
|
Packit |
c5a612 |
.byteorder = BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
.size = 8 * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.print = time_type_print,
|
|
Packit |
c5a612 |
.json = time_type_json,
|
|
Packit |
c5a612 |
.parse = time_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *concat_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return error(&sym->location, "invalid data type, expected %s",
|
|
Packit |
c5a612 |
sym->dtype->desc);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct datatype *dtype_alloc(void)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct datatype *dtype;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dtype = xzalloc(sizeof(*dtype));
|
|
Packit |
c5a612 |
dtype->flags = DTYPE_F_ALLOC;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return dtype;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct datatype *datatype_get(const struct datatype *ptr)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct datatype *dtype = (struct datatype *)ptr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!dtype)
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
if (!(dtype->flags & DTYPE_F_ALLOC))
|
|
Packit |
c5a612 |
return dtype;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dtype->refcnt++;
|
|
Packit |
c5a612 |
return dtype;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void datatype_set(struct expr *expr, const struct datatype *dtype)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
datatype_free(expr->dtype);
|
|
Packit |
c5a612 |
expr->dtype = datatype_get(dtype);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct datatype *dtype_clone(const struct datatype *orig_dtype)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct datatype *dtype;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dtype = xzalloc(sizeof(*dtype));
|
|
Packit |
c5a612 |
*dtype = *orig_dtype;
|
|
Packit |
c5a612 |
dtype->name = xstrdup(orig_dtype->name);
|
|
Packit |
c5a612 |
dtype->desc = xstrdup(orig_dtype->desc);
|
|
Packit |
c5a612 |
dtype->flags = DTYPE_F_ALLOC | orig_dtype->flags;
|
|
Packit |
c5a612 |
dtype->refcnt = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return dtype;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void datatype_free(const struct datatype *ptr)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct datatype *dtype = (struct datatype *)ptr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!dtype)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
if (!(dtype->flags & DTYPE_F_ALLOC))
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
if (--dtype->refcnt > 0)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
xfree(dtype->name);
|
|
Packit |
c5a612 |
xfree(dtype->desc);
|
|
Packit |
c5a612 |
xfree(dtype);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype *concat_type_alloc(uint32_t type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct datatype *i;
|
|
Packit |
c5a612 |
struct datatype *dtype;
|
|
Packit |
c5a612 |
char desc[256] = "concatenation of (";
|
|
Packit |
c5a612 |
char name[256] = "";
|
|
Packit |
c5a612 |
unsigned int size = 0, subtypes = 0, n;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
n = div_round_up(fls(type), TYPE_BITS);
|
|
Packit |
c5a612 |
while (n > 0 && concat_subtype_id(type, --n)) {
|
|
Packit |
c5a612 |
i = concat_subtype_lookup(type, n);
|
|
Packit |
c5a612 |
if (i == NULL)
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (subtypes != 0) {
|
|
Packit |
c5a612 |
strncat(desc, ", ", sizeof(desc) - strlen(desc) - 1);
|
|
Packit |
c5a612 |
strncat(name, " . ", sizeof(name) - strlen(name) - 1);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
strncat(desc, i->desc, sizeof(desc) - strlen(desc) - 1);
|
|
Packit |
c5a612 |
strncat(name, i->name, sizeof(name) - strlen(name) - 1);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
size += netlink_padded_len(i->size);
|
|
Packit |
c5a612 |
subtypes++;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
strncat(desc, ")", sizeof(desc) - strlen(desc) - 1);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dtype = dtype_alloc();
|
|
Packit |
c5a612 |
dtype->type = type;
|
|
Packit |
c5a612 |
dtype->size = size;
|
|
Packit |
c5a612 |
dtype->subtypes = subtypes;
|
|
Packit |
c5a612 |
dtype->name = xstrdup(name);
|
|
Packit |
c5a612 |
dtype->desc = xstrdup(desc);
|
|
Packit |
c5a612 |
dtype->parse = concat_type_parse;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return dtype;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
|
|
Packit |
c5a612 |
unsigned int byteorder)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct datatype *dtype;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* Restrict dynamic datatype allocation to generic integer datatype. */
|
|
Packit |
c5a612 |
if (orig_dtype != &integer_type)
|
|
Packit |
c5a612 |
return orig_dtype;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dtype = dtype_clone(orig_dtype);
|
|
Packit |
c5a612 |
dtype->byteorder = byteorder;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return dtype;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void set_datatype_destroy(const struct datatype *dtype)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
datatype_free(dtype);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *time_unit_parse(const struct location *loc,
|
|
Packit |
c5a612 |
const char *str, uint64_t *unit)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (strcmp(str, "second") == 0)
|
|
Packit |
c5a612 |
*unit = 1ULL;
|
|
Packit |
c5a612 |
else if (strcmp(str, "minute") == 0)
|
|
Packit |
c5a612 |
*unit = 1ULL * 60;
|
|
Packit |
c5a612 |
else if (strcmp(str, "hour") == 0)
|
|
Packit |
c5a612 |
*unit = 1ULL * 60 * 60;
|
|
Packit |
c5a612 |
else if (strcmp(str, "day") == 0)
|
|
Packit |
c5a612 |
*unit = 1ULL * 60 * 60 * 24;
|
|
Packit |
c5a612 |
else if (strcmp(str, "week") == 0)
|
|
Packit |
c5a612 |
*unit = 1ULL * 60 * 60 * 24 * 7;
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
return error(loc, "Wrong rate format");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct error_record *data_unit_parse(const struct location *loc,
|
|
Packit |
c5a612 |
const char *str, uint64_t *rate)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (strncmp(str, "bytes", strlen("bytes")) == 0)
|
|
Packit |
c5a612 |
*rate = 1ULL;
|
|
Packit |
c5a612 |
else if (strncmp(str, "kbytes", strlen("kbytes")) == 0)
|
|
Packit |
c5a612 |
*rate = 1024;
|
|
Packit |
c5a612 |
else if (strncmp(str, "mbytes", strlen("mbytes")) == 0)
|
|
Packit |
c5a612 |
*rate = 1024 * 1024;
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
return error(loc, "Wrong rate format");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct error_record *rate_parse(const struct location *loc, const char *str,
|
|
Packit |
c5a612 |
uint64_t *rate, uint64_t *unit)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct error_record *erec;
|
|
Packit |
c5a612 |
const char *slash;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
slash = strchr(str, '/');
|
|
Packit |
c5a612 |
if (!slash)
|
|
Packit |
c5a612 |
return error(loc, "wrong rate format");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
erec = data_unit_parse(loc, str, rate);
|
|
Packit |
c5a612 |
if (erec != NULL)
|
|
Packit |
c5a612 |
return erec;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
erec = time_unit_parse(loc, slash + 1, unit);
|
|
Packit |
c5a612 |
if (erec != NULL)
|
|
Packit |
c5a612 |
return erec;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct symbol_table boolean_tbl = {
|
|
Packit |
c5a612 |
.base = BASE_DECIMAL,
|
|
Packit |
c5a612 |
.symbols = {
|
|
Packit |
c5a612 |
SYMBOL("exists", true),
|
|
Packit |
c5a612 |
SYMBOL("missing", false),
|
|
Packit |
c5a612 |
SYMBOL_LIST_END
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct datatype boolean_type = {
|
|
Packit |
c5a612 |
.type = TYPE_BOOLEAN,
|
|
Packit |
c5a612 |
.name = "boolean",
|
|
Packit |
c5a612 |
.desc = "boolean type",
|
|
Packit |
c5a612 |
.size = 1,
|
|
Packit |
c5a612 |
.basetype = &integer_type,
|
|
Packit |
c5a612 |
.sym_tbl = &boolean_tbl,
|
|
Packit |
c5a612 |
.json = boolean_type_json,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *priority_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct error_record *erec;
|
|
Packit |
c5a612 |
int num;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
erec = integer_type_parse(ctx, sym, res);
|
|
Packit |
c5a612 |
if (!erec) {
|
|
Packit |
c5a612 |
num = atoi(sym->identifier);
|
|
Packit |
c5a612 |
expr_free(*res);
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &integer_type,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
sizeof(int) * BITS_PER_BYTE, &num);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
erec_destroy(erec);
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &string_type,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
strlen(sym->identifier) * BITS_PER_BYTE,
|
|
Packit |
c5a612 |
sym->identifier);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* This datatype is not registered via datatype_register()
|
|
Packit |
c5a612 |
* since this datatype should not ever be used from either
|
|
Packit |
c5a612 |
* rules or elements.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
const struct datatype priority_type = {
|
|
Packit |
c5a612 |
.type = TYPE_STRING,
|
|
Packit |
c5a612 |
.name = "priority",
|
|
Packit |
c5a612 |
.desc = "priority type",
|
|
Packit |
c5a612 |
.parse = priority_type_parse,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct error_record *policy_type_parse(struct parse_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *sym,
|
|
Packit |
c5a612 |
struct expr **res)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int policy;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!strcmp(sym->identifier, "accept"))
|
|
Packit |
c5a612 |
policy = NF_ACCEPT;
|
|
Packit |
c5a612 |
else if (!strcmp(sym->identifier, "drop"))
|
|
Packit |
c5a612 |
policy = NF_DROP;
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
return error(&sym->location, "wrong policy");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
*res = constant_expr_alloc(&sym->location, &integer_type,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN,
|
|
Packit |
c5a612 |
sizeof(int) * BITS_PER_BYTE, &policy);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* This datatype is not registered via datatype_register()
|
|
Packit |
c5a612 |
* since this datatype should not ever be used from either
|
|
Packit |
c5a612 |
* rules or elements.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
const struct datatype policy_type = {
|
|
Packit |
c5a612 |
.type = TYPE_STRING,
|
|
Packit |
c5a612 |
.name = "policy",
|
|
Packit |
c5a612 |
.desc = "policy type",
|
|
Packit |
c5a612 |
.parse = policy_type_parse,
|
|
Packit |
c5a612 |
};
|