xref: /openbsd/usr.sbin/bgpd/util.c (revision e5dd7070)
1 /*	$OpenBSD: util.c,v 1.54 2020/05/10 13:38:46 deraadt 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	*aspath_delim(u_int8_t, int);
36 
37 const char *
38 log_addr(const struct bgpd_addr *addr)
39 {
40 	static char	buf[74];
41 	char		tbuf[40];
42 
43 	switch (addr->aid) {
44 	case AID_INET:
45 	case AID_INET6:
46 		if (inet_ntop(aid2af(addr->aid), &addr->ba, buf,
47 		    sizeof(buf)) == NULL)
48 			return ("?");
49 		return (buf);
50 	case AID_VPN_IPv4:
51 		if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf,
52 		    sizeof(tbuf)) == NULL)
53 			return ("?");
54 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
55 		    tbuf);
56 		return (buf);
57 	case AID_VPN_IPv6:
58 		if (inet_ntop(aid2af(addr->aid), &addr->vpn6.addr, tbuf,
59 		    sizeof(tbuf)) == NULL)
60 			return ("?");
61 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn6.rd),
62 		    tbuf);
63 		return (buf);
64 	}
65 	return ("???");
66 }
67 
68 const char *
69 log_in6addr(const struct in6_addr *addr)
70 {
71 	struct sockaddr_in6	sa_in6;
72 	u_int16_t		tmp16;
73 
74 	bzero(&sa_in6, sizeof(sa_in6));
75 	sa_in6.sin6_family = AF_INET6;
76 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
77 
78 #ifdef __KAME__
79 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
80 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
81 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
82 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
83 		sa_in6.sin6_scope_id = ntohs(tmp16);
84 		sa_in6.sin6_addr.s6_addr[2] = 0;
85 		sa_in6.sin6_addr.s6_addr[3] = 0;
86 	}
87 #endif
88 
89 	return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
90 }
91 
92 const char *
93 log_sockaddr(struct sockaddr *sa, socklen_t len)
94 {
95 	static char	buf[NI_MAXHOST];
96 
97 	if (getnameinfo(sa, len, buf, sizeof(buf), NULL, 0,
98 	    NI_NUMERICHOST))
99 		return ("(unknown)");
100 	else
101 		return (buf);
102 }
103 
104 const char *
105 log_as(u_int32_t as)
106 {
107 	static char	buf[11];	/* "4294967294\0" */
108 
109 	if (snprintf(buf, sizeof(buf), "%u", as) < 0)
110 		return ("?");
111 
112 	return (buf);
113 }
114 
115 const char *
116 log_rd(u_int64_t rd)
117 {
118 	static char	buf[32];
119 	struct in_addr	addr;
120 	u_int32_t	u32;
121 	u_int16_t	u16;
122 
123 	rd = be64toh(rd);
124 	switch (rd >> 48) {
125 	case EXT_COMMUNITY_TRANS_TWO_AS:
126 		u32 = rd & 0xffffffff;
127 		u16 = (rd >> 32) & 0xffff;
128 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
129 		break;
130 	case EXT_COMMUNITY_TRANS_FOUR_AS:
131 		u32 = (rd >> 16) & 0xffffffff;
132 		u16 = rd & 0xffff;
133 		snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
134 		break;
135 	case EXT_COMMUNITY_TRANS_IPV4:
136 		u32 = (rd >> 16) & 0xffffffff;
137 		u16 = rd & 0xffff;
138 		addr.s_addr = htonl(u32);
139 		snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
140 		break;
141 	default:
142 		return ("rd ?");
143 	}
144 	return (buf);
145 }
146 
147 const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
148 
149 /* NOTE: this function does not check if the type/subtype combo is
150  * actually valid. */
151 const char *
152 log_ext_subtype(short type, u_int8_t subtype)
153 {
154 	static char etype[6];
155 	const struct ext_comm_pairs *cp;
156 
157 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
158 		if ((type == cp->type || type == -1) && subtype == cp->subtype)
159 			return (cp->subname);
160 	}
161 	snprintf(etype, sizeof(etype), "[%u]", subtype);
162 	return (etype);
163 }
164 
165 const char *
166 log_reason(const char *communication) {
167 	static char buf[(REASON_LEN - 1) * 4 + 1];
168 
169 	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
170 
171 	return buf;
172 }
173 
174 const char *
175 aspath_delim(u_int8_t seg_type, int closing)
176 {
177 	static char db[8];
178 
179 	switch (seg_type) {
180 	case AS_SET:
181 		if (!closing)
182 			return ("{ ");
183 		else
184 			return (" }");
185 	case AS_SEQUENCE:
186 		return ("");
187 	case AS_CONFED_SEQUENCE:
188 		if (!closing)
189 			return ("( ");
190 		else
191 			return (" )");
192 	case AS_CONFED_SET:
193 		if (!closing)
194 			return ("[ ");
195 		else
196 			return (" ]");
197 	default:
198 		if (!closing)
199 			snprintf(db, sizeof(db), "!%u ", seg_type);
200 		else
201 			snprintf(db, sizeof(db), " !%u", seg_type);
202 		return (db);
203 	}
204 }
205 
206 int
207 aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
208 {
209 #define UPDATE()				\
210 	do {					\
211 		if (r < 0)			\
212 			return (-1);		\
213 		total_size += r;		\
214 		if ((unsigned int)r < size) {	\
215 			size -= r;		\
216 			buf += r;		\
217 		} else {			\
218 			buf += size;		\
219 			size = 0;		\
220 		}				\
221 	} while (0)
222 	u_int8_t	*seg;
223 	int		 r, total_size;
224 	u_int16_t	 seg_size;
225 	u_int8_t	 i, seg_type, seg_len;
226 
227 	total_size = 0;
228 	seg = data;
229 	for (; len > 0; len -= seg_size, seg += seg_size) {
230 		seg_type = seg[0];
231 		seg_len = seg[1];
232 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
233 
234 		r = snprintf(buf, size, "%s%s",
235 		    total_size != 0 ? " " : "",
236 		    aspath_delim(seg_type, 0));
237 		UPDATE();
238 
239 		for (i = 0; i < seg_len; i++) {
240 			r = snprintf(buf, size, "%s",
241 			    log_as(aspath_extract(seg, i)));
242 			UPDATE();
243 			if (i + 1 < seg_len) {
244 				r = snprintf(buf, size, " ");
245 				UPDATE();
246 			}
247 		}
248 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
249 		UPDATE();
250 	}
251 	/* ensure that we have a valid C-string especially for empty as path */
252 	if (size > 0)
253 		*buf = '\0';
254 
255 	return (total_size);
256 #undef UPDATE
257 }
258 
259 int
260 aspath_asprint(char **ret, void *data, u_int16_t len)
261 {
262 	size_t	slen;
263 	int	plen;
264 
265 	slen = aspath_strlen(data, len) + 1;
266 	*ret = malloc(slen);
267 	if (*ret == NULL)
268 		return (-1);
269 
270 	plen = aspath_snprint(*ret, slen, data, len);
271 	if (plen == -1) {
272 		free(*ret);
273 		*ret = NULL;
274 		return (-1);
275 	}
276 
277 	return (0);
278 }
279 
280 size_t
281 aspath_strlen(void *data, u_int16_t len)
282 {
283 	u_int8_t	*seg;
284 	int		 total_size;
285 	u_int32_t	 as;
286 	u_int16_t	 seg_size;
287 	u_int8_t	 i, seg_type, seg_len;
288 
289 	total_size = 0;
290 	seg = data;
291 	for (; len > 0; len -= seg_size, seg += seg_size) {
292 		seg_type = seg[0];
293 		seg_len = seg[1];
294 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
295 
296 		if (seg_type == AS_SET)
297 			if (total_size != 0)
298 				total_size += 3;
299 			else
300 				total_size += 2;
301 		else if (total_size != 0)
302 			total_size += 1;
303 
304 		for (i = 0; i < seg_len; i++) {
305 			as = aspath_extract(seg, i);
306 
307 			do {
308 				total_size++;
309 			} while ((as = as / 10) != 0);
310 
311 			if (i + 1 < seg_len)
312 				total_size += 1;
313 		}
314 
315 		if (seg_type == AS_SET)
316 			total_size += 2;
317 	}
318 	return (total_size);
319 }
320 
321 /*
322  * Extract the asnum out of the as segment at the specified position.
323  * Direct access is not possible because of non-aligned reads.
324  * ATTENTION: no bounds checks are done.
325  */
326 u_int32_t
327 aspath_extract(const void *seg, int pos)
328 {
329 	const u_char	*ptr = seg;
330 	u_int32_t	 as;
331 
332 	ptr += 2 + sizeof(u_int32_t) * pos;
333 	memcpy(&as, ptr, sizeof(u_int32_t));
334 	return (ntohl(as));
335 }
336 
337 /*
338  * Verify that the aspath is correctly encoded.
339  */
340 int
341 aspath_verify(void *data, u_int16_t len, int as4byte)
342 {
343 	u_int8_t	*seg = data;
344 	u_int16_t	 seg_size, as_size = 2;
345 	u_int8_t	 seg_len, seg_type;
346 	int		 error = 0;
347 
348 	if (len & 1)
349 		/* odd length aspath are invalid */
350 		return (AS_ERR_BAD);
351 
352 	if (as4byte)
353 		as_size = 4;
354 
355 	for (; len > 0; len -= seg_size, seg += seg_size) {
356 		const u_int8_t	*ptr;
357 		int		 pos;
358 
359 		if (len < 2)	/* header length check */
360 			return (AS_ERR_BAD);
361 		seg_type = seg[0];
362 		seg_len = seg[1];
363 
364 		if (seg_len == 0)
365 			/* empty aspath segments are not allowed */
366 			return (AS_ERR_BAD);
367 
368 		/*
369 		 * BGP confederations should not show up but consider them
370 		 * as a soft error which invalidates the path but keeps the
371 		 * bgp session running.
372 		 */
373 		if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
374 			error = AS_ERR_SOFT;
375 		if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
376 		    seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET)
377 			return (AS_ERR_TYPE);
378 
379 		seg_size = 2 + as_size * seg_len;
380 
381 		if (seg_size > len)
382 			return (AS_ERR_LEN);
383 
384 		/* RFC 7607 - AS 0 is considered malformed */
385 		ptr = seg + 2;
386 		for (pos = 0; pos < seg_len; pos++) {
387 			u_int32_t as;
388 
389 			memcpy(&as, ptr, as_size);
390 			if (as == 0)
391 				error = AS_ERR_SOFT;
392 			ptr += as_size;
393 		}
394 	}
395 	return (error);	/* aspath is valid but probably not loop free */
396 }
397 
398 /*
399  * convert a 2 byte aspath to a 4 byte one.
400  */
401 u_char *
402 aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen)
403 {
404 	u_int8_t	*seg, *nseg, *ndata;
405 	u_int16_t	 seg_size, olen, nlen;
406 	u_int8_t	 seg_len;
407 
408 	/* first calculate the length of the aspath */
409 	seg = data;
410 	nlen = 0;
411 	for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
412 		seg_len = seg[1];
413 		seg_size = 2 + sizeof(u_int16_t) * seg_len;
414 		nlen += 2 + sizeof(u_int32_t) * seg_len;
415 
416 		if (seg_size > olen) {
417 			errno = ERANGE;
418 			return (NULL);
419 		}
420 	}
421 
422 	*newlen = nlen;
423 	if ((ndata = malloc(nlen)) == NULL)
424 		return (NULL);
425 
426 	/* then copy the aspath */
427 	seg = data;
428 	for (nseg = ndata; nseg < ndata + nlen; ) {
429 		*nseg++ = *seg++;
430 		*nseg++ = seg_len = *seg++;
431 		for (; seg_len > 0; seg_len--) {
432 			*nseg++ = 0;
433 			*nseg++ = 0;
434 			*nseg++ = *seg++;
435 			*nseg++ = *seg++;
436 		}
437 	}
438 
439 	return (ndata);
440 }
441 
442 /* NLRI functions to extract prefixes from the NLRI blobs */
443 static int
444 extract_prefix(u_char *p, u_int16_t len, void *va,
445     u_int8_t pfxlen, u_int8_t max)
446 {
447 	static u_char addrmask[] = {
448 	    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
449 	u_char		*a = va;
450 	int		 i;
451 	u_int16_t	 plen = 0;
452 
453 	for (i = 0; pfxlen && i < max; i++) {
454 		if (len <= plen)
455 			return (-1);
456 		if (pfxlen < 8) {
457 			a[i] = *p++ & addrmask[pfxlen];
458 			plen++;
459 			break;
460 		} else {
461 			a[i] = *p++;
462 			plen++;
463 			pfxlen -= 8;
464 		}
465 	}
466 	return (plen);
467 }
468 
469 int
470 nlri_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
471     u_int8_t *prefixlen)
472 {
473 	u_int8_t	 pfxlen;
474 	int		 plen;
475 
476 	if (len < 1)
477 		return (-1);
478 
479 	pfxlen = *p++;
480 	len--;
481 
482 	bzero(prefix, sizeof(struct bgpd_addr));
483 	prefix->aid = AID_INET;
484 	*prefixlen = pfxlen;
485 
486 	if (pfxlen > 32)
487 		return (-1);
488 	if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen,
489 	    sizeof(prefix->v4))) == -1)
490 		return (-1);
491 
492 	return (plen + 1);	/* pfxlen needs to be added */
493 }
494 
495 int
496 nlri_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
497     u_int8_t *prefixlen)
498 {
499 	int		plen;
500 	u_int8_t	pfxlen;
501 
502 	if (len < 1)
503 		return (-1);
504 
505 	pfxlen = *p++;
506 	len--;
507 
508 	bzero(prefix, sizeof(struct bgpd_addr));
509 	prefix->aid = AID_INET6;
510 	*prefixlen = pfxlen;
511 
512 	if (pfxlen > 128)
513 		return (-1);
514 	if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen,
515 	    sizeof(prefix->v6))) == -1)
516 		return (-1);
517 
518 	return (plen + 1);	/* pfxlen needs to be added */
519 }
520 
521 int
522 nlri_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
523     u_int8_t *prefixlen, int withdraw)
524 {
525 	int		 rv, done = 0;
526 	u_int8_t	 pfxlen;
527 	u_int16_t	 plen;
528 
529 	if (len < 1)
530 		return (-1);
531 
532 	memcpy(&pfxlen, p, 1);
533 	p += 1;
534 	plen = 1;
535 
536 	bzero(prefix, sizeof(struct bgpd_addr));
537 
538 	/* label stack */
539 	do {
540 		if (len - plen < 3 || pfxlen < 3 * 8)
541 			return (-1);
542 		if (prefix->vpn4.labellen + 3U >
543 		    sizeof(prefix->vpn4.labelstack))
544 			return (-1);
545 		if (withdraw) {
546 			/* on withdraw ignore the labelstack all together */
547 			plen += 3;
548 			pfxlen -= 3 * 8;
549 			break;
550 		}
551 		prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
552 		prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
553 		prefix->vpn4.labelstack[prefix->vpn4.labellen] = *p++;
554 		if (prefix->vpn4.labelstack[prefix->vpn4.labellen] &
555 		    BGP_MPLS_BOS)
556 			done = 1;
557 		prefix->vpn4.labellen++;
558 		plen += 3;
559 		pfxlen -= 3 * 8;
560 	} while (!done);
561 
562 	/* RD */
563 	if (len - plen < (int)sizeof(u_int64_t) ||
564 	    pfxlen < sizeof(u_int64_t) * 8)
565 		return (-1);
566 	memcpy(&prefix->vpn4.rd, p, sizeof(u_int64_t));
567 	pfxlen -= sizeof(u_int64_t) * 8;
568 	p += sizeof(u_int64_t);
569 	plen += sizeof(u_int64_t);
570 
571 	/* prefix */
572 	prefix->aid = AID_VPN_IPv4;
573 	*prefixlen = pfxlen;
574 
575 	if (pfxlen > 32)
576 		return (-1);
577 	if ((rv = extract_prefix(p, len, &prefix->vpn4.addr,
578 	    pfxlen, sizeof(prefix->vpn4.addr))) == -1)
579 		return (-1);
580 
581 	return (plen + rv);
582 }
583 
584 int
585 nlri_get_vpn6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
586     u_int8_t *prefixlen, int withdraw)
587 {
588 	int		rv, done = 0;
589 	u_int8_t	pfxlen;
590 	u_int16_t	plen;
591 
592 	if (len < 1)
593 		return (-1);
594 
595 	memcpy(&pfxlen, p, 1);
596 	p += 1;
597 	plen = 1;
598 
599 	memset(prefix, 0, sizeof(struct bgpd_addr));
600 
601 	/* label stack */
602 	do {
603 		if (len - plen < 3 || pfxlen < 3 * 8)
604 			return (-1);
605 		if (prefix->vpn6.labellen + 3U >
606 		    sizeof(prefix->vpn6.labelstack))
607 			return (-1);
608 		if (withdraw) {
609 			/* on withdraw ignore the labelstack all together */
610 			plen += 3;
611 			pfxlen -= 3 * 8;
612 			break;
613 		}
614 
615 		prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++;
616 		prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++;
617 		prefix->vpn6.labelstack[prefix->vpn6.labellen] = *p++;
618 		if (prefix->vpn6.labelstack[prefix->vpn6.labellen] &
619 		    BGP_MPLS_BOS)
620 			done = 1;
621 		prefix->vpn6.labellen++;
622 		plen += 3;
623 		pfxlen -= 3 * 8;
624 	} while (!done);
625 
626 	/* RD */
627 	if (len - plen < (int)sizeof(u_int64_t) ||
628 	    pfxlen < sizeof(u_int64_t) * 8)
629 		return (-1);
630 
631 	memcpy(&prefix->vpn6.rd, p, sizeof(u_int64_t));
632 	pfxlen -= sizeof(u_int64_t) * 8;
633 	p += sizeof(u_int64_t);
634 	plen += sizeof(u_int64_t);
635 
636 	/* prefix */
637 	prefix->aid = AID_VPN_IPv6;
638 	*prefixlen = pfxlen;
639 
640 	if (pfxlen > 128)
641 		return (-1);
642 
643 	if ((rv = extract_prefix(p, len, &prefix->vpn6.addr,
644 	    pfxlen, sizeof(prefix->vpn6.addr))) == -1)
645 		return (-1);
646 
647 	return (plen + rv);
648 }
649 
650 
651 
652 /*
653  * This function will have undefined behaviour if the passed in prefixlen is
654  * too large for the respective bgpd_addr address family.
655  */
656 int
657 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
658     int prefixlen)
659 {
660 	in_addr_t	mask, aa, ba;
661 	int		i;
662 	u_int8_t	m;
663 
664 	if (a->aid != b->aid)
665 		return (a->aid - b->aid);
666 
667 	switch (a->aid) {
668 	case AID_INET:
669 		if (prefixlen == 0)
670 			return (0);
671 		if (prefixlen > 32)
672 			return (-1);
673 		mask = htonl(prefixlen2mask(prefixlen));
674 		aa = ntohl(a->v4.s_addr & mask);
675 		ba = ntohl(b->v4.s_addr & mask);
676 		if (aa != ba)
677 			return (aa - ba);
678 		return (0);
679 	case AID_INET6:
680 		if (prefixlen == 0)
681 			return (0);
682 		if (prefixlen > 128)
683 			return (-1);
684 		for (i = 0; i < prefixlen / 8; i++)
685 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
686 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
687 		i = prefixlen % 8;
688 		if (i) {
689 			m = 0xff00 >> i;
690 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
691 			    (b->v6.s6_addr[prefixlen / 8] & m))
692 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
693 				    (b->v6.s6_addr[prefixlen / 8] & m));
694 		}
695 		return (0);
696 	case AID_VPN_IPv4:
697 		if (prefixlen > 32)
698 			return (-1);
699 		if (be64toh(a->vpn4.rd) > be64toh(b->vpn4.rd))
700 			return (1);
701 		if (be64toh(a->vpn4.rd) < be64toh(b->vpn4.rd))
702 			return (-1);
703 		mask = htonl(prefixlen2mask(prefixlen));
704 		aa = ntohl(a->vpn4.addr.s_addr & mask);
705 		ba = ntohl(b->vpn4.addr.s_addr & mask);
706 		if (aa != ba)
707 			return (aa - ba);
708 		if (a->vpn4.labellen > b->vpn4.labellen)
709 			return (1);
710 		if (a->vpn4.labellen < b->vpn4.labellen)
711 			return (-1);
712 		return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
713 		    a->vpn4.labellen));
714 	case AID_VPN_IPv6:
715 		if (prefixlen > 128)
716 			return (-1);
717 		if (be64toh(a->vpn6.rd) > be64toh(b->vpn6.rd))
718 			return (1);
719 		if (be64toh(a->vpn6.rd) < be64toh(b->vpn6.rd))
720 			return (-1);
721 		for (i = 0; i < prefixlen / 8; i++)
722 			if (a->vpn6.addr.s6_addr[i] != b->vpn6.addr.s6_addr[i])
723 				return (a->vpn6.addr.s6_addr[i] -
724 				    b->vpn6.addr.s6_addr[i]);
725 		i = prefixlen % 8;
726 		if (i) {
727 			m = 0xff00 >> i;
728 			if ((a->vpn6.addr.s6_addr[prefixlen / 8] & m) !=
729 			    (b->vpn6.addr.s6_addr[prefixlen / 8] & m))
730 				return ((a->vpn6.addr.s6_addr[prefixlen / 8] &
731 				    m) - (b->vpn6.addr.s6_addr[prefixlen / 8] &
732 				    m));
733 		}
734 		if (a->vpn6.labellen > b->vpn6.labellen)
735 			return (1);
736 		if (a->vpn6.labellen < b->vpn6.labellen)
737 			return (-1);
738 		return (memcmp(a->vpn6.labelstack, b->vpn6.labelstack,
739 		    a->vpn6.labellen));
740 	}
741 	return (-1);
742 }
743 
744 in_addr_t
745 prefixlen2mask(u_int8_t prefixlen)
746 {
747 	if (prefixlen == 0)
748 		return (0);
749 
750 	return (0xffffffff << (32 - prefixlen));
751 }
752 
753 void
754 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
755 {
756 	struct in_addr mask;
757 
758 	mask.s_addr = htonl(prefixlen2mask(prefixlen));
759 	dest->s_addr = src->s_addr & mask.s_addr;
760 }
761 
762 void
763 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
764 {
765 	struct in6_addr	mask;
766 	int		i;
767 
768 	bzero(&mask, sizeof(mask));
769 	for (i = 0; i < prefixlen / 8; i++)
770 		mask.s6_addr[i] = 0xff;
771 	i = prefixlen % 8;
772 	if (i)
773 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
774 
775 	for (i = 0; i < 16; i++)
776 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
777 }
778 
779 /* address family translation functions */
780 const struct aid aid_vals[AID_MAX] = AID_VALS;
781 
782 const char *
783 aid2str(u_int8_t aid)
784 {
785 	if (aid < AID_MAX)
786 		return (aid_vals[aid].name);
787 	return ("unknown AID");
788 }
789 
790 int
791 aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
792 {
793 	if (aid < AID_MAX) {
794 		*afi = aid_vals[aid].afi;
795 		*safi = aid_vals[aid].safi;
796 		return (0);
797 	}
798 	return (-1);
799 }
800 
801 int
802 afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
803 {
804 	u_int8_t i;
805 
806 	for (i = 0; i < AID_MAX; i++)
807 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
808 			*aid = i;
809 			return (0);
810 		}
811 
812 	return (-1);
813 }
814 
815 sa_family_t
816 aid2af(u_int8_t aid)
817 {
818 	if (aid < AID_MAX)
819 		return (aid_vals[aid].af);
820 	return (AF_UNSPEC);
821 }
822 
823 int
824 af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
825 {
826 	u_int8_t i;
827 
828 	if (safi == 0) /* default to unicast subclass */
829 		safi = SAFI_UNICAST;
830 
831 	for (i = 0; i < AID_MAX; i++)
832 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
833 			*aid = i;
834 			return (0);
835 		}
836 
837 	return (-1);
838 }
839 
840 struct sockaddr *
841 addr2sa(struct bgpd_addr *addr, u_int16_t port, socklen_t *len)
842 {
843 	static struct sockaddr_storage	 ss;
844 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
845 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
846 
847 	if (addr == NULL || addr->aid == AID_UNSPEC)
848 		return (NULL);
849 
850 	bzero(&ss, sizeof(ss));
851 	switch (addr->aid) {
852 	case AID_INET:
853 		sa_in->sin_family = AF_INET;
854 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
855 		sa_in->sin_port = htons(port);
856 		*len = sizeof(struct sockaddr_in);
857 		break;
858 	case AID_INET6:
859 		sa_in6->sin6_family = AF_INET6;
860 		memcpy(&sa_in6->sin6_addr, &addr->v6,
861 		    sizeof(sa_in6->sin6_addr));
862 		sa_in6->sin6_port = htons(port);
863 		sa_in6->sin6_scope_id = addr->scope_id;
864 		*len = sizeof(struct sockaddr_in6);
865 		break;
866 	}
867 
868 	return ((struct sockaddr *)&ss);
869 }
870 
871 void
872 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, u_int16_t *port)
873 {
874 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
875 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
876 
877 	bzero(addr, sizeof(*addr));
878 	switch (sa->sa_family) {
879 	case AF_INET:
880 		addr->aid = AID_INET;
881 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
882 		if (port)
883 			*port = ntohs(sa_in->sin_port);
884 		break;
885 	case AF_INET6:
886 		addr->aid = AID_INET6;
887 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
888 #ifdef __KAME__
889 		/*
890 		 * XXX thanks, KAME, for this ugliness...
891 		 * adopted from route/show.c
892 		 */
893 		if (IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
894 		    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr)) {
895 			uint16_t tmp16;
896 			memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
897 			    sizeof(tmp16));
898 			if (tmp16 != 0) {
899 				sa_in6->sin6_scope_id = ntohs(tmp16);
900 				sa_in6->sin6_addr.s6_addr[2] = 0;
901 				sa_in6->sin6_addr.s6_addr[3] = 0;
902 			}
903 		}
904 #endif
905 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
906 		if (port)
907 			*port = ntohs(sa_in6->sin6_port);
908 		break;
909 	}
910 }
911 
912 const char *
913 get_baudrate(unsigned long long baudrate, char *unit)
914 {
915 	static char bbuf[16];
916 	const unsigned long long kilo = 1000;
917 	const unsigned long long mega = 1000ULL * kilo;
918 	const unsigned long long giga = 1000ULL * mega;
919 
920 	if (baudrate > giga)
921 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
922 		    baudrate / giga, unit);
923 	else if (baudrate > mega)
924 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
925 		    baudrate / mega, unit);
926 	else if (baudrate > kilo)
927 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
928 		    baudrate / kilo, unit);
929 	else
930 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
931 		    baudrate, unit);
932 
933 	return (bbuf);
934 }
935