From e33b8a01fc122a3dbc281629c1d3691d05f5d844 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 4 Jul 2019 20:01:02 +0200 Subject: ipopt: missing ipopt.h and ipopt.c files Fixes: 226a0e072d5c ("exthdr: add support for matching IPv4 options") Reported-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- src/ipopt.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/ipopt.c (limited to 'src') diff --git a/src/ipopt.c b/src/ipopt.c new file mode 100644 index 00000000..b3d0279d --- /dev/null +++ b/src/ipopt.c @@ -0,0 +1,159 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +static const struct proto_hdr_template ipopt_unknown_template = + PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0); + +#define PHT(__token, __offset, __len) \ + PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \ + __offset, __len) +static const struct exthdr_desc ipopt_lsrr = { + .name = "lsrr", + .type = IPOPT_LSRR, + .templates = { + [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), + [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), + [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8), + [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32), + }, +}; + +static const struct exthdr_desc ipopt_rr = { + .name = "rr", + .type = IPOPT_RR, + .templates = { + [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), + [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), + [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8), + [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32), + }, +}; + +static const struct exthdr_desc ipopt_ssrr = { + .name = "ssrr", + .type = IPOPT_SSRR, + .templates = { + [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), + [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), + [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8), + [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32), + }, +}; + +static const struct exthdr_desc ipopt_ra = { + .name = "ra", + .type = IPOPT_RA, + .templates = { + [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), + [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), + [IPOPT_FIELD_VALUE] = PHT("value", 16, 16), + }, +}; + +const struct exthdr_desc *ipopt_protocols[UINT8_MAX] = { + [IPOPT_LSRR] = &ipopt_lsrr, + [IPOPT_RR] = &ipopt_rr, + [IPOPT_SSRR] = &ipopt_ssrr, + [IPOPT_RA] = &ipopt_ra, +}; + +static unsigned int calc_offset(const struct exthdr_desc *desc, + const struct proto_hdr_template *tmpl, + unsigned int arg) +{ + if (!desc || tmpl == &ipopt_unknown_template) + return 0; + + switch (desc->type) { + case IPOPT_RR: + case IPOPT_LSRR: + case IPOPT_SSRR: + if (tmpl == &desc->templates[IPOPT_FIELD_ADDR_0]) + return (tmpl->offset < 24) ? 0 : arg; + return 0; + default: + return 0; + } +} + +struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type, + uint8_t field, uint8_t ptr) +{ + const struct proto_hdr_template *tmpl; + const struct exthdr_desc *desc; + struct expr *expr; + + desc = ipopt_protocols[type]; + tmpl = &desc->templates[field]; + if (!tmpl) + return NULL; + + expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype, + BYTEORDER_BIG_ENDIAN, tmpl->len); + expr->exthdr.desc = desc; + expr->exthdr.tmpl = tmpl; + expr->exthdr.op = NFT_EXTHDR_OP_IPV4; + expr->exthdr.offset = calc_offset(desc, tmpl, ptr); + + return expr; +} + +void ipopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset, + unsigned int len, uint32_t flags, bool set_unknown) +{ + const struct proto_hdr_template *tmpl; + unsigned int i; + + assert(expr->etype == EXPR_EXTHDR); + + expr->len = len; + expr->exthdr.flags = flags; + expr->exthdr.offset = offset; + + assert(type < array_size(ipopt_protocols)); + expr->exthdr.desc = ipopt_protocols[type]; + expr->exthdr.flags = flags; + + for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) { + tmpl = &expr->exthdr.desc->templates[i]; + + /* Make sure that it's the right template based on offset and len */ + if (tmpl->offset != offset || tmpl->len != len) + continue; + + if (flags & NFT_EXTHDR_F_PRESENT) + expr->dtype = &boolean_type; + else + expr->dtype = tmpl->dtype; + expr->exthdr.tmpl = tmpl; + expr->exthdr.op = NFT_EXTHDR_OP_IPV4; + break; + } + if (i == array_size(expr->exthdr.desc->templates) && set_unknown) { + expr->exthdr.tmpl = &ipopt_unknown_template; + expr->exthdr.op = NFT_EXTHDR_OP_IPV4; + } +} + +bool ipopt_find_template(struct expr *expr, unsigned int offset, + unsigned int len) +{ + if (expr->exthdr.tmpl != &ipopt_unknown_template) + return false; + + ipopt_init_raw(expr, expr->exthdr.desc->type, offset, len, 0, false); + + if (expr->exthdr.tmpl == &ipopt_unknown_template) + return false; + + return true; +} -- cgit v1.2.3