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