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