From 0f144400c84c1dbab16a4727ceb219caff026970 Mon Sep 17 00:00:00 2001 From: claudio Date: Mon, 17 Apr 2023 08:02:21 +0000 Subject: [PATCH] Implement a basic API to work with flowspec NLRI. Flowspec is excessivly flexible and large so there is no way to convert the flowspec data into a struct bgpd_addr and it is better to keep it in wireformat and add a few functions to validate and extract information from the NLRI encoding. OK tb@ --- usr.sbin/bgpd/Makefile | 4 +- usr.sbin/bgpd/bgpd.h | 41 ++- usr.sbin/bgpd/flowspec.c | 610 +++++++++++++++++++++++++++++++++++++++ usr.sbin/bgpd/util.c | 6 +- 4 files changed, 644 insertions(+), 17 deletions(-) create mode 100644 usr.sbin/bgpd/flowspec.c diff --git a/usr.sbin/bgpd/Makefile b/usr.sbin/bgpd/Makefile index cdf58bf3105..aaeb0640772 100644 --- a/usr.sbin/bgpd/Makefile +++ b/usr.sbin/bgpd/Makefile @@ -1,11 +1,11 @@ -# $OpenBSD: Makefile,v 1.38 2023/01/11 13:53:17 claudio Exp $ +# $OpenBSD: Makefile,v 1.39 2023/04/17 08:02:21 claudio Exp $ PROG= bgpd SRCS= bgpd.c session.c log.c logmsg.c parse.y config.c \ rde.c rde_rib.c rde_decide.c rde_prefix.c mrt.c kroute.c control.c \ pfkey.c rde_update.c rde_attr.c rde_community.c printconf.c \ rde_filter.c rde_sets.c rde_aspa.c rde_trie.c pftable.c name2id.c \ - util.c carp.c timer.c rde_peer.c rtr.c rtr_proto.c + util.c carp.c timer.c rde_peer.c rtr.c rtr_proto.c flowspec.c CFLAGS+= -Wall -I${.CURDIR} CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 3bb27fd3d74..43bc6afbcf2 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.470 2023/04/03 10:48:00 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.471 2023/04/17 08:02:21 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -1087,18 +1087,23 @@ struct ext_comm_pairs { extern const struct ext_comm_pairs iana_ext_comms[]; /* BGP flowspec defines RFC 8955 and 8956 */ -#define FLOWSPEC_LEN_LIMIT 0xf0 -#define FLOWSPEC_OP_EOL 0x80 -#define FLOWSPEC_OP_AND 0x40 -#define FLOWSPEC_OP_LEN_MASK 0x30 -#define FLOWSPEC_OP_LEN_SHIFT 4 +#define FLOWSPEC_LEN_LIMIT 0xf0 +#define FLOWSPEC_OP_EOL 0x80 +#define FLOWSPEC_OP_AND 0x40 +#define FLOWSPEC_OP_LEN_MASK 0x30 +#define FLOWSPEC_OP_LEN_SHIFT 4 #define FLOWSPEC_OP_LEN(op) \ (1 << (((op) & FLOWSPEC_OP_LEN_MASK) >> FLOWSPEC_OP_LEN_SHIFT)) -#define FLOWSPEC_OP_NUM_LT 0x04 -#define FLOWSPEC_OP_NUM_GT 0x02 -#define FLOWSPEC_OP_NUM_EQ 0x01 -#define FLOWSPEC_OP_BIT_NOT 0x02 -#define FLOWSPEC_OP_BIT_MATCH 0x01 +#define FLOWSPEC_OP_NUM_LT 0x04 +#define FLOWSPEC_OP_NUM_GT 0x02 +#define FLOWSPEC_OP_NUM_EQ 0x01 +#define FLOWSPEC_OP_NUM_LE (FLOWSPEC_OP_NUM_LT | FLOWSPEC_OP_NUM_EQ) +#define FLOWSPEC_OP_NUM_GE (FLOWSPEC_OP_NUM_GT | FLOWSPEC_OP_NUM_EQ) +#define FLOWSPEC_OP_NUM_NOT (FLOWSPEC_OP_NUM_GT | FLOWSPEC_OP_NUM_LT) +#define FLOWSPEC_OP_NUM_MASK 0x07 +#define FLOWSPEC_OP_BIT_NOT 0x02 +#define FLOWSPEC_OP_BIT_MATCH 0x01 +#define FLOWSPEC_OP_BIT_MASK 0x03 #define FLOWSPEC_TYPE_MIN 1 #define FLOWSPEC_TYPE_DEST 1 @@ -1114,7 +1119,7 @@ extern const struct ext_comm_pairs iana_ext_comms[]; #define FLOWSPEC_TYPE_DSCP 11 #define FLOWSPEC_TYPE_FRAG 12 #define FLOWSPEC_TYPE_FLOW 13 -#define FLOWSPEC_TYPE_MAX 13 +#define FLOWSPEC_TYPE_MAX 14 struct filter_prefix { struct bgpd_addr addr; @@ -1510,6 +1515,7 @@ int aspath_verify(void *, uint16_t, int, int); #define AS_ERR_BAD -3 #define AS_ERR_SOFT -4 u_char *aspath_inflate(void *, uint16_t, uint16_t *); +int extract_prefix(const u_char *, int, void *, uint8_t, uint8_t); int nlri_get_prefix(u_char *, uint16_t, struct bgpd_addr *, uint8_t *); int nlri_get_prefix6(u_char *, uint16_t, struct bgpd_addr *, @@ -1533,6 +1539,17 @@ struct sockaddr *addr2sa(const struct bgpd_addr *, uint16_t, socklen_t *); void sa2addr(struct sockaddr *, struct bgpd_addr *, uint16_t *); const char * get_baudrate(unsigned long long, char *); +/* flowspec.c */ +int flowspec_valid(const uint8_t *, int, int); +int flowspec_cmp(const uint8_t *, int, const uint8_t *, int, int); +int flowspec_get_component(const uint8_t *, int, int, int, + const uint8_t **, int *); +int flowspec_get_addr(const uint8_t *, int, int, int, struct bgpd_addr *, + uint8_t *, uint8_t *); +const char *flowspec_fmt_label(int); +const char *flowspec_fmt_num_op(const uint8_t *, int, int *); +const char *flowspec_fmt_bin_op(const uint8_t *, int, int *, const char *); + static const char * const log_procnames[] = { "parent", "SE", diff --git a/usr.sbin/bgpd/flowspec.c b/usr.sbin/bgpd/flowspec.c new file mode 100644 index 00000000000..0a2d6a1426f --- /dev/null +++ b/usr.sbin/bgpd/flowspec.c @@ -0,0 +1,610 @@ +/* $OpenBSD: flowspec.c,v 1.1 2023/04/17 08:02:21 claudio Exp $ */ + +/* + * Copyright (c) 2023 Claudio Jeker + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "bgpd.h" +#include "rde.h" + +/* + * Extract the next component from a flowspec NLRI buffer. + * Returns the length of the component including type field or -1 on failure. + * Also checks that the prefix encoding is valid. + */ +static int +flowspec_next_component(const uint8_t *buf, int len, int is_v6, int *type) +{ + int vlen = 0; + uint8_t plen, off, op; + + *type = 0; + if (len < 1) + return -1; + *type = buf[vlen]; + vlen++; + if (*type < FLOWSPEC_TYPE_MIN || *type >= FLOWSPEC_TYPE_MAX) + return -1; + + switch (*type) { + case FLOWSPEC_TYPE_DEST: + case FLOWSPEC_TYPE_SOURCE: + if (!is_v6) { + /* regular RFC 4271 encoding of prefixes */ + if (len < vlen + 1) + return -1; + plen = buf[vlen]; + vlen += PREFIX_SIZE(plen); + if (plen > 32 || len < vlen) + return -1; + } else { + /* special RFC 8956 encoding with extra offset */ + if (len < vlen + 2) + return -1; + plen = buf[vlen]; + off = buf[vlen + 1]; + if (plen > 128 || off >= plen) + return -1; + vlen += PREFIX_SIZE(plen - off) + 1; /* off is extra */ + if (len < vlen) + return -1; + } + break; + case FLOWSPEC_TYPE_FLOW: + if (!is_v6) + return -1; + /* FALLTHROUGH */ + default: + do { + if (len < vlen + 1) + return -1; + op = buf[vlen]; + /* first component cannot have and flag set */ + if (vlen == 1 && op & FLOWSPEC_OP_AND) + return -1; + vlen += FLOWSPEC_OP_LEN(op) + 1; + + if (len < vlen) + return -1; + } while ((op & FLOWSPEC_OP_EOL) == 0); + break; + } + return vlen; +} + +#define MINIMUM(a, b) ((a) < (b) ? (a) : (b)) + +/* + * Compare two IPv4 flowspec prefix components. + * Returns 1 if first prefix is preferred, -1 if second, 0 if equal. + */ +static int +flowspec_cmp_prefix4(const uint8_t *abuf, int ablen, const uint8_t *bbuf, + int bblen) +{ + uint8_t a[4] = { 0 }, b[4] = { 0 }; + int alen, blen, clen, cmp; + + alen = abuf[1]; + blen = bbuf[1]; + clen = MINIMUM(alen, blen); + + /* only extract the common prefix */ + if (extract_prefix(abuf + 2, ablen - 2, &a, clen, sizeof(a)) == -1) + fatalx("bad flowspec prefix encoding"); + if (extract_prefix(bbuf + 2, bblen - 2, &b, clen, sizeof(b)) == -1) + fatalx("bad flowspec prefix encoding"); + + /* lowest IP value has precedence */ + cmp = memcmp(a, b, sizeof(a)); + if (cmp < 0) + return 1; + if (cmp > 0) + return -1; + + /* if common prefix, more specific route has precedence */ + if (alen > blen) + return 1; + if (alen < blen) + return -1; + return 0; +} + +/* + * Compare two IPv6 flowspec prefix components. + * Returns 1 if first prefix is preferred, -1 if second, 0 if equal. + * As usual the encoding of IPv6 addresses is extra complex. + */ +static int +flowspec_cmp_prefix6(const uint8_t *abuf, int ablen, const uint8_t *bbuf, + int bblen) +{ + uint8_t a[16] = { 0 }, b[16] = { 0 }; + int alen, blen, clen, cmp; + + /* lowest offset has precedence */ + if (abuf[2] < bbuf[2]) + return 1; + if (abuf[2] > bbuf[2]) + return -1; + + /* calculate actual pattern size (len - offset) */ + alen = abuf[1] - abuf[2]; + blen = bbuf[1] - bbuf[2]; + clen = MINIMUM(alen, blen); + + /* only extract the common prefix */ + if (extract_prefix(abuf + 3, ablen - 3, &a, clen, sizeof(a)) == -1) + fatalx("bad flowspec prefix encoding"); + if (extract_prefix(bbuf + 3, bblen - 3, &b, clen, sizeof(b)) == -1) + fatalx("bad flowspec prefix encoding"); + + /* lowest IP value has precedence */ + cmp = memcmp(a, b, sizeof(a)); + if (cmp < 0) + return 1; + if (cmp > 0) + return -1; + + /* if common prefix, more specific route has precedence */ + if (alen > blen) + return 1; + if (alen < blen) + return -1; + return 0; +} + +/* + * Check if the flowspec NLRI is syntactically valid. + */ +int +flowspec_valid(const uint8_t *buf, int len, int is_v6) +{ + int l, type, prev = 0; + + /* empty NLRI is invalid */ + if (len == 0) + return -1; + + while (len > 0) { + l = flowspec_next_component(buf, len, is_v6, &type); + if (l == -1) + return -1; + /* ensure that types are ordered */ + if (prev >= type) + return -1; + prev = type; + buf += l; + len -= l; + } + if (len < 0) + fatalx("flowspec overflow"); + return 0; +} + +/* + * Compare two valid flowspec NLRI objects according to RFC 8955 & 8956. + * Returns 1 if the first object has preference, -1 if not, and 0 if the + * two objects are equal. + */ +int +flowspec_cmp(const uint8_t *a, int alen, const uint8_t *b, int blen, int is_v6) +{ + int atype, btype; + int acomplen, bcomplen; + int cmp; + + while (alen > 0 && blen > 0) { + acomplen = flowspec_next_component(a, alen, is_v6, &atype); + if (acomplen == -1) + fatalx("bad flowspec component"); + bcomplen = flowspec_next_component(b, blen, is_v6, &btype); + if (acomplen == -1) + fatalx("bad flowspec component"); + + /* If types differ, lowest type wins. */ + if (atype < btype) + return 1; + if (atype > btype) + return -1; + + switch (atype) { + case FLOWSPEC_TYPE_DEST: + case FLOWSPEC_TYPE_SOURCE: + if (!is_v6) { + cmp = flowspec_cmp_prefix4(a, acomplen, + b, bcomplen); + } else { + cmp = flowspec_cmp_prefix6(a, acomplen, + b, bcomplen); + } + if (cmp != 0) + return cmp; + break; + default: + cmp = memcmp(a, b, MINIMUM(acomplen, bcomplen)); + /* + * Lowest common component prefix wins also + * if both commponents are same length also lowest + * string has precedence. + */ + if (cmp < 0) + return 1; + if (cmp > 0) + return -1; + /* + * Longest component wins when common prefix is equal. + * This is not really possible because EOL encoding will + * always tie break on the memcmp but the RFC mandates + * it (and it is cheap). + */ + if (acomplen > bcomplen) + return 1; + if (acomplen < bcomplen) + return -1; + break; + } + a += acomplen; + alen -= acomplen; + b += bcomplen; + blen -= bcomplen; + + /* Rule with more components wins */ + if (alen > 0 && blen <= 0) + return 1; + if (alen <= 0 && blen > 0) + return -1; + } + return 0; +} + +static void +shift_right(uint8_t *dst, const uint8_t *src, int off, int len) +{ + uint8_t carry = 0; + int i; + + dst += off / 8; /* go to inital start point */ + off %= 8; + len = (len + 7) / 8; /* how much to copy in bytes */ + + for (i = 0; i < len; i++) { + dst[i] = carry | src[i] >> off; + if (off != 0) + carry = src[i] << (8 - off); + } + dst[i] = carry; +} + +/* + * Extract a flowspec component and return its buffer and size. + * Returns 1 on success, 0 if component is not present and -1 on error. + */ +int +flowspec_get_component(const uint8_t *flow, int flowlen, int type, int is_v6, + const uint8_t **buf, int *len) +{ + int complen, t; + + *buf = NULL; + *len = 0; + + do { + complen = flowspec_next_component(flow, flowlen, is_v6, &t); + if (complen == -1) + return -1; + if (type == t) + break; + if (type < t) + return 0; + + flow += complen; + flowlen -= complen; + } while (1); + + *buf = flow + 1; + *len = complen - 1; + + return 1; +} + +/* + * Extract source or destination address into provided bgpd_addr. + * Returns 1 on success, 0 if no address was present, -1 on error. + * Sets plen to the prefix len and olen to the offset for IPv6 case. + * If olen is set to NULL when an IPv6 prefix with offset is fetched + * the function will return -1. + */ +int +flowspec_get_addr(const uint8_t *flow, int flowlen, int type, int is_v6, + struct bgpd_addr *addr, uint8_t *plen, uint8_t *olen) +{ + const uint8_t *comp; + int complen, rv; + + memset(addr, 0, sizeof(*addr)); + *plen = 0; + if (olen != NULL) + *olen = 0; + + rv = flowspec_get_component(flow, flowlen, type, is_v6, + &comp, &complen); + if (rv != 1) + return rv; + + /* flowspec_get_component only returns valid encodings */ + if (!is_v6) { + addr->aid = AID_INET; + if (extract_prefix(comp + 1, complen - 1, &addr->v4, comp[0], + sizeof(addr->v4)) == -1) + return -1; + *plen = comp[0]; + } else { + uint8_t buf[16] = { 0 }; + int xlen, xoff = 0; + + addr->aid = AID_INET6; + xlen = comp[0]; + if (comp[1] != 0) { + if (olen == NULL) + return -1; + xoff = comp[1]; + xlen -= xoff; + } + if (extract_prefix(comp + 2, complen - 2, buf, xlen, + sizeof(buf)) == -1) + return -1; + shift_right(addr->v6.s6_addr, buf, *olen, xlen); + *plen = comp[0]; + if (olen != NULL) + *olen = comp[1]; + } + + return 1; +} + +const char * +flowspec_fmt_label(int type) +{ + switch (type) { + case FLOWSPEC_TYPE_DEST: + return "to"; + case FLOWSPEC_TYPE_SOURCE: + return "from"; + case FLOWSPEC_TYPE_PROTO: + return "proto"; + case FLOWSPEC_TYPE_PORT: + case FLOWSPEC_TYPE_DST_PORT: + case FLOWSPEC_TYPE_SRC_PORT: + return "port"; + case FLOWSPEC_TYPE_ICMP_TYPE: + return "icmp-type"; + case FLOWSPEC_TYPE_ICMP_CODE: + return "icmp-code"; + case FLOWSPEC_TYPE_TCP_FLAGS: + return "flags"; + case FLOWSPEC_TYPE_PKT_LEN: + return "length"; + case FLOWSPEC_TYPE_DSCP: + return "tos"; + case FLOWSPEC_TYPE_FRAG: + return "fragment"; + case FLOWSPEC_TYPE_FLOW: + return "flow"; + default: + return "???"; + } +} + +static uint64_t +extract_val(const uint8_t *comp, int len) +{ + uint64_t val = 0; + + while (len-- > 0) { + val <<= 8; + val |= *comp++; + } + return val; +} + +const char * +flowspec_fmt_num_op(const uint8_t *comp, int complen, int *off) +{ + static char buf[32]; + uint64_t val, val2 = 0; + uint8_t op, op2 = 0; + int len, len2 = 0; + + if (*off == -1) + return ""; + if (complen < *off + 1) + return "bad encoding"; + + op = comp[*off]; + len = FLOWSPEC_OP_LEN(op) + 1; + if (complen < *off + len) + return "bad encoding"; + val = extract_val(comp + *off + 1, FLOWSPEC_OP_LEN(op)); + + if ((op & FLOWSPEC_OP_EOL) == 0) { + if (complen < *off + len + 1) + return "bad encoding"; + op2 = comp[*off + len]; + /* + * Check if this is a range specification else fall back + * to basic rules. + */ + if (op2 & FLOWSPEC_OP_AND && + (op & FLOWSPEC_OP_NUM_MASK) == FLOWSPEC_OP_NUM_GE && + (op2 & FLOWSPEC_OP_NUM_MASK) == FLOWSPEC_OP_NUM_LE) { + len2 = FLOWSPEC_OP_LEN(op2) + 1; + val2 = extract_val(comp + *off + len + 1, + FLOWSPEC_OP_LEN(op2)); + } else + op2 = 0; + } + + if (op2 & FLOWSPEC_OP_AND) { + /* binary range operation */ + snprintf(buf, sizeof(buf), "%llu - %llu", + (unsigned long long)val, (unsigned long long)val2); + } else { + /* unary operation */ + switch (op & FLOWSPEC_OP_NUM_MASK) { + case 0: + snprintf(buf, sizeof(buf), "%sfalse", + op & FLOWSPEC_OP_AND ? "&& " : ""); + break; + case FLOWSPEC_OP_NUM_EQ: + snprintf(buf, sizeof(buf), "%s%llu", + op & FLOWSPEC_OP_AND ? "&& " : "", + (unsigned long long)val); + break; + case FLOWSPEC_OP_NUM_GT: + snprintf(buf, sizeof(buf), "%s> %llu", + op & FLOWSPEC_OP_AND ? "&& " : "", + (unsigned long long)val); + break; + case FLOWSPEC_OP_NUM_GE: + snprintf(buf, sizeof(buf), "%s>= %llu", + op & FLOWSPEC_OP_AND ? "&& " : "", + (unsigned long long)val); + break; + case FLOWSPEC_OP_NUM_LT: + snprintf(buf, sizeof(buf), "%s< %llu", + op & FLOWSPEC_OP_AND ? "&& " : "", + (unsigned long long)val); + break; + case FLOWSPEC_OP_NUM_LE: + snprintf(buf, sizeof(buf), "%s<= %llu", + op & FLOWSPEC_OP_AND ? "&& " : "", + (unsigned long long)val); + break; + case FLOWSPEC_OP_NUM_NOT: + snprintf(buf, sizeof(buf), "%s!= %llu", + op & FLOWSPEC_OP_AND ? "&& " : "", + (unsigned long long)val); + break; + case 0x7: + snprintf(buf, sizeof(buf), "%strue", + op & FLOWSPEC_OP_AND ? "&& " : ""); + break; + } + } + + if (op2 & FLOWSPEC_OP_EOL || op & FLOWSPEC_OP_EOL) + *off = -1; + else + *off += len + len2; + + return buf; +} + +static const char * +fmt_flags(uint64_t val, const char *bits, char *buf, size_t blen) +{ + int i, bi; + + for (i = 0, bi = 0; i < 64 && val != 0; i++) { + if (val & 1) { + if (bits[i] == '\0' || bits[i] == ' ') + goto fail; + buf[bi++] = bits[i]; + } + val >>= 1; + } + buf[bi++] = '\0'; + return buf; + +fail: + snprintf(buf, blen, "%llx", (unsigned long long)val); + return buf; +} + +const char * +flowspec_fmt_bin_op(const uint8_t *comp, int complen, int *off, + const char *bits) +{ + static char buf[36], bit[17], mask[17]; + uint64_t val, val2 = 0; + uint8_t op, op2 = 0; + int len, len2 = 0; + + if (*off == -1) + return ""; + if (complen < *off + 1) + return "bad encoding"; + + op = comp[*off]; + len = FLOWSPEC_OP_LEN(op) + 1; + if (complen < *off + len) + return "bad encoding"; + val = extract_val(comp + *off + 1, FLOWSPEC_OP_LEN(op)); + + if ((op & FLOWSPEC_OP_EOL) == 0) { + if (complen < *off + len + 1) + return "bad encoding"; + op2 = comp[*off + len]; + /* + * Check if this is a mask specification else fall back + * to basic rules. + */ + if (op2 & FLOWSPEC_OP_AND && + (op & FLOWSPEC_OP_BIT_MASK) == FLOWSPEC_OP_BIT_MATCH && + (op2 & FLOWSPEC_OP_BIT_MASK) == FLOWSPEC_OP_BIT_NOT) { + len2 = FLOWSPEC_OP_LEN(op2) + 1; + val2 = extract_val(comp + *off + len + 1, + FLOWSPEC_OP_LEN(op2)); + } else + op2 = 0; + } + + if (op2 & FLOWSPEC_OP_AND) { + val2 |= val; + snprintf(buf, sizeof(buf), "%s / %s", + fmt_flags(val, bits, bit, sizeof(bit)), + fmt_flags(val2, bits, mask, sizeof(mask))); + } else { + switch (op & FLOWSPEC_OP_BIT_MASK) { + case 0: + snprintf(buf, sizeof(buf), "%s", + fmt_flags(val, bits, bit, sizeof(bit))); + break; + case FLOWSPEC_OP_BIT_NOT: + snprintf(buf, sizeof(buf), "/ %s", + fmt_flags(val, bits, mask, sizeof(mask))); + break; + case FLOWSPEC_OP_BIT_MATCH: + snprintf(buf, sizeof(buf), "%s / %s", + fmt_flags(val, bits, bit, sizeof(bit)), + fmt_flags(val, bits, mask, sizeof(mask))); + break; + case FLOWSPEC_OP_BIT_NOT | FLOWSPEC_OP_BIT_MATCH: + snprintf(buf, sizeof(buf), "???"); + break; + } + } + + if (op2 & FLOWSPEC_OP_EOL || op & FLOWSPEC_OP_EOL) + *off = -1; + else + *off += len + len2; + + return buf; +} diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c index e11755a0750..a7ac90a3b5d 100644 --- a/usr.sbin/bgpd/util.c +++ b/usr.sbin/bgpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.76 2023/04/03 10:48:00 claudio Exp $ */ +/* $OpenBSD: util.c,v 1.77 2023/04/17 08:02:21 claudio Exp $ */ /* * Copyright (c) 2006 Claudio Jeker @@ -494,8 +494,8 @@ aspath_inflate(void *data, uint16_t len, uint16_t *newlen) } /* NLRI functions to extract prefixes from the NLRI blobs */ -static int -extract_prefix(u_char *p, uint16_t len, void *va, uint8_t pfxlen, uint8_t max) +int +extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max) { static u_char addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; -- 2.20.1