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