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