Blame src/ipopt.c

Packit c5a612
#include <stdint.h>
Packit c5a612
Packit c5a612
#include <netinet/in.h>
Packit c5a612
#include <netinet/ip.h>
Packit c5a612
#include <netinet/ip6.h>
Packit c5a612
#include <netinet/tcp.h>
Packit c5a612
Packit c5a612
#include <utils.h>
Packit c5a612
#include <headers.h>
Packit c5a612
#include <expression.h>
Packit c5a612
#include <ipopt.h>
Packit c5a612
Packit c5a612
static const struct proto_hdr_template ipopt_unknown_template =
Packit c5a612
	PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
Packit c5a612
Packit c5a612
#define PHT(__token, __offset, __len) \
Packit c5a612
	PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
Packit c5a612
			   __offset, __len)
Packit c5a612
static const struct exthdr_desc ipopt_lsrr = {
Packit c5a612
	.name		= "lsrr",
Packit c5a612
	.type		= IPOPT_LSRR,
Packit c5a612
	.templates	= {
Packit c5a612
		[IPOPT_FIELD_TYPE]		= PHT("type",    0,  8),
Packit c5a612
		[IPOPT_FIELD_LENGTH]		= PHT("length",  8,  8),
Packit c5a612
		[IPOPT_FIELD_PTR]		= PHT("ptr",    16,  8),
Packit c5a612
		[IPOPT_FIELD_ADDR_0]		= PHT("addr",   24, 32),
Packit c5a612
	},
Packit c5a612
};
Packit c5a612
Packit c5a612
static const struct exthdr_desc ipopt_rr = {
Packit c5a612
	.name		= "rr",
Packit c5a612
	.type		= IPOPT_RR,
Packit c5a612
	.templates	= {
Packit c5a612
		[IPOPT_FIELD_TYPE]		= PHT("type",   0,   8),
Packit c5a612
		[IPOPT_FIELD_LENGTH]		= PHT("length",  8,  8),
Packit c5a612
		[IPOPT_FIELD_PTR]		= PHT("ptr",    16,  8),
Packit c5a612
		[IPOPT_FIELD_ADDR_0]		= PHT("addr",   24, 32),
Packit c5a612
	},
Packit c5a612
};
Packit c5a612
Packit c5a612
static const struct exthdr_desc ipopt_ssrr = {
Packit c5a612
	.name		= "ssrr",
Packit c5a612
	.type		= IPOPT_SSRR,
Packit c5a612
	.templates	= {
Packit c5a612
		[IPOPT_FIELD_TYPE]		= PHT("type",   0,   8),
Packit c5a612
		[IPOPT_FIELD_LENGTH]		= PHT("length",  8,  8),
Packit c5a612
		[IPOPT_FIELD_PTR]		= PHT("ptr",    16,  8),
Packit c5a612
		[IPOPT_FIELD_ADDR_0]		= PHT("addr",   24, 32),
Packit c5a612
	},
Packit c5a612
};
Packit c5a612
Packit c5a612
static const struct exthdr_desc ipopt_ra = {
Packit c5a612
	.name		= "ra",
Packit c5a612
	.type		= IPOPT_RA,
Packit c5a612
	.templates	= {
Packit c5a612
		[IPOPT_FIELD_TYPE]		= PHT("type",   0,   8),
Packit c5a612
		[IPOPT_FIELD_LENGTH]		= PHT("length", 8,   8),
Packit c5a612
		[IPOPT_FIELD_VALUE]		= PHT("value",  16, 16),
Packit c5a612
	},
Packit c5a612
};
Packit c5a612
Packit c5a612
const struct exthdr_desc *ipopt_protocols[UINT8_MAX] = {
Packit c5a612
	[IPOPT_LSRR]		= &ipopt_lsrr,
Packit c5a612
	[IPOPT_RR]		= &ipopt_rr,
Packit c5a612
	[IPOPT_SSRR]		= &ipopt_ssrr,
Packit c5a612
	[IPOPT_RA]		= &ipopt_ra,
Packit c5a612
};
Packit c5a612
Packit c5a612
static unsigned int calc_offset(const struct exthdr_desc *desc,
Packit c5a612
				const struct proto_hdr_template *tmpl,
Packit c5a612
				unsigned int arg)
