Index | Thread | Search

From:
Claudio Jeker <cjeker@diehard.n-r-g.com>
Subject:
bgpd: last bit of rde_attr_parse ibuf cleanup
To:
tech@openbsd.org
Date:
Thu, 25 Jan 2024 14:25:51 +0100

Download raw body.

Thread
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);
 }