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