xref: /openbsd/usr.sbin/bgpd/util.c (revision beb044e9)
1 /*	$OpenBSD: util.c,v 1.84 2024/03/22 07:19:28 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 *
36 log_addr(const struct bgpd_addr *addr)
37 {
38 	static char	buf[74];
39 	struct sockaddr *sa;
40 	socklen_t	len;
41 
42 	sa = addr2sa(addr, 0, &len);
43 	switch (addr->aid) {
44 	case AID_INET:
45 	case AID_INET6:
46 		return log_sockaddr(sa, len);
47 	case AID_VPN_IPv4:
48 	case AID_VPN_IPv6:
49 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd),
50 		    log_sockaddr(sa, len));
51 		return (buf);
52 	}
53 	return ("???");
54 }
55 
56 const char *
57 log_in6addr(const struct in6_addr *addr)
58 {
59 	struct sockaddr_in6	sa_in6;
60 
61 	memset(&sa_in6, 0, sizeof(sa_in6));
62 	sa_in6.sin6_family = AF_INET6;
63 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
64 
65 #ifdef __KAME__
66 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
67 	if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
68 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) ||
69 	    IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) &&
70 	    sa_in6.sin6_scope_id == 0) {
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 		snprintf(buf, sizeof(buf), "rd #%016llx",
133 		    (unsigned long long)rd);
134 		break;
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 static const char *
167 log_expires(time_t expires)
168 {
169 	static char buf[32];
170 
171 	buf[0] = '\0';
172 	if (expires != 0)
173 		snprintf(buf, sizeof(buf), " expires %lld", (long long)expires);
174 	return buf;
175 }
176 
177 const char *
178 log_roa(struct roa *roa)
179 {
180 	static char buf[256];
181 	char maxbuf[32];
182 #if defined(__GNUC__) && __GNUC__ < 4
183 	struct bgpd_addr addr = { .aid = roa->aid };
184 	addr.v6 = roa->prefix.inet6;
185 #else
186 	struct bgpd_addr addr = { .aid = roa->aid, .v6 = roa->prefix.inet6 };
187 #endif
188 
189 	maxbuf[0] = '\0';
190 	if (roa->prefixlen != roa->maxlen)
191 		snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen);
192 	snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr),
193 	    roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires));
194 	return buf;
195 }
196 
197 const char *
198 log_aspa(struct aspa_set *aspa)
199 {
200 	static char errbuf[256];
201 	static char *buf;
202 	static size_t len;
203 	char asbuf[16];
204 	size_t needed;
205 	uint32_t i;
206 
207 	/* include enough space for header and trailer */
208 	if ((uint64_t)aspa->num > (SIZE_MAX / sizeof(asbuf) - 72))
209 		goto fail;
210 	needed = aspa->num * sizeof(asbuf) + 72;
211 	if (needed > len) {
212 		char *nbuf;
213 
214 		if ((nbuf = realloc(buf, needed)) == NULL)
215 			goto fail;
216 		len = needed;
217 		buf = nbuf;
218 	}
219 
220 	snprintf(buf, len, "customer-as %s%s provider-as { ",
221 	    log_as(aspa->as), log_expires(aspa->expires));
222 
223 	for (i = 0; i < aspa->num; i++) {
224 		snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i]));
225 		if (strlcat(buf, asbuf, len) >= len)
226 			goto fail;
227 	}
228 	if (strlcat(buf, "}", len) >= len)
229 		goto fail;
230 	return buf;
231 
232  fail:
233 	free(buf);
234 	buf = NULL;
235 	len = 0;
236 	snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }",
237 	    log_as(aspa->as), log_expires(aspa->expires));
238 	return errbuf;
239 }
240 
241 const char *
242 log_aspath_error(int error)
243 {
244 	static char buf[20];
245 
246 	switch (error) {
247 	case AS_ERR_LEN:
248 		return "inconsitent lenght";
249 	case AS_ERR_TYPE:
250 		return "unknown segment type";
251 	case AS_ERR_BAD:
252 		return "invalid encoding";
253 	case AS_ERR_SOFT:
254 		return "soft failure";
255 	default:
256 		snprintf(buf, sizeof(buf), "unknown %d", error);
257 		return buf;
258 	}
259 }
260 
261 const char *
262 log_rtr_error(enum rtr_error err)
263 {
264 	static char buf[20];
265 
266 	switch (err) {
267 	case NO_ERROR:
268 		return "No Error";
269 	case CORRUPT_DATA:
270 		return "Corrupt Data";
271 	case INTERNAL_ERROR:
272 		return "Internal Error";
273 	case NO_DATA_AVAILABLE:
274 		return "No Data Available";
275 	case INVALID_REQUEST:
276 		return "Invalid Request";
277 	case UNSUPP_PROTOCOL_VERS:
278 		return "Unsupported Protocol Version";
279 	case UNSUPP_PDU_TYPE:
280 		return "Unsupported PDU Type";
281 	case UNK_REC_WDRAWL:
282 		return "Withdrawal of Unknown Record";
283 	case DUP_REC_RECV:
284 		return "Duplicate Announcement Received";
285 	case UNEXP_PROTOCOL_VERS:
286 		return "Unexpected Protocol Version";
287 	default:
288 		snprintf(buf, sizeof(buf), "unknown %u", err);
289 		return buf;
290 	}
291 }
292 
293 const char *
294 log_policy(enum role role)
295 {
296 	switch (role) {
297 	case ROLE_PROVIDER:
298 		return "provider";
299 	case ROLE_RS:
300 		return "rs";
301 	case ROLE_RS_CLIENT:
302 		return "rs-client";
303 	case ROLE_CUSTOMER:
304 		return "customer";
305 	case ROLE_PEER:
306 		return "peer";
307 	default:
308 		return "unknown";
309 	}
310 }
311 
312 const char *
313 log_capability(uint8_t capa)
314 {
315 	static char buf[20];
316 
317 	switch (capa) {
318 	case CAPA_MP:
319 		return "Multiprotocol Extensions";
320 	case CAPA_REFRESH:
321 		return "Route Refresh";
322 	case CAPA_ROLE:
323 		return "BGP Role";
324 	case CAPA_RESTART:
325 		return "Graceful Restart";
326 	case CAPA_AS4BYTE:
327 		return "4-octet AS number";
328 	case CAPA_ADD_PATH:
329 		return "ADD-PATH";
330 	case CAPA_ENHANCED_RR:
331 		return "Enhanced Route Refresh";
332 	default:
333 		snprintf(buf, sizeof(buf), "unknown %u", capa);
334 		return buf;
335 	}
336 }
337 
338 static const char *
339 aspath_delim(uint8_t seg_type, int closing)
340 {
341 	static char db[8];
342 
343 	switch (seg_type) {
344 	case AS_SET:
345 		if (!closing)
346 			return ("{ ");
347 		else
348 			return (" }");
349 	case AS_SEQUENCE:
350 		return ("");
351 	case AS_CONFED_SEQUENCE:
352 		if (!closing)
353 			return ("( ");
354 		else
355 			return (" )");
356 	case AS_CONFED_SET:
357 		if (!closing)
358 			return ("[ ");
359 		else
360 			return (" ]");
361 	default:
362 		if (!closing)
363 			snprintf(db, sizeof(db), "!%u ", seg_type);
364 		else
365 			snprintf(db, sizeof(db), " !%u", seg_type);
366 		return (db);
367 	}
368 }
369 
370 static int
371 aspath_snprint(char *buf, size_t size, struct ibuf *in)
372 {
373 #define UPDATE()						\
374 	do {							\
375 		if (r < 0 || (unsigned int)r >= size)		\
376 			return (-1);				\
377 		size -= r;					\
378 		buf += r;					\
379 	} while (0)
380 
381 	struct ibuf	data;
382 	uint32_t	as;
383 	int		r, n = 0;
384 	uint8_t		i, seg_type, seg_len;
385 
386 	ibuf_from_ibuf(&data, in);
387 	while (ibuf_size(&data) > 0) {
388 		if (ibuf_get_n8(&data, &seg_type) == -1 ||
389 		    ibuf_get_n8(&data, &seg_len) == -1 ||
390 		    seg_len == 0)
391 			return (-1);
392 
393 		r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "",
394 		    aspath_delim(seg_type, 0));
395 		UPDATE();
396 
397 		for (i = 0; i < seg_len; i++) {
398 			if (ibuf_get_n32(&data, &as) == -1)
399 				return -1;
400 
401 			r = snprintf(buf, size, "%s", log_as(as));
402 			UPDATE();
403 			if (i + 1 < seg_len) {
404 				r = snprintf(buf, size, " ");
405 				UPDATE();
406 			}
407 		}
408 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
409 		UPDATE();
410 	}
411 	/* ensure that we have a valid C-string especially for empty as path */
412 	*buf = '\0';
413 	return (0);
414 #undef UPDATE
415 }
416 
417 static ssize_t
418 aspath_strsize(struct ibuf *in)
419 {
420 	struct ibuf	 buf;
421 	ssize_t		 total_size = 0;
422 	uint32_t	 as;
423 	uint8_t		 i, seg_type, seg_len;
424 
425 	ibuf_from_ibuf(&buf, in);
426 	while (ibuf_size(&buf) > 0) {
427 		if (ibuf_get_n8(&buf, &seg_type) == -1 ||
428 		    ibuf_get_n8(&buf, &seg_len) == -1 ||
429 		    seg_len == 0)
430 			return (-1);
431 
432 		if (total_size != 0)
433 			total_size += 1;
434 		total_size += strlen(aspath_delim(seg_type, 0));
435 
436 		for (i = 0; i < seg_len; i++) {
437 			if (ibuf_get_n32(&buf, &as) == -1)
438 				return (-1);
439 
440 			do {
441 				total_size++;
442 			} while ((as = as / 10) != 0);
443 		}
444 		total_size += seg_len - 1;
445 
446 		total_size += strlen(aspath_delim(seg_type, 1));
447 	}
448 	return (total_size + 1);
449 }
450 
451 int
452 aspath_asprint(char **ret, struct ibuf *data)
453 {
454 	ssize_t	slen;
455 
456 	if ((slen = aspath_strsize(data)) == -1) {
457 		*ret = NULL;
458 		errno = EINVAL;
459 		return (-1);
460 	}
461 
462 	*ret = malloc(slen);
463 	if (*ret == NULL)
464 		return (-1);
465 
466 	if (aspath_snprint(*ret, slen, data) == -1) {
467 		free(*ret);
468 		*ret = NULL;
469 		errno = EINVAL;
470 		return (-1);
471 	}
472 
473 	return (0);
474 }
475 
476 /*
477  * Extract the asnum out of the as segment at the specified position.
478  * Direct access is not possible because of non-aligned reads.
479  * Only works on verified 4-byte AS paths.
480  */
481 uint32_t
482 aspath_extract(const void *seg, int pos)
483 {
484 	const u_char	*ptr = seg;
485 	uint32_t	 as;
486 
487 	/* minimal pos check, return 0 since that is an invalid ASN */
488 	if (pos < 0 || pos >= ptr[1])
489 		return (0);
490 	ptr += 2 + sizeof(uint32_t) * pos;
491 	memcpy(&as, ptr, sizeof(uint32_t));
492 	return (ntohl(as));
493 }
494 
495 /*
496  * Verify that the aspath is correctly encoded.
497  */
498 int
499 aspath_verify(struct ibuf *in, int as4byte, int noset)
500 {
501 	struct ibuf	 buf;
502 	int		 pos, error = 0;
503 	uint8_t		 seg_len, seg_type;
504 
505 	ibuf_from_ibuf(&buf, in);
506 	if (ibuf_size(&buf) & 1) {
507 		/* odd length aspath are invalid */
508 		error = AS_ERR_BAD;
509 		goto done;
510 	}
511 
512 	while (ibuf_size(&buf) > 0) {
513 		if (ibuf_get_n8(&buf, &seg_type) == -1 ||
514 		    ibuf_get_n8(&buf, &seg_len) == -1) {
515 			error = AS_ERR_LEN;
516 			goto done;
517 		}
518 
519 		if (seg_len == 0) {
520 			/* empty aspath segments are not allowed */
521 			error = AS_ERR_BAD;
522 			goto done;
523 		}
524 
525 		/*
526 		 * BGP confederations should not show up but consider them
527 		 * as a soft error which invalidates the path but keeps the
528 		 * bgp session running.
529 		 */
530 		if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
531 			error = AS_ERR_SOFT;
532 		/*
533 		 * If AS_SET filtering (RFC6472) is on, error out on AS_SET
534 		 * as well.
535 		 */
536 		if (noset && seg_type == AS_SET)
537 			error = AS_ERR_SOFT;
538 		if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
539 		    seg_type != AS_CONFED_SEQUENCE &&
540 		    seg_type != AS_CONFED_SET) {
541 			error = AS_ERR_TYPE;
542 			goto done;
543 		}
544 
545 		/* RFC 7607 - AS 0 is considered malformed */
546 		for (pos = 0; pos < seg_len; pos++) {
547 			uint32_t as;
548 
549 			if (as4byte) {
550 				if (ibuf_get_n32(&buf, &as) == -1) {
551 					error = AS_ERR_LEN;
552 					goto done;
553 				}
554 			} else {
555 				uint16_t tmp;
556 				if (ibuf_get_n16(&buf, &tmp) == -1) {
557 					error = AS_ERR_LEN;
558 					goto done;
559 				}
560 				as = tmp;
561 			}
562 			if (as == 0)
563 				error = AS_ERR_SOFT;
564 		}
565 	}
566 
567  done:
568 	return (error);	/* aspath is valid but probably not loop free */
569 }
570 
571 /*
572  * convert a 2 byte aspath to a 4 byte one.
573  */
574 struct ibuf *
575 aspath_inflate(struct ibuf *in)
576 {
577 	struct ibuf	*out;
578 	uint16_t	 short_as;
579 	uint8_t		 seg_type, seg_len;
580 
581 	/*
582 	 * Allocate enough space for the worst case.
583 	 * XXX add 1 byte for the empty ASPATH case since we can't
584 	 * allocate an ibuf of 0 length.
585 	 */
586 	if ((out = ibuf_open(ibuf_size(in) * 2 + 1)) == NULL)
587 		return (NULL);
588 
589 	/* then copy the aspath */
590 	while (ibuf_size(in) > 0) {
591 		if (ibuf_get_n8(in, &seg_type) == -1 ||
592 		    ibuf_get_n8(in, &seg_len) == -1 ||
593 		    seg_len == 0)
594 			goto fail;
595 		if (ibuf_add_n8(out, seg_type) == -1 ||
596 		    ibuf_add_n8(out, seg_len) == -1)
597 			goto fail;
598 
599 		for (; seg_len > 0; seg_len--) {
600 			if (ibuf_get_n16(in, &short_as) == -1)
601 				goto fail;
602 			if (ibuf_add_n32(out, short_as) == -1)
603 				goto fail;
604 		}
605 	}
606 
607 	return (out);
608 
609 fail:
610 	ibuf_free(out);
611 	return (NULL);
612 }
613 
614 static const u_char	addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
615 			    0xf8, 0xfc, 0xfe, 0xff };
616 
617 /* NLRI functions to extract prefixes from the NLRI blobs */
618 int
619 extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max)
620 {
621 	u_char		*a = va;
622 	int		 plen;
623 
624 	plen = PREFIX_SIZE(pfxlen) - 1;
625 	if (len < plen || max < plen)
626 		return -1;
627 
628 	while (pfxlen > 0) {
629 		if (pfxlen < 8) {
630 			*a++ = *p++ & addrmask[pfxlen];
631 			break;
632 		} else {
633 			*a++ = *p++;
634 			pfxlen -= 8;
635 		}
636 	}
637 	return (plen);
638 }
639 
640 static int
641 extract_prefix_buf(struct ibuf *buf, void *va, uint8_t pfxlen, uint8_t max)
642 {
643 	u_char		*a = va;
644 	unsigned int	 plen;
645 	uint8_t		 tmp;
646 
647 	plen = PREFIX_SIZE(pfxlen) - 1;
648 	if (ibuf_size(buf) < plen || max < plen)
649 		return -1;
650 
651 	while (pfxlen > 0) {
652 		if (ibuf_get_n8(buf, &tmp) == -1)
653 			return -1;
654 
655 		if (pfxlen < 8) {
656 			*a++ = tmp & addrmask[pfxlen];
657 			break;
658 		} else {
659 			*a++ = tmp;
660 			pfxlen -= 8;
661 		}
662 	}
663 	return (0);
664 }
665 
666 int
667 nlri_get_prefix(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
668 {
669 	uint8_t	 pfxlen;
670 
671 	if (ibuf_get_n8(buf, &pfxlen) == -1)
672 		return (-1);
673 	if (pfxlen > 32)
674 		return (-1);
675 
676 	memset(prefix, 0, sizeof(struct bgpd_addr));
677 	prefix->aid = AID_INET;
678 
679 	if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
680 	    sizeof(prefix->v4)) == -1)
681 		return (-1);
682 
683 	*prefixlen = pfxlen;
684 	return (0);
685 }
686 
687 int
688 nlri_get_prefix6(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
689 {
690 	uint8_t	pfxlen;
691 
692 	if (ibuf_get_n8(buf, &pfxlen) == -1)
693 		return (-1);
694 	if (pfxlen > 128)
695 		return (-1);
696 
697 	memset(prefix, 0, sizeof(struct bgpd_addr));
698 	prefix->aid = AID_INET6;
699 
700 	if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
701 	    sizeof(prefix->v6)) == -1)
702 		return (-1);
703 
704 	*prefixlen = pfxlen;
705 	return (0);
706 }
707 
708 int
709 nlri_get_vpn4(struct ibuf *buf, struct bgpd_addr *prefix,
710     uint8_t *prefixlen, int withdraw)
711 {
712 	int		 done = 0;
713 	uint8_t		 pfxlen;
714 
715 	if (ibuf_get_n8(buf, &pfxlen) == -1)
716 		return (-1);
717 
718 	memset(prefix, 0, sizeof(struct bgpd_addr));
719 	prefix->aid = AID_VPN_IPv4;
720 
721 	/* label stack */
722 	do {
723 		if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
724 		    pfxlen < 3 * 8)
725 			return (-1);
726 		if (withdraw) {
727 			/* on withdraw ignore the labelstack all together */
728 			if (ibuf_skip(buf, 3) == -1)
729 				return (-1);
730 			pfxlen -= 3 * 8;
731 			break;
732 		}
733 		if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
734 		    -1)
735 			return -1;
736 		if (prefix->labelstack[prefix->labellen + 2] &
737 		    BGP_MPLS_BOS)
738 			done = 1;
739 		prefix->labellen += 3;
740 		pfxlen -= 3 * 8;
741 	} while (!done);
742 
743 	/* RD */
744 	if (pfxlen < sizeof(uint64_t) * 8 ||
745 	    ibuf_get_h64(buf, &prefix->rd) == -1)
746 		return (-1);
747 	pfxlen -= sizeof(uint64_t) * 8;
748 
749 	/* prefix */
750 	if (pfxlen > 32)
751 		return (-1);
752 	if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
753 	    sizeof(prefix->v4)) == -1)
754 		return (-1);
755 
756 	*prefixlen = pfxlen;
757 	return (0);
758 }
759 
760 int
761 nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix,
762     uint8_t *prefixlen, int withdraw)
763 {
764 	int		done = 0;
765 	uint8_t		pfxlen;
766 
767 	if (ibuf_get_n8(buf, &pfxlen) == -1)
768 		return (-1);
769 
770 	memset(prefix, 0, sizeof(struct bgpd_addr));
771 	prefix->aid = AID_VPN_IPv6;
772 
773 	/* label stack */
774 	do {
775 		if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
776 		    pfxlen < 3 * 8)
777 			return (-1);
778 		if (withdraw) {
779 			/* on withdraw ignore the labelstack all together */
780 			if (ibuf_skip(buf, 3) == -1)
781 				return (-1);
782 			pfxlen -= 3 * 8;
783 			break;
784 		}
785 
786 		if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
787 		    -1)
788 			return (-1);
789 		if (prefix->labelstack[prefix->labellen + 2] &
790 		    BGP_MPLS_BOS)
791 			done = 1;
792 		prefix->labellen += 3;
793 		pfxlen -= 3 * 8;
794 	} while (!done);
795 
796 	/* RD */
797 	if (pfxlen < sizeof(uint64_t) * 8 ||
798 	    ibuf_get_h64(buf, &prefix->rd) == -1)
799 		return (-1);
800 	pfxlen -= sizeof(uint64_t) * 8;
801 
802 	/* prefix */
803 	if (pfxlen > 128)
804 		return (-1);
805 	if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
806 	    sizeof(prefix->v6)) == -1)
807 		return (-1);
808 
809 	*prefixlen = pfxlen;
810 	return (0);
811 }
812 
813 static in_addr_t
814 prefixlen2mask(uint8_t prefixlen)
815 {
816 	if (prefixlen == 0)
817 		return (0);
818 
819 	return (0xffffffff << (32 - prefixlen));
820 }
821 
822 /*
823  * This function will have undefined behaviour if the passed in prefixlen is
824  * too large for the respective bgpd_addr address family.
825  */
826 int
827 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
828     int prefixlen)
829 {
830 	in_addr_t	mask, aa, ba;
831 	int		i;
832 	uint8_t		m;
833 
834 	if (a->aid != b->aid)
835 		return (a->aid - b->aid);
836 
837 	switch (a->aid) {
838 	case AID_VPN_IPv4:
839 		if (be64toh(a->rd) > be64toh(b->rd))
840 			return (1);
841 		if (be64toh(a->rd) < be64toh(b->rd))
842 			return (-1);
843 		/* FALLTHROUGH */
844 	case AID_INET:
845 		if (prefixlen == 0)
846 			return (0);
847 		if (prefixlen > 32)
848 			return (-1);
849 		mask = htonl(prefixlen2mask(prefixlen));
850 		aa = ntohl(a->v4.s_addr & mask);
851 		ba = ntohl(b->v4.s_addr & mask);
852 		if (aa > ba)
853 			return (1);
854 		if (aa < ba)
855 			return (-1);
856 		break;
857 	case AID_VPN_IPv6:
858 		if (be64toh(a->rd) > be64toh(b->rd))
859 			return (1);
860 		if (be64toh(a->rd) < be64toh(b->rd))
861 			return (-1);
862 		/* FALLTHROUGH */
863 	case AID_INET6:
864 		if (prefixlen == 0)
865 			return (0);
866 		if (prefixlen > 128)
867 			return (-1);
868 		for (i = 0; i < prefixlen / 8; i++)
869 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
870 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
871 		i = prefixlen % 8;
872 		if (i) {
873 			m = 0xff00 >> i;
874 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
875 			    (b->v6.s6_addr[prefixlen / 8] & m))
876 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
877 				    (b->v6.s6_addr[prefixlen / 8] & m));
878 		}
879 		break;
880 	default:
881 		return (-1);
882 	}
883 
884 	if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) {
885 		if (a->labellen > b->labellen)
886 			return (1);
887 		if (a->labellen < b->labellen)
888 			return (-1);
889 		return (memcmp(a->labelstack, b->labelstack, a->labellen));
890 	}
891 	return (0);
892 
893 }
894 
895 void
896 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
897 {
898 	struct in_addr mask;
899 
900 	mask.s_addr = htonl(prefixlen2mask(prefixlen));
901 	dest->s_addr = src->s_addr & mask.s_addr;
902 }
903 
904 void
905 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
906 {
907 	struct in6_addr	mask;
908 	int		i;
909 
910 	memset(&mask, 0, sizeof(mask));
911 	for (i = 0; i < prefixlen / 8; i++)
912 		mask.s6_addr[i] = 0xff;
913 	i = prefixlen % 8;
914 	if (i)
915 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
916 
917 	for (i = 0; i < 16; i++)
918 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
919 }
920 
921 void
922 applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen)
923 {
924 	*dest = *src;
925 	switch (src->aid) {
926 	case AID_INET:
927 	case AID_VPN_IPv4:
928 		inet4applymask(&dest->v4, &src->v4, prefixlen);
929 		break;
930 	case AID_INET6:
931 	case AID_VPN_IPv6:
932 		inet6applymask(&dest->v6, &src->v6, prefixlen);
933 		break;
934 	}
935 }
936 
937 /* address family translation functions */
938 const struct aid aid_vals[AID_MAX] = AID_VALS;
939 
940 const char *
941 aid2str(uint8_t aid)
942 {
943 	if (aid < AID_MAX)
944 		return (aid_vals[aid].name);
945 	return ("unknown AID");
946 }
947 
948 int
949 aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
950 {
951 	if (aid != AID_UNSPEC && aid < AID_MAX) {
952 		*afi = aid_vals[aid].afi;
953 		*safi = aid_vals[aid].safi;
954 		return (0);
955 	}
956 	return (-1);
957 }
958 
959 int
960 afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
961 {
962 	uint8_t i;
963 
964 	for (i = AID_MIN; i < AID_MAX; i++)
965 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
966 			*aid = i;
967 			return (0);
968 		}
969 
970 	return (-1);
971 }
972 
973 sa_family_t
974 aid2af(uint8_t aid)
975 {
976 	if (aid < AID_MAX)
977 		return (aid_vals[aid].af);
978 	return (AF_UNSPEC);
979 }
980 
981 int
982 af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
983 {
984 	uint8_t i;
985 
986 	if (safi == 0) /* default to unicast subclass */
987 		safi = SAFI_UNICAST;
988 
989 	for (i = AID_UNSPEC; i < AID_MAX; i++)
990 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
991 			*aid = i;
992 			return (0);
993 		}
994 
995 	return (-1);
996 }
997 
998 /*
999  * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
1000  * the included label stack is ignored and needs to be handled by the caller.
1001  */
1002 struct sockaddr *
1003 addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
1004 {
1005 	static struct sockaddr_storage	 ss;
1006 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
1007 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
1008 
1009 	if (addr == NULL || addr->aid == AID_UNSPEC)
1010 		return (NULL);
1011 
1012 	memset(&ss, 0, sizeof(ss));
1013 	switch (addr->aid) {
1014 	case AID_INET:
1015 	case AID_VPN_IPv4:
1016 		sa_in->sin_family = AF_INET;
1017 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
1018 		sa_in->sin_port = htons(port);
1019 		*len = sizeof(struct sockaddr_in);
1020 		break;
1021 	case AID_INET6:
1022 	case AID_VPN_IPv6:
1023 		sa_in6->sin6_family = AF_INET6;
1024 		memcpy(&sa_in6->sin6_addr, &addr->v6,
1025 		    sizeof(sa_in6->sin6_addr));
1026 		sa_in6->sin6_port = htons(port);
1027 		sa_in6->sin6_scope_id = addr->scope_id;
1028 		*len = sizeof(struct sockaddr_in6);
1029 		break;
1030 	case AID_FLOWSPECv4:
1031 	case AID_FLOWSPECv6:
1032 		return (NULL);
1033 	}
1034 
1035 	return ((struct sockaddr *)&ss);
1036 }
1037 
1038 void
1039 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
1040 {
1041 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
1042 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
1043 
1044 	memset(addr, 0, sizeof(*addr));
1045 	switch (sa->sa_family) {
1046 	case AF_INET:
1047 		addr->aid = AID_INET;
1048 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
1049 		if (port)
1050 			*port = ntohs(sa_in->sin_port);
1051 		break;
1052 	case AF_INET6:
1053 		addr->aid = AID_INET6;
1054 #ifdef __KAME__
1055 		/*
1056 		 * XXX thanks, KAME, for this ugliness...
1057 		 * adopted from route/show.c
1058 		 */
1059 		if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
1060 		    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) ||
1061 		    IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) &&
1062 		    sa_in6->sin6_scope_id == 0) {
1063 			uint16_t tmp16;
1064 			memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
1065 			    sizeof(tmp16));
1066 			sa_in6->sin6_scope_id = ntohs(tmp16);
1067 			sa_in6->sin6_addr.s6_addr[2] = 0;
1068 			sa_in6->sin6_addr.s6_addr[3] = 0;
1069 		}
1070 #endif
1071 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
1072 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
1073 		if (port)
1074 			*port = ntohs(sa_in6->sin6_port);
1075 		break;
1076 	}
1077 }
1078 
1079 const char *
1080 get_baudrate(unsigned long long baudrate, char *unit)
1081 {
1082 	static char bbuf[16];
1083 	const unsigned long long kilo = 1000;
1084 	const unsigned long long mega = 1000ULL * kilo;
1085 	const unsigned long long giga = 1000ULL * mega;
1086 
1087 	if (baudrate > giga)
1088 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
1089 		    baudrate / giga, unit);
1090 	else if (baudrate > mega)
1091 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
1092 		    baudrate / mega, unit);
1093 	else if (baudrate > kilo)
1094 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
1095 		    baudrate / kilo, unit);
1096 	else
1097 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
1098 		    baudrate, unit);
1099 
1100 	return (bbuf);
1101 }
1102