Packit c5a612
{
Packit c5a612
	if (!desc || tmpl == &ipopt_unknown_template)
Packit c5a612
		return 0;
Packit c5a612
Packit c5a612
	switch (desc->type) {
Packit c5a612
	case IPOPT_RR:
Packit c5a612
	case IPOPT_LSRR:
Packit c5a612
	case IPOPT_SSRR:
Packit c5a612
		if (tmpl == &desc->templates[IPOPT_FIELD_ADDR_0])
Packit c5a612
			return (tmpl->offset < 24) ? 0 : arg;
Packit c5a612
		return 0;
Packit c5a612
	default:
Packit c5a612
		return 0;
Packit c5a612
	}
Packit c5a612
}
Packit c5a612
Packit c5a612
struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
Packit c5a612
			       uint8_t field, uint8_t ptr)
Packit c5a612
{
Packit c5a612
	const struct proto_hdr_template *tmpl;
Packit c5a612
	const struct exthdr_desc *desc;
Packit c5a612
	struct expr *expr;
Packit c5a612
Packit c5a612
	desc = ipopt_protocols[type];
Packit c5a612
	tmpl = &desc->templates[field];
Packit c5a612
	if (!tmpl)
Packit c5a612
		return NULL;
Packit c5a612
Packit c5a612
	expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
Packit c5a612
			  BYTEORDER_BIG_ENDIAN, tmpl->len);
Packit c5a612
	expr->exthdr.desc   = desc;
Packit c5a612
	expr->exthdr.tmpl   = tmpl;
Packit c5a612
	expr->exthdr.op     = NFT_EXTHDR_OP_IPV4;
Packit c5a612
	expr->exthdr.offset = calc_offset(desc, tmpl, ptr);
Packit c5a612
Packit c5a612
	return expr;
Packit c5a612
}
Packit c5a612
Packit c5a612
void ipopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
Packit c5a612
		     unsigned int len, uint32_t flags, bool set_unknown)
Packit c5a612
{
Packit c5a612
	const struct proto_hdr_template *tmpl;
Packit c5a612
	unsigned int i;
Packit c5a612
Packit c5a612
	assert(expr->etype == EXPR_EXTHDR);
Packit c5a612
Packit c5a612
	expr->len = len;
Packit c5a612
	expr->exthdr.flags = flags;
Packit c5a612
	expr->exthdr.offset = offset;
Packit c5a612
Packit c5a612
	assert(type < array_size(ipopt_protocols));
Packit c5a612
	expr->exthdr.desc = ipopt_protocols[type];
Packit c5a612
	expr->exthdr.flags = flags;
Packit c5a612
Packit c5a612
	for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
Packit c5a612
		tmpl = &expr->exthdr.desc->templates[i];
Packit c5a612
Packit c5a612
		/* Make sure that it's the right template based on offset and len */
Packit c5a612
		if (tmpl->offset != offset || tmpl->len != len)
Packit c5a612
			continue;
Packit c5a612
Packit c5a612
		if (flags & NFT_EXTHDR_F_PRESENT)
Packit c5a612
			expr->dtype = &boolean_type;
Packit c5a612
		else
Packit c5a612
			expr->dtype = tmpl->dtype;
Packit c5a612
		expr->exthdr.tmpl = tmpl;
Packit c5a612
		expr->exthdr.op   = NFT_EXTHDR_OP_IPV4;
Packit c5a612
		break;
Packit c5a612
	}
Packit c5a612
	if (i == array_size(expr->exthdr.desc->templates) && set_unknown) {
Packit c5a612
		expr->exthdr.tmpl = &ipopt_unknown_template;
Packit c5a612
		expr->exthdr.op   = NFT_EXTHDR_OP_IPV4;
Packit c5a612
	}
Packit c5a612
}
Packit c5a612
Packit c5a612
bool ipopt_find_template(struct expr *expr, unsigned int offset,
Packit c5a612
			  unsigned int len)
Packit c5a612
{
Packit c5a612
	if (expr->exthdr.tmpl != &ipopt_unknown_template)
Packit c5a612
		return false;
Packit c5a612
Packit c5a612
	ipopt_init_raw(expr, expr->exthdr.desc->type, offset, len, 0, false);
Packit c5a612
Packit c5a612
	if (expr->exthdr.tmpl == &ipopt_unknown_template)
Packit c5a612
		return false;
Packit c5a612
Packit c5a612
	return true;
Packit c5a612
}