xref: /openbsd/usr.sbin/bgpd/util.c (revision 9ea232b5)
1 /*	$OpenBSD: util.c,v 1.81 2024/02/02 16:14:51 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <endian.h>
24 #include <errno.h>
25 #include <netdb.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <vis.h>
30 
31 #include "bgpd.h"
32 #include "rde.h"
33 #include "log.h"
34 
35 const char *
36 log_addr(const struct bgpd_addr *addr)
37 {
38 	static char	buf[74];
39 	struct sockaddr *sa;
40 	socklen_t	len;
41 
42 	sa = addr2sa(addr, 0, &len);
43 	switch (addr->aid) {
44 	case AID_INET:
45 	case AID_INET6:
46 		return log_sockaddr(sa, len);
47 	case AID_VPN_IPv4:
48 	case AID_VPN_IPv6:
49 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd),
50 		    log_sockaddr(sa, len));
51 		return (buf);
52 	}
53 	return ("???");
54 }
55 
56 const char *
57 log_in6addr(const struct in6_addr *addr)
58 {
59 	struct sockaddr_in6	sa_in6;
60 
61 	memset(&sa_in6, 0, sizeof(sa_in6));
62 	sa_in6.sin6_family = AF_INET6;
63 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
64 
65 #ifdef __KAME__
66 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
67 	if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
68 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) ||
69 	    IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) &&
70 	    sa_in6.sin6_scope_id == 0) {
71 		uint16_t tmp16;
72 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
73 		sa_in6.sin6_scope_id = ntohs(tmp16);
74 		sa_in6.sin6_addr.s6_addr[2] = 0;
75 		sa_in6.sin6_addr.s6_addr[3] = 0;
76 	}
77 #endif
78 
79 	return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
80 }
81 
82 const char *
83 log_sockaddr(struct sockaddr *sa, socklen_t len)
84 {
85 	static char	buf[NI_MAXHOST];
86 
87 	if (sa == NULL || getnameinfo(sa, len, buf, sizeof(buf), NULL, 0,
88 	    NI_NUMERICHOST))
89 		return ("(unknown)");
90 	else
91 		return (buf);
92 }
93 
94 const char *
95 log_as(uint32_t as)
96 {
97 	static char	buf[11];	/* "4294967294\0" */
98 
99 	if (snprintf(buf, sizeof(buf), "%u", as) < 0)
100 		return ("?");
101 
102 	return (buf);
103 }
104 
105 const char *
106 log_rd(uint64_t rd)
107 {
108 	static char	buf[32];
109 	struct in_addr	addr;
110 	uint32_t	u32;
111 	uint16_t	u16;
112 
113 	rd = be64toh(rd);
114 	switch (rd >> 48) {
115 	case EXT_COMMUNITY_TRANS_TWO_AS:
116 		u32 = rd & 0xffffffff;
117 		u16 = (rd >> 32) & 0xffff;
118 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
119 		break;
120 	case EXT_COMMUNITY_TRANS_FOUR_AS:
121 		u32 = (rd >> 16) & 0xffffffff;
122 		u16 = rd & 0xffff;
123 		snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
124 		break;
125 	case EXT_COMMUNITY_TRANS_IPV4:
126 		u32 = (rd >> 16) & 0xffffffff;
127 		u16 = rd & 0xffff;
128 		addr.s_addr = htonl(u32);
129 		snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
130 		break;
131 	default:
132 		snprintf(buf, sizeof(buf), "rd #%016llx",
133 		    (unsigned long long)rd);
134 		break;
135 	}
136 	return (buf);
137 }
138 
139 const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
140 
141 /* NOTE: this function does not check if the type/subtype combo is
142  * actually valid. */
143 const char *
144 log_ext_subtype(int type, uint8_t subtype)
145 {
146 	static char etype[6];
147 	const struct ext_comm_pairs *cp;
148 
149 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
150 		if ((type == cp->type || type == -1) && subtype == cp->subtype)
151 			return (cp->subname);
152 	}
153 	snprintf(etype, sizeof(etype), "[%u]", subtype);
154 	return (etype);
155 }
156 
157 const char *
158 log_reason(const char *communication) {
159 	static char buf[(REASON_LEN - 1) * 4 + 1];
160 
161 	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
162 
163 	return buf;
164 }
165 
166 static const char *
167 log_expires(time_t expires)
168 {
169 	static char buf[32];
170 
171 	buf[0] = '\0';
172 	if (expires != 0)
173 		snprintf(buf, sizeof(buf), " expires %lld", (long long)expires);
174 	return buf;
175 }
176 
177 const char *
178 log_roa(struct roa *roa)
179 {
180 	static char buf[256];
181 	struct bgpd_addr addr = { .aid = roa->aid, .v6 = roa->prefix.inet6 };
182 	char maxbuf[32];
183 
184 	maxbuf[0] = '\0';
185 	if (roa->prefixlen != roa->maxlen)
186 		snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen);
187 	snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr),
188 	    roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires));
189 	return buf;
190 }
191 
192 const char *
193 log_aspa(struct aspa_set *aspa)
194 {
195 	static char errbuf[256];
196 	static char *buf;
197 	static size_t len;
198 	char asbuf[16];
199 	size_t needed;
200 	uint32_t i;
201 
202 	/* include enough space for header and trailer */
203 	if ((uint64_t)aspa->num > (SIZE_MAX / sizeof(asbuf) - 72))
204 		goto fail;
205 	needed = aspa->num * sizeof(asbuf) + 72;
206 	if (needed > len) {
207 		char *nbuf;
208 
209 		if ((nbuf = realloc(buf, needed)) == NULL)
210 			goto fail;
211 		len = needed;
212 		buf = nbuf;
213 	}
214 
215 	snprintf(buf, len, "customer-as %s%s provider-as { ",
216 	    log_as(aspa->as), log_expires(aspa->expires));
217 
218 	for (i = 0; i < aspa->num; i++) {
219 		snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i]));
220 		if (strlcat(buf, asbuf, len) >= len)
221 			goto fail;
222 	}
223 	if (strlcat(buf, "}", len) >= len)
224 		goto fail;
225 	return buf;
226 
227  fail:
228 	free(buf);
229 	buf = NULL;
230 	len = 0;
231 	snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }",
232 	    log_as(aspa->as), log_expires(aspa->expires));
233 	return errbuf;
234 }
235 
236 const char *
237 log_aspath_error(int error)
238 {
239 	static char buf[20];
240 
241 	switch (error) {
242 	case AS_ERR_LEN:
243 		return "inconsitent lenght";
244 	case AS_ERR_TYPE:
245 		return "unknown segment type";
246 	case AS_ERR_BAD:
247 		return "invalid encoding";
248 	case AS_ERR_SOFT:
249 		return "soft failure";
250 	default:
251 		snprintf(buf, sizeof(buf), "unknown %d", error);
252 		return buf;
253 	}
254 }
255 
256 const char *
257 log_rtr_error(enum rtr_error err)
258 {
259 	static char buf[20];
260 
261 	switch (err) {
262 	case NO_ERROR:
263 		return "No Error";
264 	case CORRUPT_DATA:
265 		return "Corrupt Data";
266 	case INTERNAL_ERROR:
267 		return "Internal Error";
268 	case NO_DATA_AVAILABLE:
269 		return "No Data Available";
270 	case INVALID_REQUEST:
271 		return "Invalid Request";
272 	case UNSUPP_PROTOCOL_VERS:
273 		return "Unsupported Protocol Version";
274 	case UNSUPP_PDU_TYPE:
275 		return "Unsupported PDU Type";
276 	case UNK_REC_WDRAWL:
277 		return "Withdrawal of Unknown Record";
278 	case DUP_REC_RECV:
279 		return "Duplicate Announcement Received";
280 	case UNEXP_PROTOCOL_VERS:
281 		return "Unexpected Protocol Version";
282 	default:
283 		snprintf(buf, sizeof(buf), "unknown %u", err);
284 		return buf;
285 	}
286 }
287 
288 const char *
289 log_policy(enum role role)
290 {
291 	switch (role) {
292 	case ROLE_PROVIDER:
293 		return "provider";
294 	case ROLE_RS:
295 		return "rs";
296 	case ROLE_RS_CLIENT:
297 		return "rs-client";
298 	case ROLE_CUSTOMER:
299 		return "customer";
300 	case ROLE_PEER:
301 		return "peer";
302 	default:
303 		return "unknown";
304 	}
305 }
306 
307 static const char *
308 aspath_delim(uint8_t seg_type, int closing)
309 {
310 	static char db[8];
311 
312 	switch (seg_type) {
313 	case AS_SET:
314 		if (!closing)
315 			return ("{ ");
316 		else
317 			return (" }");
318 	case AS_SEQUENCE:
319 		return ("");
320 	case AS_CONFED_SEQUENCE:
321 		if (!closing)
322 			return ("( ");
323 		else
324 			return (" )");
325 	case AS_CONFED_SET:
326 		if (!closing)
327 			return ("[ ");
328 		else
329 			return (" ]");
330 	default:
331 		if (!closing)
332 			snprintf(db, sizeof(db), "!%u ", seg_type);
333 		else
334 			snprintf(db, sizeof(db), " !%u", seg_type);
335 		return (db);
336 	}
337 }
338 
339 static int
340 aspath_snprint(char *buf, size_t size, struct ibuf *in)
341 {
342 #define UPDATE()						\
343 	do {							\
344 		if (r < 0 || (unsigned int)r >= size)		\
345 			return (-1);				\
346 		size -= r;					\
347 		buf += r;					\
348 	} while (0)
349 
350 	struct ibuf	data;
351 	uint32_t	as;
352 	int		r, n = 0;
353 	uint8_t		i, seg_type, seg_len;
354 
355 	ibuf_from_ibuf(&data, in);
356 	while (ibuf_size(&data) > 0) {
357 		if (ibuf_get_n8(&data, &seg_type) == -1 ||
358 		    ibuf_get_n8(&data, &seg_len) == -1 ||
359 		    seg_len == 0)
360 			return (-1);
361 
362 		r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "",
363 		    aspath_delim(seg_type, 0));
364 		UPDATE();
365 
366 		for (i = 0; i < seg_len; i++) {
367 			if (ibuf_get_n32(&data, &as) == -1)
368 				return -1;
369 
370 			r = snprintf(buf, size, "%s", log_as(as));
371 			UPDATE();
372 			if (i + 1 < seg_len) {
373 				r = snprintf(buf, size, " ");
374 				UPDATE();
375 			}
376 		}
377 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
378 		UPDATE();
379 	}
380 	/* ensure that we have a valid C-string especially for empty as path */
381 	*buf = '\0';
382 	return (0);
383 #undef UPDATE
384 }
385 
386 static ssize_t
387 aspath_strsize(struct ibuf *in)
388 {
389 	struct ibuf	 buf;
390 	ssize_t		 total_size = 0;
391 	uint32_t	 as;
392 	uint8_t		 i, seg_type, seg_len;
393 
394 	ibuf_from_ibuf(&buf, in);
395 	while (ibuf_size(&buf) > 0) {
396 		if (ibuf_get_n8(&buf, &seg_type) == -1 ||
397 		    ibuf_get_n8(&buf, &seg_len) == -1 ||
398 		    seg_len == 0)
399 			return (-1);
400 
401 		if (total_size != 0)
402 			total_size += 1;
403 		total_size += strlen(aspath_delim(seg_type, 0));
404 
405 		for (i = 0; i < seg_len; i++) {
406 			if (ibuf_get_n32(&buf, &as) == -1)
407 				return (-1);
408 
409 			do {
410 				total_size++;
411 			} while ((as = as / 10) != 0);
412 		}
413 		total_size += seg_len - 1;
414 
415 		total_size += strlen(aspath_delim(seg_type, 1));
416 	}
417 	return (total_size + 1);
418 }
419 
420 int
421 aspath_asprint(char **ret, struct ibuf *data)
422 {
423 	ssize_t	slen;
424 
425 	if ((slen = aspath_strsize(data)) == -1) {
426 		*ret = NULL;
427 		errno = EINVAL;
428 		return (-1);
429 	}
430 
431 	*ret = malloc(slen);
432 	if (*ret == NULL)
433 		return (-1);
434 
435 	if (aspath_snprint(*ret, slen, data) == -1) {
436 		free(*ret);
437 		*ret = NULL;
438 		errno = EINVAL;
439 		return (-1);
440 	}
441 
442 	return (0);
443 }
444 
445 /*
446  * Extract the asnum out of the as segment at the specified position.
447  * Direct access is not possible because of non-aligned reads.
448  * Only works on verified 4-byte AS paths.
449  */
450 uint32_t
451 aspath_extract(const void *seg, int pos)
452 {
453 	const u_char	*ptr = seg;
454 	uint32_t	 as;
455 
456 	/* minimal pos check, return 0 since that is an invalid ASN */
457 	if (pos < 0 || pos >= ptr[1])
458 		return (0);
459 	ptr += 2 + sizeof(uint32_t) * pos;
460 	memcpy(&as, ptr, sizeof(uint32_t));
461 	return (ntohl(as));
462 }
463 
464 /*
465  * Verify that the aspath is correctly encoded.
466  */
467 int
468 aspath_verify(struct ibuf *in, int as4byte, int noset)
469 {
470 	struct ibuf	 buf;
471 	int		 pos, error = 0;
472 	uint8_t		 seg_len, seg_type;
473 
474 	ibuf_from_ibuf(&buf, in);
475 	if (ibuf_size(&buf) & 1) {
476 		/* odd length aspath are invalid */
477 		error = AS_ERR_BAD;
478 		goto done;
479 	}
480 
481 	while (ibuf_size(&buf) > 0) {
482 		if (ibuf_get_n8(&buf, &seg_type) == -1 ||
483 		    ibuf_get_n8(&buf, &seg_len) == -1) {
484 			error = AS_ERR_LEN;
485 			goto done;
486 		}
487 
488 		if (seg_len == 0) {
489 			/* empty aspath segments are not allowed */
490 			error = AS_ERR_BAD;
491 			goto done;
492 		}
493 
494 		/*
495 		 * BGP confederations should not show up but consider them
496 		 * as a soft error which invalidates the path but keeps the
497 		 * bgp session running.
498 		 */
499 		if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
500 			error = AS_ERR_SOFT;
501 		/*
502 		 * If AS_SET filtering (RFC6472) is on, error out on AS_SET
503 		 * as well.
504 		 */
505 		if (noset && seg_type == AS_SET)
506 			error = AS_ERR_SOFT;
507 		if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
508 		    seg_type != AS_CONFED_SEQUENCE &&
509 		    seg_type != AS_CONFED_SET) {
510 			error = AS_ERR_TYPE;
511 			goto done;
512 		}
513 
514 		/* RFC 7607 - AS 0 is considered malformed */
515 		for (pos = 0; pos < seg_len; pos++) {
516 			uint32_t as;
517 
518 			if (as4byte) {
519 				if (ibuf_get_n32(&buf, &as) == -1) {
520 					error = AS_ERR_LEN;
521 					goto done;
522 				}
523 			} else {
524 				uint16_t tmp;
525 				if (ibuf_get_n16(&buf, &tmp) == -1) {
526 					error = AS_ERR_LEN;
527 					goto done;
528 				}
529 				as = tmp;
530 			}
531 			if (as == 0)
532 				error = AS_ERR_SOFT;
533 		}
534 	}
535 
536  done:
537 	return (error);	/* aspath is valid but probably not loop free */
538 }
539 
540 /*
541  * convert a 2 byte aspath to a 4 byte one.
542  */
543 struct ibuf *
544 aspath_inflate(struct ibuf *in)
545 {
546 	struct ibuf	*out;
547 	uint16_t	 short_as;
548 	uint8_t		 seg_type, seg_len;
549 
550 	/*
551 	 * Allocate enough space for the worst case.
552 	 * XXX add 1 byte for the empty ASPATH case since we can't
553 	 * allocate an ibuf of 0 length.
554 	 */
555 	if ((out = ibuf_open(ibuf_size(in) * 2 + 1)) == NULL)
556 		return (NULL);
557 
558 	/* then copy the aspath */
559 	while (ibuf_size(in) > 0) {
560 		if (ibuf_get_n8(in, &seg_type) == -1 ||
561 		    ibuf_get_n8(in, &seg_len) == -1 ||
562 		    seg_len == 0)
563 			goto fail;
564 		if (ibuf_add_n8(out, seg_type) == -1 ||
565 		    ibuf_add_n8(out, seg_len) == -1)
566 			goto fail;
567 
568 		for (; seg_len > 0; seg_len--) {
569 			if (ibuf_get_n16(in, &short_as) == -1)
570 				goto fail;
571 			if (ibuf_add_n32(out, short_as) == -1)
572 				goto fail;
573 		}
574 	}
575 
576 	return (out);
577 
578 fail:
579 	ibuf_free(out);
580 	return (NULL);
581 }
582 
583 static const u_char	addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
584 			    0xf8, 0xfc, 0xfe, 0xff };
585 
586 /* NLRI functions to extract prefixes from the NLRI blobs */
587 int
588 extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max)
589 {
590 	u_char		*a = va;
591 	int		 plen;
592 
593 	plen = PREFIX_SIZE(pfxlen) - 1;
594 	if (len < plen || max < plen)
595 		return -1;
596 
597 	while (pfxlen > 0) {
598 		if (pfxlen < 8) {
599 			*a++ = *p++ & addrmask[pfxlen];
600 			break;
601 		} else {
602 			*a++ = *p++;
603 			pfxlen -= 8;
604 		}
605 	}
606 	return (plen);
607 }
608 
609 static int
610 extract_prefix_buf(struct ibuf *buf, void *va, uint8_t pfxlen, uint8_t max)
611 {
612 	u_char		*a = va;
613 	unsigned int	 plen;
614 	uint8_t		 tmp;
615 
616 	plen = PREFIX_SIZE(pfxlen) - 1;
617 	if (ibuf_size(buf) < plen || max < plen)
618 		return -1;
619 
620 	while (pfxlen > 0) {
621 		if (ibuf_get_n8(buf, &tmp) == -1)
622 			return -1;
623 
624 		if (pfxlen < 8) {
625 			*a++ = tmp & addrmask[pfxlen];
626 			break;
627 		} else {
628 			*a++ = tmp;
629 			pfxlen -= 8;
630 		}
631 	}
632 	return (0);
633 }
634 
635 int
636 nlri_get_prefix(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
637 {
638 	uint8_t	 pfxlen;
639 
640 	if (ibuf_get_n8(buf, &pfxlen) == -1)
641 		return (-1);
642 	if (pfxlen > 32)
643 		return (-1);
644 
645 	memset(prefix, 0, sizeof(struct bgpd_addr));
646 	prefix->aid = AID_INET;
647 
648 	if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
649 	    sizeof(prefix->v4)) == -1)
650 		return (-1);
651 
652 	*prefixlen = pfxlen;
653 	return (0);
654 }
655 
656 int
657 nlri_get_prefix6(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
658 {
659 	uint8_t	pfxlen;
660 
661 	if (ibuf_get_n8(buf, &pfxlen) == -1)
662 		return (-1);
663 	if (pfxlen > 128)
664 		return (-1);
665 
666 	memset(prefix, 0, sizeof(struct bgpd_addr));
667 	prefix->aid = AID_INET6;
668 
669 	if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
670 	    sizeof(prefix->v6)) == -1)
671 		return (-1);
672 
673 	*prefixlen = pfxlen;
674 	return (0);
675 }
676 
677 int
678 nlri_get_vpn4(struct ibuf *buf, struct bgpd_addr *prefix,
679     uint8_t *prefixlen, int withdraw)
680 {
681 	int		 done = 0;
682 	uint8_t		 pfxlen;
683 
684 	if (ibuf_get_n8(buf, &pfxlen) == -1)
685 		return (-1);
686 
687 	memset(prefix, 0, sizeof(struct bgpd_addr));
688 	prefix->aid = AID_VPN_IPv4;
689 
690 	/* label stack */
691 	do {
692 		if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
693 		    pfxlen < 3 * 8)
694 			return (-1);
695 		if (withdraw) {
696 			/* on withdraw ignore the labelstack all together */
697 			if (ibuf_skip(buf, 3) == -1)
698 				return (-1);
699 			pfxlen -= 3 * 8;
700 			break;
701 		}
702 		if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
703 		    -1)
704 			return -1;
705 		if (prefix->labelstack[prefix->labellen + 2] &
706 		    BGP_MPLS_BOS)
707 			done = 1;
708 		prefix->labellen += 3;
709 		pfxlen -= 3 * 8;
710 	} while (!done);
711 
712 	/* RD */
713 	if (pfxlen < sizeof(uint64_t) * 8 ||
714 	    ibuf_get_h64(buf, &prefix->rd) == -1)
715 		return (-1);
716 	pfxlen -= sizeof(uint64_t) * 8;
717 
718 	/* prefix */
719 	if (pfxlen > 32)
720 		return (-1);
721 	if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
722 	    sizeof(prefix->v4)) == -1)
723 		return (-1);
724 
725 	*prefixlen = pfxlen;
726 	return (0);
727 }
728 
729 int
730 nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix,
731     uint8_t *prefixlen, int withdraw)
732 {
733 	int		done = 0;
734 	uint8_t		pfxlen;
735 
736 	if (ibuf_get_n8(buf, &pfxlen) == -1)
737 		return (-1);
738 
739 	memset(prefix, 0, sizeof(struct bgpd_addr));
740 	prefix->aid = AID_VPN_IPv6;
741 
742 	/* label stack */
743 	do {
744 		if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
745 		    pfxlen < 3 * 8)
746 			return (-1);
747 		if (withdraw) {
748 			/* on withdraw ignore the labelstack all together */
749 			if (ibuf_skip(buf, 3) == -1)
750 				return (-1);
751 			pfxlen -= 3 * 8;
752 			break;
753 		}
754 
755 		if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
756 		    -1)
757 			return (-1);
758 		if (prefix->labelstack[prefix->labellen + 2] &
759 		    BGP_MPLS_BOS)
760 			done = 1;
761 		prefix->labellen += 3;
762 		pfxlen -= 3 * 8;
763 	} while (!done);
764 
765 	/* RD */
766 	if (pfxlen < sizeof(uint64_t) * 8 ||
767 	    ibuf_get_h64(buf, &prefix->rd) == -1)
768 		return (-1);
769 	pfxlen -= sizeof(uint64_t) * 8;
770 
771 	/* prefix */
772 	if (pfxlen > 128)
773 		return (-1);
774 	if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
775 	    sizeof(prefix->v6)) == -1)
776 		return (-1);
777 
778 	*prefixlen = pfxlen;
779 	return (0);
780 }
781 
782 static in_addr_t
783 prefixlen2mask(uint8_t prefixlen)
784 {
785 	if (prefixlen == 0)
786 		return (0);
787 
788 	return (0xffffffff << (32 - prefixlen));
789 }
790 
791 /*
792  * This function will have undefined behaviour if the passed in prefixlen is
793  * too large for the respective bgpd_addr address family.
794  */
795 int
796 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
797     int prefixlen)
798 {
799 	in_addr_t	mask, aa, ba;
800 	int		i;
801 	uint8_t		m;
802 
803 	if (a->aid != b->aid)
804 		return (a->aid - b->aid);
805 
806 	switch (a->aid) {
807 	case AID_VPN_IPv4:
808 		if (be64toh(a->rd) > be64toh(b->rd))
809 			return (1);
810 		if (be64toh(a->rd) < be64toh(b->rd))
811 			return (-1);
812 		/* FALLTHROUGH */
813 	case AID_INET:
814 		if (prefixlen == 0)
815 			return (0);
816 		if (prefixlen > 32)
817 			return (-1);
818 		mask = htonl(prefixlen2mask(prefixlen));
819 		aa = ntohl(a->v4.s_addr & mask);
820 		ba = ntohl(b->v4.s_addr & mask);
821 		if (aa > ba)
822 			return (1);
823 		if (aa < ba)
824 			return (-1);
825 		break;
826 	case AID_VPN_IPv6:
827 		if (be64toh(a->rd) > be64toh(b->rd))
828 			return (1);
829 		if (be64toh(a->rd) < be64toh(b->rd))
830 			return (-1);
831 		/* FALLTHROUGH */
832 	case AID_INET6:
833 		if (prefixlen == 0)
834 			return (0);
835 		if (prefixlen > 128)
836 			return (-1);
837 		for (i = 0; i < prefixlen / 8; i++)
838 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
839 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
840 		i = prefixlen % 8;
841 		if (i) {
842 			m = 0xff00 >> i;
843 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
844 			    (b->v6.s6_addr[prefixlen / 8] & m))
845 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
846 				    (b->v6.s6_addr[prefixlen / 8] & m));
847 		}
848 		break;
849 	default:
850 		return (-1);
851 	}
852 
853 	if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) {
854 		if (a->labellen > b->labellen)
855 			return (1);
856 		if (a->labellen < b->labellen)
857 			return (-1);
858 		return (memcmp(a->labelstack, b->labelstack, a->labellen));
859 	}
860 	return (0);
861 
862 }
863 
864 void
865 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
866 {
867 	struct in_addr mask;
868 
869 	mask.s_addr = htonl(prefixlen2mask(prefixlen));
870 	dest->s_addr = src->s_addr & mask.s_addr;
871 }
872 
873 void
874 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
875 {
876 	struct in6_addr	mask;
877 	int		i;
878 
879 	memset(&mask, 0, sizeof(mask));
880 	for (i = 0; i < prefixlen / 8; i++)
881 		mask.s6_addr[i] = 0xff;
882 	i = prefixlen % 8;
883 	if (i)
884 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
885 
886 	for (i = 0; i < 16; i++)
887 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
888 }
889 
890 void
891 applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen)
892 {
893 	*dest = *src;
894 	switch (src->aid) {
895 	case AID_INET:
896 	case AID_VPN_IPv4:
897 		inet4applymask(&dest->v4, &src->v4, prefixlen);
898 		break;
899 	case AID_INET6:
900 	case AID_VPN_IPv6:
901 		inet6applymask(&dest->v6, &src->v6, prefixlen);
902 		break;
903 	}
904 }
905 
906 /* address family translation functions */
907 const struct aid aid_vals[AID_MAX] = AID_VALS;
908 
909 const char *
910 aid2str(uint8_t aid)
911 {
912 	if (aid < AID_MAX)
913 		return (aid_vals[aid].name);
914 	return ("unknown AID");
915 }
916 
917 int
918 aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
919 {
920 	if (aid < AID_MAX) {
921 		*afi = aid_vals[aid].afi;
922 		*safi = aid_vals[aid].safi;
923 		return (0);
924 	}
925 	return (-1);
926 }
927 
928 int
929 afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
930 {
931 	uint8_t i;
932 
933 	for (i = 0; i < AID_MAX; i++)
934 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
935 			*aid = i;
936 			return (0);
937 		}
938 
939 	return (-1);
940 }
941 
942 sa_family_t
943 aid2af(uint8_t aid)
944 {
945 	if (aid < AID_MAX)
946 		return (aid_vals[aid].af);
947 	return (AF_UNSPEC);
948 }
949 
950 int
951 af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
952 {
953 	uint8_t i;
954 
955 	if (safi == 0) /* default to unicast subclass */
956 		safi = SAFI_UNICAST;
957 
958 	for (i = 0; i < AID_MAX; i++)
959 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
960 			*aid = i;
961 			return (0);
962 		}
963 
964 	return (-1);
965 }
966 
967 /*
968  * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
969  * the included label stack is ignored and needs to be handled by the caller.
970  */
971 struct sockaddr *
972 addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
973 {
974 	static struct sockaddr_storage	 ss;
975 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
976 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
977 
978 	if (addr == NULL || addr->aid == AID_UNSPEC)
979 		return (NULL);
980 
981 	memset(&ss, 0, sizeof(ss));
982 	switch (addr->aid) {
983 	case AID_INET:
984 	case AID_VPN_IPv4:
985 		sa_in->sin_family = AF_INET;
986 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
987 		sa_in->sin_port = htons(port);
988 		*len = sizeof(struct sockaddr_in);
989 		break;
990 	case AID_INET6:
991 	case AID_VPN_IPv6:
992 		sa_in6->sin6_family = AF_INET6;
993 		memcpy(&sa_in6->sin6_addr, &addr->v6,
994 		    sizeof(sa_in6->sin6_addr));
995 		sa_in6->sin6_port = htons(port);
996 		sa_in6->sin6_scope_id = addr->scope_id;
997 		*len = sizeof(struct sockaddr_in6);
998 		break;
999 	case AID_FLOWSPECv4:
1000 	case AID_FLOWSPECv6:
1001 		return (NULL);
1002 	}
1003 
1004 	return ((struct sockaddr *)&ss);
1005 }
1006 
1007 void
1008 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
1009 {
1010 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
1011 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
1012 
1013 	memset(addr, 0, sizeof(*addr));
1014 	switch (sa->sa_family) {
1015 	case AF_INET:
1016 		addr->aid = AID_INET;
1017 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
1018 		if (port)
1019 			*port = ntohs(sa_in->sin_port);
1020 		break;
1021 	case AF_INET6:
1022 		addr->aid = AID_INET6;
1023 #ifdef __KAME__
1024 		/*
1025 		 * XXX thanks, KAME, for this ugliness...
1026 		 * adopted from route/show.c
1027 		 */
1028 		if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
1029 		    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) ||
1030 		    IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) &&
1031 		    sa_in6->sin6_scope_id == 0) {
1032 			uint16_t tmp16;
1033 			memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
1034 			    sizeof(tmp16));
1035 			sa_in6->sin6_scope_id = ntohs(tmp16);
1036 			sa_in6->sin6_addr.s6_addr[2] = 0;
1037 			sa_in6->sin6_addr.s6_addr[3] = 0;
1038 		}
1039 #endif
1040 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
1041 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
1042 		if (port)
1043 			*port = ntohs(sa_in6->sin6_port);
1044 		break;
1045 	}
1046 }
1047 
1048 const char *
1049 get_baudrate(unsigned long long baudrate, char *unit)
1050 {
1051 	static char bbuf[16];
1052 	const unsigned long long kilo = 1000;
1053 	const unsigned long long mega = 1000ULL * kilo;
1054 	const unsigned long long giga = 1000ULL * mega;
1055 
1056 	if (baudrate > giga)
1057 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
1058 		    baudrate / giga, unit);
1059 	else if (baudrate > mega)
1060 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
1061 		    baudrate / mega, unit);
1062 	else if (baudrate > kilo)
1063 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
1064 		    baudrate / kilo, unit);
1065 	else
1066 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
1067 		    baudrate, unit);
1068 
1069 	return (bbuf);
1070 }
1071