Download raw body.
bgpd: last bit of rde_attr_parse ibuf cleanup
This converts the ATTR_ASPATH and ATTR_AS4_PATH handlers in
rde_attr_parse(). To do this the various aspath validation and print
functions got some ibuf treatment and the result is IMO nicer then the
code before.
Again there are tentacles in bgpctl so handle them as well. This converts
IMSG_CTL_SHOW_RIB and adds a bit of a hack to the show_attr() bits --
those will be cleaned up soon.
The util.c changes are the ones that need some careful review. The rest of
this change is rather simple.
--
:wq Claudio
Index: usr.sbin/bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
diff -u -p -r1.302 bgpctl.c
--- usr.sbin/bgpctl/bgpctl.c 25 Jan 2024 09:54:21 -0000 1.302
+++ usr.sbin/bgpctl/bgpctl.c 25 Jan 2024 11:52:40 -0000
@@ -471,9 +471,7 @@ show(struct imsg *imsg, struct parse_res
struct ctl_show_rib rib;
struct rde_memstats stats;
struct ibuf ibuf;
- u_char *asdata;
u_int rescode, ilen;
- size_t aslen;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_NEIGHBOR:
@@ -528,16 +526,13 @@ show(struct imsg *imsg, struct parse_res
output->fib_table(&kt);
break;
case IMSG_CTL_SHOW_RIB:
- if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(rib))
- errx(1, "wrong imsg len");
if (output->rib == NULL)
break;
- /* XXX */
- memcpy(&rib, imsg->data, sizeof(rib));
- aslen = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof(rib);
- asdata = imsg->data;
- asdata += sizeof(rib);
- output->rib(&rib, asdata, aslen, res);
+ if (imsg_get_ibuf(imsg, &ibuf) == -1)
+ err(1, "imsg_get_ibuf");
+ if (ibuf_get(&ibuf, &rib, sizeof(rib)) == -1)
+ err(1, "imsg_get_ibuf");
+ output->rib(&rib, &ibuf, res);
break;
case IMSG_CTL_SHOW_RIB_COMMUNITIES:
if (output->communities == NULL)
@@ -1231,6 +1226,7 @@ show_mrt_dump(struct mrt_rib *mr, struct
struct parse_result res;
struct ctl_show_rib_request *req = arg;
struct mrt_rib_entry *mre;
+ struct ibuf ibuf;
time_t now;
uint16_t i, j;
@@ -1296,7 +1292,8 @@ show_mrt_dump(struct mrt_rib *mr, struct
!match_aspath(mre->aspath, mre->aspath_len, &req->as))
continue;
- output->rib(&ctl, mre->aspath, mre->aspath_len, &res);
+ ibuf_from_buffer(&ibuf, mre->aspath, mre->aspath_len);
+ output->rib(&ctl, &ibuf, &res);
if (req->flags & F_CTL_DETAIL) {
for (j = 0; j < mre->nattrs; j++)
output->attr(mre->attrs[j].attr,
Index: usr.sbin/bgpctl/bgpctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.h,v
diff -u -p -r1.22 bgpctl.h
--- usr.sbin/bgpctl/bgpctl.h 25 Jan 2024 09:54:21 -0000 1.22
+++ usr.sbin/bgpctl/bgpctl.h 25 Jan 2024 11:51:02 -0000
@@ -29,7 +29,7 @@ struct output {
void (*interface)(struct ctl_show_interface *);
void (*attr)(u_char *, size_t, int, int);
void (*communities)(struct ibuf *, struct parse_result *);
- void (*rib)(struct ctl_show_rib *, u_char *, size_t,
+ void (*rib)(struct ctl_show_rib *, struct ibuf *,
struct parse_result *);
void (*rib_mem)(struct rde_memstats *);
void (*set)(struct ctl_show_set *);
Index: usr.sbin/bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
diff -u -p -r1.48 output.c
--- usr.sbin/bgpctl/output.c 25 Jan 2024 09:54:21 -0000 1.48
+++ usr.sbin/bgpctl/output.c 25 Jan 2024 11:53:03 -0000
@@ -769,10 +769,10 @@ show_ext_community(u_char *data, uint16_
static void
show_attr(u_char *data, size_t len, int reqflags, int addpath)
{
- u_char *path;
+ u_char *path = NULL;
struct in_addr id;
struct bgpd_addr prefix;
- struct ibuf ibuf, *buf = &ibuf;
+ struct ibuf ibuf, *buf = &ibuf, asbuf;
char *aspath;
uint32_t as, pathid;
uint16_t alen, ioff, short_as, afi;
@@ -820,25 +820,26 @@ show_attr(u_char *data, size_t len, int
break;
case ATTR_ASPATH:
case ATTR_AS4_PATH:
+ ibuf_from_buffer(buf, data, alen);
/* prefer 4-byte AS here */
- e4 = aspath_verify(data, alen, 1, 0);
- e2 = aspath_verify(data, alen, 0, 0);
+ e4 = aspath_verify(buf, 1, 0);
+ e2 = aspath_verify(buf, 0, 0);
if (e4 == 0 || e4 == AS_ERR_SOFT) {
- path = data;
+ ibuf_from_ibuf(&asbuf, buf);
} else if (e2 == 0 || e2 == AS_ERR_SOFT) {
- path = aspath_inflate(data, alen, &alen);
- if (path == NULL)
- errx(1, "aspath_inflate failed");
+ if ((path = aspath_inflate(buf, &asbuf)) == NULL) {
+ printf("aspath_inflate failed");
+ break;
+ }
} else {
printf("bad AS-Path");
break;
}
- if (aspath_asprint(&aspath, path, alen) == -1)
+ if (aspath_asprint(&aspath, &asbuf) == -1)
err(1, NULL);
printf("%s", aspath);
free(aspath);
- if (path != data)
- free(path);
+ free(path);
break;
case ATTR_NEXTHOP:
if (alen == 4) {
@@ -1013,7 +1014,7 @@ show_attr(u_char *data, size_t len, int
}
static void
-show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen)
+show_rib_brief(struct ctl_show_rib *r, struct ibuf *asbuf)
{
char *p, *aspath;
@@ -1025,7 +1026,7 @@ show_rib_brief(struct ctl_show_rib *r, u
log_addr(&r->exit_nexthop), r->local_pref, r->med);
free(p);
- if (aspath_asprint(&aspath, asdata, aslen) == -1)
+ if (aspath_asprint(&aspath, asbuf) == -1)
err(1, NULL);
if (strlen(aspath) > 0)
printf("%s ", aspath);
@@ -1035,8 +1036,7 @@ show_rib_brief(struct ctl_show_rib *r, u
}
static void
-show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen,
- int flag0)
+show_rib_detail(struct ctl_show_rib *r, struct ibuf *asbuf, int flag0)
{
struct in_addr id;
char *aspath, *s;
@@ -1045,7 +1045,7 @@ show_rib_detail(struct ctl_show_rib *r,
log_addr(&r->prefix), r->prefixlen,
EOL0(flag0));
- if (aspath_asprint(&aspath, asdata, aslen) == -1)
+ if (aspath_asprint(&aspath, asbuf) == -1)
err(1, NULL);
if (strlen(aspath) > 0)
printf(" %s%c", aspath, EOL0(flag0));
@@ -1072,13 +1072,12 @@ show_rib_detail(struct ctl_show_rib *r,
}
static void
-show_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen,
- struct parse_result *res)
+show_rib(struct ctl_show_rib *r, struct ibuf *aspath, struct parse_result *res)
{
if (res->flags & F_CTL_DETAIL)
- show_rib_detail(r, asdata, aslen, res->flags);
+ show_rib_detail(r, aspath, res->flags);
else
- show_rib_brief(r, asdata, aslen);
+ show_rib_brief(r, aspath);
}
static void
Index: usr.sbin/bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
diff -u -p -r1.40 output_json.c
--- usr.sbin/bgpctl/output_json.c 25 Jan 2024 09:54:21 -0000 1.40
+++ usr.sbin/bgpctl/output_json.c 25 Jan 2024 11:56:08 -0000
@@ -589,9 +589,9 @@ json_attr(u_char *data, size_t len, int
{
struct bgpd_addr prefix;
struct in_addr id;
- struct ibuf ibuf, *buf = &ibuf;
+ struct ibuf ibuf, *buf = &ibuf, asbuf;
char *aspath;
- u_char *path;
+ u_char *path = NULL;
uint32_t as, pathid;
uint16_t alen, afi, off, short_as;
uint8_t flags, type, safi, aid, prefixlen;
@@ -645,25 +645,27 @@ json_attr(u_char *data, size_t len, int
break;
case ATTR_ASPATH:
case ATTR_AS4_PATH:
+ ibuf_from_buffer(buf, data, alen);
/* prefer 4-byte AS here */
- e4 = aspath_verify(data, alen, 1, 0);
- e2 = aspath_verify(data, alen, 0, 0);
+ e4 = aspath_verify(buf, 1, 0);
+ e2 = aspath_verify(buf, 0, 0);
if (e4 == 0 || e4 == AS_ERR_SOFT) {
- path = data;
+ ibuf_from_ibuf(&asbuf, buf);
} else if (e2 == 0 || e2 == AS_ERR_SOFT) {
- path = aspath_inflate(data, alen, &alen);
- if (path == NULL)
- errx(1, "aspath_inflate failed");
+ if ((path = aspath_inflate(buf, &asbuf)) == NULL) {
+ json_do_string("error",
+ "aspath_inflate failed");
+ break;
+ }
} else {
json_do_string("error", "bad AS-Path");
break;
}
- if (aspath_asprint(&aspath, path, alen) == -1)
+ if (aspath_asprint(&aspath, &asbuf) == -1)
err(1, NULL);
json_do_string("aspath", aspath);
free(aspath);
- if (path != data)
- free(path);
+ free(path);
break;
case ATTR_NEXTHOP:
if (alen == 4) {
@@ -841,8 +843,7 @@ bad_len:
}
static void
-json_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen,
- struct parse_result *res)
+json_rib(struct ctl_show_rib *r, struct ibuf *asbuf, struct parse_result *res)
{
struct in_addr id;
char *aspath;
@@ -853,7 +854,7 @@ json_rib(struct ctl_show_rib *r, u_char
json_do_printf("prefix", "%s/%u", log_addr(&r->prefix), r->prefixlen);
- if (aspath_asprint(&aspath, asdata, aslen) == -1)
+ if (aspath_asprint(&aspath, asbuf) == -1)
err(1, NULL);
json_do_string("aspath", aspath);
free(aspath);
Index: usr.sbin/bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
diff -u -p -r1.483 bgpd.h
--- usr.sbin/bgpd/bgpd.h 23 Jan 2024 16:13:35 -0000 1.483
+++ usr.sbin/bgpd/bgpd.h 25 Jan 2024 11:14:50 -0000
@@ -1542,20 +1542,19 @@ const char *log_as(uint32_t);
const char *log_rd(uint64_t);
const char *log_ext_subtype(int, uint8_t);
const char *log_reason(const char *);
+const char *log_aspath_error(int);
const char *log_roa(struct roa *);
const char *log_aspa(struct aspa_set *);
const char *log_rtr_error(enum rtr_error);
const char *log_policy(enum role);
-int aspath_snprint(char *, size_t, void *, uint16_t);
-int aspath_asprint(char **, void *, uint16_t);
-size_t aspath_strlen(void *, uint16_t);
+int aspath_asprint(char **, struct ibuf *);
uint32_t aspath_extract(const void *, int);
-int aspath_verify(void *, uint16_t, int, int);
+int aspath_verify(struct ibuf *, int, int);
#define AS_ERR_LEN -1
#define AS_ERR_TYPE -2
#define AS_ERR_BAD -3
#define AS_ERR_SOFT -4
-u_char *aspath_inflate(void *, uint16_t, uint16_t *);
+void *aspath_inflate(struct ibuf *, struct ibuf *);
int extract_prefix(const u_char *, int, void *, uint8_t, uint8_t);
int nlri_get_prefix(struct ibuf *, struct bgpd_addr *, uint8_t *);
int nlri_get_prefix6(struct ibuf *, struct bgpd_addr *, uint8_t *);
Index: usr.sbin/bgpd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
diff -u -p -r1.619 rde.c
--- usr.sbin/bgpd/rde.c 25 Jan 2024 11:13:35 -0000 1.619
+++ usr.sbin/bgpd/rde.c 25 Jan 2024 11:14:50 -0000
@@ -1916,13 +1916,6 @@ rde_update_withdraw(struct rde_peer *pee
*/
/* attribute parser specific macros */
-#define UPD_READ(t, p, plen, n) \
- do { \
- memcpy(t, p, n); \
- p += n; \
- plen += n; \
- } while (0)
-
#define CHECK_FLAGS(s, t, m) \
(((s) & ~(ATTR_DEFMASK | (m))) == (t))
@@ -1933,11 +1926,10 @@ rde_attr_parse(struct ibuf *buf, struct
struct bgpd_addr nexthop;
struct rde_aspath *a = &state->aspath;
struct ibuf attrbuf, tmpbuf;
- u_char *p, *npath;
+ u_char *npath = NULL;
+ size_t alen, hlen;
uint32_t tmp32, zero = 0;
int error;
- uint16_t nlen;
- size_t attr_len, hlen, plen;
uint8_t flags, type;
ibuf_from_ibuf(&attrbuf, buf);
@@ -1945,30 +1937,26 @@ rde_attr_parse(struct ibuf *buf, struct
ibuf_get_n8(&attrbuf, &type) == -1)
goto bad_list;
-
if (flags & ATTR_EXTLEN) {
- uint16_t alen;
- if (ibuf_get_n16(&attrbuf, &alen) == -1)
+ uint16_t attr_len;
+ if (ibuf_get_n16(&attrbuf, &attr_len) == -1)
goto bad_list;
- attr_len = alen;
+ alen = attr_len;
hlen = 4;
} else {
- uint8_t alen;
- if (ibuf_get_n8(&attrbuf, &alen) == -1)
+ uint8_t attr_len;
+ if (ibuf_get_n8(&attrbuf, &attr_len) == -1)
goto bad_list;
- attr_len = alen;
+ alen = attr_len;
hlen = 3;
}
- if (ibuf_truncate(&attrbuf, attr_len) == -1)
+ if (ibuf_truncate(&attrbuf, alen) == -1)
goto bad_list;
/* consume the attribute in buf before moving forward */
- if (ibuf_skip(buf, hlen + attr_len) == -1)
+ if (ibuf_skip(buf, hlen + alen) == -1)
goto bad_list;
- p = ibuf_data(&attrbuf);
- plen = ibuf_size(&attrbuf);
-
switch (type) {
case ATTR_UNDEF:
/* ignore and drop path attributes with a type code of 0 */
@@ -1998,44 +1986,43 @@ rde_attr_parse(struct ibuf *buf, struct
case ATTR_ASPATH:
if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
goto bad_flags;
- error = aspath_verify(p, attr_len, peer_has_as4byte(peer),
+ if (a->flags & F_ATTR_ASPATH)
+ goto bad_list;
+ error = aspath_verify(&attrbuf, peer_has_as4byte(peer),
peer_accept_no_as_set(peer));
- if (error == AS_ERR_SOFT) {
- /*
- * soft errors like unexpected segment types are
- * not considered fatal and the path is just
- * marked invalid.
- */
- a->flags |= F_ATTR_PARSE_ERR;
- } else if (error != 0) {
+ if (error != 0 && error != AS_ERR_SOFT) {
+ log_peer_warnx(&peer->conf, "bad ASPATH, %s",
+ log_aspath_error(error));
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
NULL);
return (-1);
}
- if (a->flags & F_ATTR_ASPATH)
- goto bad_list;
if (peer_has_as4byte(peer)) {
- npath = p;
- nlen = attr_len;
+ ibuf_from_ibuf(&tmpbuf, &attrbuf);
} else {
- npath = aspath_inflate(p, attr_len, &nlen);
+ npath = aspath_inflate(&attrbuf, &tmpbuf);
if (npath == NULL)
fatal("aspath_inflate");
}
if (error == AS_ERR_SOFT) {
char *str;
- aspath_asprint(&str, npath, nlen);
+ /*
+ * soft errors like unexpected segment types are
+ * not considered fatal and the path is just
+ * marked invalid.
+ */
+ a->flags |= F_ATTR_PARSE_ERR;
+
+ aspath_asprint(&str, &tmpbuf);
log_peer_warnx(&peer->conf, "bad ASPATH %s, "
"path invalidated and prefix withdrawn",
str ? str : "(bad aspath)");
free(str);
}
a->flags |= F_ATTR_ASPATH;
- a->aspath = aspath_get(npath, nlen);
- if (npath != p)
- free(npath);
- plen += attr_len;
+ a->aspath = aspath_get(ibuf_data(&tmpbuf), ibuf_size(&tmpbuf));
+ free(npath);
break;
case ATTR_NEXTHOP:
if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
@@ -2050,7 +2037,6 @@ rde_attr_parse(struct ibuf *buf, struct
nexthop.aid = AID_INET;
if (ibuf_get_h32(&attrbuf, &nexthop.v4.s_addr) == -1)
goto bad_len;
-
/*
* Check if the nexthop is a valid IP address. We consider
* multicast addresses as invalid.
@@ -2245,12 +2231,11 @@ rde_attr_parse(struct ibuf *buf, struct
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
ATTR_PARTIAL))
goto bad_flags;
- if ((error = aspath_verify(p, attr_len, 1,
+ if ((error = aspath_verify(&attrbuf, 1,
peer_accept_no_as_set(peer))) != 0) {
/* As per RFC6793 use "attribute discard" here. */
log_peer_warnx(&peer->conf, "bad AS4_PATH, "
"attribute discarded");
- plen += attr_len;
break;
}
a->flags |= F_ATTR_AS4BYTE_NEW;
@@ -2295,7 +2280,6 @@ rde_attr_parse(struct ibuf *buf, struct
break;
}
- (void)plen; /* XXX make compiler happy for now */
return (0);
bad_len:
@@ -2309,7 +2293,6 @@ rde_attr_parse(struct ibuf *buf, struct
return (-1);
}
-#undef UPD_READ
#undef CHECK_FLAGS
int
Index: usr.sbin/bgpd/util.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
diff -u -p -r1.79 util.c
--- usr.sbin/bgpd/util.c 23 Jan 2024 16:13:35 -0000 1.79
+++ usr.sbin/bgpd/util.c 25 Jan 2024 11:14:50 -0000
@@ -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)
{
@@ -236,6 +234,26 @@ log_aspa(struct aspa_set *aspa)
}
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)
{
static char buf[20];
@@ -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,37 @@ aspath_delim(uint8_t seg_type, int closi
}
}
-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;
+
+ 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)
+ return (-1);
- r = snprintf(buf, size, "%s%s",
- total_size != 0 ? " " : "",
+ 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 +377,67 @@ aspath_snprint(char *buf, size_t size, v
UPDATE();
}
/* ensure that we have a valid C-string especially for empty as path */
- if (size > 0)
- *buf = '\0';
-
- return (total_size);
-#undef UPDATE
-}
-
-int
-aspath_asprint(char **ret, void *data, uint16_t len)
-{
- 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);
- }
-
+ *buf = '\0';
return (0);
+#undef UPDATE
}
-size_t
-aspath_strlen(void *data, uint16_t len)
+static ssize_t
+aspath_strsize(struct ibuf *in)
{
- 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;
-
- if (seg_type == AS_SET)
- if (total_size != 0)
- total_size += 3;
- else
- total_size += 2;
- else if (total_size != 0)
+ 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)
+ return (-1);
+
+ 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 +463,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);
-
- if (as4byte)
- as_size = 4;
-
- for (; len > 0; len -= seg_size, seg += seg_size) {
- const uint8_t *ptr;
- int pos;
+ error = AS_ERR_BAD;
+ goto done;
+ }
- if (len < 2) /* header length check */
- return (AS_ERR_BAD);
- seg_type = seg[0];
- seg_len = seg[1];
+ 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;
+ }
- 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,69 +503,86 @@ aspath_verify(void *data, uint16_t len,
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)
+void *
+aspath_inflate(struct ibuf *in, struct ibuf *out)
{
- uint8_t *seg, *nseg, *ndata;
- uint16_t seg_size, olen, nlen;
+ struct ibuf buf;
+ uint8_t *nseg, *ndata;
+ size_t seg_size, nlen = 0;
uint8_t seg_len;
+ /* clone buffer so we can pass it twice without altering in */
+ ibuf_from_ibuf(&buf, in);
/* 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;
+ while (ibuf_size(&buf) > 0) {
+ if (ibuf_skip(&buf, 1) == -1 ||
+ ibuf_get_n8(&buf, &seg_len) == -1)
return (NULL);
- }
+ seg_size = sizeof(uint16_t) * seg_len;
+ if (ibuf_skip(&buf, seg_size) == -1)
+ return (NULL);
+ nlen += 2 + sizeof(uint32_t) * seg_len;
}
- *newlen = nlen;
- if ((ndata = malloc(nlen)) == NULL)
+ if ((nseg = ndata = malloc(nlen)) == NULL)
return (NULL);
+ ibuf_from_ibuf(&buf, in);
/* then copy the aspath */
- seg = data;
- for (nseg = ndata; nseg < ndata + nlen; ) {
- *nseg++ = *seg++;
- *nseg++ = seg_len = *seg++;
+ while (ibuf_size(&buf) > 0) {
+ if (ibuf_get_n8(&buf, nseg++) == -1 ||
+ ibuf_get_n8(&buf, &seg_len) == -1) {
+ free(ndata);
+ return (NULL);
+ }
+ *nseg++ = seg_len;
for (; seg_len > 0; seg_len--) {
*nseg++ = 0;
*nseg++ = 0;
- *nseg++ = *seg++;
- *nseg++ = *seg++;
+ if (ibuf_get_n8(&buf, nseg++) == -1 ||
+ ibuf_get_n8(&buf, nseg++) == -1) {
+ free(ndata);
+ return (NULL);
+ }
}
}
+ ibuf_from_buffer(out, ndata, nlen);
return (ndata);
}
bgpd: last bit of rde_attr_parse ibuf cleanup