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