xref: /openbsd-src/usr.sbin/bgpctl/mrtparser.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: mrtparser.c,v 1.3 2012/03/26 20:40:32 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 <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;
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 	return (NULL);
317 }
318 
319 struct mrt_rib *
320 mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg)
321 {
322 	struct mrt_rib_entry *entries;
323 	struct mrt_rib	*r;
324 	u_int8_t	*b = msg;
325 	u_int		len = ntohl(hdr->length);
326 	u_int32_t	snum;
327 	u_int16_t	cnt, i;
328 	u_int8_t	plen;
329 
330 	if (len < sizeof(snum) + 1)
331 		return NULL;
332 
333 	r = calloc(1, sizeof(struct mrt_rib));
334 	if (r == NULL)
335 		err(1, "calloc");
336 
337 	/* seq_num */
338 	memcpy(&snum, b, sizeof(snum));
339 	b += sizeof(snum);
340 	len -= sizeof(snum);
341 	r->seqnum = ntohl(snum);
342 
343 	switch (ntohs(hdr->subtype)) {
344 	case MRT_DUMP_V2_RIB_IPV4_UNICAST:
345 	case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
346 		plen = *b++;
347 		len -= 1;
348 		if (len < MRT_PREFIX_LEN(plen))
349 			goto fail;
350 		r->prefix.sin.sin_family = AF_INET;
351 		r->prefix.sin.sin_len = sizeof(struct sockaddr_in);
352 		memcpy(&r->prefix.sin.sin_addr, b, MRT_PREFIX_LEN(plen));
353 		b += MRT_PREFIX_LEN(plen);
354 		len -= MRT_PREFIX_LEN(plen);
355 		r->prefixlen = plen;
356 		break;
357 	case MRT_DUMP_V2_RIB_IPV6_UNICAST:
358 	case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
359 		plen = *b++;
360 		len -= 1;
361 		if (len < MRT_PREFIX_LEN(plen))
362 			goto fail;
363 		r->prefix.sin6.sin6_family = AF_INET6;
364 		r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6);
365 		memcpy(&r->prefix.sin6.sin6_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_GENERIC:
371 		/* XXX unhandled */
372 		errx(1, "MRT_DUMP_V2_RIB_GENERIC subtype not yet implemented");
373 		goto fail;
374 	}
375 
376 	/* entries count */
377 	if (len < sizeof(cnt))
378 		goto fail;
379 	memcpy(&cnt, b, sizeof(cnt));
380 	b += sizeof(cnt);
381 	len -= sizeof(cnt);
382 	cnt = ntohs(cnt);
383 	r->nentries = cnt;
384 
385 	/* entries */
386 	if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL)
387 		err(1, "calloc");
388 	for (i = 0; i < cnt; i++) {
389 		u_int32_t	otm;
390 		u_int16_t	pix, alen;
391 		if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t))
392 			goto fail;
393 		/* peer index */
394 		memcpy(&pix, b, sizeof(pix));
395 		b += sizeof(pix);
396 		len -= sizeof(pix);
397 		entries[i].peer_idx = ntohs(pix);
398 
399 		/* originated */
400 		memcpy(&otm, b, sizeof(otm));
401 		b += sizeof(otm);
402 		len -= sizeof(otm);
403 		entries[i].originated = ntohl(otm);
404 
405 		/* attr_len */
406 		memcpy(&alen, b, sizeof(alen));
407 		b += sizeof(alen);
408 		len -= sizeof(alen);
409 		alen = ntohs(alen);
410 
411 		/* attr */
412 		if (len < alen)
413 			goto fail;
414 		if (mrt_extract_attr(&entries[i], b, alen,
415 		    r->prefix.sa.sa_family, 1) == -1)
416 			goto fail;
417 		b += alen;
418 		len -= alen;
419 	}
420 	r->entries = entries;
421 	return (r);
422 fail:
423 	mrt_free_rib(r);
424 	return (NULL);
425 }
426 
427 int
428 mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
429     struct mrt_rib **rp)
430 {
431 	struct mrt_peer		*p;
432 	struct mrt_rib		*r;
433 	struct mrt_rib_entry	*re;
434 	u_int8_t		*b = msg;
435 	u_int			 len = ntohl(hdr->length);
436 	u_int16_t		 asnum, alen;
437 
438 	if (*pp == NULL) {
439 		*pp = calloc(1, sizeof(struct mrt_peer));
440 		if (*pp == NULL)
441 			err(1, "calloc");
442 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
443 		if ((*pp)->peers == NULL)
444 			err(1, "calloc");
445 		(*pp)->npeers = 1;
446 	}
447 	p = *pp;
448 
449 	*rp = r = calloc(1, sizeof(struct mrt_rib));
450 	if (r == NULL)
451 		err(1, "calloc");
452 	re = calloc(1, sizeof(struct mrt_rib_entry));
453 	if (re == NULL)
454 		err(1, "calloc");
455 	r->nentries = 1;
456 	r->entries = re;
457 
458 	if (len < 2 * sizeof(u_int16_t))
459 		goto fail;
460 	/* view */
461 	b += sizeof(u_int16_t);
462 	len -= sizeof(u_int16_t);
463 	/* seqnum */
464 	memcpy(&r->seqnum, b, sizeof(u_int16_t));
465 	b += sizeof(u_int16_t);
466 	len -= sizeof(u_int16_t);
467 	r->seqnum = ntohs(r->seqnum);
468 
469 	switch (ntohs(hdr->subtype)) {
470 	case MRT_DUMP_AFI_IP:
471 		if (mrt_extract_addr(b, len, &r->prefix, AF_INET) == -1)
472 			goto fail;
473 		b += sizeof(struct in_addr);
474 		len -= sizeof(struct in_addr);
475 		break;
476 	case MRT_DUMP_AFI_IPv6:
477 		if (mrt_extract_addr(b, len, &r->prefix, AF_INET6) == -1)
478 			goto fail;
479 		b += sizeof(struct in6_addr);
480 		len -= sizeof(struct in6_addr);
481 		break;
482 	}
483 	if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2)
484 		goto fail;
485 	r->prefixlen = *b++;
486 	len -= 1;
487 	/* status */
488 	b += 1;
489 	len -= 1;
490 	/* originated */
491 	memcpy(&re->originated, b, sizeof(u_int32_t));
492 	b += sizeof(u_int32_t);
493 	len -= sizeof(u_int32_t);
494 	re->originated = ntohl(re->originated);
495 	/* peer ip */
496 	switch (ntohs(hdr->subtype)) {
497 	case MRT_DUMP_AFI_IP:
498 		if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1)
499 			goto fail;
500 		b += sizeof(struct in_addr);
501 		len -= sizeof(struct in_addr);
502 		break;
503 	case MRT_DUMP_AFI_IPv6:
504 		if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1)
505 			goto fail;
506 		b += sizeof(struct in6_addr);
507 		len -= sizeof(struct in6_addr);
508 		break;
509 	}
510 	memcpy(&asnum, b, sizeof(asnum));
511 	b += sizeof(asnum);
512 	len -= sizeof(asnum);
513 	p->peers->asnum = ntohs(asnum);
514 
515 	memcpy(&alen, b, sizeof(alen));
516 	b += sizeof(alen);
517 	len -= sizeof(alen);
518 	alen = ntohs(alen);
519 
520 	/* attr */
521 	if (len < alen)
522 		goto fail;
523 	if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1)
524 		goto fail;
525 	b += alen;
526 	len -= alen;
527 
528 	return (0);
529 fail:
530 	mrt_free_rib(r);
531 	return (-1);
532 }
533 
534 int
535 mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
536     struct mrt_rib **rp)
537 {
538 	struct mrt_peer		*p;
539 	struct mrt_rib		*r;
540 	struct mrt_rib_entry	*re;
541 	u_int8_t		*b = msg;
542 	u_int			 len = ntohl(hdr->length);
543 	u_int16_t		 asnum, alen, afi;
544 	u_int8_t		 safi, nhlen;
545 	sa_family_t		 af;
546 
547 	if (*pp == NULL) {
548 		*pp = calloc(1, sizeof(struct mrt_peer));
549 		if (*pp == NULL)
550 			err(1, "calloc");
551 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
552 		if ((*pp)->peers == NULL)
553 			err(1, "calloc");
554 		(*pp)->npeers = 1;
555 	}
556 	p = *pp;
557 
558 	*rp = r = calloc(1, sizeof(struct mrt_rib));
559 	if (r == NULL)
560 		err(1, "calloc");
561 	re = calloc(1, sizeof(struct mrt_rib_entry));
562 	if (re == NULL)
563 		err(1, "calloc");
564 	r->nentries = 1;
565 	r->entries = re;
566 
567 	if (len < 4 * sizeof(u_int16_t))
568 		goto fail;
569 	/* source AS */
570 	b += sizeof(u_int16_t);
571 	len -= sizeof(u_int16_t);
572 	/* dest AS */
573 	memcpy(&asnum, b, sizeof(asnum));
574 	b += sizeof(asnum);
575 	len -= sizeof(asnum);
576 	p->peers->asnum = ntohs(asnum);
577 	/* iface index */
578 	b += sizeof(u_int16_t);
579 	len -= sizeof(u_int16_t);
580 	/* afi */
581 	memcpy(&afi, b, sizeof(afi));
582 	b += sizeof(afi);
583 	len -= sizeof(afi);
584 	afi = ntohs(afi);
585 
586 	/* source + dest ip */
587 	switch (afi) {
588 	case MRT_DUMP_AFI_IP:
589 		if (len < 2 * sizeof(struct in_addr))
590 			goto fail;
591 		/* source IP */
592 		b += sizeof(struct in_addr);
593 		len -= sizeof(struct in_addr);
594 		/* dest IP */
595 		if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1)
596 			goto fail;
597 		b += sizeof(struct in_addr);
598 		len -= sizeof(struct in_addr);
599 		break;
600 	case MRT_DUMP_AFI_IPv6:
601 		if (len < 2 * sizeof(struct in6_addr))
602 			goto fail;
603 		/* source IP */
604 		b += sizeof(struct in6_addr);
605 		len -= sizeof(struct in6_addr);
606 		/* dest IP */
607 		if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1)
608 			goto fail;
609 		b += sizeof(struct in6_addr);
610 		len -= sizeof(struct in6_addr);
611 		break;
612 	}
613 
614 	if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t))
615 		goto fail;
616 	/* view + status */
617 	b += 2 * sizeof(u_int16_t);
618 	len -= 2 * sizeof(u_int16_t);
619 	/* originated */
620 	memcpy(&re->originated, b, sizeof(u_int32_t));
621 	b += sizeof(u_int32_t);
622 	len -= sizeof(u_int32_t);
623 	re->originated = ntohl(re->originated);
624 
625 	/* afi */
626 	memcpy(&afi, b, sizeof(afi));
627 	b += sizeof(afi);
628 	len -= sizeof(afi);
629 	afi = ntohs(afi);
630 
631 	/* safi */
632 	safi = *b++;
633 	len -= 1;
634 
635 	switch (afi) {
636 	case MRT_DUMP_AFI_IP:
637 		if (safi == 1 || safi == 2) {
638 			af = AF_INET;
639 			break;
640 		} else if (safi == 128) {
641 			af = AF_VPNv4;
642 			break;
643 		}
644 		goto fail;
645 	case MRT_DUMP_AFI_IPv6:
646 		if (safi != 1 && safi != 2)
647 			goto fail;
648 		af = AF_INET6;
649 		break;
650 	default:
651 		goto fail;
652 	}
653 
654 	/* nhlen */
655 	nhlen = *b++;
656 	len -= 1;
657 
658 	/* nexthop */
659 	if (mrt_extract_addr(b, len, &re->nexthop, af) == -1)
660 		goto fail;
661 	if (len < nhlen)
662 		goto fail;
663 	b += nhlen;
664 	len -= nhlen;
665 
666 	if (len < 1)
667 		goto fail;
668 	r->prefixlen = *b++;
669 	len -= 1;
670 
671 	/* prefix */
672 	switch (af) {
673 	case AF_INET:
674 		if (len < MRT_PREFIX_LEN(r->prefixlen))
675 			goto fail;
676 		r->prefix.sin.sin_family = AF_INET;
677 		r->prefix.sin.sin_len = sizeof(struct sockaddr_in);
678 		memcpy(&r->prefix.sin.sin_addr, b,
679 		    MRT_PREFIX_LEN(r->prefixlen));
680 		b += MRT_PREFIX_LEN(r->prefixlen);
681 		len -= MRT_PREFIX_LEN(r->prefixlen);
682 		break;
683 	case AF_INET6:
684 		if (len < MRT_PREFIX_LEN(r->prefixlen))
685 			goto fail;
686 		r->prefix.sin6.sin6_family = AF_INET6;
687 		r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6);
688 		memcpy(&r->prefix.sin6.sin6_addr, b,
689 		    MRT_PREFIX_LEN(r->prefixlen));
690 		b += MRT_PREFIX_LEN(r->prefixlen);
691 		len -= MRT_PREFIX_LEN(r->prefixlen);
692 		break;
693 	case AF_VPNv4:
694 		if (len < MRT_PREFIX_LEN(r->prefixlen))
695 			goto fail;
696 		errx(1, "AF_VPNv4 handling not yet implemented");
697 		goto fail;
698 	}
699 
700 	memcpy(&alen, b, sizeof(alen));
701 	b += sizeof(alen);
702 	len -= sizeof(alen);
703 	alen = ntohs(alen);
704 
705 	/* attr */
706 	if (len < alen)
707 		goto fail;
708 	if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1)
709 		goto fail;
710 	b += alen;
711 	len -= alen;
712 
713 	return (0);
714 fail:
715 	mrt_free_rib(r);
716 	return (-1);
717 }
718 
719 int
720 mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, sa_family_t af,
721     int as4)
722 {
723 	struct mrt_attr	*ap;
724 	u_int32_t	tmp;
725 	u_int16_t	attr_len;
726 	u_int8_t	type, flags, *attr;
727 
728 	do {
729 		if (alen < 3)
730 			return (-1);
731 		attr = a;
732 		flags = *a++;
733 		alen -= 1;
734 		type = *a++;
735 		alen -= 1;
736 
737 		if (flags & MRT_ATTR_EXTLEN) {
738 			if (alen < 2)
739 				return (-1);
740 			memcpy(&attr_len, a, sizeof(attr_len));
741 			attr_len = ntohs(attr_len);
742 			a += sizeof(attr_len);
743 			alen -= sizeof(attr_len);
744 		} else {
745 			attr_len = *a++;
746 			alen -= 1;
747 		}
748 		switch (type) {
749 		case MRT_ATTR_ORIGIN:
750 			if (attr_len != 1)
751 				return (-1);
752 			re->origin = *a;
753 			break;
754 		case MRT_ATTR_ASPATH:
755 			if (as4) {
756 				re->aspath_len = attr_len;
757 				if ((re->aspath = malloc(attr_len)) == NULL)
758 					err(1, "malloc");
759 				memcpy(re->aspath, a, attr_len);
760 			} else {
761 				re->aspath = mrt_aspath_inflate(a, attr_len,
762 				    &re->aspath_len);
763 				if (re->aspath == NULL)
764 					return (-1);
765 			}
766 			break;
767 		case MRT_ATTR_NEXTHOP:
768 			if (attr_len != 4)
769 				return (-1);
770 			if (af != AF_INET)
771 				break;
772 			memcpy(&tmp, a, sizeof(tmp));
773 			re->nexthop.sin.sin_len = sizeof(struct sockaddr_in);
774 			re->nexthop.sin.sin_family = AF_INET;
775 			re->nexthop.sin.sin_addr.s_addr = tmp;
776 			break;
777 		case MRT_ATTR_MED:
778 			if (attr_len != 4)
779 				return (-1);
780 			memcpy(&tmp, a, sizeof(tmp));
781 			re->med = ntohl(tmp);
782 			break;
783 		case MRT_ATTR_LOCALPREF:
784 			if (attr_len != 4)
785 				return (-1);
786 			memcpy(&tmp, a, sizeof(tmp));
787 			re->local_pref = ntohl(tmp);
788 			break;
789 		case MRT_ATTR_MP_REACH_NLRI:
790 			/*
791 			 * XXX horrible hack:
792 			 * Once again IETF and the real world differ in the
793 			 * implementation. In short the abbreviated MP_NLRI
794 			 * hack in the standard is not used in real life.
795 			 * Detect the two cases by looking at the first byte
796 			 * of the payload (either the nexthop addr length (RFC)
797 			 * or the high byte of the AFI (old form)). If the
798 			 * first byte matches the expected nexthop length it
799 			 * is expected to be the RFC 6396 encoding.
800 			 */
801 			if (*a != attr_len - 1) {
802 				a += 3;
803 				alen -= 3;
804 				attr_len -= 3;
805 			}
806 			switch (af) {
807 			case AF_INET6:
808 				if (attr_len < sizeof(struct in6_addr) + 1)
809 					return (-1);
810 				re->nexthop.sin6.sin6_len =
811 				    sizeof(struct sockaddr_in6);
812 				re->nexthop.sin6.sin6_family = AF_INET6;
813 				memcpy(&re->nexthop.sin6.sin6_addr, a + 1,
814 				    sizeof(struct in6_addr));
815 				break;
816 			case AF_VPNv4:
817 				if (attr_len < sizeof(u_int64_t) +
818 				    sizeof(struct in_addr))
819 					return (-1);
820 				re->nexthop.svpn4.sv_len =
821 				    sizeof(struct sockaddr_vpn4);
822 				re->nexthop.svpn4.sv_family = AF_VPNv4;
823 				memcpy(&tmp, a + 1 + sizeof(u_int64_t),
824 				    sizeof(tmp));
825 				re->nexthop.svpn4.sv_addr.s_addr = tmp;
826 				break;
827 			}
828 			break;
829 		case MRT_ATTR_AS4PATH:
830 			if (!as4) {
831 				if (re->aspath)
832 					free(re->aspath);
833 				re->aspath_len = attr_len;
834 				if ((re->aspath = malloc(attr_len)) == NULL)
835 					err(1, "malloc");
836 				memcpy(re->aspath, a, attr_len);
837 				break;
838 			}
839 			/* FALLTHROUGH */
840 		default:
841 			re->nattrs++;
842 			if (re->nattrs >= UCHAR_MAX)
843 				err(1, "too many attributes");
844 			ap = realloc(re->attrs,
845 			    re->nattrs * sizeof(struct mrt_attr));
846 			if (ap == NULL)
847 				err(1, "realloc");
848 			re->attrs = ap;
849 			ap = re->attrs + re->nattrs - 1;
850 			ap->attr_len = a + attr_len - attr;
851 			if ((ap->attr = malloc(ap->attr_len)) == NULL)
852 				err(1, "malloc");
853 			memcpy(ap->attr, attr, ap->attr_len);
854 			break;
855 		}
856 		a += attr_len;
857 		alen -= attr_len;
858 	} while (alen > 0);
859 
860 	return (0);
861 }
862 
863 void
864 mrt_free_peers(struct mrt_peer *p)
865 {
866 	free(p->peers);
867 	free(p->view);
868 	free(p);
869 }
870 
871 void
872 mrt_free_rib(struct mrt_rib *r)
873 {
874 	u_int16_t	i, j;
875 
876 	for (i = 0; i < r->nentries && r->entries; i++) {
877 		for (j = 0; j < r->entries[i].nattrs; j++)
878 			 free(r->entries[i].attrs[j].attr);
879 		free(r->entries[i].attrs);
880 		free(r->entries[i].aspath);
881 	}
882 
883 	free(r->entries);
884 	free(r);
885 }
886 
887 void
888 mrt_free_bgp_state(struct mrt_bgp_state *s)
889 {
890 	free(s);
891 }
892 
893 void
894 mrt_free_bgp_msg(struct mrt_bgp_msg *m)
895 {
896 	free(m->msg);
897 	free(m);
898 }
899 
900 u_char *
901 mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen)
902 {
903 	u_int8_t	*seg, *nseg, *ndata;
904 	u_int16_t	 seg_size, olen, nlen;
905 	u_int8_t	 seg_len;
906 
907 	/* first calculate the length of the aspath */
908 	seg = data;
909 	nlen = 0;
910 	for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
911 		seg_len = seg[1];
912 		seg_size = 2 + sizeof(u_int16_t) * seg_len;
913 		nlen += 2 + sizeof(u_int32_t) * seg_len;
914 
915 		if (seg_size > olen)
916 			return NULL;
917 	}
918 
919 	*newlen = nlen;
920 	if ((ndata = malloc(nlen)) == NULL)
921 		err(1, "malloc");
922 
923 	/* then copy the aspath */
924 	seg = data;
925 	for (nseg = ndata; nseg < ndata + nlen; ) {
926 		*nseg++ = *seg++;
927 		*nseg++ = seg_len = *seg++;
928 		for (; seg_len > 0; seg_len--) {
929 			*nseg++ = 0;
930 			*nseg++ = 0;
931 			*nseg++ = *seg++;
932 			*nseg++ = *seg++;
933 		}
934 	}
935 
936 	return (ndata);
937 }
938 
939 int
940 mrt_extract_addr(void *msg, u_int len, union mrt_addr *addr, sa_family_t af)
941 {
942 	u_int8_t	*b = msg;
943 
944 	switch (af) {
945 	case AF_INET:
946 		if (len < sizeof(struct in_addr))
947 			return (-1);
948 		addr->sin.sin_family = AF_INET;
949 		addr->sin.sin_len = sizeof(struct sockaddr_in);
950 		memcpy(&addr->sin.sin_addr, b, sizeof(struct in_addr));
951 		return sizeof(struct in_addr);
952 	case AF_INET6:
953 		if (len < sizeof(struct in6_addr))
954 			return (-1);
955 		addr->sin6.sin6_family = AF_INET6;
956 		addr->sin6.sin6_len = sizeof(struct sockaddr_in6);
957 		memcpy(&addr->sin6.sin6_addr, b, sizeof(struct in6_addr));
958 		return sizeof(struct in6_addr);
959 	case AF_VPNv4:
960 		if (len < sizeof(u_int64_t) + sizeof(struct in_addr))
961 			return (-1);
962 		addr->svpn4.sv_len = sizeof(struct sockaddr_vpn4);
963 		addr->svpn4.sv_family = AF_VPNv4;
964 		memcpy(&addr->svpn4.sv_addr, b + sizeof(u_int64_t),
965 		    sizeof(struct in_addr));
966 		return (sizeof(u_int64_t) + sizeof(struct in_addr));
967 	default:
968 		return (-1);
969 	}
970 }
971