xref: /openbsd-src/usr.sbin/bgpctl/mrtparser.c (revision 4b70baf6e17fc8b27fc1f7fa7929335753fa94c3)
1 /*	$OpenBSD: mrtparser.c,v 1.10 2019/02/25 11:51:58 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, 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 
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 DUMP_V2 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 			    AID_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 			    AID_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.aid = AID_INET;
364 		memcpy(&r->prefix.v4, b, MRT_PREFIX_LEN(plen));
365 		b += MRT_PREFIX_LEN(plen);
366 		len -= MRT_PREFIX_LEN(plen);
367 		r->prefixlen = plen;
368 		break;
369 	case MRT_DUMP_V2_RIB_IPV6_UNICAST:
370 	case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
371 		plen = *b++;
372 		len -= 1;
373 		if (len < MRT_PREFIX_LEN(plen))
374 			goto fail;
375 		r->prefix.aid = AID_INET6;
376 		memcpy(&r->prefix.v6, b, MRT_PREFIX_LEN(plen));
377 		b += MRT_PREFIX_LEN(plen);
378 		len -= MRT_PREFIX_LEN(plen);
379 		r->prefixlen = plen;
380 		break;
381 	case MRT_DUMP_V2_RIB_GENERIC:
382 		/* XXX unhandled */
383 		errx(1, "MRT_DUMP_V2_RIB_GENERIC subtype not yet implemented");
384 		goto fail;
385 	}
386 
387 	/* entries count */
388 	if (len < sizeof(cnt))
389 		goto fail;
390 	memcpy(&cnt, b, sizeof(cnt));
391 	b += sizeof(cnt);
392 	len -= sizeof(cnt);
393 	cnt = ntohs(cnt);
394 	r->nentries = cnt;
395 
396 	/* entries */
397 	if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL)
398 		err(1, "calloc");
399 	for (i = 0; i < cnt; i++) {
400 		u_int32_t	otm;
401 		u_int16_t	pix, alen;
402 		if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t))
403 			goto fail;
404 		/* peer index */
405 		memcpy(&pix, b, sizeof(pix));
406 		b += sizeof(pix);
407 		len -= sizeof(pix);
408 		entries[i].peer_idx = ntohs(pix);
409 
410 		/* originated */
411 		memcpy(&otm, b, sizeof(otm));
412 		b += sizeof(otm);
413 		len -= sizeof(otm);
414 		entries[i].originated = ntohl(otm);
415 
416 		/* attr_len */
417 		memcpy(&alen, b, sizeof(alen));
418 		b += sizeof(alen);
419 		len -= sizeof(alen);
420 		alen = ntohs(alen);
421 
422 		/* attr */
423 		if (len < alen)
424 			goto fail;
425 		if (mrt_extract_attr(&entries[i], b, alen,
426 		    r->prefix.aid, 1) == -1)
427 			goto fail;
428 		b += alen;
429 		len -= alen;
430 	}
431 	r->entries = entries;
432 	return (r);
433 fail:
434 	mrt_free_rib(r);
435 	free(entries);
436 	return (NULL);
437 }
438 
439 int
440 mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
441     struct mrt_rib **rp)
442 {
443 	struct mrt_peer		*p;
444 	struct mrt_rib		*r;
445 	struct mrt_rib_entry	*re;
446 	u_int8_t		*b = msg;
447 	u_int			 len = ntohl(hdr->length);
448 	u_int16_t		 asnum, alen;
449 
450 	if (*pp == NULL) {
451 		*pp = calloc(1, sizeof(struct mrt_peer));
452 		if (*pp == NULL)
453 			err(1, "calloc");
454 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
455 		if ((*pp)->peers == NULL)
456 			err(1, "calloc");
457 		(*pp)->npeers = 1;
458 	}
459 	p = *pp;
460 
461 	*rp = r = calloc(1, sizeof(struct mrt_rib));
462 	if (r == NULL)
463 		err(1, "calloc");
464 	re = calloc(1, sizeof(struct mrt_rib_entry));
465 	if (re == NULL)
466 		err(1, "calloc");
467 	r->nentries = 1;
468 	r->entries = re;
469 
470 	if (len < 2 * sizeof(u_int16_t))
471 		goto fail;
472 	/* view */
473 	b += sizeof(u_int16_t);
474 	len -= sizeof(u_int16_t);
475 	/* seqnum */
476 	memcpy(&r->seqnum, b, sizeof(u_int16_t));
477 	b += sizeof(u_int16_t);
478 	len -= sizeof(u_int16_t);
479 	r->seqnum = ntohs(r->seqnum);
480 
481 	switch (ntohs(hdr->subtype)) {
482 	case MRT_DUMP_AFI_IP:
483 		if (mrt_extract_addr(b, len, &r->prefix, AID_INET) == -1)
484 			goto fail;
485 		b += sizeof(struct in_addr);
486 		len -= sizeof(struct in_addr);
487 		break;
488 	case MRT_DUMP_AFI_IPv6:
489 		if (mrt_extract_addr(b, len, &r->prefix, AID_INET6) == -1)
490 			goto fail;
491 		b += sizeof(struct in6_addr);
492 		len -= sizeof(struct in6_addr);
493 		break;
494 	}
495 	if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2)
496 		goto fail;
497 	r->prefixlen = *b++;
498 	len -= 1;
499 	/* status */
500 	b += 1;
501 	len -= 1;
502 	/* originated */
503 	memcpy(&re->originated, b, sizeof(u_int32_t));
504 	b += sizeof(u_int32_t);
505 	len -= sizeof(u_int32_t);
506 	re->originated = ntohl(re->originated);
507 	/* peer ip */
508 	switch (ntohs(hdr->subtype)) {
509 	case MRT_DUMP_AFI_IP:
510 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
511 			goto fail;
512 		b += sizeof(struct in_addr);
513 		len -= sizeof(struct in_addr);
514 		break;
515 	case MRT_DUMP_AFI_IPv6:
516 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
517 			goto fail;
518 		b += sizeof(struct in6_addr);
519 		len -= sizeof(struct in6_addr);
520 		break;
521 	}
522 	memcpy(&asnum, b, sizeof(asnum));
523 	b += sizeof(asnum);
524 	len -= sizeof(asnum);
525 	p->peers->asnum = ntohs(asnum);
526 
527 	memcpy(&alen, b, sizeof(alen));
528 	b += sizeof(alen);
529 	len -= sizeof(alen);
530 	alen = ntohs(alen);
531 
532 	/* attr */
533 	if (len < alen)
534 		goto fail;
535 	if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
536 		goto fail;
537 	b += alen;
538 	len -= alen;
539 
540 	return (0);
541 fail:
542 	mrt_free_rib(r);
543 	return (-1);
544 }
545 
546 int
547 mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
548     struct mrt_rib **rp)
549 {
550 	struct mrt_peer		*p;
551 	struct mrt_rib		*r;
552 	struct mrt_rib_entry	*re;
553 	u_int8_t		*b = msg;
554 	u_int			 len = ntohl(hdr->length);
555 	u_int16_t		 asnum, alen, afi;
556 	u_int8_t		 safi, nhlen, aid;
557 
558 	/* just ignore the microsec field for _ET header for now */
559 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
560 		b = (char *)b + sizeof(u_int32_t);
561 		len -= sizeof(u_int32_t);
562 	}
563 
564 	if (*pp == NULL) {
565 		*pp = calloc(1, sizeof(struct mrt_peer));
566 		if (*pp == NULL)
567 			err(1, "calloc");
568 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
569 		if ((*pp)->peers == NULL)
570 			err(1, "calloc");
571 		(*pp)->npeers = 1;
572 	}
573 	p = *pp;
574 
575 	*rp = r = calloc(1, sizeof(struct mrt_rib));
576 	if (r == NULL)
577 		err(1, "calloc");
578 	re = calloc(1, sizeof(struct mrt_rib_entry));
579 	if (re == NULL)
580 		err(1, "calloc");
581 	r->nentries = 1;
582 	r->entries = re;
583 
584 	if (len < 4 * sizeof(u_int16_t))
585 		goto fail;
586 	/* source AS */
587 	b += sizeof(u_int16_t);
588 	len -= sizeof(u_int16_t);
589 	/* dest AS */
590 	memcpy(&asnum, b, sizeof(asnum));
591 	b += sizeof(asnum);
592 	len -= sizeof(asnum);
593 	p->peers->asnum = ntohs(asnum);
594 	/* iface index */
595 	b += sizeof(u_int16_t);
596 	len -= sizeof(u_int16_t);
597 	/* afi */
598 	memcpy(&afi, b, sizeof(afi));
599 	b += sizeof(afi);
600 	len -= sizeof(afi);
601 	afi = ntohs(afi);
602 
603 	/* source + dest ip */
604 	switch (afi) {
605 	case MRT_DUMP_AFI_IP:
606 		if (len < 2 * sizeof(struct in_addr))
607 			goto fail;
608 		/* source IP */
609 		b += sizeof(struct in_addr);
610 		len -= sizeof(struct in_addr);
611 		/* dest IP */
612 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
613 			goto fail;
614 		b += sizeof(struct in_addr);
615 		len -= sizeof(struct in_addr);
616 		break;
617 	case MRT_DUMP_AFI_IPv6:
618 		if (len < 2 * sizeof(struct in6_addr))
619 			goto fail;
620 		/* source IP */
621 		b += sizeof(struct in6_addr);
622 		len -= sizeof(struct in6_addr);
623 		/* dest IP */
624 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
625 			goto fail;
626 		b += sizeof(struct in6_addr);
627 		len -= sizeof(struct in6_addr);
628 		break;
629 	}
630 
631 	if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t))
632 		goto fail;
633 	/* view + status */
634 	b += 2 * sizeof(u_int16_t);
635 	len -= 2 * sizeof(u_int16_t);
636 	/* originated */
637 	memcpy(&re->originated, b, sizeof(u_int32_t));
638 	b += sizeof(u_int32_t);
639 	len -= sizeof(u_int32_t);
640 	re->originated = ntohl(re->originated);
641 
642 	/* afi */
643 	memcpy(&afi, b, sizeof(afi));
644 	b += sizeof(afi);
645 	len -= sizeof(afi);
646 	afi = ntohs(afi);
647 
648 	/* safi */
649 	safi = *b++;
650 	len -= 1;
651 
652 	switch (afi) {
653 	case MRT_DUMP_AFI_IP:
654 		if (safi == 1 || safi == 2) {
655 			aid = AID_INET;
656 			break;
657 		} else if (safi == 128) {
658 			aid = AID_VPN_IPv4;
659 			break;
660 		}
661 		goto fail;
662 	case MRT_DUMP_AFI_IPv6:
663 		if (safi == 1 || safi == 2) {
664 			aid = AID_INET6;
665 			break;
666 		} else if (safi == 128) {
667 			aid = AID_VPN_IPv6;
668 			break;
669 		}
670 		goto fail;
671 	default:
672 		goto fail;
673 	}
674 
675 	/* nhlen */
676 	nhlen = *b++;
677 	len -= 1;
678 
679 	/* nexthop */
680 	if (mrt_extract_addr(b, len, &re->nexthop, aid) == -1)
681 		goto fail;
682 	if (len < nhlen)
683 		goto fail;
684 	b += nhlen;
685 	len -= nhlen;
686 
687 	if (len < 1)
688 		goto fail;
689 	r->prefixlen = *b++;
690 	len -= 1;
691 
692 	/* prefix */
693 	switch (aid) {
694 	case AID_INET:
695 		if (len < MRT_PREFIX_LEN(r->prefixlen))
696 			goto fail;
697 		r->prefix.aid = aid;
698 		memcpy(&r->prefix.v4, b, MRT_PREFIX_LEN(r->prefixlen));
699 		b += MRT_PREFIX_LEN(r->prefixlen);
700 		len -= MRT_PREFIX_LEN(r->prefixlen);
701 		break;
702 	case AID_INET6:
703 		if (len < MRT_PREFIX_LEN(r->prefixlen))
704 			goto fail;
705 		r->prefix.aid = aid;
706 		memcpy(&r->prefix.v6, b, MRT_PREFIX_LEN(r->prefixlen));
707 		b += MRT_PREFIX_LEN(r->prefixlen);
708 		len -= MRT_PREFIX_LEN(r->prefixlen);
709 		break;
710 	case AID_VPN_IPv4:
711 		if (len < MRT_PREFIX_LEN(r->prefixlen))
712 			goto fail;
713 		errx(1, "AID_VPN_IPv4 handling not yet implemented");
714 		goto fail;
715 	case AID_VPN_IPv6:
716 		if (len < MRT_PREFIX_LEN(r->prefixlen))
717 			goto fail;
718 		errx(1, "AID_VPN_IPv6 handling not yet implemented");
719 		goto fail;
720 	}
721 
722 	memcpy(&alen, b, sizeof(alen));
723 	b += sizeof(alen);
724 	len -= sizeof(alen);
725 	alen = ntohs(alen);
726 
727 	/* attr */
728 	if (len < alen)
729 		goto fail;
730 	if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
731 		goto fail;
732 	b += alen;
733 	len -= alen;
734 
735 	return (0);
736 fail:
737 	mrt_free_rib(r);
738 	return (-1);
739 }
740 
741 int
742 mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, u_int8_t aid,
743     int as4)
744 {
745 	struct mrt_attr	*ap;
746 	u_int32_t	tmp;
747 	u_int16_t	attr_len;
748 	u_int8_t	type, flags, *attr;
749 
750 	do {
751 		if (alen < 3)
752 			return (-1);
753 		attr = a;
754 		flags = *a++;
755 		alen -= 1;
756 		type = *a++;
757 		alen -= 1;
758 
759 		if (flags & MRT_ATTR_EXTLEN) {
760 			if (alen < 2)
761 				return (-1);
762 			memcpy(&attr_len, a, sizeof(attr_len));
763 			attr_len = ntohs(attr_len);
764 			a += sizeof(attr_len);
765 			alen -= sizeof(attr_len);
766 		} else {
767 			attr_len = *a++;
768 			alen -= 1;
769 		}
770 		switch (type) {
771 		case MRT_ATTR_ORIGIN:
772 			if (attr_len != 1)
773 				return (-1);
774 			re->origin = *a;
775 			break;
776 		case MRT_ATTR_ASPATH:
777 			if (as4) {
778 				re->aspath_len = attr_len;
779 				if ((re->aspath = malloc(attr_len)) == NULL)
780 					err(1, "malloc");
781 				memcpy(re->aspath, a, attr_len);
782 			} else {
783 				re->aspath = mrt_aspath_inflate(a, attr_len,
784 				    &re->aspath_len);
785 				if (re->aspath == NULL)
786 					return (-1);
787 			}
788 			break;
789 		case MRT_ATTR_NEXTHOP:
790 			if (attr_len != 4)
791 				return (-1);
792 			if (aid != AID_INET)
793 				break;
794 			memcpy(&tmp, a, sizeof(tmp));
795 			re->nexthop.aid = AID_INET;
796 			re->nexthop.v4.s_addr = tmp;
797 			break;
798 		case MRT_ATTR_MED:
799 			if (attr_len != 4)
800 				return (-1);
801 			memcpy(&tmp, a, sizeof(tmp));
802 			re->med = ntohl(tmp);
803 			break;
804 		case MRT_ATTR_LOCALPREF:
805 			if (attr_len != 4)
806 				return (-1);
807 			memcpy(&tmp, a, sizeof(tmp));
808 			re->local_pref = ntohl(tmp);
809 			break;
810 		case MRT_ATTR_MP_REACH_NLRI:
811 			/*
812 			 * XXX horrible hack:
813 			 * Once again IETF and the real world differ in the
814 			 * implementation. In short the abbreviated MP_NLRI
815 			 * hack in the standard is not used in real life.
816 			 * Detect the two cases by looking at the first byte
817 			 * of the payload (either the nexthop addr length (RFC)
818 			 * or the high byte of the AFI (old form)). If the
819 			 * first byte matches the expected nexthop length it
820 			 * is expected to be the RFC 6396 encoding.
821 			 */
822 			if (*a != attr_len - 1) {
823 				a += 3;
824 				alen -= 3;
825 				attr_len -= 3;
826 			}
827 			switch (aid) {
828 			case AID_INET6:
829 				if (attr_len < sizeof(struct in6_addr) + 1)
830 					return (-1);
831 				re->nexthop.aid = aid;
832 				memcpy(&re->nexthop.v6, a + 1,
833 				    sizeof(struct in6_addr));
834 				break;
835 			case AID_VPN_IPv4:
836 				if (attr_len < sizeof(u_int64_t) +
837 				    sizeof(struct in_addr))
838 					return (-1);
839 				re->nexthop.aid = aid;
840 				memcpy(&tmp, a + 1 + sizeof(u_int64_t),
841 				    sizeof(tmp));
842 				re->nexthop.vpn4.addr.s_addr = tmp;
843 				break;
844 			case AID_VPN_IPv6:
845 				errx(1, "AID_VPN_IPv6 not yet implemented");
846 				break;
847 			}
848 			break;
849 		case MRT_ATTR_AS4PATH:
850 			if (!as4) {
851 				free(re->aspath);
852 				re->aspath_len = attr_len;
853 				if ((re->aspath = malloc(attr_len)) == NULL)
854 					err(1, "malloc");
855 				memcpy(re->aspath, a, attr_len);
856 				break;
857 			}
858 			/* FALLTHROUGH */
859 		default:
860 			re->nattrs++;
861 			if (re->nattrs >= UCHAR_MAX)
862 				err(1, "too many attributes");
863 			ap = reallocarray(re->attrs,
864 			    re->nattrs, sizeof(struct mrt_attr));
865 			if (ap == NULL)
866 				err(1, "realloc");
867 			re->attrs = ap;
868 			ap = re->attrs + re->nattrs - 1;
869 			ap->attr_len = a + attr_len - attr;
870 			if ((ap->attr = malloc(ap->attr_len)) == NULL)
871 				err(1, "malloc");
872 			memcpy(ap->attr, attr, ap->attr_len);
873 			break;
874 		}
875 		a += attr_len;
876 		alen -= attr_len;
877 	} while (alen > 0);
878 
879 	return (0);
880 }
881 
882 void
883 mrt_free_peers(struct mrt_peer *p)
884 {
885 	free(p->peers);
886 	free(p->view);
887 	free(p);
888 }
889 
890 void
891 mrt_free_rib(struct mrt_rib *r)
892 {
893 	u_int16_t	i, j;
894 
895 	for (i = 0; i < r->nentries && r->entries; i++) {
896 		for (j = 0; j < r->entries[i].nattrs; j++)
897 			 free(r->entries[i].attrs[j].attr);
898 		free(r->entries[i].attrs);
899 		free(r->entries[i].aspath);
900 	}
901 
902 	free(r->entries);
903 	free(r);
904 }
905 
906 void
907 mrt_free_bgp_state(struct mrt_bgp_state *s)
908 {
909 	free(s);
910 }
911 
912 void
913 mrt_free_bgp_msg(struct mrt_bgp_msg *m)
914 {
915 	free(m->msg);
916 	free(m);
917 }
918 
919 u_char *
920 mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen)
921 {
922 	u_int8_t	*seg, *nseg, *ndata;
923 	u_int16_t	 seg_size, olen, nlen;
924 	u_int8_t	 seg_len;
925 
926 	/* first calculate the length of the aspath */
927 	seg = data;
928 	nlen = 0;
929 	for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
930 		seg_len = seg[1];
931 		seg_size = 2 + sizeof(u_int16_t) * seg_len;
932 		nlen += 2 + sizeof(u_int32_t) * seg_len;
933 
934 		if (seg_size > olen)
935 			return NULL;
936 	}
937 
938 	*newlen = nlen;
939 	if ((ndata = malloc(nlen)) == NULL)
940 		err(1, "malloc");
941 
942 	/* then copy the aspath */
943 	seg = data;
944 	for (nseg = ndata; nseg < ndata + nlen; ) {
945 		*nseg++ = *seg++;
946 		*nseg++ = seg_len = *seg++;
947 		for (; seg_len > 0; seg_len--) {
948 			*nseg++ = 0;
949 			*nseg++ = 0;
950 			*nseg++ = *seg++;
951 			*nseg++ = *seg++;
952 		}
953 	}
954 
955 	return (ndata);
956 }
957 
958 int
959 mrt_extract_addr(void *msg, u_int len, struct bgpd_addr *addr, u_int8_t aid)
960 {
961 	u_int8_t	*b = msg;
962 
963 	memset(addr, 0, sizeof(*addr));
964 	switch (aid) {
965 	case AID_INET:
966 		if (len < sizeof(struct in_addr))
967 			return (-1);
968 		addr->aid = aid;
969 		memcpy(&addr->v4, b, sizeof(struct in_addr));
970 		return sizeof(struct in_addr);
971 	case AID_INET6:
972 		if (len < sizeof(struct in6_addr))
973 			return (-1);
974 		addr->aid = aid;
975 		memcpy(&addr->v6, b, sizeof(struct in6_addr));
976 		return sizeof(struct in6_addr);
977 	case AID_VPN_IPv4:
978 		if (len < sizeof(u_int64_t) + sizeof(struct in_addr))
979 			return (-1);
980 		addr->aid = aid;
981 		/* XXX labelstack and rd missing */
982 		memcpy(&addr->vpn4.addr, b + sizeof(u_int64_t),
983 		    sizeof(struct in_addr));
984 		return (sizeof(u_int64_t) + sizeof(struct in_addr));
985 	case AID_VPN_IPv6:
986 		if (len < sizeof(u_int64_t) + sizeof(struct in6_addr))
987 			return (-1);
988 		addr->aid = aid;
989 		/* XXX labelstack and rd missing */
990 		memcpy(&addr->vpn6.addr, b + sizeof(u_int64_t),
991 		    sizeof(struct in6_addr));
992 		return (sizeof(u_int64_t) + sizeof(struct in6_addr));
993 	default:
994 		return (-1);
995 	}
996 }
997 
998 struct mrt_bgp_state *
999 mrt_parse_state(struct mrt_hdr *hdr, void *msg)
1000 {
1001 	struct timespec		 t;
1002 	struct mrt_bgp_state	*s;
1003 	u_int8_t		*b = msg;
1004 	u_int			 len = ntohl(hdr->length);
1005 	u_int32_t		 sas, das, usec;
1006 	u_int16_t		 tmp16, afi;
1007 	int			 r;
1008 	u_int8_t		 aid;
1009 
1010 	t.tv_sec = ntohl(hdr->timestamp);
1011 	t.tv_nsec = 0;
1012 
1013 	/* handle the microsec field for _ET header */
1014 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
1015 		memcpy(&usec, b, sizeof(usec));
1016 		b += sizeof(usec);
1017 		len -= sizeof(usec);
1018 		t.tv_nsec = ntohl(usec) * 1000;
1019 	}
1020 
1021 	switch (ntohs(hdr->subtype)) {
1022 	case BGP4MP_STATE_CHANGE:
1023 		if (len < 8)
1024 			return (0);
1025 		/* source as */
1026 		memcpy(&tmp16, b, sizeof(tmp16));
1027 		b += sizeof(tmp16);
1028 		len -= sizeof(tmp16);
1029 		sas = ntohs(tmp16);
1030 		/* dest as */
1031 		memcpy(&tmp16, b, sizeof(tmp16));
1032 		b += sizeof(tmp16);
1033 		len -= sizeof(tmp16);
1034 		das = ntohs(tmp16);
1035 		/* if_index, ignored */
1036 		b += sizeof(tmp16);
1037 		len -= sizeof(tmp16);
1038 		/* afi */
1039 		memcpy(&tmp16, b, sizeof(tmp16));
1040 		b += sizeof(tmp16);
1041 		len -= sizeof(tmp16);
1042 		afi = ntohs(tmp16);
1043 		break;
1044 	case BGP4MP_STATE_CHANGE_AS4:
1045 		if (len < 12)
1046 			return (0);
1047 		/* source as */
1048 		memcpy(&sas, b, sizeof(sas));
1049 		b += sizeof(sas);
1050 		len -= sizeof(sas);
1051 		sas = ntohl(sas);
1052 		/* dest as */
1053 		memcpy(&das, b, sizeof(das));
1054 		b += sizeof(das);
1055 		len -= sizeof(das);
1056 		das = ntohl(das);
1057 		/* if_index, ignored */
1058 		b += sizeof(tmp16);
1059 		len -= sizeof(tmp16);
1060 		/* afi */
1061 		memcpy(&tmp16, b, sizeof(tmp16));
1062 		b += sizeof(tmp16);
1063 		len -= sizeof(tmp16);
1064 		afi = ntohs(tmp16);
1065 		break;
1066 	default:
1067 		errx(1, "mrt_parse_state: bad subtype");
1068 	}
1069 
1070 	/* src & dst addr */
1071 	switch (afi) {
1072 	case MRT_DUMP_AFI_IP:
1073 		aid = AID_INET;
1074 		break;
1075 	case MRT_DUMP_AFI_IPv6:
1076 		aid = AID_INET6;
1077 		break;
1078 	default:
1079 		 errx(1, "mrt_parse_state: bad afi");
1080 	}
1081 
1082 	if ((s = calloc(1, sizeof(struct mrt_bgp_state))) == NULL)
1083 		err(1, "calloc");
1084 	s->time = t;
1085 	s->src_as = sas;
1086 	s->dst_as = das;
1087 
1088 	if ((r = mrt_extract_addr(b, len, &s->src, aid)) == -1)
1089 		goto fail;
1090 	b += r;
1091 	len -= r;
1092 	if ((r = mrt_extract_addr(b, len, &s->dst, aid)) == -1)
1093 		goto fail;
1094 	b += r;
1095 	len -= r;
1096 
1097 	/* states */
1098 	memcpy(&tmp16, b, sizeof(tmp16));
1099 	b += sizeof(tmp16);
1100 	len -= sizeof(tmp16);
1101 	s->old_state = ntohs(tmp16);
1102 	memcpy(&tmp16, b, sizeof(tmp16));
1103 	b += sizeof(tmp16);
1104 	len -= sizeof(tmp16);
1105 	s->new_state = ntohs(tmp16);
1106 
1107 	return (s);
1108 
1109 fail:
1110 	free(s);
1111 	return (NULL);
1112 }
1113 
1114 struct mrt_bgp_msg *
1115 mrt_parse_msg(struct mrt_hdr *hdr, void *msg)
1116 {
1117 	struct timespec		 t;
1118 	struct mrt_bgp_msg	*m;
1119 	u_int8_t		*b = msg;
1120 	u_int			 len = ntohl(hdr->length);
1121 	u_int32_t		 sas, das, usec;
1122 	u_int16_t		 tmp16, afi;
1123 	int			 r;
1124 	u_int8_t		 aid;
1125 
1126 	t.tv_sec = ntohl(hdr->timestamp);
1127 	t.tv_nsec = 0;
1128 
1129 	/* handle the microsec field for _ET header */
1130 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
1131 		memcpy(&usec, b, sizeof(usec));
1132 		b += sizeof(usec);
1133 		len -= sizeof(usec);
1134 		t.tv_nsec = ntohl(usec) * 1000;
1135 	}
1136 
1137 	switch (ntohs(hdr->subtype)) {
1138 	case BGP4MP_MESSAGE:
1139 		if (len < 8)
1140 			return (0);
1141 		/* source as */
1142 		memcpy(&tmp16, b, sizeof(tmp16));
1143 		b += sizeof(tmp16);
1144 		len -= sizeof(tmp16);
1145 		sas = ntohs(tmp16);
1146 		/* dest as */
1147 		memcpy(&tmp16, b, sizeof(tmp16));
1148 		b += sizeof(tmp16);
1149 		len -= sizeof(tmp16);
1150 		das = ntohs(tmp16);
1151 		/* if_index, ignored */
1152 		b += sizeof(tmp16);
1153 		len -= sizeof(tmp16);
1154 		/* afi */
1155 		memcpy(&tmp16, b, sizeof(tmp16));
1156 		b += sizeof(tmp16);
1157 		len -= sizeof(tmp16);
1158 		afi = ntohs(tmp16);
1159 		break;
1160 	case BGP4MP_MESSAGE_AS4:
1161 		if (len < 12)
1162 			return (0);
1163 		/* source as */
1164 		memcpy(&sas, b, sizeof(sas));
1165 		b += sizeof(sas);
1166 		len -= sizeof(sas);
1167 		sas = ntohl(sas);
1168 		/* dest as */
1169 		memcpy(&das, b, sizeof(das));
1170 		b += sizeof(das);
1171 		len -= sizeof(das);
1172 		das = ntohl(das);
1173 		/* if_index, ignored */
1174 		b += sizeof(tmp16);
1175 		len -= sizeof(tmp16);
1176 		/* afi */
1177 		memcpy(&tmp16, b, sizeof(tmp16));
1178 		b += sizeof(tmp16);
1179 		len -= sizeof(tmp16);
1180 		afi = ntohs(tmp16);
1181 		break;
1182 	default:
1183 		errx(1, "mrt_parse_msg: bad subtype");
1184 	}
1185 
1186 	/* src & dst addr */
1187 	switch (afi) {
1188 	case MRT_DUMP_AFI_IP:
1189 		aid = AID_INET;
1190 		break;
1191 	case MRT_DUMP_AFI_IPv6:
1192 		aid = AID_INET6;
1193 		break;
1194 	default:
1195 		 errx(1, "mrt_parse_msg: bad afi");
1196 	}
1197 
1198 	if ((m = calloc(1, sizeof(struct mrt_bgp_msg))) == NULL)
1199 		err(1, "calloc");
1200 	m->time = t;
1201 	m->src_as = sas;
1202 	m->dst_as = das;
1203 
1204 	if ((r = mrt_extract_addr(b, len, &m->src, aid)) == -1)
1205 		goto fail;
1206 	b += r;
1207 	len -= r;
1208 	if ((r = mrt_extract_addr(b, len, &m->dst, aid)) == -1)
1209 		goto fail;
1210 	b += r;
1211 	len -= r;
1212 
1213 	/* msg */
1214 	if (len > 0) {
1215 		m->msg_len = len;
1216 		if ((m->msg = malloc(len)) == NULL)
1217 			err(1, "malloc");
1218 		memcpy(m->msg, b, len);
1219 	}
1220 
1221 	return (m);
1222 
1223 fail:
1224 	free(m->msg);
1225 	free(m);
1226 	return (NULL);
1227 }
1228