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