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