sync with OpenBSD -current

This commit is contained in:
purplerain 2024-01-31 03:34:50 +00:00
parent 4b5c843641
commit fe0bbab526
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
22 changed files with 1045 additions and 594 deletions

View file

@ -1,4 +1,4 @@
/* $OpenBSD: util.c,v 1.79 2024/01/23 16:13:35 claudio Exp $ */
/* $OpenBSD: util.c,v 1.80 2024/01/30 13:50:09 claudio Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@ -32,8 +32,6 @@
#include "rde.h"
#include "log.h"
const char *aspath_delim(uint8_t, int);
const char *
log_addr(const struct bgpd_addr *addr)
{
@ -235,6 +233,26 @@ log_aspa(struct aspa_set *aspa)
return errbuf;
}
const char *
log_aspath_error(int error)
{
static char buf[20];
switch (error) {
case AS_ERR_LEN:
return "inconsitent lenght";
case AS_ERR_TYPE:
return "unknown segment type";
case AS_ERR_BAD:
return "invalid encoding";
case AS_ERR_SOFT:
return "soft failure";
default:
snprintf(buf, sizeof(buf), "unknown %d", error);
return buf;
}
}
const char *
log_rtr_error(enum rtr_error err)
{
@ -286,7 +304,7 @@ log_policy(enum role role)
}
}
const char *
static const char *
aspath_delim(uint8_t seg_type, int closing)
{
static char db[8];
@ -318,42 +336,38 @@ aspath_delim(uint8_t seg_type, int closing)
}
}
int
aspath_snprint(char *buf, size_t size, void *data, uint16_t len)
static int
aspath_snprint(char *buf, size_t size, struct ibuf *in)
{
#define UPDATE() \
do { \
if (r < 0) \
return (-1); \
total_size += r; \
if ((unsigned int)r < size) { \
size -= r; \
buf += r; \
} else { \
buf += size; \
size = 0; \
} \
#define UPDATE() \
do { \
if (r < 0 || (unsigned int)r >= size) \
return (-1); \
size -= r; \
buf += r; \
} while (0)
uint8_t *seg;
int r, total_size;
uint16_t seg_size;
uint8_t i, seg_type, seg_len;
total_size = 0;
seg = data;
for (; len > 0; len -= seg_size, seg += seg_size) {
seg_type = seg[0];
seg_len = seg[1];
seg_size = 2 + sizeof(uint32_t) * seg_len;
struct ibuf data;
uint32_t as;
int r, n = 0;
uint8_t i, seg_type, seg_len;
r = snprintf(buf, size, "%s%s",
total_size != 0 ? " " : "",
ibuf_from_ibuf(&data, in);
while (ibuf_size(&data) > 0) {
if (ibuf_get_n8(&data, &seg_type) == -1 ||
ibuf_get_n8(&data, &seg_len) == -1 ||
seg_len == 0)
return (-1);
r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "",
aspath_delim(seg_type, 0));
UPDATE();
for (i = 0; i < seg_len; i++) {
r = snprintf(buf, size, "%s",
log_as(aspath_extract(seg, i)));
if (ibuf_get_n32(&data, &as) == -1)
return -1;
r = snprintf(buf, size, "%s", log_as(as));
UPDATE();
if (i + 1 < seg_len) {
r = snprintf(buf, size, " ");
@ -364,73 +378,68 @@ aspath_snprint(char *buf, size_t size, void *data, uint16_t len)
UPDATE();
}
/* ensure that we have a valid C-string especially for empty as path */
if (size > 0)
*buf = '\0';
return (total_size);
*buf = '\0';
return (0);
#undef UPDATE
}
int
aspath_asprint(char **ret, void *data, uint16_t len)
static ssize_t
aspath_strsize(struct ibuf *in)
{
size_t slen;
int plen;
slen = aspath_strlen(data, len) + 1;
*ret = malloc(slen);
if (*ret == NULL)
return (-1);
plen = aspath_snprint(*ret, slen, data, len);
if (plen == -1) {
free(*ret);
*ret = NULL;
return (-1);
}
return (0);
}
size_t
aspath_strlen(void *data, uint16_t len)
{
uint8_t *seg;
int total_size;
struct ibuf buf;
ssize_t total_size = 0;
uint32_t as;
uint16_t seg_size;
uint8_t i, seg_type, seg_len;
total_size = 0;
seg = data;
for (; len > 0; len -= seg_size, seg += seg_size) {
seg_type = seg[0];
seg_len = seg[1];
seg_size = 2 + sizeof(uint32_t) * seg_len;
ibuf_from_ibuf(&buf, in);
while (ibuf_size(&buf) > 0) {
if (ibuf_get_n8(&buf, &seg_type) == -1 ||
ibuf_get_n8(&buf, &seg_len) == -1 ||
seg_len == 0)
return (-1);
if (seg_type == AS_SET)
if (total_size != 0)
total_size += 3;
else
total_size += 2;
else if (total_size != 0)
if (total_size != 0)
total_size += 1;
total_size += strlen(aspath_delim(seg_type, 0));
for (i = 0; i < seg_len; i++) {
as = aspath_extract(seg, i);
if (ibuf_get_n32(&buf, &as) == -1)
return (-1);
do {
total_size++;
} while ((as = as / 10) != 0);
if (i + 1 < seg_len)
total_size += 1;
}
total_size += seg_len - 1;
if (seg_type == AS_SET)
total_size += 2;
total_size += strlen(aspath_delim(seg_type, 1));
}
return (total_size);
return (total_size + 1);
}
int
aspath_asprint(char **ret, struct ibuf *data)
{
ssize_t slen;
if ((slen = aspath_strsize(data)) == -1) {
*ret = NULL;
errno = EINVAL;
return (-1);
}
*ret = malloc(slen);
if (*ret == NULL)
return (-1);
if (aspath_snprint(*ret, slen, data) == -1) {
free(*ret);
*ret = NULL;
errno = EINVAL;
return (-1);
}
return (0);
}
/*
@ -456,32 +465,31 @@ aspath_extract(const void *seg, int pos)
* Verify that the aspath is correctly encoded.
*/
int
aspath_verify(void *data, uint16_t len, int as4byte, int noset)
aspath_verify(struct ibuf *in, int as4byte, int noset)
{
uint8_t *seg = data;
uint16_t seg_size, as_size = 2;
struct ibuf buf;
int pos, error = 0;
uint8_t seg_len, seg_type;
int error = 0;
if (len & 1)
ibuf_from_ibuf(&buf, in);
if (ibuf_size(&buf) & 1) {
/* odd length aspath are invalid */
return (AS_ERR_BAD);
error = AS_ERR_BAD;
goto done;
}
if (as4byte)
as_size = 4;
while (ibuf_size(&buf) > 0) {
if (ibuf_get_n8(&buf, &seg_type) == -1 ||
ibuf_get_n8(&buf, &seg_len) == -1) {
error = AS_ERR_LEN;
goto done;
}
for (; len > 0; len -= seg_size, seg += seg_size) {
const uint8_t *ptr;
int pos;
if (len < 2) /* header length check */
return (AS_ERR_BAD);
seg_type = seg[0];
seg_len = seg[1];
if (seg_len == 0)
if (seg_len == 0) {
/* empty aspath segments are not allowed */
return (AS_ERR_BAD);
error = AS_ERR_BAD;
goto done;
}
/*
* BGP confederations should not show up but consider them
@ -497,70 +505,75 @@ aspath_verify(void *data, uint16_t len, int as4byte, int noset)
if (noset && seg_type == AS_SET)
error = AS_ERR_SOFT;
if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET)
return (AS_ERR_TYPE);
seg_size = 2 + as_size * seg_len;
if (seg_size > len)
return (AS_ERR_LEN);
seg_type != AS_CONFED_SEQUENCE &&
seg_type != AS_CONFED_SET) {
error = AS_ERR_TYPE;
goto done;
}
/* RFC 7607 - AS 0 is considered malformed */
ptr = seg + 2;
for (pos = 0; pos < seg_len; pos++) {
uint32_t as;
memcpy(&as, ptr, as_size);
if (as4byte) {
if (ibuf_get_n32(&buf, &as) == -1) {
error = AS_ERR_LEN;
goto done;
}
} else {
uint16_t tmp;
if (ibuf_get_n16(&buf, &tmp) == -1) {
error = AS_ERR_LEN;
goto done;
}
as = tmp;
}
if (as == 0)
error = AS_ERR_SOFT;
ptr += as_size;
}
}
done:
return (error); /* aspath is valid but probably not loop free */
}
/*
* convert a 2 byte aspath to a 4 byte one.
*/
u_char *
aspath_inflate(void *data, uint16_t len, uint16_t *newlen)
struct ibuf *
aspath_inflate(struct ibuf *in)
{
uint8_t *seg, *nseg, *ndata;
uint16_t seg_size, olen, nlen;
uint8_t seg_len;
struct ibuf *out;
uint16_t short_as;
uint8_t seg_type, seg_len;
/* first calculate the length of the aspath */
seg = data;
nlen = 0;
for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
seg_len = seg[1];
seg_size = 2 + sizeof(uint16_t) * seg_len;
nlen += 2 + sizeof(uint32_t) * seg_len;
if (seg_size > olen) {
errno = ERANGE;
return (NULL);
}
}
*newlen = nlen;
if ((ndata = malloc(nlen)) == NULL)
/* allocate enough space for the worst case */
if ((out = ibuf_open(ibuf_size(in) * 2)) == NULL)
return (NULL);
/* then copy the aspath */
seg = data;
for (nseg = ndata; nseg < ndata + nlen; ) {
*nseg++ = *seg++;
*nseg++ = seg_len = *seg++;
while (ibuf_size(in) > 0) {
if (ibuf_get_n8(in, &seg_type) == -1 ||
ibuf_get_n8(in, &seg_len) == -1 ||
seg_len == 0)
goto fail;
if (ibuf_add_n8(out, seg_type) == -1 ||
ibuf_add_n8(out, seg_len) == -1)
goto fail;
for (; seg_len > 0; seg_len--) {
*nseg++ = 0;
*nseg++ = 0;
*nseg++ = *seg++;
*nseg++ = *seg++;
if (ibuf_get_n16(in, &short_as) == -1)
goto fail;
if (ibuf_add_n32(out, short_as) == -1)
goto fail;
}
}
return (ndata);
return (out);
fail:
ibuf_free(out);
return (NULL);
}
static const u_char addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,