xref: /openbsd/usr.sbin/bgpd/util.c (revision 5177244f)
1*5177244fSclaudio /*	$OpenBSD: util.c,v 1.65 2022/06/17 09:12:06 claudio Exp $ */
22ffcd4e0Sclaudio 
32ffcd4e0Sclaudio /*
42ffcd4e0Sclaudio  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
52ffcd4e0Sclaudio  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
62ffcd4e0Sclaudio  *
72ffcd4e0Sclaudio  * Permission to use, copy, modify, and distribute this software for any
82ffcd4e0Sclaudio  * purpose with or without fee is hereby granted, provided that the above
92ffcd4e0Sclaudio  * copyright notice and this permission notice appear in all copies.
102ffcd4e0Sclaudio  *
112ffcd4e0Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
122ffcd4e0Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
132ffcd4e0Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
142ffcd4e0Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
152ffcd4e0Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
162ffcd4e0Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
172ffcd4e0Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
182ffcd4e0Sclaudio  */
192ffcd4e0Sclaudio #include <sys/types.h>
202ffcd4e0Sclaudio #include <sys/socket.h>
212ffcd4e0Sclaudio #include <netinet/in.h>
222ffcd4e0Sclaudio #include <arpa/inet.h>
2348bae517Sclaudio #include <endian.h>
2429328a94Sclaudio #include <errno.h>
252ffcd4e0Sclaudio #include <netdb.h>
262ffcd4e0Sclaudio #include <stdlib.h>
272ffcd4e0Sclaudio #include <stdio.h>
282ffcd4e0Sclaudio #include <string.h>
290561b344Sphessler #include <vis.h>
302ffcd4e0Sclaudio 
312ffcd4e0Sclaudio #include "bgpd.h"
322ffcd4e0Sclaudio #include "rde.h"
335e3f6f95Sbenno #include "log.h"
342ffcd4e0Sclaudio 
3539386878Sclaudio const char	*aspath_delim(uint8_t, int);
361e590dcfSclaudio 
372ffcd4e0Sclaudio const char *
382ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr)
392ffcd4e0Sclaudio {
40290f96faSdenis 	static char	buf[74];
4145350f87Sclaudio 	struct sockaddr *sa;
425624d029Sclaudio 	socklen_t	len;
432ffcd4e0Sclaudio 
4445350f87Sclaudio 	sa = addr2sa(addr, 0, &len);
4515d8de66Sclaudio 	switch (addr->aid) {
4615d8de66Sclaudio 	case AID_INET:
4715d8de66Sclaudio 	case AID_INET6:
4845350f87Sclaudio 		return log_sockaddr(sa, len);
4915d8de66Sclaudio 	case AID_VPN_IPv4:
50290f96faSdenis 	case AID_VPN_IPv6:
513038d3d1Sclaudio 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd),
5245350f87Sclaudio 		    log_sockaddr(sa, len));
53290f96faSdenis 		return (buf);
5415d8de66Sclaudio 	}
5515d8de66Sclaudio 	return ("???");
562ffcd4e0Sclaudio }
572ffcd4e0Sclaudio 
582ffcd4e0Sclaudio const char *
592ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr)
602ffcd4e0Sclaudio {
612ffcd4e0Sclaudio 	struct sockaddr_in6	sa_in6;
622ffcd4e0Sclaudio 
632ffcd4e0Sclaudio 	bzero(&sa_in6, sizeof(sa_in6));
642ffcd4e0Sclaudio 	sa_in6.sin6_family = AF_INET6;
652ffcd4e0Sclaudio 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
662ffcd4e0Sclaudio 
67be6ced5eSclaudio #ifdef __KAME__
682ffcd4e0Sclaudio 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
692ffcd4e0Sclaudio 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
702ffcd4e0Sclaudio 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
7139386878Sclaudio 		uint16_t tmp16;
722ffcd4e0Sclaudio 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
732ffcd4e0Sclaudio 		sa_in6.sin6_scope_id = ntohs(tmp16);
742ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[2] = 0;
752ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[3] = 0;
762ffcd4e0Sclaudio 	}
77be6ced5eSclaudio #endif
782ffcd4e0Sclaudio 
79255fe563Sclaudio 	return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
802ffcd4e0Sclaudio }
812ffcd4e0Sclaudio 
822ffcd4e0Sclaudio const char *
83255fe563Sclaudio log_sockaddr(struct sockaddr *sa, socklen_t len)
842ffcd4e0Sclaudio {
852ffcd4e0Sclaudio 	static char	buf[NI_MAXHOST];
862ffcd4e0Sclaudio 
8745350f87Sclaudio 	if (sa == NULL || getnameinfo(sa, len, buf, sizeof(buf), NULL, 0,
882ffcd4e0Sclaudio 	    NI_NUMERICHOST))
892ffcd4e0Sclaudio 		return ("(unknown)");
902ffcd4e0Sclaudio 	else
912ffcd4e0Sclaudio 		return (buf);
922ffcd4e0Sclaudio }
932ffcd4e0Sclaudio 
940c88bf70Sclaudio const char *
9539386878Sclaudio log_as(uint32_t as)
960c88bf70Sclaudio {
9706bcde9cSphessler 	static char	buf[11];	/* "4294967294\0" */
980c88bf70Sclaudio 
99515e489cSderaadt 	if (snprintf(buf, sizeof(buf), "%u", as) < 0)
1000c88bf70Sclaudio 		return ("?");
10106bcde9cSphessler 
1020c88bf70Sclaudio 	return (buf);
1030c88bf70Sclaudio }
1040c88bf70Sclaudio 
105256b680eSclaudio const char *
10639386878Sclaudio log_rd(uint64_t rd)
107256b680eSclaudio {
108256b680eSclaudio 	static char	buf[32];
109256b680eSclaudio 	struct in_addr	addr;
11039386878Sclaudio 	uint32_t	u32;
11139386878Sclaudio 	uint16_t	u16;
112256b680eSclaudio 
113f4c0eb52Sclaudio 	rd = be64toh(rd);
114256b680eSclaudio 	switch (rd >> 48) {
115bf8e2920Sclaudio 	case EXT_COMMUNITY_TRANS_TWO_AS:
116256b680eSclaudio 		u32 = rd & 0xffffffff;
117256b680eSclaudio 		u16 = (rd >> 32) & 0xffff;
11832ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
119256b680eSclaudio 		break;
120bf8e2920Sclaudio 	case EXT_COMMUNITY_TRANS_FOUR_AS:
121256b680eSclaudio 		u32 = (rd >> 16) & 0xffffffff;
122256b680eSclaudio 		u16 = rd & 0xffff;
12332ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
124256b680eSclaudio 		break;
125bf8e2920Sclaudio 	case EXT_COMMUNITY_TRANS_IPV4:
126256b680eSclaudio 		u32 = (rd >> 16) & 0xffffffff;
127256b680eSclaudio 		u16 = rd & 0xffff;
128256b680eSclaudio 		addr.s_addr = htonl(u32);
12932ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
130256b680eSclaudio 		break;
131256b680eSclaudio 	default:
132256b680eSclaudio 		return ("rd ?");
133256b680eSclaudio 	}
134256b680eSclaudio 	return (buf);
135256b680eSclaudio }
136256b680eSclaudio 
137bf8e2920Sclaudio const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
138bf8e2920Sclaudio 
139256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is
140536f41e5Sclaudio  * actually valid. */
141536f41e5Sclaudio const char *
142f8162053Sclaudio log_ext_subtype(int type, uint8_t subtype)
143536f41e5Sclaudio {
144536f41e5Sclaudio 	static char etype[6];
145bf8e2920Sclaudio 	const struct ext_comm_pairs *cp;
146536f41e5Sclaudio 
147bf8e2920Sclaudio 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
1480e6216fdSclaudio 		if ((type == cp->type || type == -1) && subtype == cp->subtype)
149bf8e2920Sclaudio 			return (cp->subname);
150bf8e2920Sclaudio 	}
151d6340f7aSderaadt 	snprintf(etype, sizeof(etype), "[%u]", subtype);
152536f41e5Sclaudio 	return (etype);
153536f41e5Sclaudio }
154536f41e5Sclaudio 
1551e590dcfSclaudio const char *
156a78f83ceSderaadt log_reason(const char *communication) {
157a78f83ceSderaadt 	static char buf[(REASON_LEN - 1) * 4 + 1];
1580561b344Sphessler 
1590561b344Sphessler 	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
1600561b344Sphessler 
1610561b344Sphessler 	return buf;
1620561b344Sphessler }
1630561b344Sphessler 
1640561b344Sphessler const char *
165bd9df44eSclaudio log_rtr_error(enum rtr_error err)
166bd9df44eSclaudio {
167bd9df44eSclaudio 	static char buf[20];
168bd9df44eSclaudio 
169bd9df44eSclaudio 	switch (err) {
170bd9df44eSclaudio 	case NO_ERROR:
171bd9df44eSclaudio 		return "No Error";
172bd9df44eSclaudio 	case CORRUPT_DATA:
173bd9df44eSclaudio 		return "Corrupt Data";
174bd9df44eSclaudio 	case INTERNAL_ERROR:
175bd9df44eSclaudio 		return "Internal Error";
176bd9df44eSclaudio 	case NO_DATA_AVAILABLE:
177bd9df44eSclaudio 		return "No Data Available";
178bd9df44eSclaudio 	case INVALID_REQUEST:
179bd9df44eSclaudio 		return "Invalid Request";
180bd9df44eSclaudio 	case UNSUPP_PROTOCOL_VERS:
181bd9df44eSclaudio 		return "Unsupported Protocol Version";
182bd9df44eSclaudio 	case UNSUPP_PDU_TYPE:
183bd9df44eSclaudio 		return "Unsupported PDU Type";
184bd9df44eSclaudio 	case UNK_REC_WDRAWL:
185bd9df44eSclaudio 		return "Withdrawl of Unknown Record";
186bd9df44eSclaudio 	case DUP_REC_RECV:
187bd9df44eSclaudio 		return "Duplicate Announcement Received";
188bd9df44eSclaudio 	case UNEXP_PROTOCOL_VERS:
189bd9df44eSclaudio 		return "Unexpected Protocol Version";
190bd9df44eSclaudio 	default:
191bd9df44eSclaudio 		snprintf(buf, sizeof(buf), "unknown %u", err);
192bd9df44eSclaudio 		return buf;
193bd9df44eSclaudio 	}
194bd9df44eSclaudio }
195bd9df44eSclaudio 
196bd9df44eSclaudio const char *
19739386878Sclaudio aspath_delim(uint8_t seg_type, int closing)
1981e590dcfSclaudio {
1991e590dcfSclaudio 	static char db[8];
2001e590dcfSclaudio 
2011e590dcfSclaudio 	switch (seg_type) {
2021e590dcfSclaudio 	case AS_SET:
2031e590dcfSclaudio 		if (!closing)
2041e590dcfSclaudio 			return ("{ ");
2051e590dcfSclaudio 		else
2061e590dcfSclaudio 			return (" }");
2071e590dcfSclaudio 	case AS_SEQUENCE:
2081e590dcfSclaudio 		return ("");
2091e590dcfSclaudio 	case AS_CONFED_SEQUENCE:
2101e590dcfSclaudio 		if (!closing)
2111e590dcfSclaudio 			return ("( ");
2121e590dcfSclaudio 		else
2131e590dcfSclaudio 			return (" )");
2141e590dcfSclaudio 	case AS_CONFED_SET:
2151e590dcfSclaudio 		if (!closing)
2161e590dcfSclaudio 			return ("[ ");
2171e590dcfSclaudio 		else
2181e590dcfSclaudio 			return (" ]");
2191e590dcfSclaudio 	default:
2201e590dcfSclaudio 		if (!closing)
2211e590dcfSclaudio 			snprintf(db, sizeof(db), "!%u ", seg_type);
2221e590dcfSclaudio 		else
2231e590dcfSclaudio 			snprintf(db, sizeof(db), " !%u", seg_type);
2241e590dcfSclaudio 		return (db);
2251e590dcfSclaudio 	}
2261e590dcfSclaudio }
2271e590dcfSclaudio 
2282ffcd4e0Sclaudio int
22939386878Sclaudio aspath_snprint(char *buf, size_t size, void *data, uint16_t len)
2302ffcd4e0Sclaudio {
2312ffcd4e0Sclaudio #define UPDATE()				\
2322ffcd4e0Sclaudio 	do {					\
233515e489cSderaadt 		if (r < 0)			\
2342ffcd4e0Sclaudio 			return (-1);		\
2352ffcd4e0Sclaudio 		total_size += r;		\
2362ffcd4e0Sclaudio 		if ((unsigned int)r < size) {	\
2372ffcd4e0Sclaudio 			size -= r;		\
2382ffcd4e0Sclaudio 			buf += r;		\
2392ffcd4e0Sclaudio 		} else {			\
2402ffcd4e0Sclaudio 			buf += size;		\
2412ffcd4e0Sclaudio 			size = 0;		\
2422ffcd4e0Sclaudio 		}				\
2432ffcd4e0Sclaudio 	} while (0)
24439386878Sclaudio 	uint8_t		*seg;
2452ffcd4e0Sclaudio 	int		 r, total_size;
24639386878Sclaudio 	uint16_t	 seg_size;
24739386878Sclaudio 	uint8_t		 i, seg_type, seg_len;
2482ffcd4e0Sclaudio 
2492ffcd4e0Sclaudio 	total_size = 0;
2502ffcd4e0Sclaudio 	seg = data;
2512ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
2522ffcd4e0Sclaudio 		seg_type = seg[0];
2532ffcd4e0Sclaudio 		seg_len = seg[1];
25439386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
2552ffcd4e0Sclaudio 
2561e590dcfSclaudio 		r = snprintf(buf, size, "%s%s",
2571e590dcfSclaudio 		    total_size != 0 ? " " : "",
2581e590dcfSclaudio 		    aspath_delim(seg_type, 0));
2592ffcd4e0Sclaudio 		UPDATE();
2602ffcd4e0Sclaudio 
2612ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
2620c88bf70Sclaudio 			r = snprintf(buf, size, "%s",
2630c88bf70Sclaudio 			    log_as(aspath_extract(seg, i)));
2642ffcd4e0Sclaudio 			UPDATE();
2652ffcd4e0Sclaudio 			if (i + 1 < seg_len) {
2662ffcd4e0Sclaudio 				r = snprintf(buf, size, " ");
2672ffcd4e0Sclaudio 				UPDATE();
2682ffcd4e0Sclaudio 			}
2692ffcd4e0Sclaudio 		}
2701e590dcfSclaudio 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
2712ffcd4e0Sclaudio 		UPDATE();
2722ffcd4e0Sclaudio 	}
27355e49665Sclaudio 	/* ensure that we have a valid C-string especially for empty as path */
2742ffcd4e0Sclaudio 	if (size > 0)
2752ffcd4e0Sclaudio 		*buf = '\0';
2762ffcd4e0Sclaudio 
2772ffcd4e0Sclaudio 	return (total_size);
2782ffcd4e0Sclaudio #undef UPDATE
2792ffcd4e0Sclaudio }
2802ffcd4e0Sclaudio 
2812ffcd4e0Sclaudio int
28239386878Sclaudio aspath_asprint(char **ret, void *data, uint16_t len)
2832ffcd4e0Sclaudio {
2842ffcd4e0Sclaudio 	size_t	slen;
2852ffcd4e0Sclaudio 	int	plen;
2862ffcd4e0Sclaudio 
2872ffcd4e0Sclaudio 	slen = aspath_strlen(data, len) + 1;
2882ffcd4e0Sclaudio 	*ret = malloc(slen);
2892ffcd4e0Sclaudio 	if (*ret == NULL)
2902ffcd4e0Sclaudio 		return (-1);
2912ffcd4e0Sclaudio 
2922ffcd4e0Sclaudio 	plen = aspath_snprint(*ret, slen, data, len);
2932ffcd4e0Sclaudio 	if (plen == -1) {
2942ffcd4e0Sclaudio 		free(*ret);
2952ffcd4e0Sclaudio 		*ret = NULL;
2962ffcd4e0Sclaudio 		return (-1);
2972ffcd4e0Sclaudio 	}
2982ffcd4e0Sclaudio 
2992ffcd4e0Sclaudio 	return (0);
3002ffcd4e0Sclaudio }
3012ffcd4e0Sclaudio 
3022ffcd4e0Sclaudio size_t
30339386878Sclaudio aspath_strlen(void *data, uint16_t len)
3042ffcd4e0Sclaudio {
30539386878Sclaudio 	uint8_t		*seg;
3062ffcd4e0Sclaudio 	int		 total_size;
30739386878Sclaudio 	uint32_t	 as;
30839386878Sclaudio 	uint16_t	 seg_size;
30939386878Sclaudio 	uint8_t		 i, seg_type, seg_len;
3102ffcd4e0Sclaudio 
3112ffcd4e0Sclaudio 	total_size = 0;
3122ffcd4e0Sclaudio 	seg = data;
3132ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
3142ffcd4e0Sclaudio 		seg_type = seg[0];
3152ffcd4e0Sclaudio 		seg_len = seg[1];
31639386878Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
3172ffcd4e0Sclaudio 
3182ffcd4e0Sclaudio 		if (seg_type == AS_SET)
3192ffcd4e0Sclaudio 			if (total_size != 0)
3202ffcd4e0Sclaudio 				total_size += 3;
3212ffcd4e0Sclaudio 			else
3222ffcd4e0Sclaudio 				total_size += 2;
3232ffcd4e0Sclaudio 		else if (total_size != 0)
3242ffcd4e0Sclaudio 			total_size += 1;
3252ffcd4e0Sclaudio 
3262ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
3272ffcd4e0Sclaudio 			as = aspath_extract(seg, i);
3280c88bf70Sclaudio 
3298db4f5d2Sclaudio 			do {
3308db4f5d2Sclaudio 				total_size++;
3318db4f5d2Sclaudio 			} while ((as = as / 10) != 0);
3322ffcd4e0Sclaudio 
3332ffcd4e0Sclaudio 			if (i + 1 < seg_len)
3342ffcd4e0Sclaudio 				total_size += 1;
3352ffcd4e0Sclaudio 		}
3362ffcd4e0Sclaudio 
3372ffcd4e0Sclaudio 		if (seg_type == AS_SET)
3382ffcd4e0Sclaudio 			total_size += 2;
3392ffcd4e0Sclaudio 	}
3402ffcd4e0Sclaudio 	return (total_size);
3412ffcd4e0Sclaudio }
3422ffcd4e0Sclaudio 
3432ffcd4e0Sclaudio /*
3442ffcd4e0Sclaudio  * Extract the asnum out of the as segment at the specified position.
3452ffcd4e0Sclaudio  * Direct access is not possible because of non-aligned reads.
346c5508ee4Sclaudio  * ATTENTION: no bounds checks are done.
3472ffcd4e0Sclaudio  */
34839386878Sclaudio uint32_t
3492ffcd4e0Sclaudio aspath_extract(const void *seg, int pos)
3502ffcd4e0Sclaudio {
3512ffcd4e0Sclaudio 	const u_char	*ptr = seg;
35239386878Sclaudio 	uint32_t	 as;
3532ffcd4e0Sclaudio 
35439386878Sclaudio 	ptr += 2 + sizeof(uint32_t) * pos;
35539386878Sclaudio 	memcpy(&as, ptr, sizeof(uint32_t));
3560c88bf70Sclaudio 	return (ntohl(as));
3572ffcd4e0Sclaudio }
35821a825c9Sclaudio 
359de5c2eedSclaudio /*
36029328a94Sclaudio  * Verify that the aspath is correctly encoded.
36129328a94Sclaudio  */
36229328a94Sclaudio int
36339386878Sclaudio aspath_verify(void *data, uint16_t len, int as4byte, int noset)
36429328a94Sclaudio {
36539386878Sclaudio 	uint8_t		*seg = data;
36639386878Sclaudio 	uint16_t	 seg_size, as_size = 2;
36739386878Sclaudio 	uint8_t		 seg_len, seg_type;
36829328a94Sclaudio 	int		 error = 0;
36929328a94Sclaudio 
37029328a94Sclaudio 	if (len & 1)
37129328a94Sclaudio 		/* odd length aspath are invalid */
37229328a94Sclaudio 		return (AS_ERR_BAD);
37329328a94Sclaudio 
37429328a94Sclaudio 	if (as4byte)
37529328a94Sclaudio 		as_size = 4;
37629328a94Sclaudio 
37729328a94Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
37839386878Sclaudio 		const uint8_t	*ptr;
37929328a94Sclaudio 		int		 pos;
38029328a94Sclaudio 
38129328a94Sclaudio 		if (len < 2)	/* header length check */
38229328a94Sclaudio 			return (AS_ERR_BAD);
38329328a94Sclaudio 		seg_type = seg[0];
38429328a94Sclaudio 		seg_len = seg[1];
38529328a94Sclaudio 
386d04df938Sclaudio 		if (seg_len == 0)
387d04df938Sclaudio 			/* empty aspath segments are not allowed */
388d04df938Sclaudio 			return (AS_ERR_BAD);
389d04df938Sclaudio 
39029328a94Sclaudio 		/*
39129328a94Sclaudio 		 * BGP confederations should not show up but consider them
39229328a94Sclaudio 		 * as a soft error which invalidates the path but keeps the
39329328a94Sclaudio 		 * bgp session running.
39429328a94Sclaudio 		 */
39529328a94Sclaudio 		if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
39629328a94Sclaudio 			error = AS_ERR_SOFT;
397aa528464Sclaudio 		/*
398aa528464Sclaudio 		 * If AS_SET filtering (RFC6472) is on, error out on AS_SET
399aa528464Sclaudio 		 * as well.
400aa528464Sclaudio 		 */
401aa528464Sclaudio 		if (noset && seg_type == AS_SET)
402aa528464Sclaudio 			error = AS_ERR_SOFT;
40329328a94Sclaudio 		if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
40429328a94Sclaudio 		    seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET)
40529328a94Sclaudio 			return (AS_ERR_TYPE);
40629328a94Sclaudio 
40729328a94Sclaudio 		seg_size = 2 + as_size * seg_len;
40829328a94Sclaudio 
40929328a94Sclaudio 		if (seg_size > len)
41029328a94Sclaudio 			return (AS_ERR_LEN);
41129328a94Sclaudio 
41229328a94Sclaudio 		/* RFC 7607 - AS 0 is considered malformed */
41329328a94Sclaudio 		ptr = seg + 2;
41429328a94Sclaudio 		for (pos = 0; pos < seg_len; pos++) {
41539386878Sclaudio 			uint32_t as;
41629328a94Sclaudio 
41729328a94Sclaudio 			memcpy(&as, ptr, as_size);
41829328a94Sclaudio 			if (as == 0)
41956a9a1b8Sclaudio 				error = AS_ERR_SOFT;
42051491708Sclaudio 			ptr += as_size;
42129328a94Sclaudio 		}
42229328a94Sclaudio 	}
42329328a94Sclaudio 	return (error);	/* aspath is valid but probably not loop free */
42429328a94Sclaudio }
42529328a94Sclaudio 
42629328a94Sclaudio /*
42729328a94Sclaudio  * convert a 2 byte aspath to a 4 byte one.
42829328a94Sclaudio  */
42929328a94Sclaudio u_char *
43039386878Sclaudio aspath_inflate(void *data, uint16_t len, uint16_t *newlen)
43129328a94Sclaudio {
43239386878Sclaudio 	uint8_t		*seg, *nseg, *ndata;
43339386878Sclaudio 	uint16_t	 seg_size, olen, nlen;
43439386878Sclaudio 	uint8_t		 seg_len;
43529328a94Sclaudio 
43629328a94Sclaudio 	/* first calculate the length of the aspath */
43729328a94Sclaudio 	seg = data;
43829328a94Sclaudio 	nlen = 0;
43929328a94Sclaudio 	for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
44029328a94Sclaudio 		seg_len = seg[1];
44139386878Sclaudio 		seg_size = 2 + sizeof(uint16_t) * seg_len;
44239386878Sclaudio 		nlen += 2 + sizeof(uint32_t) * seg_len;
44329328a94Sclaudio 
44429328a94Sclaudio 		if (seg_size > olen) {
44529328a94Sclaudio 			errno = ERANGE;
44629328a94Sclaudio 			return (NULL);
44729328a94Sclaudio 		}
44829328a94Sclaudio 	}
44929328a94Sclaudio 
45029328a94Sclaudio 	*newlen = nlen;
45129328a94Sclaudio 	if ((ndata = malloc(nlen)) == NULL)
45229328a94Sclaudio 		return (NULL);
45329328a94Sclaudio 
45429328a94Sclaudio 	/* then copy the aspath */
45529328a94Sclaudio 	seg = data;
45629328a94Sclaudio 	for (nseg = ndata; nseg < ndata + nlen; ) {
45729328a94Sclaudio 		*nseg++ = *seg++;
45829328a94Sclaudio 		*nseg++ = seg_len = *seg++;
45929328a94Sclaudio 		for (; seg_len > 0; seg_len--) {
46029328a94Sclaudio 			*nseg++ = 0;
46129328a94Sclaudio 			*nseg++ = 0;
46229328a94Sclaudio 			*nseg++ = *seg++;
46329328a94Sclaudio 			*nseg++ = *seg++;
46429328a94Sclaudio 		}
46529328a94Sclaudio 	}
46629328a94Sclaudio 
46729328a94Sclaudio 	return (ndata);
46829328a94Sclaudio }
46929328a94Sclaudio 
4706d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */
4716d3e8673Sclaudio static int
47239386878Sclaudio extract_prefix(u_char *p, uint16_t len, void *va,
47339386878Sclaudio     uint8_t pfxlen, uint8_t max)
4746d3e8673Sclaudio {
4756d3e8673Sclaudio 	static u_char	 addrmask[] = {
4766d3e8673Sclaudio 	    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
4776d3e8673Sclaudio 	u_char		*a = va;
4786d3e8673Sclaudio 	int		 i;
47939386878Sclaudio 	uint16_t	 plen = 0;
4806d3e8673Sclaudio 
4816d3e8673Sclaudio 	for (i = 0; pfxlen && i < max; i++) {
4826d3e8673Sclaudio 		if (len <= plen)
4836d3e8673Sclaudio 			return (-1);
4846d3e8673Sclaudio 		if (pfxlen < 8) {
4856d3e8673Sclaudio 			a[i] = *p++ & addrmask[pfxlen];
4866d3e8673Sclaudio 			plen++;
4876d3e8673Sclaudio 			break;
4886d3e8673Sclaudio 		} else {
4896d3e8673Sclaudio 			a[i] = *p++;
4906d3e8673Sclaudio 			plen++;
4916d3e8673Sclaudio 			pfxlen -= 8;
4926d3e8673Sclaudio 		}
4936d3e8673Sclaudio 	}
4946d3e8673Sclaudio 	return (plen);
4956d3e8673Sclaudio }
4966d3e8673Sclaudio 
4976d3e8673Sclaudio int
49839386878Sclaudio nlri_get_prefix(u_char *p, uint16_t len, struct bgpd_addr *prefix,
49939386878Sclaudio     uint8_t *prefixlen)
5006d3e8673Sclaudio {
5016d3e8673Sclaudio 	int	 plen;
50239386878Sclaudio 	uint8_t	 pfxlen;
5036d3e8673Sclaudio 
5046d3e8673Sclaudio 	if (len < 1)
5056d3e8673Sclaudio 		return (-1);
5066d3e8673Sclaudio 
5076d3e8673Sclaudio 	pfxlen = *p++;
5086d3e8673Sclaudio 	len--;
5096d3e8673Sclaudio 
5106d3e8673Sclaudio 	bzero(prefix, sizeof(struct bgpd_addr));
5116d3e8673Sclaudio 	prefix->aid = AID_INET;
5126d3e8673Sclaudio 	*prefixlen = pfxlen;
5136d3e8673Sclaudio 
5146d3e8673Sclaudio 	if (pfxlen > 32)
5156d3e8673Sclaudio 		return (-1);
5166d3e8673Sclaudio 	if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen,
5176d3e8673Sclaudio 	    sizeof(prefix->v4))) == -1)
5186d3e8673Sclaudio 		return (-1);
5196d3e8673Sclaudio 
5206d3e8673Sclaudio 	return (plen + 1);	/* pfxlen needs to be added */
5216d3e8673Sclaudio }
5226d3e8673Sclaudio 
5236d3e8673Sclaudio int
52439386878Sclaudio nlri_get_prefix6(u_char *p, uint16_t len, struct bgpd_addr *prefix,
52539386878Sclaudio     uint8_t *prefixlen)
5266d3e8673Sclaudio {
5276d3e8673Sclaudio 	int	plen;
52839386878Sclaudio 	uint8_t	pfxlen;
5296d3e8673Sclaudio 
5306d3e8673Sclaudio 	if (len < 1)
5316d3e8673Sclaudio 		return (-1);
5326d3e8673Sclaudio 
5336d3e8673Sclaudio 	pfxlen = *p++;
5346d3e8673Sclaudio 	len--;
5356d3e8673Sclaudio 
5366d3e8673Sclaudio 	bzero(prefix, sizeof(struct bgpd_addr));
5376d3e8673Sclaudio 	prefix->aid = AID_INET6;
5386d3e8673Sclaudio 	*prefixlen = pfxlen;
5396d3e8673Sclaudio 
5406d3e8673Sclaudio 	if (pfxlen > 128)
5416d3e8673Sclaudio 		return (-1);
5426d3e8673Sclaudio 	if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen,
5436d3e8673Sclaudio 	    sizeof(prefix->v6))) == -1)
5446d3e8673Sclaudio 		return (-1);
5456d3e8673Sclaudio 
5466d3e8673Sclaudio 	return (plen + 1);	/* pfxlen needs to be added */
5476d3e8673Sclaudio }
5486d3e8673Sclaudio 
5496d3e8673Sclaudio int
55039386878Sclaudio nlri_get_vpn4(u_char *p, uint16_t len, struct bgpd_addr *prefix,
55139386878Sclaudio     uint8_t *prefixlen, int withdraw)
5526d3e8673Sclaudio {
5536d3e8673Sclaudio 	int		 rv, done = 0;
55439386878Sclaudio 	uint16_t	 plen;
55539386878Sclaudio 	uint8_t		 pfxlen;
5566d3e8673Sclaudio 
5576d3e8673Sclaudio 	if (len < 1)
5586d3e8673Sclaudio 		return (-1);
5596d3e8673Sclaudio 
5606d3e8673Sclaudio 	memcpy(&pfxlen, p, 1);
5616d3e8673Sclaudio 	p += 1;
5626d3e8673Sclaudio 	plen = 1;
5636d3e8673Sclaudio 
5646d3e8673Sclaudio 	bzero(prefix, sizeof(struct bgpd_addr));
5656d3e8673Sclaudio 
5666d3e8673Sclaudio 	/* label stack */
5676d3e8673Sclaudio 	do {
5686d3e8673Sclaudio 		if (len - plen < 3 || pfxlen < 3 * 8)
5696d3e8673Sclaudio 			return (-1);
5703038d3d1Sclaudio 		if (prefix->labellen + 3U >
5713038d3d1Sclaudio 		    sizeof(prefix->labelstack))
5726d3e8673Sclaudio 			return (-1);
5736d3e8673Sclaudio 		if (withdraw) {
5746d3e8673Sclaudio 			/* on withdraw ignore the labelstack all together */
5756d3e8673Sclaudio 			plen += 3;
5766d3e8673Sclaudio 			pfxlen -= 3 * 8;
5776d3e8673Sclaudio 			break;
5786d3e8673Sclaudio 		}
5793038d3d1Sclaudio 		prefix->labelstack[prefix->labellen++] = *p++;
5803038d3d1Sclaudio 		prefix->labelstack[prefix->labellen++] = *p++;
5813038d3d1Sclaudio 		prefix->labelstack[prefix->labellen] = *p++;
5823038d3d1Sclaudio 		if (prefix->labelstack[prefix->labellen] &
5836d3e8673Sclaudio 		    BGP_MPLS_BOS)
5846d3e8673Sclaudio 			done = 1;
5853038d3d1Sclaudio 		prefix->labellen++;
5866d3e8673Sclaudio 		plen += 3;
5876d3e8673Sclaudio 		pfxlen -= 3 * 8;
5886d3e8673Sclaudio 	} while (!done);
5896d3e8673Sclaudio 
5906d3e8673Sclaudio 	/* RD */
59139386878Sclaudio 	if (len - plen < (int)sizeof(uint64_t) ||
59239386878Sclaudio 	    pfxlen < sizeof(uint64_t) * 8)
5936d3e8673Sclaudio 		return (-1);
59439386878Sclaudio 	memcpy(&prefix->rd, p, sizeof(uint64_t));
59539386878Sclaudio 	pfxlen -= sizeof(uint64_t) * 8;
59639386878Sclaudio 	p += sizeof(uint64_t);
59739386878Sclaudio 	plen += sizeof(uint64_t);
5986d3e8673Sclaudio 
5996d3e8673Sclaudio 	/* prefix */
6006d3e8673Sclaudio 	prefix->aid = AID_VPN_IPv4;
6016d3e8673Sclaudio 	*prefixlen = pfxlen;
6026d3e8673Sclaudio 
6036d3e8673Sclaudio 	if (pfxlen > 32)
6046d3e8673Sclaudio 		return (-1);
6053038d3d1Sclaudio 	if ((rv = extract_prefix(p, len, &prefix->v4,
6063038d3d1Sclaudio 	    pfxlen, sizeof(prefix->v4))) == -1)
6076d3e8673Sclaudio 		return (-1);
6086d3e8673Sclaudio 
6096d3e8673Sclaudio 	return (plen + rv);
6106d3e8673Sclaudio }
6116d3e8673Sclaudio 
612290f96faSdenis int
61339386878Sclaudio nlri_get_vpn6(u_char *p, uint16_t len, struct bgpd_addr *prefix,
61439386878Sclaudio     uint8_t *prefixlen, int withdraw)
615290f96faSdenis {
616290f96faSdenis 	int		rv, done = 0;
61739386878Sclaudio 	uint16_t	plen;
61839386878Sclaudio 	uint8_t		pfxlen;
619290f96faSdenis 
620290f96faSdenis 	if (len < 1)
621290f96faSdenis 		return (-1);
622290f96faSdenis 
623290f96faSdenis 	memcpy(&pfxlen, p, 1);
624290f96faSdenis 	p += 1;
625290f96faSdenis 	plen = 1;
626290f96faSdenis 
627290f96faSdenis 	memset(prefix, 0, sizeof(struct bgpd_addr));
628290f96faSdenis 
629290f96faSdenis 	/* label stack */
630290f96faSdenis 	do {
631290f96faSdenis 		if (len - plen < 3 || pfxlen < 3 * 8)
632290f96faSdenis 			return (-1);
6333038d3d1Sclaudio 		if (prefix->labellen + 3U >
6343038d3d1Sclaudio 		    sizeof(prefix->labelstack))
635290f96faSdenis 			return (-1);
636290f96faSdenis 		if (withdraw) {
637290f96faSdenis 			/* on withdraw ignore the labelstack all together */
638290f96faSdenis 			plen += 3;
639290f96faSdenis 			pfxlen -= 3 * 8;
640290f96faSdenis 			break;
641290f96faSdenis 		}
642290f96faSdenis 
6433038d3d1Sclaudio 		prefix->labelstack[prefix->labellen++] = *p++;
6443038d3d1Sclaudio 		prefix->labelstack[prefix->labellen++] = *p++;
6453038d3d1Sclaudio 		prefix->labelstack[prefix->labellen] = *p++;
6463038d3d1Sclaudio 		if (prefix->labelstack[prefix->labellen] &
647290f96faSdenis 		    BGP_MPLS_BOS)
648290f96faSdenis 			done = 1;
6493038d3d1Sclaudio 		prefix->labellen++;
650290f96faSdenis 		plen += 3;
651290f96faSdenis 		pfxlen -= 3 * 8;
652290f96faSdenis 	} while (!done);
653290f96faSdenis 
654290f96faSdenis 	/* RD */
65539386878Sclaudio 	if (len - plen < (int)sizeof(uint64_t) ||
65639386878Sclaudio 	    pfxlen < sizeof(uint64_t) * 8)
657290f96faSdenis 		return (-1);
658290f96faSdenis 
65939386878Sclaudio 	memcpy(&prefix->rd, p, sizeof(uint64_t));
66039386878Sclaudio 	pfxlen -= sizeof(uint64_t) * 8;
66139386878Sclaudio 	p += sizeof(uint64_t);
66239386878Sclaudio 	plen += sizeof(uint64_t);
663290f96faSdenis 
664290f96faSdenis 	/* prefix */
665290f96faSdenis 	prefix->aid = AID_VPN_IPv6;
666290f96faSdenis 	*prefixlen = pfxlen;
667290f96faSdenis 
668290f96faSdenis 	if (pfxlen > 128)
669290f96faSdenis 		return (-1);
670290f96faSdenis 
6713038d3d1Sclaudio 	if ((rv = extract_prefix(p, len, &prefix->v6,
6723038d3d1Sclaudio 	    pfxlen, sizeof(prefix->v6))) == -1)
673290f96faSdenis 		return (-1);
674290f96faSdenis 
675290f96faSdenis 	return (plen + rv);
676290f96faSdenis }
677290f96faSdenis 
678fa3a38bbSclaudio static in_addr_t
679fa3a38bbSclaudio prefixlen2mask(uint8_t prefixlen)
680fa3a38bbSclaudio {
681fa3a38bbSclaudio 	if (prefixlen == 0)
682fa3a38bbSclaudio 		return (0);
683290f96faSdenis 
684fa3a38bbSclaudio 	return (0xffffffff << (32 - prefixlen));
685fa3a38bbSclaudio }
686290f96faSdenis 
68729328a94Sclaudio /*
688de5c2eedSclaudio  * This function will have undefined behaviour if the passed in prefixlen is
689290f96faSdenis  * too large for the respective bgpd_addr address family.
690de5c2eedSclaudio  */
691fafbb788Sclaudio int
692fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
693fafbb788Sclaudio     int prefixlen)
694fafbb788Sclaudio {
695fafbb788Sclaudio 	in_addr_t	mask, aa, ba;
696fafbb788Sclaudio 	int		i;
69739386878Sclaudio 	uint8_t		m;
698fafbb788Sclaudio 
699fafbb788Sclaudio 	if (a->aid != b->aid)
700fafbb788Sclaudio 		return (a->aid - b->aid);
701fafbb788Sclaudio 
702fafbb788Sclaudio 	switch (a->aid) {
7033038d3d1Sclaudio 	case AID_VPN_IPv4:
7043038d3d1Sclaudio 		if (be64toh(a->rd) > be64toh(b->rd))
7053038d3d1Sclaudio 			return (1);
7063038d3d1Sclaudio 		if (be64toh(a->rd) < be64toh(b->rd))
7073038d3d1Sclaudio 			return (-1);
7083038d3d1Sclaudio 		/* FALLTHROUGH */
709fafbb788Sclaudio 	case AID_INET:
7107da59fecSclaudio 		if (prefixlen == 0)
7117da59fecSclaudio 			return (0);
712fafbb788Sclaudio 		if (prefixlen > 32)
713de5c2eedSclaudio 			return (-1);
714fafbb788Sclaudio 		mask = htonl(prefixlen2mask(prefixlen));
715fafbb788Sclaudio 		aa = ntohl(a->v4.s_addr & mask);
716fafbb788Sclaudio 		ba = ntohl(b->v4.s_addr & mask);
7173038d3d1Sclaudio 		if (aa > ba)
7183038d3d1Sclaudio 			return (1);
7193038d3d1Sclaudio 		if (aa < ba)
7203038d3d1Sclaudio 			return (-1);
7213038d3d1Sclaudio 		break;
7223038d3d1Sclaudio 	case AID_VPN_IPv6:
7233038d3d1Sclaudio 		if (be64toh(a->rd) > be64toh(b->rd))
7243038d3d1Sclaudio 			return (1);
7253038d3d1Sclaudio 		if (be64toh(a->rd) < be64toh(b->rd))
7263038d3d1Sclaudio 			return (-1);
7273038d3d1Sclaudio 		/* FALLTHROUGH */
728fafbb788Sclaudio 	case AID_INET6:
7297da59fecSclaudio 		if (prefixlen == 0)
7307da59fecSclaudio 			return (0);
731fafbb788Sclaudio 		if (prefixlen > 128)
732de5c2eedSclaudio 			return (-1);
733fafbb788Sclaudio 		for (i = 0; i < prefixlen / 8; i++)
734fafbb788Sclaudio 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
735fafbb788Sclaudio 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
736fafbb788Sclaudio 		i = prefixlen % 8;
737fafbb788Sclaudio 		if (i) {
738fafbb788Sclaudio 			m = 0xff00 >> i;
739fafbb788Sclaudio 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
740fafbb788Sclaudio 			    (b->v6.s6_addr[prefixlen / 8] & m))
741fafbb788Sclaudio 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
742fafbb788Sclaudio 				    (b->v6.s6_addr[prefixlen / 8] & m));
743fafbb788Sclaudio 		}
7443038d3d1Sclaudio 		break;
7453038d3d1Sclaudio 	default:
7463038d3d1Sclaudio 		return (-1);
7473038d3d1Sclaudio 	}
7483038d3d1Sclaudio 
7493038d3d1Sclaudio 	if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) {
7503038d3d1Sclaudio 		if (a->labellen > b->labellen)
7513038d3d1Sclaudio 			return (1);
7523038d3d1Sclaudio 		if (a->labellen < b->labellen)
7533038d3d1Sclaudio 			return (-1);
7543038d3d1Sclaudio 		return (memcmp(a->labelstack, b->labelstack, a->labellen));
7553038d3d1Sclaudio 	}
756fafbb788Sclaudio 	return (0);
7573038d3d1Sclaudio 
758fafbb788Sclaudio }
759fafbb788Sclaudio 
76021a825c9Sclaudio void
7612b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
7622b5c88feSclaudio {
7632b5c88feSclaudio 	struct in_addr mask;
7642b5c88feSclaudio 
7652b5c88feSclaudio 	mask.s_addr = htonl(prefixlen2mask(prefixlen));
7662b5c88feSclaudio 	dest->s_addr = src->s_addr & mask.s_addr;
7672b5c88feSclaudio }
7682b5c88feSclaudio 
7692b5c88feSclaudio void
77021a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
77121a825c9Sclaudio {
77221a825c9Sclaudio 	struct in6_addr	mask;
77321a825c9Sclaudio 	int		i;
77421a825c9Sclaudio 
77521a825c9Sclaudio 	bzero(&mask, sizeof(mask));
77621a825c9Sclaudio 	for (i = 0; i < prefixlen / 8; i++)
77721a825c9Sclaudio 		mask.s6_addr[i] = 0xff;
77821a825c9Sclaudio 	i = prefixlen % 8;
77921a825c9Sclaudio 	if (i)
78021a825c9Sclaudio 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
78121a825c9Sclaudio 
78221a825c9Sclaudio 	for (i = 0; i < 16; i++)
78321a825c9Sclaudio 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
78421a825c9Sclaudio }
785d6c2e4e8Sclaudio 
786d6c2e4e8Sclaudio /* address family translation functions */
787d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS;
788d6c2e4e8Sclaudio 
78986729c90Sclaudio const char *
79039386878Sclaudio aid2str(uint8_t aid)
79186729c90Sclaudio {
79286729c90Sclaudio 	if (aid < AID_MAX)
79386729c90Sclaudio 		return (aid_vals[aid].name);
79486729c90Sclaudio 	return ("unknown AID");
79586729c90Sclaudio }
79686729c90Sclaudio 
797d6c2e4e8Sclaudio int
79839386878Sclaudio aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
799d6c2e4e8Sclaudio {
800d6c2e4e8Sclaudio 	if (aid < AID_MAX) {
801d6c2e4e8Sclaudio 		*afi = aid_vals[aid].afi;
802d6c2e4e8Sclaudio 		*safi = aid_vals[aid].safi;
803d6c2e4e8Sclaudio 		return (0);
804d6c2e4e8Sclaudio 	}
805d6c2e4e8Sclaudio 	return (-1);
806d6c2e4e8Sclaudio }
807d6c2e4e8Sclaudio 
808d6c2e4e8Sclaudio int
80939386878Sclaudio afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
810d6c2e4e8Sclaudio {
81139386878Sclaudio 	uint8_t i;
812d6c2e4e8Sclaudio 
813d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
814d6c2e4e8Sclaudio 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
815d6c2e4e8Sclaudio 			*aid = i;
816d6c2e4e8Sclaudio 			return (0);
817d6c2e4e8Sclaudio 		}
818d6c2e4e8Sclaudio 
819d6c2e4e8Sclaudio 	return (-1);
820d6c2e4e8Sclaudio }
821d6c2e4e8Sclaudio 
822d6c2e4e8Sclaudio sa_family_t
82339386878Sclaudio aid2af(uint8_t aid)
824d6c2e4e8Sclaudio {
825d6c2e4e8Sclaudio 	if (aid < AID_MAX)
826d6c2e4e8Sclaudio 		return (aid_vals[aid].af);
827d6c2e4e8Sclaudio 	return (AF_UNSPEC);
828d6c2e4e8Sclaudio }
829d6c2e4e8Sclaudio 
830d6c2e4e8Sclaudio int
83139386878Sclaudio af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
832d6c2e4e8Sclaudio {
83339386878Sclaudio 	uint8_t i;
834d6c2e4e8Sclaudio 
835d6c2e4e8Sclaudio 	if (safi == 0) /* default to unicast subclass */
836d6c2e4e8Sclaudio 		safi = SAFI_UNICAST;
837d6c2e4e8Sclaudio 
838d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
839d6c2e4e8Sclaudio 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
840d6c2e4e8Sclaudio 			*aid = i;
841d6c2e4e8Sclaudio 			return (0);
842d6c2e4e8Sclaudio 		}
843d6c2e4e8Sclaudio 
844d6c2e4e8Sclaudio 	return (-1);
845d6c2e4e8Sclaudio }
846d6c2e4e8Sclaudio 
84745350f87Sclaudio /*
84845350f87Sclaudio  * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
84945350f87Sclaudio  * the included label stack is ignored and needs to be handled by the caller.
85045350f87Sclaudio  */
851d6c2e4e8Sclaudio struct sockaddr *
85239386878Sclaudio addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
853d6c2e4e8Sclaudio {
854d6c2e4e8Sclaudio 	static struct sockaddr_storage	 ss;
855d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
856d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
857d6c2e4e8Sclaudio 
8584886db4cSclaudio 	if (addr == NULL || addr->aid == AID_UNSPEC)
8594886db4cSclaudio 		return (NULL);
86045350f87Sclaudio 
8614886db4cSclaudio 	bzero(&ss, sizeof(ss));
862d6c2e4e8Sclaudio 	switch (addr->aid) {
863d6c2e4e8Sclaudio 	case AID_INET:
8643038d3d1Sclaudio 	case AID_VPN_IPv4:
865d6c2e4e8Sclaudio 		sa_in->sin_family = AF_INET;
866d6c2e4e8Sclaudio 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
867d6c2e4e8Sclaudio 		sa_in->sin_port = htons(port);
868255fe563Sclaudio 		*len = sizeof(struct sockaddr_in);
869d6c2e4e8Sclaudio 		break;
870d6c2e4e8Sclaudio 	case AID_INET6:
87145350f87Sclaudio 	case AID_VPN_IPv6:
87245350f87Sclaudio 		sa_in6->sin6_family = AF_INET6;
8733038d3d1Sclaudio 		memcpy(&sa_in6->sin6_addr, &addr->v6,
87445350f87Sclaudio 		    sizeof(sa_in6->sin6_addr));
87545350f87Sclaudio 		sa_in6->sin6_port = htons(port);
87645350f87Sclaudio 		sa_in6->sin6_scope_id = addr->scope_id;
87745350f87Sclaudio 		*len = sizeof(struct sockaddr_in6);
87845350f87Sclaudio 		break;
879d6c2e4e8Sclaudio 	}
880d6c2e4e8Sclaudio 
881d6c2e4e8Sclaudio 	return ((struct sockaddr *)&ss);
882d6c2e4e8Sclaudio }
883d6c2e4e8Sclaudio 
884d6c2e4e8Sclaudio void
88539386878Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
886d6c2e4e8Sclaudio {
887d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
888d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
889d6c2e4e8Sclaudio 
890d6c2e4e8Sclaudio 	bzero(addr, sizeof(*addr));
891d6c2e4e8Sclaudio 	switch (sa->sa_family) {
892d6c2e4e8Sclaudio 	case AF_INET:
893d6c2e4e8Sclaudio 		addr->aid = AID_INET;
894d6c2e4e8Sclaudio 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
895a27d9e33Sclaudio 		if (port)
896a27d9e33Sclaudio 			*port = ntohs(sa_in->sin_port);
897d6c2e4e8Sclaudio 		break;
898d6c2e4e8Sclaudio 	case AF_INET6:
899d6c2e4e8Sclaudio 		addr->aid = AID_INET6;
900be6ced5eSclaudio #ifdef __KAME__
901be6ced5eSclaudio 		/*
902be6ced5eSclaudio 		 * XXX thanks, KAME, for this ugliness...
903be6ced5eSclaudio 		 * adopted from route/show.c
904be6ced5eSclaudio 		 */
905*5177244fSclaudio 		if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
906*5177244fSclaudio 		    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) ||
907*5177244fSclaudio 		    IN6_IS_ADDR_MC_INTFACELOCAL(&sa_in6->sin6_addr)) &&
908*5177244fSclaudio 		    sa_in6->sin6_scope_id == 0) {
909be6ced5eSclaudio 			uint16_t tmp16;
910be6ced5eSclaudio 			memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
911be6ced5eSclaudio 			    sizeof(tmp16));
912be6ced5eSclaudio 			sa_in6->sin6_scope_id = ntohs(tmp16);
913be6ced5eSclaudio 			sa_in6->sin6_addr.s6_addr[2] = 0;
914be6ced5eSclaudio 			sa_in6->sin6_addr.s6_addr[3] = 0;
915be6ced5eSclaudio 		}
916be6ced5eSclaudio #endif
917*5177244fSclaudio 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
918d6c2e4e8Sclaudio 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
919a27d9e33Sclaudio 		if (port)
920a27d9e33Sclaudio 			*port = ntohs(sa_in6->sin6_port);
921d6c2e4e8Sclaudio 		break;
922d6c2e4e8Sclaudio 	}
923d6c2e4e8Sclaudio }
9246e8089a5Sclaudio 
9256e8089a5Sclaudio const char *
926bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit)
9276e8089a5Sclaudio {
9286e8089a5Sclaudio 	static char bbuf[16];
9293eaf1285Sclaudio 	const unsigned long long kilo = 1000;
9303eaf1285Sclaudio 	const unsigned long long mega = 1000ULL * kilo;
9313eaf1285Sclaudio 	const unsigned long long giga = 1000ULL * mega;
9326e8089a5Sclaudio 
9333eaf1285Sclaudio 	if (baudrate > giga)
9346e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
9353eaf1285Sclaudio 		    baudrate / giga, unit);
9363eaf1285Sclaudio 	else if (baudrate > mega)
9376e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
9383eaf1285Sclaudio 		    baudrate / mega, unit);
9393eaf1285Sclaudio 	else if (baudrate > kilo)
9406e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
9413eaf1285Sclaudio 		    baudrate / kilo, unit);
9426e8089a5Sclaudio 	else
9436e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
9446e8089a5Sclaudio 		    baudrate, unit);
9456e8089a5Sclaudio 
9466e8089a5Sclaudio 	return (bbuf);
9476e8089a5Sclaudio }
948