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