|
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 |
}
|