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