Blame src/datatype.c

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]	= &etheraddr_type,
Packit c5a612
	[TYPE_ETHERTYPE]	= &ethertype_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
};