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