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