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