xref: /openbsd-src/usr.sbin/bgpctl/mrtparser.c (revision d0fc3bb68efd6c434b4053cd7adb29023cbec341)
1 /*	$OpenBSD: mrtparser.c,v 1.14 2021/01/18 12:16:09 claudio Exp $ */
2 /*
3  * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <err.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include "mrt.h"
30 #include "mrtparser.h"
31 
32 void	*mrt_read_msg(int, struct mrt_hdr *);
33 size_t	 mrt_read_buf(int, void *, size_t);
34 
35 struct mrt_peer	*mrt_parse_v2_peer(struct mrt_hdr *, void *);
36 struct mrt_rib	*mrt_parse_v2_rib(struct mrt_hdr *, void *, int);
37 int	mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **,
38 	    struct mrt_rib **);
39 int	mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **,
40 	    struct mrt_rib **, int);
41 int	mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, u_int8_t,
42 	    int);
43 
44 void	mrt_free_peers(struct mrt_peer *);
45 void	mrt_free_rib(struct mrt_rib *);
46 void	mrt_free_bgp_state(struct mrt_bgp_state *);
47 void	mrt_free_bgp_msg(struct mrt_bgp_msg *);
48 
49 u_char *mrt_aspath_inflate(void *, u_int16_t, u_int16_t *);
50 int	mrt_extract_addr(void *, u_int, struct bgpd_addr *, u_int8_t);
51 int	mrt_extract_prefix(void *, u_int, u_int8_t, struct bgpd_addr *,
52 	    u_int8_t *, int);
53 
54 struct mrt_bgp_state	*mrt_parse_state(struct mrt_hdr *, void *, int);
55 struct mrt_bgp_msg	*mrt_parse_msg(struct mrt_hdr *, void *, int);
56 
57 void *
58 mrt_read_msg(int fd, struct mrt_hdr *hdr)
59 {
60 	void *buf;
61 
62 	bzero(hdr, sizeof(*hdr));
63 	if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr))
64 		return (NULL);
65 
66 	if ((buf = malloc(ntohl(hdr->length))) == NULL)
67 		err(1, "malloc(%d)", hdr->length);
68 
69 	if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) {
70 		free(buf);
71 		return (NULL);
72 	}
73 	return (buf);
74 }
75 
76 size_t
77 mrt_read_buf(int fd, void *buf, size_t len)
78 {
79 	char *b = buf;
80 	ssize_t n;
81 
82 	while (len > 0) {
83 		if ((n = read(fd, b, len)) == -1) {
84 			if (errno == EINTR)
85 				continue;
86 			err(1, "read");
87 		}
88 		if (n == 0)
89 			break;
90 		b += n;
91 		len -= n;
92 	}
93 
94 	return (b - (char *)buf);
95 }
96 
97 void
98 mrt_parse(int fd, struct mrt_parser *p, int verbose)
99 {
100 	struct mrt_hdr		h;
101 	struct mrt_peer		*pctx = NULL;
102 	struct mrt_rib		*r;
103 	struct mrt_bgp_state	*s;
104 	struct mrt_bgp_msg	*m;
105 	void			*msg;
106 
107 	while ((msg = mrt_read_msg(fd, &h))) {
108 		switch (ntohs(h.type)) {
109 		case MSG_NULL:
110 		case MSG_START:
111 		case MSG_DIE:
112 		case MSG_I_AM_DEAD:
113 		case MSG_PEER_DOWN:
114 		case MSG_PROTOCOL_BGP:
115 		case MSG_PROTOCOL_IDRP:
116 		case MSG_PROTOCOL_BGP4PLUS:
117 		case MSG_PROTOCOL_BGP4PLUS1:
118 			if (verbose)
119 				printf("deprecated MRT type %d\n",
120 				    ntohs(h.type));
121 			break;
122 		case MSG_PROTOCOL_RIP:
123 		case MSG_PROTOCOL_RIPNG:
124 		case MSG_PROTOCOL_OSPF:
125 		case MSG_PROTOCOL_ISIS_ET:
126 		case MSG_PROTOCOL_ISIS:
127 		case MSG_PROTOCOL_OSPFV3_ET:
128 		case MSG_PROTOCOL_OSPFV3:
129 			if (verbose)
130 				printf("unsuported MRT type %d\n",
131 				    ntohs(h.type));
132 			break;
133 		case MSG_TABLE_DUMP:
134 			switch (ntohs(h.subtype)) {
135 			case MRT_DUMP_AFI_IP:
136 			case MRT_DUMP_AFI_IPv6:
137 				if (p->dump == NULL)
138 					break;
139 				if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) {
140 					if (p->dump)
141 						p->dump(r, pctx, p->arg);
142 					mrt_free_rib(r);
143 				}
144 				break;
145 			default:
146 				if (verbose)
147 					printf("unknown AFI %d in table dump\n",
148 					    ntohs(h.subtype));
149 				break;
150 			}
151 			break;
152 		case MSG_TABLE_DUMP_V2:
153 			switch (ntohs(h.subtype)) {
154 			case MRT_DUMP_V2_PEER_INDEX_TABLE:
155 				if (p->dump == NULL)
156 					break;
157 				if (pctx)
158 					mrt_free_peers(pctx);
159 				pctx = mrt_parse_v2_peer(&h, msg);
160 				break;
161 			case MRT_DUMP_V2_RIB_IPV4_UNICAST:
162 			case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
163 			case MRT_DUMP_V2_RIB_IPV6_UNICAST:
164 			case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
165 			case MRT_DUMP_V2_RIB_GENERIC:
166 				if (p->dump == NULL)
167 					break;
168 				r = mrt_parse_v2_rib(&h, msg, verbose);
169 				if (r) {
170 					if (p->dump)
171 						p->dump(r, pctx, p->arg);
172 					mrt_free_rib(r);
173 				}
174 				break;
175 			default:
176 				if (verbose)
177 					printf("unhandled DUMP_V2 subtype %d\n",
178 					    ntohs(h.subtype));
179 				break;
180 			}
181 			break;
182 		case MSG_PROTOCOL_BGP4MP_ET:
183 		case MSG_PROTOCOL_BGP4MP:
184 			switch (ntohs(h.subtype)) {
185 			case BGP4MP_STATE_CHANGE:
186 			case BGP4MP_STATE_CHANGE_AS4:
187 				if ((s = mrt_parse_state(&h, msg, verbose))) {
188 					if (p->state)
189 						p->state(s, p->arg);
190 					free(s);
191 				}
192 				break;
193 			case BGP4MP_MESSAGE:
194 			case BGP4MP_MESSAGE_AS4:
195 			case BGP4MP_MESSAGE_LOCAL:
196 			case BGP4MP_MESSAGE_AS4_LOCAL:
197 				if ((m = mrt_parse_msg(&h, msg, verbose))) {
198 					if (p->message)
199 						p->message(m, p->arg);
200 					free(m->msg);
201 					free(m);
202 				}
203 				break;
204 			case BGP4MP_ENTRY:
205 				if (p->dump == NULL)
206 					break;
207 				if (mrt_parse_dump_mp(&h, msg, &pctx, &r,
208 				    verbose) == 0) {
209 					if (p->dump)
210 						p->dump(r, pctx, p->arg);
211 					mrt_free_rib(r);
212 				}
213 				break;
214 			default:
215 				if (verbose)
216 					printf("unhandled BGP4MP subtype %d\n",
217 					    ntohs(h.subtype));
218 				break;
219 			}
220 			break;
221 		default:
222 			if (verbose)
223 				printf("unknown MRT type %d\n", ntohs(h.type));
224 			break;
225 		}
226 		free(msg);
227 	}
228 	if (pctx)
229 		mrt_free_peers(pctx);
230 }
231 
232 static int
233 mrt_afi2aid(int afi, int safi, int verbose)
234 {
235 	switch (afi) {
236 	case MRT_DUMP_AFI_IP:
237 		if (safi == -1 || safi == 1 || safi == 2)
238 			return AID_INET;
239 		else if (safi == 128)
240 			return AID_VPN_IPv4;
241 		break;
242 	case MRT_DUMP_AFI_IPv6:
243 		if (safi == -1 || safi == 1 || safi == 2)
244 			return AID_INET6;
245 		else if (safi == 128)
246 			return AID_VPN_IPv6;
247 		break;
248 	default:
249 		break;
250 	}
251 	if (verbose)
252 		printf("unhandled AFI/SAFI %d/%d\n", afi, safi);
253 	return AID_UNSPEC;
254 }
255 
256 struct mrt_peer *
257 mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg)
258 {
259 	struct mrt_peer_entry	*peers = NULL;
260 	struct mrt_peer	*p;
261 	u_int8_t	*b = msg;
262 	u_int32_t	bid, as4;
263 	u_int16_t	cnt, i, as2;
264 	u_int		len = ntohl(hdr->length);
265 
266 	if (len < 8)	/* min msg size */
267 		return NULL;
268 
269 	p = calloc(1, sizeof(struct mrt_peer));
270 	if (p == NULL)
271 		err(1, "calloc");
272 
273 	/* collector bgp id */
274 	memcpy(&bid, b, sizeof(bid));
275 	b += sizeof(bid);
276 	len -= sizeof(bid);
277 	p->bgp_id = ntohl(bid);
278 
279 	/* view name length */
280 	memcpy(&cnt, b, sizeof(cnt));
281 	b += sizeof(cnt);
282 	len -= sizeof(cnt);
283 	cnt = ntohs(cnt);
284 
285 	/* view name */
286 	if (cnt > len)
287 		goto fail;
288 	if (cnt != 0) {
289 		if ((p->view = malloc(cnt + 1)) == NULL)
290 			err(1, "malloc");
291 		memcpy(p->view, b, cnt);
292 		p->view[cnt] = 0;
293 	} else
294 		if ((p->view = strdup("")) == NULL)
295 			err(1, "strdup");
296 	b += cnt;
297 	len -= cnt;
298 
299 	/* peer_count */
300 	if (len < sizeof(cnt))
301 		goto fail;
302 	memcpy(&cnt, b, sizeof(cnt));
303 	b += sizeof(cnt);
304 	len -= sizeof(cnt);
305 	cnt = ntohs(cnt);
306 
307 	/* peer entries */
308 	if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL)
309 		err(1, "calloc");
310 	for (i = 0; i < cnt; i++) {
311 		u_int8_t type;
312 
313 		if (len < sizeof(u_int8_t) + sizeof(u_int32_t))
314 			goto fail;
315 		type = *b++;
316 		len -= 1;
317 		memcpy(&bid, b, sizeof(bid));
318 		b += sizeof(bid);
319 		len -= sizeof(bid);
320 		peers[i].bgp_id = ntohl(bid);
321 
322 		if (type & MRT_DUMP_V2_PEER_BIT_I) {
323 			if (mrt_extract_addr(b, len, &peers[i].addr,
324 			    AID_INET6) == -1)
325 				goto fail;
326 			b += sizeof(struct in6_addr);
327 			len -= sizeof(struct in6_addr);
328 		} else {
329 			if (mrt_extract_addr(b, len, &peers[i].addr,
330 			    AID_INET) == -1)
331 				goto fail;
332 			b += sizeof(struct in_addr);
333 			len -= sizeof(struct in_addr);
334 		}
335 
336 		if (type & MRT_DUMP_V2_PEER_BIT_A) {
337 			memcpy(&as4, b, sizeof(as4));
338 			b += sizeof(as4);
339 			len -= sizeof(as4);
340 			as4 = ntohl(as4);
341 		} else {
342 			memcpy(&as2, b, sizeof(as2));
343 			b += sizeof(as2);
344 			len -= sizeof(as2);
345 			as4 = ntohs(as2);
346 		}
347 		peers[i].asnum = as4;
348 	}
349 	p->peers = peers;
350 	p->npeers = cnt;
351 	return (p);
352 fail:
353 	mrt_free_peers(p);
354 	free(peers);
355 	return (NULL);
356 }
357 
358 struct mrt_rib *
359 mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose)
360 {
361 	struct mrt_rib_entry *entries = NULL;
362 	struct mrt_rib	*r;
363 	u_int8_t	*b = msg;
364 	u_int		len = ntohl(hdr->length);
365 	u_int32_t	snum;
366 	u_int16_t	cnt, i, afi;
367 	u_int8_t	safi, aid;
368 	int		ret;
369 
370 	if (len < sizeof(snum) + 1)
371 		return NULL;
372 
373 	r = calloc(1, sizeof(struct mrt_rib));
374 	if (r == NULL)
375 		err(1, "calloc");
376 
377 	/* seq_num */
378 	memcpy(&snum, b, sizeof(snum));
379 	b += sizeof(snum);
380 	len -= sizeof(snum);
381 	r->seqnum = ntohl(snum);
382 
383 	switch (ntohs(hdr->subtype)) {
384 	case MRT_DUMP_V2_RIB_IPV4_UNICAST:
385 	case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
386 		/* prefix */
387 		ret = mrt_extract_prefix(b, len, AID_INET, &r->prefix,
388 		    &r->prefixlen, verbose);
389 		if (ret == 1)
390 			goto fail;
391 		break;
392 	case MRT_DUMP_V2_RIB_IPV6_UNICAST:
393 	case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
394 		/* prefix */
395 		ret = mrt_extract_prefix(b, len, AID_INET6, &r->prefix,
396 		    &r->prefixlen, verbose);
397 		if (ret == 1)
398 			goto fail;
399 		break;
400 	case MRT_DUMP_V2_RIB_GENERIC:
401 		/* fetch AFI/SAFI pair */
402 		memcpy(&afi, b, sizeof(afi));
403 		b += sizeof(afi);
404 		len -= sizeof(afi);
405 		afi = ntohs(afi);
406 
407 		safi = *b++;
408 		len -= 1;
409 
410 		if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
411 			goto fail;
412 
413 		/* prefix */
414 		ret = mrt_extract_prefix(b, len, aid, &r->prefix,
415 		    &r->prefixlen, verbose);
416 		if (ret == 1)
417 			goto fail;
418 		break;
419 	default:
420 		errx(1, "unknonw subtype %hd", ntohs(hdr->subtype));
421 	}
422 
423 	/* adjust length */
424 	b += ret;
425 	len -= ret;
426 
427 	/* entries count */
428 	if (len < sizeof(cnt))
429 		goto fail;
430 	memcpy(&cnt, b, sizeof(cnt));
431 	b += sizeof(cnt);
432 	len -= sizeof(cnt);
433 	cnt = ntohs(cnt);
434 	r->nentries = cnt;
435 
436 	/* entries */
437 	if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL)
438 		err(1, "calloc");
439 	for (i = 0; i < cnt; i++) {
440 		u_int32_t	otm;
441 		u_int16_t	pix, alen;
442 		if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t))
443 			goto fail;
444 		/* peer index */
445 		memcpy(&pix, b, sizeof(pix));
446 		b += sizeof(pix);
447 		len -= sizeof(pix);
448 		entries[i].peer_idx = ntohs(pix);
449 
450 		/* originated */
451 		memcpy(&otm, b, sizeof(otm));
452 		b += sizeof(otm);
453 		len -= sizeof(otm);
454 		entries[i].originated = ntohl(otm);
455 
456 		/* attr_len */
457 		memcpy(&alen, b, sizeof(alen));
458 		b += sizeof(alen);
459 		len -= sizeof(alen);
460 		alen = ntohs(alen);
461 
462 		/* attr */
463 		if (len < alen)
464 			goto fail;
465 		if (mrt_extract_attr(&entries[i], b, alen,
466 		    r->prefix.aid, 1) == -1)
467 			goto fail;
468 		b += alen;
469 		len -= alen;
470 	}
471 	r->entries = entries;
472 	return (r);
473 fail:
474 	mrt_free_rib(r);
475 	free(entries);
476 	return (NULL);
477 }
478 
479 int
480 mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
481     struct mrt_rib **rp)
482 {
483 	struct mrt_peer		*p;
484 	struct mrt_rib		*r;
485 	struct mrt_rib_entry	*re;
486 	u_int8_t		*b = msg;
487 	u_int			 len = ntohl(hdr->length);
488 	u_int16_t		 asnum, alen;
489 
490 	if (*pp == NULL) {
491 		*pp = calloc(1, sizeof(struct mrt_peer));
492 		if (*pp == NULL)
493 			err(1, "calloc");
494 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
495 		if ((*pp)->peers == NULL)
496 			err(1, "calloc");
497 		(*pp)->npeers = 1;
498 	}
499 	p = *pp;
500 
501 	*rp = r = calloc(1, sizeof(struct mrt_rib));
502 	if (r == NULL)
503 		err(1, "calloc");
504 	re = calloc(1, sizeof(struct mrt_rib_entry));
505 	if (re == NULL)
506 		err(1, "calloc");
507 	r->nentries = 1;
508 	r->entries = re;
509 
510 	if (len < 2 * sizeof(u_int16_t))
511 		goto fail;
512 	/* view */
513 	b += sizeof(u_int16_t);
514 	len -= sizeof(u_int16_t);
515 	/* seqnum */
516 	memcpy(&r->seqnum, b, sizeof(u_int16_t));
517 	b += sizeof(u_int16_t);
518 	len -= sizeof(u_int16_t);
519 	r->seqnum = ntohs(r->seqnum);
520 
521 	switch (ntohs(hdr->subtype)) {
522 	case MRT_DUMP_AFI_IP:
523 		if (mrt_extract_addr(b, len, &r->prefix, AID_INET) == -1)
524 			goto fail;
525 		b += sizeof(struct in_addr);
526 		len -= sizeof(struct in_addr);
527 		break;
528 	case MRT_DUMP_AFI_IPv6:
529 		if (mrt_extract_addr(b, len, &r->prefix, AID_INET6) == -1)
530 			goto fail;
531 		b += sizeof(struct in6_addr);
532 		len -= sizeof(struct in6_addr);
533 		break;
534 	}
535 	if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2)
536 		goto fail;
537 	r->prefixlen = *b++;
538 	len -= 1;
539 	/* status */
540 	b += 1;
541 	len -= 1;
542 	/* originated */
543 	memcpy(&re->originated, b, sizeof(u_int32_t));
544 	b += sizeof(u_int32_t);
545 	len -= sizeof(u_int32_t);
546 	re->originated = ntohl(re->originated);
547 	/* peer ip */
548 	switch (ntohs(hdr->subtype)) {
549 	case MRT_DUMP_AFI_IP:
550 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
551 			goto fail;
552 		b += sizeof(struct in_addr);
553 		len -= sizeof(struct in_addr);
554 		break;
555 	case MRT_DUMP_AFI_IPv6:
556 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
557 			goto fail;
558 		b += sizeof(struct in6_addr);
559 		len -= sizeof(struct in6_addr);
560 		break;
561 	}
562 	memcpy(&asnum, b, sizeof(asnum));
563 	b += sizeof(asnum);
564 	len -= sizeof(asnum);
565 	p->peers->asnum = ntohs(asnum);
566 
567 	memcpy(&alen, b, sizeof(alen));
568 	b += sizeof(alen);
569 	len -= sizeof(alen);
570 	alen = ntohs(alen);
571 
572 	/* attr */
573 	if (len < alen)
574 		goto fail;
575 	if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
576 		goto fail;
577 	b += alen;
578 	len -= alen;
579 
580 	return (0);
581 fail:
582 	mrt_free_rib(r);
583 	return (-1);
584 }
585 
586 int
587 mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
588     struct mrt_rib **rp, int verbose)
589 {
590 	struct mrt_peer		*p;
591 	struct mrt_rib		*r;
592 	struct mrt_rib_entry	*re;
593 	u_int8_t		*b = msg;
594 	u_int			 len = ntohl(hdr->length);
595 	u_int16_t		 asnum, alen, afi;
596 	u_int8_t		 safi, nhlen, aid;
597 	int			 ret;
598 
599 	/* just ignore the microsec field for _ET header for now */
600 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
601 		b = (char *)b + sizeof(u_int32_t);
602 		len -= sizeof(u_int32_t);
603 	}
604 
605 	if (*pp == NULL) {
606 		*pp = calloc(1, sizeof(struct mrt_peer));
607 		if (*pp == NULL)
608 			err(1, "calloc");
609 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
610 		if ((*pp)->peers == NULL)
611 			err(1, "calloc");
612 		(*pp)->npeers = 1;
613 	}
614 	p = *pp;
615 
616 	*rp = r = calloc(1, sizeof(struct mrt_rib));
617 	if (r == NULL)
618 		err(1, "calloc");
619 	re = calloc(1, sizeof(struct mrt_rib_entry));
620 	if (re == NULL)
621 		err(1, "calloc");
622 	r->nentries = 1;
623 	r->entries = re;
624 
625 	if (len < 4 * sizeof(u_int16_t))
626 		goto fail;
627 	/* source AS */
628 	b += sizeof(u_int16_t);
629 	len -= sizeof(u_int16_t);
630 	/* dest AS */
631 	memcpy(&asnum, b, sizeof(asnum));
632 	b += sizeof(asnum);
633 	len -= sizeof(asnum);
634 	p->peers->asnum = ntohs(asnum);
635 	/* iface index */
636 	b += sizeof(u_int16_t);
637 	len -= sizeof(u_int16_t);
638 	/* afi */
639 	memcpy(&afi, b, sizeof(afi));
640 	b += sizeof(afi);
641 	len -= sizeof(afi);
642 	afi = ntohs(afi);
643 
644 	/* source + dest ip */
645 	switch (afi) {
646 	case MRT_DUMP_AFI_IP:
647 		if (len < 2 * sizeof(struct in_addr))
648 			goto fail;
649 		/* source IP */
650 		b += sizeof(struct in_addr);
651 		len -= sizeof(struct in_addr);
652 		/* dest IP */
653 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
654 			goto fail;
655 		b += sizeof(struct in_addr);
656 		len -= sizeof(struct in_addr);
657 		break;
658 	case MRT_DUMP_AFI_IPv6:
659 		if (len < 2 * sizeof(struct in6_addr))
660 			goto fail;
661 		/* source IP */
662 		b += sizeof(struct in6_addr);
663 		len -= sizeof(struct in6_addr);
664 		/* dest IP */
665 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
666 			goto fail;
667 		b += sizeof(struct in6_addr);
668 		len -= sizeof(struct in6_addr);
669 		break;
670 	}
671 
672 	if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t))
673 		goto fail;
674 	/* view + status */
675 	b += 2 * sizeof(u_int16_t);
676 	len -= 2 * sizeof(u_int16_t);
677 	/* originated */
678 	memcpy(&re->originated, b, sizeof(u_int32_t));
679 	b += sizeof(u_int32_t);
680 	len -= sizeof(u_int32_t);
681 	re->originated = ntohl(re->originated);
682 
683 	/* afi */
684 	memcpy(&afi, b, sizeof(afi));
685 	b += sizeof(afi);
686 	len -= sizeof(afi);
687 	afi = ntohs(afi);
688 
689 	/* safi */
690 	safi = *b++;
691 	len -= 1;
692 
693 	if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
694 		goto fail;
695 
696 	/* nhlen */
697 	nhlen = *b++;
698 	len -= 1;
699 
700 	/* nexthop */
701 	if (mrt_extract_addr(b, len, &re->nexthop, aid) == -1)
702 		goto fail;
703 	if (len < nhlen)
704 		goto fail;
705 	b += nhlen;
706 	len -= nhlen;
707 
708 	/* prefix */
709 	ret = mrt_extract_prefix(b, len, aid, &r->prefix, &r->prefixlen,
710 	    verbose);
711 	if (ret == 1)
712 		goto fail;
713 	b += ret;
714 	len -= ret;
715 
716 	memcpy(&alen, b, sizeof(alen));
717 	b += sizeof(alen);
718 	len -= sizeof(alen);
719 	alen = ntohs(alen);
720 
721 	/* attr */
722 	if (len < alen)
723 		goto fail;
724 	if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
725 		goto fail;
726 	b += alen;
727 	len -= alen;
728 
729 	return (0);
730 fail:
731 	mrt_free_rib(r);
732 	return (-1);
733 }
734 
735 int
736 mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, u_int8_t aid,
737     int as4)
738 {
739 	struct mrt_attr	*ap;
740 	u_int32_t	tmp;
741 	u_int16_t	attr_len;
742 	u_int8_t	type, flags, *attr;
743 
744 	do {
745 		if (alen < 3)
746 			return (-1);
747 		attr = a;
748 		flags = *a++;
749 		alen -= 1;
750 		type = *a++;
751 		alen -= 1;
752 
753 		if (flags & MRT_ATTR_EXTLEN) {
754 			if (alen < 2)
755 				return (-1);
756 			memcpy(&attr_len, a, sizeof(attr_len));
757 			attr_len = ntohs(attr_len);
758 			a += sizeof(attr_len);
759 			alen -= sizeof(attr_len);
760 		} else {
761 			attr_len = *a++;
762 			alen -= 1;
763 		}
764 		switch (type) {
765 		case MRT_ATTR_ORIGIN:
766 			if (attr_len != 1)
767 				return (-1);
768 			re->origin = *a;
769 			break;
770 		case MRT_ATTR_ASPATH:
771 			if (as4) {
772 				re->aspath_len = attr_len;
773 				if ((re->aspath = malloc(attr_len)) == NULL)
774 					err(1, "malloc");
775 				memcpy(re->aspath, a, attr_len);
776 			} else {
777 				re->aspath = mrt_aspath_inflate(a, attr_len,
778 				    &re->aspath_len);
779 				if (re->aspath == NULL)
780 					return (-1);
781 			}
782 			break;
783 		case MRT_ATTR_NEXTHOP:
784 			if (attr_len != 4)
785 				return (-1);
786 			if (aid != AID_INET)
787 				break;
788 			memcpy(&tmp, a, sizeof(tmp));
789 			re->nexthop.aid = AID_INET;
790 			re->nexthop.v4.s_addr = tmp;
791 			break;
792 		case MRT_ATTR_MED:
793 			if (attr_len != 4)
794 				return (-1);
795 			memcpy(&tmp, a, sizeof(tmp));
796 			re->med = ntohl(tmp);
797 			break;
798 		case MRT_ATTR_LOCALPREF:
799 			if (attr_len != 4)
800 				return (-1);
801 			memcpy(&tmp, a, sizeof(tmp));
802 			re->local_pref = ntohl(tmp);
803 			break;
804 		case MRT_ATTR_MP_REACH_NLRI:
805 			/*
806 			 * XXX horrible hack:
807 			 * Once again IETF and the real world differ in the
808 			 * implementation. In short the abbreviated MP_NLRI
809 			 * hack in the standard is not used in real life.
810 			 * Detect the two cases by looking at the first byte
811 			 * of the payload (either the nexthop addr length (RFC)
812 			 * or the high byte of the AFI (old form)). If the
813 			 * first byte matches the expected nexthop length it
814 			 * is expected to be the RFC 6396 encoding.
815 			 */
816 			if (*a != attr_len - 1) {
817 				a += 3;
818 				alen -= 3;
819 				attr_len -= 3;
820 			}
821 			switch (aid) {
822 			case AID_INET6:
823 				if (attr_len < sizeof(struct in6_addr) + 1)
824 					return (-1);
825 				re->nexthop.aid = aid;
826 				memcpy(&re->nexthop.v6, a + 1,
827 				    sizeof(struct in6_addr));
828 				break;
829 			case AID_VPN_IPv4:
830 				if (attr_len < sizeof(u_int64_t) +
831 				    sizeof(struct in_addr))
832 					return (-1);
833 				re->nexthop.aid = aid;
834 				memcpy(&tmp, a + 1 + sizeof(u_int64_t),
835 				    sizeof(tmp));
836 				re->nexthop.v4.s_addr = tmp;
837 				break;
838 			case AID_VPN_IPv6:
839 				if (attr_len < sizeof(u_int64_t) +
840 				    sizeof(struct in6_addr))
841 					return (-1);
842 				re->nexthop.aid = aid;
843 				memcpy(&re->nexthop.v6,
844 				    a + 1 + sizeof(u_int64_t),
845 				    sizeof(struct in6_addr));
846 				break;
847 			}
848 			break;
849 		case MRT_ATTR_AS4PATH:
850 			if (!as4) {
851 				free(re->aspath);
852 				re->aspath_len = attr_len;
853 				if ((re->aspath = malloc(attr_len)) == NULL)
854 					err(1, "malloc");
855 				memcpy(re->aspath, a, attr_len);
856 				break;
857 			}
858 			/* FALLTHROUGH */
859 		default:
860 			re->nattrs++;
861 			if (re->nattrs >= UCHAR_MAX)
862 				err(1, "too many attributes");
863 			ap = reallocarray(re->attrs,
864 			    re->nattrs, sizeof(struct mrt_attr));
865 			if (ap == NULL)
866 				err(1, "realloc");
867 			re->attrs = ap;
868 			ap = re->attrs + re->nattrs - 1;
869 			ap->attr_len = a + attr_len - attr;
870 			if ((ap->attr = malloc(ap->attr_len)) == NULL)
871 				err(1, "malloc");
872 			memcpy(ap->attr, attr, ap->attr_len);
873 			break;
874 		}
875 		a += attr_len;
876 		alen -= attr_len;
877 	} while (alen > 0);
878 
879 	return (0);
880 }
881 
882 void
883 mrt_free_peers(struct mrt_peer *p)
884 {
885 	free(p->peers);
886 	free(p->view);
887 	free(p);
888 }
889 
890 void
891 mrt_free_rib(struct mrt_rib *r)
892 {
893 	u_int16_t	i, j;
894 
895 	for (i = 0; i < r->nentries && r->entries; i++) {
896 		for (j = 0; j < r->entries[i].nattrs; j++)
897 			 free(r->entries[i].attrs[j].attr);
898 		free(r->entries[i].attrs);
899 		free(r->entries[i].aspath);
900 	}
901 
902 	free(r->entries);
903 	free(r);
904 }
905 
906 void
907 mrt_free_bgp_state(struct mrt_bgp_state *s)
908 {
909 	free(s);
910 }
911 
912 void
913 mrt_free_bgp_msg(struct mrt_bgp_msg *m)
914 {
915 	free(m->msg);
916 	free(m);
917 }
918 
919 u_char *
920 mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen)
921 {
922 	u_int8_t	*seg, *nseg, *ndata;
923 	u_int16_t	 seg_size, olen, nlen;
924 	u_int8_t	 seg_len;
925 
926 	/* first calculate the length of the aspath */
927 	seg = data;
928 	nlen = 0;
929 	for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
930 		seg_len = seg[1];
931 		seg_size = 2 + sizeof(u_int16_t) * seg_len;
932 		nlen += 2 + sizeof(u_int32_t) * seg_len;
933 
934 		if (seg_size > olen)
935 			return NULL;
936 	}
937 
938 	*newlen = nlen;
939 	if ((ndata = malloc(nlen)) == NULL)
940 		err(1, "malloc");
941 
942 	/* then copy the aspath */
943 	seg = data;
944 	for (nseg = ndata; nseg < ndata + nlen; ) {
945 		*nseg++ = *seg++;
946 		*nseg++ = seg_len = *seg++;
947 		for (; seg_len > 0; seg_len--) {
948 			*nseg++ = 0;
949 			*nseg++ = 0;
950 			*nseg++ = *seg++;
951 			*nseg++ = *seg++;
952 		}
953 	}
954 
955 	return (ndata);
956 }
957 
958 int
959 mrt_extract_addr(void *msg, u_int len, struct bgpd_addr *addr, u_int8_t aid)
960 {
961 	u_int8_t	*b = msg;
962 
963 	memset(addr, 0, sizeof(*addr));
964 	switch (aid) {
965 	case AID_INET:
966 		if (len < sizeof(struct in_addr))
967 			return (-1);
968 		addr->aid = aid;
969 		memcpy(&addr->v4, b, sizeof(struct in_addr));
970 		return sizeof(struct in_addr);
971 	case AID_INET6:
972 		if (len < sizeof(struct in6_addr))
973 			return (-1);
974 		addr->aid = aid;
975 		memcpy(&addr->v6, b, sizeof(struct in6_addr));
976 		return sizeof(struct in6_addr);
977 	case AID_VPN_IPv4:
978 		if (len < sizeof(u_int64_t) + sizeof(struct in_addr))
979 			return (-1);
980 		addr->aid = aid;
981 		/* XXX labelstack and rd missing */
982 		memcpy(&addr->v4, b + sizeof(u_int64_t),
983 		    sizeof(struct in_addr));
984 		return (sizeof(u_int64_t) + sizeof(struct in_addr));
985 	case AID_VPN_IPv6:
986 		if (len < sizeof(u_int64_t) + sizeof(struct in6_addr))
987 			return (-1);
988 		addr->aid = aid;
989 		/* XXX labelstack and rd missing */
990 		memcpy(&addr->v6, b + sizeof(u_int64_t),
991 		    sizeof(struct in6_addr));
992 		return (sizeof(u_int64_t) + sizeof(struct in6_addr));
993 	default:
994 		return (-1);
995 	}
996 }
997 
998 int
999 mrt_extract_prefix(void *msg, u_int len, u_int8_t aid,
1000     struct bgpd_addr *prefix, u_int8_t *prefixlen, int verbose)
1001 {
1002 	int r;
1003 
1004 	switch (aid) {
1005 	case AID_INET:
1006 		r = nlri_get_prefix(msg, len, prefix, prefixlen);
1007 		break;
1008 	case AID_INET6:
1009 		r = nlri_get_prefix6(msg, len, prefix, prefixlen);
1010 		break;
1011 	case AID_VPN_IPv4:
1012 		r = nlri_get_vpn4(msg, len, prefix, prefixlen, 0);
1013 		break;
1014 	case AID_VPN_IPv6:
1015 		r = nlri_get_vpn6(msg, len, prefix, prefixlen, 0);
1016 		break;
1017 	default:
1018 		if (verbose)
1019 			printf("unknown prefix AID %d\n", aid);
1020 		return -1;
1021 	}
1022 	if (r == -1 && verbose)
1023 		printf("failed to parse prefix of AID %d\n", aid);
1024 	return r;
1025 }
1026 
1027 struct mrt_bgp_state *
1028 mrt_parse_state(struct mrt_hdr *hdr, void *msg, int verbose)
1029 {
1030 	struct timespec		 t;
1031 	struct mrt_bgp_state	*s;
1032 	u_int8_t		*b = msg;
1033 	u_int			 len = ntohl(hdr->length);
1034 	u_int32_t		 sas, das, usec;
1035 	u_int16_t		 tmp16, afi;
1036 	int			 r;
1037 	u_int8_t		 aid;
1038 
1039 	t.tv_sec = ntohl(hdr->timestamp);
1040 	t.tv_nsec = 0;
1041 
1042 	/* handle the microsec field for _ET header */
1043 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
1044 		memcpy(&usec, b, sizeof(usec));
1045 		b += sizeof(usec);
1046 		len -= sizeof(usec);
1047 		t.tv_nsec = ntohl(usec) * 1000;
1048 	}
1049 
1050 	switch (ntohs(hdr->subtype)) {
1051 	case BGP4MP_STATE_CHANGE:
1052 		if (len < 8)
1053 			return (0);
1054 		/* source as */
1055 		memcpy(&tmp16, b, sizeof(tmp16));
1056 		b += sizeof(tmp16);
1057 		len -= sizeof(tmp16);
1058 		sas = ntohs(tmp16);
1059 		/* dest as */
1060 		memcpy(&tmp16, b, sizeof(tmp16));
1061 		b += sizeof(tmp16);
1062 		len -= sizeof(tmp16);
1063 		das = ntohs(tmp16);
1064 		/* if_index, ignored */
1065 		b += sizeof(tmp16);
1066 		len -= sizeof(tmp16);
1067 		/* afi */
1068 		memcpy(&tmp16, b, sizeof(tmp16));
1069 		b += sizeof(tmp16);
1070 		len -= sizeof(tmp16);
1071 		afi = ntohs(tmp16);
1072 		break;
1073 	case BGP4MP_STATE_CHANGE_AS4:
1074 		if (len < 12)
1075 			return (0);
1076 		/* source as */
1077 		memcpy(&sas, b, sizeof(sas));
1078 		b += sizeof(sas);
1079 		len -= sizeof(sas);
1080 		sas = ntohl(sas);
1081 		/* dest as */
1082 		memcpy(&das, b, sizeof(das));
1083 		b += sizeof(das);
1084 		len -= sizeof(das);
1085 		das = ntohl(das);
1086 		/* if_index, ignored */
1087 		b += sizeof(tmp16);
1088 		len -= sizeof(tmp16);
1089 		/* afi */
1090 		memcpy(&tmp16, b, sizeof(tmp16));
1091 		b += sizeof(tmp16);
1092 		len -= sizeof(tmp16);
1093 		afi = ntohs(tmp16);
1094 		break;
1095 	default:
1096 		errx(1, "mrt_parse_state: bad subtype");
1097 	}
1098 
1099 	/* src & dst addr */
1100 	if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
1101 		return (NULL);
1102 
1103 	if ((s = calloc(1, sizeof(struct mrt_bgp_state))) == NULL)
1104 		err(1, "calloc");
1105 	s->time = t;
1106 	s->src_as = sas;
1107 	s->dst_as = das;
1108 
1109 	if ((r = mrt_extract_addr(b, len, &s->src, aid)) == -1)
1110 		goto fail;
1111 	b += r;
1112 	len -= r;
1113 	if ((r = mrt_extract_addr(b, len, &s->dst, aid)) == -1)
1114 		goto fail;
1115 	b += r;
1116 	len -= r;
1117 
1118 	/* states */
1119 	memcpy(&tmp16, b, sizeof(tmp16));
1120 	b += sizeof(tmp16);
1121 	len -= sizeof(tmp16);
1122 	s->old_state = ntohs(tmp16);
1123 	memcpy(&tmp16, b, sizeof(tmp16));
1124 	b += sizeof(tmp16);
1125 	len -= sizeof(tmp16);
1126 	s->new_state = ntohs(tmp16);
1127 
1128 	return (s);
1129 
1130 fail:
1131 	free(s);
1132 	return (NULL);
1133 }
1134 
1135 struct mrt_bgp_msg *
1136 mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose)
1137 {
1138 	struct timespec		 t;
1139 	struct mrt_bgp_msg	*m;
1140 	u_int8_t		*b = msg;
1141 	u_int			 len = ntohl(hdr->length);
1142 	u_int32_t		 sas, das, usec;
1143 	u_int16_t		 tmp16, afi;
1144 	int			 r;
1145 	u_int8_t		 aid;
1146 
1147 	t.tv_sec = ntohl(hdr->timestamp);
1148 	t.tv_nsec = 0;
1149 
1150 	/* handle the microsec field for _ET header */
1151 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
1152 		memcpy(&usec, b, sizeof(usec));
1153 		b += sizeof(usec);
1154 		len -= sizeof(usec);
1155 		t.tv_nsec = ntohl(usec) * 1000;
1156 	}
1157 
1158 	switch (ntohs(hdr->subtype)) {
1159 	case BGP4MP_MESSAGE:
1160 		if (len < 8)
1161 			return (0);
1162 		/* source as */
1163 		memcpy(&tmp16, b, sizeof(tmp16));
1164 		b += sizeof(tmp16);
1165 		len -= sizeof(tmp16);
1166 		sas = ntohs(tmp16);
1167 		/* dest as */
1168 		memcpy(&tmp16, b, sizeof(tmp16));
1169 		b += sizeof(tmp16);
1170 		len -= sizeof(tmp16);
1171 		das = ntohs(tmp16);
1172 		/* if_index, ignored */
1173 		b += sizeof(tmp16);
1174 		len -= sizeof(tmp16);
1175 		/* afi */
1176 		memcpy(&tmp16, b, sizeof(tmp16));
1177 		b += sizeof(tmp16);
1178 		len -= sizeof(tmp16);
1179 		afi = ntohs(tmp16);
1180 		break;
1181 	case BGP4MP_MESSAGE_AS4:
1182 		if (len < 12)
1183 			return (0);
1184 		/* source as */
1185 		memcpy(&sas, b, sizeof(sas));
1186 		b += sizeof(sas);
1187 		len -= sizeof(sas);
1188 		sas = ntohl(sas);
1189 		/* dest as */
1190 		memcpy(&das, b, sizeof(das));
1191 		b += sizeof(das);
1192 		len -= sizeof(das);
1193 		das = ntohl(das);
1194 		/* if_index, ignored */
1195 		b += sizeof(tmp16);
1196 		len -= sizeof(tmp16);
1197 		/* afi */
1198 		memcpy(&tmp16, b, sizeof(tmp16));
1199 		b += sizeof(tmp16);
1200 		len -= sizeof(tmp16);
1201 		afi = ntohs(tmp16);
1202 		break;
1203 	default:
1204 		errx(1, "mrt_parse_msg: bad subtype");
1205 	}
1206 
1207 	/* src & dst addr */
1208 	if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
1209 		return (NULL);
1210 
1211 	if ((m = calloc(1, sizeof(struct mrt_bgp_msg))) == NULL)
1212 		err(1, "calloc");
1213 	m->time = t;
1214 	m->src_as = sas;
1215 	m->dst_as = das;
1216 
1217 	if ((r = mrt_extract_addr(b, len, &m->src, aid)) == -1)
1218 		goto fail;
1219 	b += r;
1220 	len -= r;
1221 	if ((r = mrt_extract_addr(b, len, &m->dst, aid)) == -1)
1222 		goto fail;
1223 	b += r;
1224 	len -= r;
1225 
1226 	/* msg */
1227 	if (len > 0) {
1228 		m->msg_len = len;
1229 		if ((m->msg = malloc(len)) == NULL)
1230 			err(1, "malloc");
1231 		memcpy(m->msg, b, len);
1232 	}
1233 
1234 	return (m);
1235 
1236 fail:
1237 	free(m->msg);
1238 	free(m);
1239 	return (NULL);
1240 }
1241