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