xref: /openbsd-src/usr.sbin/bgpd/util.c (revision ff0e7be1ebbcc809ea8ad2b6dafe215824da9e46)
1 /*	$OpenBSD: util.c,v 1.77 2023/04/17 08:02:21 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(enum role role)
202 {
203 	switch (role) {
204 	case ROLE_PROVIDER:
205 		return "provider";
206 	case ROLE_RS:
207 		return "rs";
208 	case ROLE_RS_CLIENT:
209 		return "rs-client";
210 	case ROLE_CUSTOMER:
211 		return "customer";
212 	case 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 int
498 extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max)
499 {
500 	static u_char	 addrmask[] = {
501 	    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
502 	u_char		*a = va;
503 	int		 plen;
504 
505 	plen = PREFIX_SIZE(pfxlen) - 1;
506 	if (len < plen || max < plen)
507 		return -1;
508 
509 	while (pfxlen > 0) {
510 		if (pfxlen < 8) {
511 			*a++ = *p++ & addrmask[pfxlen];
512 			break;
513 		} else {
514 			*a++ = *p++;
515 			pfxlen -= 8;
516 		}
517 	}
518 	return (plen);
519 }
520 
521 int
522 nlri_get_prefix(u_char *p, uint16_t len, struct bgpd_addr *prefix,
523     uint8_t *prefixlen)
524 {
525 	int	 plen;
526 	uint8_t	 pfxlen;
527 
528 	if (len < 1)
529 		return (-1);
530 
531 	pfxlen = *p++;
532 	len--;
533 
534 	memset(prefix, 0, sizeof(struct bgpd_addr));
535 	prefix->aid = AID_INET;
536 	*prefixlen = pfxlen;
537 
538 	if (pfxlen > 32)
539 		return (-1);
540 	if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen,
541 	    sizeof(prefix->v4))) == -1)
542 		return (-1);
543 
544 	return (plen + 1);	/* pfxlen needs to be added */
545 }
546 
547 int
548 nlri_get_prefix6(u_char *p, uint16_t len, struct bgpd_addr *prefix,
549     uint8_t *prefixlen)
550 {
551 	int	plen;
552 	uint8_t	pfxlen;
553 
554 	if (len < 1)
555 		return (-1);
556 
557 	pfxlen = *p++;
558 	len--;
559 
560 	memset(prefix, 0, sizeof(struct bgpd_addr));
561 	prefix->aid = AID_INET6;
562 	*prefixlen = pfxlen;
563 
564 	if (pfxlen > 128)
565 		return (-1);
566 	if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen,
567 	    sizeof(prefix->v6))) == -1)
568 		return (-1);
569 
570 	return (plen + 1);	/* pfxlen needs to be added */
571 }
572 
573 int
574 nlri_get_vpn4(u_char *p, uint16_t len, struct bgpd_addr *prefix,
575     uint8_t *prefixlen, int withdraw)
576 {
577 	int		 rv, done = 0;
578 	uint16_t	 plen;
579 	uint8_t		 pfxlen;
580 
581 	if (len < 1)
582 		return (-1);
583 
584 	memcpy(&pfxlen, p, 1);
585 	p += 1;
586 	plen = 1;
587 
588 	memset(prefix, 0, sizeof(struct bgpd_addr));
589 
590 	/* label stack */
591 	do {
592 		if (len - plen < 3 || pfxlen < 3 * 8)
593 			return (-1);
594 		if (prefix->labellen + 3U >
595 		    sizeof(prefix->labelstack))
596 			return (-1);
597 		if (withdraw) {
598 			/* on withdraw ignore the labelstack all together */
599 			p += 3;
600 			plen += 3;
601 			pfxlen -= 3 * 8;
602 			break;
603 		}
604 		prefix->labelstack[prefix->labellen++] = *p++;
605 		prefix->labelstack[prefix->labellen++] = *p++;
606 		prefix->labelstack[prefix->labellen] = *p++;
607 		if (prefix->labelstack[prefix->labellen] &
608 		    BGP_MPLS_BOS)
609 			done = 1;
610 		prefix->labellen++;
611 		plen += 3;
612 		pfxlen -= 3 * 8;
613 	} while (!done);
614 
615 	/* RD */
616 	if (len - plen < (int)sizeof(uint64_t) ||
617 	    pfxlen < sizeof(uint64_t) * 8)
618 		return (-1);
619 	memcpy(&prefix->rd, p, sizeof(uint64_t));
620 	pfxlen -= sizeof(uint64_t) * 8;
621 	p += sizeof(uint64_t);
622 	plen += sizeof(uint64_t);
623 
624 	/* prefix */
625 	prefix->aid = AID_VPN_IPv4;
626 	*prefixlen = pfxlen;
627 
628 	if (pfxlen > 32)
629 		return (-1);
630 	if ((rv = extract_prefix(p, len, &prefix->v4,
631 	    pfxlen, sizeof(prefix->v4))) == -1)
632 		return (-1);
633 
634 	return (plen + rv);
635 }
636 
637 int
638 nlri_get_vpn6(u_char *p, uint16_t len, struct bgpd_addr *prefix,
639     uint8_t *prefixlen, int withdraw)
640 {
641 	int		rv, done = 0;
642 	uint16_t	plen;
643 	uint8_t		pfxlen;
644 
645 	if (len < 1)
646 		return (-1);
647 
648 	memcpy(&pfxlen, p, 1);
649 	p += 1;
650 	plen = 1;
651 
652 	memset(prefix, 0, sizeof(struct bgpd_addr));
653 
654 	/* label stack */
655 	do {
656 		if (len - plen < 3 || pfxlen < 3 * 8)
657 			return (-1);
658 		if (prefix->labellen + 3U >
659 		    sizeof(prefix->labelstack))
660 			return (-1);
661 		if (withdraw) {
662 			/* on withdraw ignore the labelstack all together */
663 			p += 3;
664 			plen += 3;
665 			pfxlen -= 3 * 8;
666 			break;
667 		}
668 
669 		prefix->labelstack[prefix->labellen++] = *p++;
670 		prefix->labelstack[prefix->labellen++] = *p++;
671 		prefix->labelstack[prefix->labellen] = *p++;
672 		if (prefix->labelstack[prefix->labellen] &
673 		    BGP_MPLS_BOS)
674 			done = 1;
675 		prefix->labellen++;
676 		plen += 3;
677 		pfxlen -= 3 * 8;
678 	} while (!done);
679 
680 	/* RD */
681 	if (len - plen < (int)sizeof(uint64_t) ||
682 	    pfxlen < sizeof(uint64_t) * 8)
683 		return (-1);
684 
685 	memcpy(&prefix->rd, p, sizeof(uint64_t));
686 	pfxlen -= sizeof(uint64_t) * 8;
687 	p += sizeof(uint64_t);
688 	plen += sizeof(uint64_t);
689 
690 	/* prefix */
691 	prefix->aid = AID_VPN_IPv6;
692 	*prefixlen = pfxlen;
693 
694 	if (pfxlen > 128)
695 		return (-1);
696 
697 	if ((rv = extract_prefix(p, len, &prefix->v6,
698 	    pfxlen, sizeof(prefix->v6))) == -1)
699 		return (-1);
700 
701 	return (plen + rv);
702 }
703 
704 static in_addr_t
705 prefixlen2mask(uint8_t prefixlen)
706 {
707 	if (prefixlen == 0)
708 		return (0);
709 
710 	return (0xffffffff << (32 - prefixlen));
711 }
712 
713 /*
714  * This function will have undefined behaviour if the passed in prefixlen is
715  * too large for the respective bgpd_addr address family.
716  */
717 int
718 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
719     int prefixlen)
720 {
721 	in_addr_t	mask, aa, ba;
722 	int		i;
723 	uint8_t		m;
724 
725 	if (a->aid != b->aid)
726 		return (a->aid - b->aid);
727 
728 	switch (a->aid) {
729 	case AID_VPN_IPv4:
730 		if (be64toh(a->rd) > be64toh(b->rd))
731 			return (1);
732 		if (be64toh(a->rd) < be64toh(b->rd))
733 			return (-1);
734 		/* FALLTHROUGH */
735 	case AID_INET:
736 		if (prefixlen == 0)
737 			return (0);
738 		if (prefixlen > 32)
739 			return (-1);
740 		mask = htonl(prefixlen2mask(prefixlen));
741 		aa = ntohl(a->v4.s_addr & mask);
742 		ba = ntohl(b->v4.s_addr & mask);
743 		if (aa > ba)
744 			return (1);
745 		if (aa < ba)
746 			return (-1);
747 		break;
748 	case AID_VPN_IPv6:
749 		if (be64toh(a->rd) > be64toh(b->rd))
750 			return (1);
751 		if (be64toh(a->rd) < be64toh(b->rd))
752 			return (-1);
753 		/* FALLTHROUGH */
754 	case AID_INET6:
755 		if (prefixlen == 0)
756 			return (0);
757 		if (prefixlen > 128)
758 			return (-1);
759 		for (i = 0; i < prefixlen / 8; i++)
760 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
761 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
762 		i = prefixlen % 8;
763 		if (i) {
764 			m = 0xff00 >> i;
765 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
766 			    (b->v6.s6_addr[prefixlen / 8] & m))
767 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
768 				    (b->v6.s6_addr[prefixlen / 8] & m));
769 		}
770 		break;
771 	default:
772 		return (-1);
773 	}
774 
775 	if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) {
776 		if (a->labellen > b->labellen)
777 			return (1);
778 		if (a->labellen < b->labellen)
779 			return (-1);
780 		return (memcmp(a->labelstack, b->labelstack, a->labellen));
781 	}
782 	return (0);
783 
784 }
785 
786 void
787 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
788 {
789 	struct in_addr mask;
790 
791 	mask.s_addr = htonl(prefixlen2mask(prefixlen));
792 	dest->s_addr = src->s_addr & mask.s_addr;
793 }
794 
795 void
796 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
797 {
798 	struct in6_addr	mask;
799 	int		i;
800 
801 	memset(&mask, 0, sizeof(mask));
802 	for (i = 0; i < prefixlen / 8; i++)
803 		mask.s6_addr[i] = 0xff;
804 	i = prefixlen % 8;
805 	if (i)
806 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
807 
808 	for (i = 0; i < 16; i++)
809 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
810 }
811 
812 void
813 applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen)
814 {
815 	*dest = *src;
816 	switch (src->aid) {
817 	case AID_INET:
818 	case AID_VPN_IPv4:
819 		inet4applymask(&dest->v4, &src->v4, prefixlen);
820 		break;
821 	case AID_INET6:
822 	case AID_VPN_IPv6:
823 		inet6applymask(&dest->v6, &src->v6, prefixlen);
824 		break;
825 	}
826 }
827 
828 /* address family translation functions */
829 const struct aid aid_vals[AID_MAX] = AID_VALS;
830 
831 const char *
832 aid2str(uint8_t aid)
833 {
834 	if (aid < AID_MAX)
835 		return (aid_vals[aid].name);
836 	return ("unknown AID");
837 }
838 
839 int
840 aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
841 {
842 	if (aid < AID_MAX) {
843 		*afi = aid_vals[aid].afi;
844 		*safi = aid_vals[aid].safi;
845 		return (0);
846 	}
847 	return (-1);
848 }
849 
850 int
851 afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
852 {
853 	uint8_t i;
854 
855 	for (i = 0; i < AID_MAX; i++)
856 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
857 			*aid = i;
858 			return (0);
859 		}
860 
861 	return (-1);
862 }
863 
864 sa_family_t
865 aid2af(uint8_t aid)
866 {
867 	if (aid < AID_MAX)
868 		return (aid_vals[aid].af);
869 	return (AF_UNSPEC);
870 }
871 
872 int
873 af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
874 {
875 	uint8_t i;
876 
877 	if (safi == 0) /* default to unicast subclass */
878 		safi = SAFI_UNICAST;
879 
880 	for (i = 0; i < AID_MAX; i++)
881 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
882 			*aid = i;
883 			return (0);
884 		}
885 
886 	return (-1);
887 }
888 
889 /*
890  * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
891  * the included label stack is ignored and needs to be handled by the caller.
892  */
893 struct sockaddr *
894 addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
895 {
896 	static struct sockaddr_storage	 ss;
897 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
898 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
899 
900 	if (addr == NULL || addr->aid == AID_UNSPEC)
901 		return (NULL);
902 
903 	memset(&ss, 0, sizeof(ss));
904 	switch (addr->aid) {
905 	case AID_INET:
906 	case AID_VPN_IPv4:
907 		sa_in->sin_family = AF_INET;
908 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
909 		sa_in->sin_port = htons(port);
910 		*len = sizeof(struct sockaddr_in);
911 		break;
912 	case AID_INET6:
913 	case AID_VPN_IPv6:
914 		sa_in6->sin6_family = AF_INET6;
915 		memcpy(&sa_in6->sin6_addr, &addr->v6,
916 		    sizeof(sa_in6->sin6_addr));
917 		sa_in6->sin6_port = htons(port);
918 		sa_in6->sin6_scope_id = addr->scope_id;
919 		*len = sizeof(struct sockaddr_in6);
920 		break;
921 	case AID_FLOWSPECv4:
922 	case AID_FLOWSPECv6:
923 		return (NULL);
924 	}
925 
926 	return ((struct sockaddr *)&ss);
927 }
928 
929 void
930 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
931 {
932 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
933 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
934 
935 	memset(addr, 0, sizeof(*addr));
936 	switch (sa->sa_family) {
937 	case AF_INET:
938 		addr->aid = AID_INET;
939 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
940 		if (port)
941 			*port = ntohs(sa_in->sin_port);
942 		break;
943 	case AF_INET6:
944 		addr->aid = AID_INET6;
945 #ifdef __KAME__
946 		/*
947 		 * XXX thanks, KAME, for this ugliness...
948 		 * adopted from route/show.c
949 		 */
950 		if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
951 		    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) ||
952 		    IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) &&
953 		    sa_in6->sin6_scope_id == 0) {
954 			uint16_t tmp16;
955 			memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
956 			    sizeof(tmp16));
957 			sa_in6->sin6_scope_id = ntohs(tmp16);
958 			sa_in6->sin6_addr.s6_addr[2] = 0;
959 			sa_in6->sin6_addr.s6_addr[3] = 0;
960 		}
961 #endif
962 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
963 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
964 		if (port)
965 			*port = ntohs(sa_in6->sin6_port);
966 		break;
967 	}
968 }
969 
970 const char *
971 get_baudrate(unsigned long long baudrate, char *unit)
972 {
973 	static char bbuf[16];
974 	const unsigned long long kilo = 1000;
975 	const unsigned long long mega = 1000ULL * kilo;
976 	const unsigned long long giga = 1000ULL * mega;
977 
978 	if (baudrate > giga)
979 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
980 		    baudrate / giga, unit);
981 	else if (baudrate > mega)
982 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
983 		    baudrate / mega, unit);
984 	else if (baudrate > kilo)
985 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
986 		    baudrate / kilo, unit);
987 	else
988 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
989 		    baudrate, unit);
990 
991 	return (bbuf);
992 }
993