xref: /openbsd/usr.sbin/bgpd/util.c (revision 4886db4c)
1*4886db4cSclaudio /*	$OpenBSD: util.c,v 1.58 2021/01/05 10:00:28 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 
351e590dcfSclaudio const char	*aspath_delim(u_int8_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:
50256b680eSclaudio 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
5145350f87Sclaudio 		    log_sockaddr(sa, len));
5215d8de66Sclaudio 		return (buf);
53290f96faSdenis 	case AID_VPN_IPv6:
54290f96faSdenis 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn6.rd),
5545350f87Sclaudio 		    log_sockaddr(sa, len));
56290f96faSdenis 		return (buf);
5715d8de66Sclaudio 	}
5815d8de66Sclaudio 	return ("???");
592ffcd4e0Sclaudio }
602ffcd4e0Sclaudio 
612ffcd4e0Sclaudio const char *
622ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr)
632ffcd4e0Sclaudio {
642ffcd4e0Sclaudio 	struct sockaddr_in6	sa_in6;
652ffcd4e0Sclaudio 
662ffcd4e0Sclaudio 	bzero(&sa_in6, sizeof(sa_in6));
672ffcd4e0Sclaudio 	sa_in6.sin6_family = AF_INET6;
682ffcd4e0Sclaudio 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
692ffcd4e0Sclaudio 
70be6ced5eSclaudio #ifdef __KAME__
712ffcd4e0Sclaudio 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
722ffcd4e0Sclaudio 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
732ffcd4e0Sclaudio 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
74a5df8d9bSclaudio 		u_int16_t tmp16;
752ffcd4e0Sclaudio 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
762ffcd4e0Sclaudio 		sa_in6.sin6_scope_id = ntohs(tmp16);
772ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[2] = 0;
782ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[3] = 0;
792ffcd4e0Sclaudio 	}
80be6ced5eSclaudio #endif
812ffcd4e0Sclaudio 
82255fe563Sclaudio 	return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
832ffcd4e0Sclaudio }
842ffcd4e0Sclaudio 
852ffcd4e0Sclaudio const char *
86255fe563Sclaudio log_sockaddr(struct sockaddr *sa, socklen_t len)
872ffcd4e0Sclaudio {
882ffcd4e0Sclaudio 	static char	buf[NI_MAXHOST];
892ffcd4e0Sclaudio 
9045350f87Sclaudio 	if (sa == NULL || getnameinfo(sa, len, buf, sizeof(buf), NULL, 0,
912ffcd4e0Sclaudio 	    NI_NUMERICHOST))
922ffcd4e0Sclaudio 		return ("(unknown)");
932ffcd4e0Sclaudio 	else
942ffcd4e0Sclaudio 		return (buf);
952ffcd4e0Sclaudio }
962ffcd4e0Sclaudio 
970c88bf70Sclaudio const char *
980c88bf70Sclaudio log_as(u_int32_t as)
990c88bf70Sclaudio {
10006bcde9cSphessler 	static char	buf[11];	/* "4294967294\0" */
1010c88bf70Sclaudio 
102515e489cSderaadt 	if (snprintf(buf, sizeof(buf), "%u", as) < 0)
1030c88bf70Sclaudio 		return ("?");
10406bcde9cSphessler 
1050c88bf70Sclaudio 	return (buf);
1060c88bf70Sclaudio }
1070c88bf70Sclaudio 
108256b680eSclaudio const char *
109256b680eSclaudio log_rd(u_int64_t rd)
110256b680eSclaudio {
111256b680eSclaudio 	static char	buf[32];
112256b680eSclaudio 	struct in_addr	addr;
113256b680eSclaudio 	u_int32_t	u32;
114256b680eSclaudio 	u_int16_t	u16;
115256b680eSclaudio 
116f4c0eb52Sclaudio 	rd = be64toh(rd);
117256b680eSclaudio 	switch (rd >> 48) {
118bf8e2920Sclaudio 	case EXT_COMMUNITY_TRANS_TWO_AS:
119256b680eSclaudio 		u32 = rd & 0xffffffff;
120256b680eSclaudio 		u16 = (rd >> 32) & 0xffff;
12132ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
122256b680eSclaudio 		break;
123bf8e2920Sclaudio 	case EXT_COMMUNITY_TRANS_FOUR_AS:
124256b680eSclaudio 		u32 = (rd >> 16) & 0xffffffff;
125256b680eSclaudio 		u16 = rd & 0xffff;
12632ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
127256b680eSclaudio 		break;
128bf8e2920Sclaudio 	case EXT_COMMUNITY_TRANS_IPV4:
129256b680eSclaudio 		u32 = (rd >> 16) & 0xffffffff;
130256b680eSclaudio 		u16 = rd & 0xffff;
131256b680eSclaudio 		addr.s_addr = htonl(u32);
13232ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
133256b680eSclaudio 		break;
134256b680eSclaudio 	default:
135256b680eSclaudio 		return ("rd ?");
136256b680eSclaudio 	}
137256b680eSclaudio 	return (buf);
138256b680eSclaudio }
139256b680eSclaudio 
140bf8e2920Sclaudio const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
141bf8e2920Sclaudio 
142256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is
143536f41e5Sclaudio  * actually valid. */
144536f41e5Sclaudio const char *
1450e6216fdSclaudio log_ext_subtype(short type, u_int8_t subtype)
146536f41e5Sclaudio {
147536f41e5Sclaudio 	static char etype[6];
148bf8e2920Sclaudio 	const struct ext_comm_pairs *cp;
149536f41e5Sclaudio 
150bf8e2920Sclaudio 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
1510e6216fdSclaudio 		if ((type == cp->type || type == -1) && subtype == cp->subtype)
152bf8e2920Sclaudio 			return (cp->subname);
153bf8e2920Sclaudio 	}
154d6340f7aSderaadt 	snprintf(etype, sizeof(etype), "[%u]", subtype);
155536f41e5Sclaudio 	return (etype);
156536f41e5Sclaudio }
157536f41e5Sclaudio 
1581e590dcfSclaudio const char *
159a78f83ceSderaadt log_reason(const char *communication) {
160a78f83ceSderaadt 	static char buf[(REASON_LEN - 1) * 4 + 1];
1610561b344Sphessler 
1620561b344Sphessler 	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
1630561b344Sphessler 
1640561b344Sphessler 	return buf;
1650561b344Sphessler }
1660561b344Sphessler 
1670561b344Sphessler const char *
1681e590dcfSclaudio aspath_delim(u_int8_t seg_type, int closing)
1691e590dcfSclaudio {
1701e590dcfSclaudio 	static char db[8];
1711e590dcfSclaudio 
1721e590dcfSclaudio 	switch (seg_type) {
1731e590dcfSclaudio 	case AS_SET:
1741e590dcfSclaudio 		if (!closing)
1751e590dcfSclaudio 			return ("{ ");
1761e590dcfSclaudio 		else
1771e590dcfSclaudio 			return (" }");
1781e590dcfSclaudio 	case AS_SEQUENCE:
1791e590dcfSclaudio 		return ("");
1801e590dcfSclaudio 	case AS_CONFED_SEQUENCE:
1811e590dcfSclaudio 		if (!closing)
1821e590dcfSclaudio 			return ("( ");
1831e590dcfSclaudio 		else
1841e590dcfSclaudio 			return (" )");
1851e590dcfSclaudio 	case AS_CONFED_SET:
1861e590dcfSclaudio 		if (!closing)
1871e590dcfSclaudio 			return ("[ ");
1881e590dcfSclaudio 		else
1891e590dcfSclaudio 			return (" ]");
1901e590dcfSclaudio 	default:
1911e590dcfSclaudio 		if (!closing)
1921e590dcfSclaudio 			snprintf(db, sizeof(db), "!%u ", seg_type);
1931e590dcfSclaudio 		else
1941e590dcfSclaudio 			snprintf(db, sizeof(db), " !%u", seg_type);
1951e590dcfSclaudio 		return (db);
1961e590dcfSclaudio 	}
1971e590dcfSclaudio }
1981e590dcfSclaudio 
1992ffcd4e0Sclaudio int
2002ffcd4e0Sclaudio aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
2012ffcd4e0Sclaudio {
2022ffcd4e0Sclaudio #define UPDATE()				\
2032ffcd4e0Sclaudio 	do {					\
204515e489cSderaadt 		if (r < 0)			\
2052ffcd4e0Sclaudio 			return (-1);		\
2062ffcd4e0Sclaudio 		total_size += r;		\
2072ffcd4e0Sclaudio 		if ((unsigned int)r < size) {	\
2082ffcd4e0Sclaudio 			size -= r;		\
2092ffcd4e0Sclaudio 			buf += r;		\
2102ffcd4e0Sclaudio 		} else {			\
2112ffcd4e0Sclaudio 			buf += size;		\
2122ffcd4e0Sclaudio 			size = 0;		\
2132ffcd4e0Sclaudio 		}				\
2142ffcd4e0Sclaudio 	} while (0)
2152ffcd4e0Sclaudio 	u_int8_t	*seg;
2162ffcd4e0Sclaudio 	int		 r, total_size;
2172ffcd4e0Sclaudio 	u_int16_t	 seg_size;
2182ffcd4e0Sclaudio 	u_int8_t	 i, seg_type, seg_len;
2192ffcd4e0Sclaudio 
2202ffcd4e0Sclaudio 	total_size = 0;
2212ffcd4e0Sclaudio 	seg = data;
2222ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
2232ffcd4e0Sclaudio 		seg_type = seg[0];
2242ffcd4e0Sclaudio 		seg_len = seg[1];
2250c88bf70Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
2262ffcd4e0Sclaudio 
2271e590dcfSclaudio 		r = snprintf(buf, size, "%s%s",
2281e590dcfSclaudio 		    total_size != 0 ? " " : "",
2291e590dcfSclaudio 		    aspath_delim(seg_type, 0));
2302ffcd4e0Sclaudio 		UPDATE();
2312ffcd4e0Sclaudio 
2322ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
2330c88bf70Sclaudio 			r = snprintf(buf, size, "%s",
2340c88bf70Sclaudio 			    log_as(aspath_extract(seg, i)));
2352ffcd4e0Sclaudio 			UPDATE();
2362ffcd4e0Sclaudio 			if (i + 1 < seg_len) {
2372ffcd4e0Sclaudio 				r = snprintf(buf, size, " ");
2382ffcd4e0Sclaudio 				UPDATE();
2392ffcd4e0Sclaudio 			}
2402ffcd4e0Sclaudio 		}
2411e590dcfSclaudio 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
2422ffcd4e0Sclaudio 		UPDATE();
2432ffcd4e0Sclaudio 	}
24455e49665Sclaudio 	/* ensure that we have a valid C-string especially for empty as path */
2452ffcd4e0Sclaudio 	if (size > 0)
2462ffcd4e0Sclaudio 		*buf = '\0';
2472ffcd4e0Sclaudio 
2482ffcd4e0Sclaudio 	return (total_size);
2492ffcd4e0Sclaudio #undef UPDATE
2502ffcd4e0Sclaudio }
2512ffcd4e0Sclaudio 
2522ffcd4e0Sclaudio int
2532ffcd4e0Sclaudio aspath_asprint(char **ret, void *data, u_int16_t len)
2542ffcd4e0Sclaudio {
2552ffcd4e0Sclaudio 	size_t	slen;
2562ffcd4e0Sclaudio 	int	plen;
2572ffcd4e0Sclaudio 
2582ffcd4e0Sclaudio 	slen = aspath_strlen(data, len) + 1;
2592ffcd4e0Sclaudio 	*ret = malloc(slen);
2602ffcd4e0Sclaudio 	if (*ret == NULL)
2612ffcd4e0Sclaudio 		return (-1);
2622ffcd4e0Sclaudio 
2632ffcd4e0Sclaudio 	plen = aspath_snprint(*ret, slen, data, len);
2642ffcd4e0Sclaudio 	if (plen == -1) {
2652ffcd4e0Sclaudio 		free(*ret);
2662ffcd4e0Sclaudio 		*ret = NULL;
2672ffcd4e0Sclaudio 		return (-1);
2682ffcd4e0Sclaudio 	}
2692ffcd4e0Sclaudio 
2702ffcd4e0Sclaudio 	return (0);
2712ffcd4e0Sclaudio }
2722ffcd4e0Sclaudio 
2732ffcd4e0Sclaudio size_t
2742ffcd4e0Sclaudio aspath_strlen(void *data, u_int16_t len)
2752ffcd4e0Sclaudio {
2762ffcd4e0Sclaudio 	u_int8_t	*seg;
2772ffcd4e0Sclaudio 	int		 total_size;
2780c88bf70Sclaudio 	u_int32_t	 as;
2790c88bf70Sclaudio 	u_int16_t	 seg_size;
2802ffcd4e0Sclaudio 	u_int8_t	 i, seg_type, seg_len;
2812ffcd4e0Sclaudio 
2822ffcd4e0Sclaudio 	total_size = 0;
2832ffcd4e0Sclaudio 	seg = data;
2842ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
2852ffcd4e0Sclaudio 		seg_type = seg[0];
2862ffcd4e0Sclaudio 		seg_len = seg[1];
2870c88bf70Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
2882ffcd4e0Sclaudio 
2892ffcd4e0Sclaudio 		if (seg_type == AS_SET)
2902ffcd4e0Sclaudio 			if (total_size != 0)
2912ffcd4e0Sclaudio 				total_size += 3;
2922ffcd4e0Sclaudio 			else
2932ffcd4e0Sclaudio 				total_size += 2;
2942ffcd4e0Sclaudio 		else if (total_size != 0)
2952ffcd4e0Sclaudio 			total_size += 1;
2962ffcd4e0Sclaudio 
2972ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
2982ffcd4e0Sclaudio 			as = aspath_extract(seg, i);
2990c88bf70Sclaudio 
3008db4f5d2Sclaudio 			do {
3018db4f5d2Sclaudio 				total_size++;
3028db4f5d2Sclaudio 			} while ((as = as / 10) != 0);
3032ffcd4e0Sclaudio 
3042ffcd4e0Sclaudio 			if (i + 1 < seg_len)
3052ffcd4e0Sclaudio 				total_size += 1;
3062ffcd4e0Sclaudio 		}
3072ffcd4e0Sclaudio 
3082ffcd4e0Sclaudio 		if (seg_type == AS_SET)
3092ffcd4e0Sclaudio 			total_size += 2;
3102ffcd4e0Sclaudio 	}
3112ffcd4e0Sclaudio 	return (total_size);
3122ffcd4e0Sclaudio }
3132ffcd4e0Sclaudio 
3142ffcd4e0Sclaudio /*
3152ffcd4e0Sclaudio  * Extract the asnum out of the as segment at the specified position.
3162ffcd4e0Sclaudio  * Direct access is not possible because of non-aligned reads.
317c5508ee4Sclaudio  * ATTENTION: no bounds checks are done.
3182ffcd4e0Sclaudio  */
3190c88bf70Sclaudio u_int32_t
3202ffcd4e0Sclaudio aspath_extract(const void *seg, int pos)
3212ffcd4e0Sclaudio {
3222ffcd4e0Sclaudio 	const u_char	*ptr = seg;
3230c88bf70Sclaudio 	u_int32_t	 as;
3242ffcd4e0Sclaudio 
3250c88bf70Sclaudio 	ptr += 2 + sizeof(u_int32_t) * pos;
3260c88bf70Sclaudio 	memcpy(&as, ptr, sizeof(u_int32_t));
3270c88bf70Sclaudio 	return (ntohl(as));
3282ffcd4e0Sclaudio }
32921a825c9Sclaudio 
330de5c2eedSclaudio /*
33129328a94Sclaudio  * Verify that the aspath is correctly encoded.
33229328a94Sclaudio  */
33329328a94Sclaudio int
33429328a94Sclaudio aspath_verify(void *data, u_int16_t len, int as4byte)
33529328a94Sclaudio {
33629328a94Sclaudio 	u_int8_t	*seg = data;
33729328a94Sclaudio 	u_int16_t	 seg_size, as_size = 2;
33829328a94Sclaudio 	u_int8_t	 seg_len, seg_type;
33929328a94Sclaudio 	int		 error = 0;
34029328a94Sclaudio 
34129328a94Sclaudio 	if (len & 1)
34229328a94Sclaudio 		/* odd length aspath are invalid */
34329328a94Sclaudio 		return (AS_ERR_BAD);
34429328a94Sclaudio 
34529328a94Sclaudio 	if (as4byte)
34629328a94Sclaudio 		as_size = 4;
34729328a94Sclaudio 
34829328a94Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
34951491708Sclaudio 		const u_int8_t	*ptr;
35029328a94Sclaudio 		int		 pos;
35129328a94Sclaudio 
35229328a94Sclaudio 		if (len < 2)	/* header length check */
35329328a94Sclaudio 			return (AS_ERR_BAD);
35429328a94Sclaudio 		seg_type = seg[0];
35529328a94Sclaudio 		seg_len = seg[1];
35629328a94Sclaudio 
357d04df938Sclaudio 		if (seg_len == 0)
358d04df938Sclaudio 			/* empty aspath segments are not allowed */
359d04df938Sclaudio 			return (AS_ERR_BAD);
360d04df938Sclaudio 
36129328a94Sclaudio 		/*
36229328a94Sclaudio 		 * BGP confederations should not show up but consider them
36329328a94Sclaudio 		 * as a soft error which invalidates the path but keeps the
36429328a94Sclaudio 		 * bgp session running.
36529328a94Sclaudio 		 */
36629328a94Sclaudio 		if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
36729328a94Sclaudio 			error = AS_ERR_SOFT;
36829328a94Sclaudio 		if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
36929328a94Sclaudio 		    seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET)
37029328a94Sclaudio 			return (AS_ERR_TYPE);
37129328a94Sclaudio 
37229328a94Sclaudio 		seg_size = 2 + as_size * seg_len;
37329328a94Sclaudio 
37429328a94Sclaudio 		if (seg_size > len)
37529328a94Sclaudio 			return (AS_ERR_LEN);
37629328a94Sclaudio 
37729328a94Sclaudio 		/* RFC 7607 - AS 0 is considered malformed */
37829328a94Sclaudio 		ptr = seg + 2;
37929328a94Sclaudio 		for (pos = 0; pos < seg_len; pos++) {
38051491708Sclaudio 			u_int32_t as;
38129328a94Sclaudio 
38229328a94Sclaudio 			memcpy(&as, ptr, as_size);
38329328a94Sclaudio 			if (as == 0)
38456a9a1b8Sclaudio 				error = AS_ERR_SOFT;
38551491708Sclaudio 			ptr += as_size;
38629328a94Sclaudio 		}
38729328a94Sclaudio 	}
38829328a94Sclaudio 	return (error);	/* aspath is valid but probably not loop free */
38929328a94Sclaudio }
39029328a94Sclaudio 
39129328a94Sclaudio /*
39229328a94Sclaudio  * convert a 2 byte aspath to a 4 byte one.
39329328a94Sclaudio  */
39429328a94Sclaudio u_char *
39529328a94Sclaudio aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen)
39629328a94Sclaudio {
39729328a94Sclaudio 	u_int8_t	*seg, *nseg, *ndata;
39829328a94Sclaudio 	u_int16_t	 seg_size, olen, nlen;
39929328a94Sclaudio 	u_int8_t	 seg_len;
40029328a94Sclaudio 
40129328a94Sclaudio 	/* first calculate the length of the aspath */
40229328a94Sclaudio 	seg = data;
40329328a94Sclaudio 	nlen = 0;
40429328a94Sclaudio 	for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
40529328a94Sclaudio 		seg_len = seg[1];
40629328a94Sclaudio 		seg_size = 2 + sizeof(u_int16_t) * seg_len;
40729328a94Sclaudio 		nlen += 2 + sizeof(u_int32_t) * seg_len;
40829328a94Sclaudio 
40929328a94Sclaudio 		if (seg_size > olen) {
41029328a94Sclaudio 			errno = ERANGE;
41129328a94Sclaudio 			return (NULL);
41229328a94Sclaudio 		}
41329328a94Sclaudio 	}
41429328a94Sclaudio 
41529328a94Sclaudio 	*newlen = nlen;
41629328a94Sclaudio 	if ((ndata = malloc(nlen)) == NULL)
41729328a94Sclaudio 		return (NULL);
41829328a94Sclaudio 
41929328a94Sclaudio 	/* then copy the aspath */
42029328a94Sclaudio 	seg = data;
42129328a94Sclaudio 	for (nseg = ndata; nseg < ndata + nlen; ) {
42229328a94Sclaudio 		*nseg++ = *seg++;
42329328a94Sclaudio 		*nseg++ = seg_len = *seg++;
42429328a94Sclaudio 		for (; seg_len > 0; seg_len--) {
42529328a94Sclaudio 			*nseg++ = 0;
42629328a94Sclaudio 			*nseg++ = 0;
42729328a94Sclaudio 			*nseg++ = *seg++;
42829328a94Sclaudio 			*nseg++ = *seg++;
42929328a94Sclaudio 		}
43029328a94Sclaudio 	}
43129328a94Sclaudio 
43229328a94Sclaudio 	return (ndata);
43329328a94Sclaudio }
43429328a94Sclaudio 
4356d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */
4366d3e8673Sclaudio static int
4376d3e8673Sclaudio extract_prefix(u_char *p, u_int16_t len, void *va,
4386d3e8673Sclaudio     u_int8_t pfxlen, u_int8_t max)
4396d3e8673Sclaudio {
4406d3e8673Sclaudio 	static u_char addrmask[] = {
4416d3e8673Sclaudio 	    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
4426d3e8673Sclaudio 	u_char		*a = va;
4436d3e8673Sclaudio 	int		 i;
4446d3e8673Sclaudio 	u_int16_t	 plen = 0;
4456d3e8673Sclaudio 
4466d3e8673Sclaudio 	for (i = 0; pfxlen && i < max; i++) {
4476d3e8673Sclaudio 		if (len <= plen)
4486d3e8673Sclaudio 			return (-1);
4496d3e8673Sclaudio 		if (pfxlen < 8) {
4506d3e8673Sclaudio 			a[i] = *p++ & addrmask[pfxlen];
4516d3e8673Sclaudio 			plen++;
4526d3e8673Sclaudio 			break;
4536d3e8673Sclaudio 		} else {
4546d3e8673Sclaudio 			a[i] = *p++;
4556d3e8673Sclaudio 			plen++;
4566d3e8673Sclaudio 			pfxlen -= 8;
4576d3e8673Sclaudio 		}
4586d3e8673Sclaudio 	}
4596d3e8673Sclaudio 	return (plen);
4606d3e8673Sclaudio }
4616d3e8673Sclaudio 
4626d3e8673Sclaudio int
4636d3e8673Sclaudio nlri_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
4646d3e8673Sclaudio     u_int8_t *prefixlen)
4656d3e8673Sclaudio {
4666d3e8673Sclaudio 	u_int8_t	 pfxlen;
4676d3e8673Sclaudio 	int		 plen;
4686d3e8673Sclaudio 
4696d3e8673Sclaudio 	if (len < 1)
4706d3e8673Sclaudio 		return (-1);
4716d3e8673Sclaudio 
4726d3e8673Sclaudio 	pfxlen = *p++;
4736d3e8673Sclaudio 	len--;
4746d3e8673Sclaudio 
4756d3e8673Sclaudio 	bzero(prefix, sizeof(struct bgpd_addr));
4766d3e8673Sclaudio 	prefix->aid = AID_INET;
4776d3e8673Sclaudio 	*prefixlen = pfxlen;
4786d3e8673Sclaudio 
4796d3e8673Sclaudio 	if (pfxlen > 32)
4806d3e8673Sclaudio 		return (-1);
4816d3e8673Sclaudio 	if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen,
4826d3e8673Sclaudio 	    sizeof(prefix->v4))) == -1)
4836d3e8673Sclaudio 		return (-1);
4846d3e8673Sclaudio 
4856d3e8673Sclaudio 	return (plen + 1);	/* pfxlen needs to be added */
4866d3e8673Sclaudio }
4876d3e8673Sclaudio 
4886d3e8673Sclaudio int
4896d3e8673Sclaudio nlri_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
4906d3e8673Sclaudio     u_int8_t *prefixlen)
4916d3e8673Sclaudio {
4926d3e8673Sclaudio 	int		plen;
4936d3e8673Sclaudio 	u_int8_t	pfxlen;
4946d3e8673Sclaudio 
4956d3e8673Sclaudio 	if (len < 1)
4966d3e8673Sclaudio 		return (-1);
4976d3e8673Sclaudio 
4986d3e8673Sclaudio 	pfxlen = *p++;
4996d3e8673Sclaudio 	len--;
5006d3e8673Sclaudio 
5016d3e8673Sclaudio 	bzero(prefix, sizeof(struct bgpd_addr));
5026d3e8673Sclaudio 	prefix->aid = AID_INET6;
5036d3e8673Sclaudio 	*prefixlen = pfxlen;
5046d3e8673Sclaudio 
5056d3e8673Sclaudio 	if (pfxlen > 128)
5066d3e8673Sclaudio 		return (-1);
5076d3e8673Sclaudio 	if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen,
5086d3e8673Sclaudio 	    sizeof(prefix->v6))) == -1)
5096d3e8673Sclaudio 		return (-1);
5106d3e8673Sclaudio 
5116d3e8673Sclaudio 	return (plen + 1);	/* pfxlen needs to be added */
5126d3e8673Sclaudio }
5136d3e8673Sclaudio 
5146d3e8673Sclaudio int
5156d3e8673Sclaudio nlri_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
5166d3e8673Sclaudio     u_int8_t *prefixlen, int withdraw)
5176d3e8673Sclaudio {
5186d3e8673Sclaudio 	int		 rv, done = 0;
5196d3e8673Sclaudio 	u_int8_t	 pfxlen;
5206d3e8673Sclaudio 	u_int16_t	 plen;
5216d3e8673Sclaudio 
5226d3e8673Sclaudio 	if (len < 1)
5236d3e8673Sclaudio 		return (-1);
5246d3e8673Sclaudio 
5256d3e8673Sclaudio 	memcpy(&pfxlen, p, 1);
5266d3e8673Sclaudio 	p += 1;
5276d3e8673Sclaudio 	plen = 1;
5286d3e8673Sclaudio 
5296d3e8673Sclaudio 	bzero(prefix, sizeof(struct bgpd_addr));
5306d3e8673Sclaudio 
5316d3e8673Sclaudio 	/* label stack */
5326d3e8673Sclaudio 	do {
5336d3e8673Sclaudio 		if (len - plen < 3 || pfxlen < 3 * 8)
5346d3e8673Sclaudio 			return (-1);
5356d3e8673Sclaudio 		if (prefix->vpn4.labellen + 3U >
5366d3e8673Sclaudio 		    sizeof(prefix->vpn4.labelstack))
5376d3e8673Sclaudio 			return (-1);
5386d3e8673Sclaudio 		if (withdraw) {
5396d3e8673Sclaudio 			/* on withdraw ignore the labelstack all together */
5406d3e8673Sclaudio 			plen += 3;
5416d3e8673Sclaudio 			pfxlen -= 3 * 8;
5426d3e8673Sclaudio 			break;
5436d3e8673Sclaudio 		}
5446d3e8673Sclaudio 		prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
5456d3e8673Sclaudio 		prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
5466d3e8673Sclaudio 		prefix->vpn4.labelstack[prefix->vpn4.labellen] = *p++;
5476d3e8673Sclaudio 		if (prefix->vpn4.labelstack[prefix->vpn4.labellen] &
5486d3e8673Sclaudio 		    BGP_MPLS_BOS)
5496d3e8673Sclaudio 			done = 1;
5506d3e8673Sclaudio 		prefix->vpn4.labellen++;
5516d3e8673Sclaudio 		plen += 3;
5526d3e8673Sclaudio 		pfxlen -= 3 * 8;
5536d3e8673Sclaudio 	} while (!done);
5546d3e8673Sclaudio 
5556d3e8673Sclaudio 	/* RD */
5566d3e8673Sclaudio 	if (len - plen < (int)sizeof(u_int64_t) ||
5576d3e8673Sclaudio 	    pfxlen < sizeof(u_int64_t) * 8)
5586d3e8673Sclaudio 		return (-1);
5596d3e8673Sclaudio 	memcpy(&prefix->vpn4.rd, p, sizeof(u_int64_t));
5606d3e8673Sclaudio 	pfxlen -= sizeof(u_int64_t) * 8;
5616d3e8673Sclaudio 	p += sizeof(u_int64_t);
5626d3e8673Sclaudio 	plen += sizeof(u_int64_t);
5636d3e8673Sclaudio 
5646d3e8673Sclaudio 	/* prefix */
5656d3e8673Sclaudio 	prefix->aid = AID_VPN_IPv4;
5666d3e8673Sclaudio 	*prefixlen = pfxlen;
5676d3e8673Sclaudio 
5686d3e8673Sclaudio 	if (pfxlen > 32)
5696d3e8673Sclaudio 		return (-1);
5706d3e8673Sclaudio 	if ((rv = extract_prefix(p, len, &prefix->vpn4.addr,
5716d3e8673Sclaudio 	    pfxlen, sizeof(prefix->vpn4.addr))) == -1)
5726d3e8673Sclaudio 		return (-1);
5736d3e8673Sclaudio 
5746d3e8673Sclaudio 	return (plen + rv);
5756d3e8673Sclaudio }
5766d3e8673Sclaudio 
577290f96faSdenis int
578290f96faSdenis nlri_get_vpn6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
579290f96faSdenis     u_int8_t *prefixlen, int withdraw)
580290f96faSdenis {
581290f96faSdenis 	int		rv, done = 0;
582290f96faSdenis 	u_int8_t	pfxlen;
583290f96faSdenis 	u_int16_t	plen;
584290f96faSdenis 
585290f96faSdenis 	if (len < 1)
586290f96faSdenis 		return (-1);
587290f96faSdenis 
588290f96faSdenis 	memcpy(&pfxlen, p, 1);
589290f96faSdenis 	p += 1;
590290f96faSdenis 	plen = 1;
591290f96faSdenis 
592290f96faSdenis 	memset(prefix, 0, sizeof(struct bgpd_addr));
593290f96faSdenis 
594290f96faSdenis 	/* label stack */
595290f96faSdenis 	do {
596290f96faSdenis 		if (len - plen < 3 || pfxlen < 3 * 8)
597290f96faSdenis 			return (-1);
598290f96faSdenis 		if (prefix->vpn6.labellen + 3U >
599290f96faSdenis 		    sizeof(prefix->vpn6.labelstack))
600290f96faSdenis 			return (-1);
601290f96faSdenis 		if (withdraw) {
602290f96faSdenis 			/* on withdraw ignore the labelstack all together */
603290f96faSdenis 			plen += 3;
604290f96faSdenis 			pfxlen -= 3 * 8;
605290f96faSdenis 			break;
606290f96faSdenis 		}
607290f96faSdenis 
608290f96faSdenis 		prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++;
609290f96faSdenis 		prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++;
610290f96faSdenis 		prefix->vpn6.labelstack[prefix->vpn6.labellen] = *p++;
611290f96faSdenis 		if (prefix->vpn6.labelstack[prefix->vpn6.labellen] &
612290f96faSdenis 		    BGP_MPLS_BOS)
613290f96faSdenis 			done = 1;
614290f96faSdenis 		prefix->vpn6.labellen++;
615290f96faSdenis 		plen += 3;
616290f96faSdenis 		pfxlen -= 3 * 8;
617290f96faSdenis 	} while (!done);
618290f96faSdenis 
619290f96faSdenis 	/* RD */
620290f96faSdenis 	if (len - plen < (int)sizeof(u_int64_t) ||
621290f96faSdenis 	    pfxlen < sizeof(u_int64_t) * 8)
622290f96faSdenis 		return (-1);
623290f96faSdenis 
624290f96faSdenis 	memcpy(&prefix->vpn6.rd, p, sizeof(u_int64_t));
625290f96faSdenis 	pfxlen -= sizeof(u_int64_t) * 8;
626290f96faSdenis 	p += sizeof(u_int64_t);
627290f96faSdenis 	plen += sizeof(u_int64_t);
628290f96faSdenis 
629290f96faSdenis 	/* prefix */
630290f96faSdenis 	prefix->aid = AID_VPN_IPv6;
631290f96faSdenis 	*prefixlen = pfxlen;
632290f96faSdenis 
633290f96faSdenis 	if (pfxlen > 128)
634290f96faSdenis 		return (-1);
635290f96faSdenis 
636290f96faSdenis 	if ((rv = extract_prefix(p, len, &prefix->vpn6.addr,
637290f96faSdenis 	    pfxlen, sizeof(prefix->vpn6.addr))) == -1)
638290f96faSdenis 		return (-1);
639290f96faSdenis 
640290f96faSdenis 	return (plen + rv);
641290f96faSdenis }
642290f96faSdenis 
643290f96faSdenis 
644290f96faSdenis 
64529328a94Sclaudio /*
646de5c2eedSclaudio  * This function will have undefined behaviour if the passed in prefixlen is
647290f96faSdenis  * too large for the respective bgpd_addr address family.
648de5c2eedSclaudio  */
649fafbb788Sclaudio int
650fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
651fafbb788Sclaudio     int prefixlen)
652fafbb788Sclaudio {
653fafbb788Sclaudio 	in_addr_t	mask, aa, ba;
654fafbb788Sclaudio 	int		i;
655fafbb788Sclaudio 	u_int8_t	m;
656fafbb788Sclaudio 
657fafbb788Sclaudio 	if (a->aid != b->aid)
658fafbb788Sclaudio 		return (a->aid - b->aid);
659fafbb788Sclaudio 
660fafbb788Sclaudio 	switch (a->aid) {
661fafbb788Sclaudio 	case AID_INET:
6627da59fecSclaudio 		if (prefixlen == 0)
6637da59fecSclaudio 			return (0);
664fafbb788Sclaudio 		if (prefixlen > 32)
665de5c2eedSclaudio 			return (-1);
666fafbb788Sclaudio 		mask = htonl(prefixlen2mask(prefixlen));
667fafbb788Sclaudio 		aa = ntohl(a->v4.s_addr & mask);
668fafbb788Sclaudio 		ba = ntohl(b->v4.s_addr & mask);
669fafbb788Sclaudio 		if (aa != ba)
670fafbb788Sclaudio 			return (aa - ba);
671fafbb788Sclaudio 		return (0);
672fafbb788Sclaudio 	case AID_INET6:
6737da59fecSclaudio 		if (prefixlen == 0)
6747da59fecSclaudio 			return (0);
675fafbb788Sclaudio 		if (prefixlen > 128)
676de5c2eedSclaudio 			return (-1);
677fafbb788Sclaudio 		for (i = 0; i < prefixlen / 8; i++)
678fafbb788Sclaudio 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
679fafbb788Sclaudio 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
680fafbb788Sclaudio 		i = prefixlen % 8;
681fafbb788Sclaudio 		if (i) {
682fafbb788Sclaudio 			m = 0xff00 >> i;
683fafbb788Sclaudio 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
684fafbb788Sclaudio 			    (b->v6.s6_addr[prefixlen / 8] & m))
685fafbb788Sclaudio 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
686fafbb788Sclaudio 				    (b->v6.s6_addr[prefixlen / 8] & m));
687fafbb788Sclaudio 		}
688fafbb788Sclaudio 		return (0);
689fafbb788Sclaudio 	case AID_VPN_IPv4:
690fafbb788Sclaudio 		if (prefixlen > 32)
691de5c2eedSclaudio 			return (-1);
692f4c0eb52Sclaudio 		if (be64toh(a->vpn4.rd) > be64toh(b->vpn4.rd))
693fafbb788Sclaudio 			return (1);
694f4c0eb52Sclaudio 		if (be64toh(a->vpn4.rd) < be64toh(b->vpn4.rd))
695fafbb788Sclaudio 			return (-1);
696fafbb788Sclaudio 		mask = htonl(prefixlen2mask(prefixlen));
697fafbb788Sclaudio 		aa = ntohl(a->vpn4.addr.s_addr & mask);
698fafbb788Sclaudio 		ba = ntohl(b->vpn4.addr.s_addr & mask);
699fafbb788Sclaudio 		if (aa != ba)
700fafbb788Sclaudio 			return (aa - ba);
701fafbb788Sclaudio 		if (a->vpn4.labellen > b->vpn4.labellen)
702fafbb788Sclaudio 			return (1);
703fafbb788Sclaudio 		if (a->vpn4.labellen < b->vpn4.labellen)
704fafbb788Sclaudio 			return (-1);
705fafbb788Sclaudio 		return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
706fafbb788Sclaudio 		    a->vpn4.labellen));
707290f96faSdenis 	case AID_VPN_IPv6:
708290f96faSdenis 		if (prefixlen > 128)
709290f96faSdenis 			return (-1);
710f4c0eb52Sclaudio 		if (be64toh(a->vpn6.rd) > be64toh(b->vpn6.rd))
711290f96faSdenis 			return (1);
712f4c0eb52Sclaudio 		if (be64toh(a->vpn6.rd) < be64toh(b->vpn6.rd))
713290f96faSdenis 			return (-1);
714290f96faSdenis 		for (i = 0; i < prefixlen / 8; i++)
715290f96faSdenis 			if (a->vpn6.addr.s6_addr[i] != b->vpn6.addr.s6_addr[i])
716290f96faSdenis 				return (a->vpn6.addr.s6_addr[i] -
717290f96faSdenis 				    b->vpn6.addr.s6_addr[i]);
718290f96faSdenis 		i = prefixlen % 8;
719290f96faSdenis 		if (i) {
720290f96faSdenis 			m = 0xff00 >> i;
721290f96faSdenis 			if ((a->vpn6.addr.s6_addr[prefixlen / 8] & m) !=
722290f96faSdenis 			    (b->vpn6.addr.s6_addr[prefixlen / 8] & m))
723290f96faSdenis 				return ((a->vpn6.addr.s6_addr[prefixlen / 8] &
724290f96faSdenis 				    m) - (b->vpn6.addr.s6_addr[prefixlen / 8] &
725290f96faSdenis 				    m));
726290f96faSdenis 		}
727290f96faSdenis 		if (a->vpn6.labellen > b->vpn6.labellen)
728290f96faSdenis 			return (1);
729290f96faSdenis 		if (a->vpn6.labellen < b->vpn6.labellen)
730290f96faSdenis 			return (-1);
731290f96faSdenis 		return (memcmp(a->vpn6.labelstack, b->vpn6.labelstack,
732290f96faSdenis 		    a->vpn6.labellen));
733fafbb788Sclaudio 	}
734fafbb788Sclaudio 	return (-1);
735fafbb788Sclaudio }
736fafbb788Sclaudio 
73721a825c9Sclaudio in_addr_t
73821a825c9Sclaudio prefixlen2mask(u_int8_t prefixlen)
73921a825c9Sclaudio {
74021a825c9Sclaudio 	if (prefixlen == 0)
74121a825c9Sclaudio 		return (0);
74221a825c9Sclaudio 
74321a825c9Sclaudio 	return (0xffffffff << (32 - prefixlen));
74421a825c9Sclaudio }
74521a825c9Sclaudio 
74621a825c9Sclaudio void
7472b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
7482b5c88feSclaudio {
7492b5c88feSclaudio 	struct in_addr mask;
7502b5c88feSclaudio 
7512b5c88feSclaudio 	mask.s_addr = htonl(prefixlen2mask(prefixlen));
7522b5c88feSclaudio 	dest->s_addr = src->s_addr & mask.s_addr;
7532b5c88feSclaudio }
7542b5c88feSclaudio 
7552b5c88feSclaudio void
75621a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
75721a825c9Sclaudio {
75821a825c9Sclaudio 	struct in6_addr	mask;
75921a825c9Sclaudio 	int		i;
76021a825c9Sclaudio 
76121a825c9Sclaudio 	bzero(&mask, sizeof(mask));
76221a825c9Sclaudio 	for (i = 0; i < prefixlen / 8; i++)
76321a825c9Sclaudio 		mask.s6_addr[i] = 0xff;
76421a825c9Sclaudio 	i = prefixlen % 8;
76521a825c9Sclaudio 	if (i)
76621a825c9Sclaudio 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
76721a825c9Sclaudio 
76821a825c9Sclaudio 	for (i = 0; i < 16; i++)
76921a825c9Sclaudio 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
77021a825c9Sclaudio }
771d6c2e4e8Sclaudio 
772d6c2e4e8Sclaudio /* address family translation functions */
773d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS;
774d6c2e4e8Sclaudio 
77586729c90Sclaudio const char *
77686729c90Sclaudio aid2str(u_int8_t aid)
77786729c90Sclaudio {
77886729c90Sclaudio 	if (aid < AID_MAX)
77986729c90Sclaudio 		return (aid_vals[aid].name);
78086729c90Sclaudio 	return ("unknown AID");
78186729c90Sclaudio }
78286729c90Sclaudio 
783d6c2e4e8Sclaudio int
784d6c2e4e8Sclaudio aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
785d6c2e4e8Sclaudio {
786d6c2e4e8Sclaudio 	if (aid < AID_MAX) {
787d6c2e4e8Sclaudio 		*afi = aid_vals[aid].afi;
788d6c2e4e8Sclaudio 		*safi = aid_vals[aid].safi;
789d6c2e4e8Sclaudio 		return (0);
790d6c2e4e8Sclaudio 	}
791d6c2e4e8Sclaudio 	return (-1);
792d6c2e4e8Sclaudio }
793d6c2e4e8Sclaudio 
794d6c2e4e8Sclaudio int
795d6c2e4e8Sclaudio afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
796d6c2e4e8Sclaudio {
797d6c2e4e8Sclaudio 	u_int8_t i;
798d6c2e4e8Sclaudio 
799d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
800d6c2e4e8Sclaudio 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
801d6c2e4e8Sclaudio 			*aid = i;
802d6c2e4e8Sclaudio 			return (0);
803d6c2e4e8Sclaudio 		}
804d6c2e4e8Sclaudio 
805d6c2e4e8Sclaudio 	return (-1);
806d6c2e4e8Sclaudio }
807d6c2e4e8Sclaudio 
808d6c2e4e8Sclaudio sa_family_t
809d6c2e4e8Sclaudio aid2af(u_int8_t aid)
810d6c2e4e8Sclaudio {
811d6c2e4e8Sclaudio 	if (aid < AID_MAX)
812d6c2e4e8Sclaudio 		return (aid_vals[aid].af);
813d6c2e4e8Sclaudio 	return (AF_UNSPEC);
814d6c2e4e8Sclaudio }
815d6c2e4e8Sclaudio 
816d6c2e4e8Sclaudio int
817d6c2e4e8Sclaudio af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
818d6c2e4e8Sclaudio {
819d6c2e4e8Sclaudio 	u_int8_t i;
820d6c2e4e8Sclaudio 
821d6c2e4e8Sclaudio 	if (safi == 0) /* default to unicast subclass */
822d6c2e4e8Sclaudio 		safi = SAFI_UNICAST;
823d6c2e4e8Sclaudio 
824d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
825d6c2e4e8Sclaudio 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
826d6c2e4e8Sclaudio 			*aid = i;
827d6c2e4e8Sclaudio 			return (0);
828d6c2e4e8Sclaudio 		}
829d6c2e4e8Sclaudio 
830d6c2e4e8Sclaudio 	return (-1);
831d6c2e4e8Sclaudio }
832d6c2e4e8Sclaudio 
83345350f87Sclaudio /*
83445350f87Sclaudio  * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
83545350f87Sclaudio  * the included label stack is ignored and needs to be handled by the caller.
83645350f87Sclaudio  */
837d6c2e4e8Sclaudio struct sockaddr *
8385624d029Sclaudio addr2sa(const struct bgpd_addr *addr, u_int16_t port, socklen_t *len)
839d6c2e4e8Sclaudio {
840d6c2e4e8Sclaudio 	static struct sockaddr_storage	 ss;
841d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
842d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
843d6c2e4e8Sclaudio 
844*4886db4cSclaudio 	if (addr == NULL || addr->aid == AID_UNSPEC)
845*4886db4cSclaudio 		return (NULL);
84645350f87Sclaudio 
847*4886db4cSclaudio 	bzero(&ss, sizeof(ss));
848d6c2e4e8Sclaudio 	switch (addr->aid) {
849d6c2e4e8Sclaudio 	case AID_INET:
850d6c2e4e8Sclaudio 		sa_in->sin_family = AF_INET;
851d6c2e4e8Sclaudio 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
852d6c2e4e8Sclaudio 		sa_in->sin_port = htons(port);
853255fe563Sclaudio 		*len = sizeof(struct sockaddr_in);
854d6c2e4e8Sclaudio 		break;
855d6c2e4e8Sclaudio 	case AID_INET6:
856d6c2e4e8Sclaudio 		sa_in6->sin6_family = AF_INET6;
857d6c2e4e8Sclaudio 		memcpy(&sa_in6->sin6_addr, &addr->v6,
858d6c2e4e8Sclaudio 		    sizeof(sa_in6->sin6_addr));
859d6c2e4e8Sclaudio 		sa_in6->sin6_port = htons(port);
860d6c2e4e8Sclaudio 		sa_in6->sin6_scope_id = addr->scope_id;
861255fe563Sclaudio 		*len = sizeof(struct sockaddr_in6);
862d6c2e4e8Sclaudio 		break;
86345350f87Sclaudio 	case AID_VPN_IPv4:
86445350f87Sclaudio 		sa_in->sin_family = AF_INET;
86545350f87Sclaudio 		sa_in->sin_addr.s_addr = addr->vpn4.addr.s_addr;
86645350f87Sclaudio 		sa_in->sin_port = htons(port);
86745350f87Sclaudio 		*len = sizeof(struct sockaddr_in);
86845350f87Sclaudio 		break;
86945350f87Sclaudio 	case AID_VPN_IPv6:
87045350f87Sclaudio 		sa_in6->sin6_family = AF_INET6;
87145350f87Sclaudio 		memcpy(&sa_in6->sin6_addr, &addr->vpn6.addr,
87245350f87Sclaudio 		    sizeof(sa_in6->sin6_addr));
87345350f87Sclaudio 		sa_in6->sin6_port = htons(port);
87445350f87Sclaudio 		sa_in6->sin6_scope_id = addr->scope_id;
87545350f87Sclaudio 		*len = sizeof(struct sockaddr_in6);
87645350f87Sclaudio 		break;
877d6c2e4e8Sclaudio 	}
878d6c2e4e8Sclaudio 
879d6c2e4e8Sclaudio 	return ((struct sockaddr *)&ss);
880d6c2e4e8Sclaudio }
881d6c2e4e8Sclaudio 
882d6c2e4e8Sclaudio void
883a27d9e33Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, u_int16_t *port)
884d6c2e4e8Sclaudio {
885d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
886d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
887d6c2e4e8Sclaudio 
888d6c2e4e8Sclaudio 	bzero(addr, sizeof(*addr));
889d6c2e4e8Sclaudio 	switch (sa->sa_family) {
890d6c2e4e8Sclaudio 	case AF_INET:
891d6c2e4e8Sclaudio 		addr->aid = AID_INET;
892d6c2e4e8Sclaudio 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
893a27d9e33Sclaudio 		if (port)
894a27d9e33Sclaudio 			*port = ntohs(sa_in->sin_port);
895d6c2e4e8Sclaudio 		break;
896d6c2e4e8Sclaudio 	case AF_INET6:
897d6c2e4e8Sclaudio 		addr->aid = AID_INET6;
898d6c2e4e8Sclaudio 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
899be6ced5eSclaudio #ifdef __KAME__
900be6ced5eSclaudio 		/*
901be6ced5eSclaudio 		 * XXX thanks, KAME, for this ugliness...
902be6ced5eSclaudio 		 * adopted from route/show.c
903be6ced5eSclaudio 		 */
904be6ced5eSclaudio 		if (IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
905be6ced5eSclaudio 		    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr)) {
906be6ced5eSclaudio 			uint16_t tmp16;
907be6ced5eSclaudio 			memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
908be6ced5eSclaudio 			    sizeof(tmp16));
909be6ced5eSclaudio 			if (tmp16 != 0) {
910be6ced5eSclaudio 				sa_in6->sin6_scope_id = ntohs(tmp16);
911be6ced5eSclaudio 				sa_in6->sin6_addr.s6_addr[2] = 0;
912be6ced5eSclaudio 				sa_in6->sin6_addr.s6_addr[3] = 0;
913be6ced5eSclaudio 			}
914be6ced5eSclaudio 		}
915be6ced5eSclaudio #endif
916d6c2e4e8Sclaudio 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
917a27d9e33Sclaudio 		if (port)
918a27d9e33Sclaudio 			*port = ntohs(sa_in6->sin6_port);
919d6c2e4e8Sclaudio 		break;
920d6c2e4e8Sclaudio 	}
921d6c2e4e8Sclaudio }
9226e8089a5Sclaudio 
9236e8089a5Sclaudio const char *
924bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit)
9256e8089a5Sclaudio {
9266e8089a5Sclaudio 	static char bbuf[16];
9273eaf1285Sclaudio 	const unsigned long long kilo = 1000;
9283eaf1285Sclaudio 	const unsigned long long mega = 1000ULL * kilo;
9293eaf1285Sclaudio 	const unsigned long long giga = 1000ULL * mega;
9306e8089a5Sclaudio 
9313eaf1285Sclaudio 	if (baudrate > giga)
9326e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
9333eaf1285Sclaudio 		    baudrate / giga, unit);
9343eaf1285Sclaudio 	else if (baudrate > mega)
9356e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
9363eaf1285Sclaudio 		    baudrate / mega, unit);
9373eaf1285Sclaudio 	else if (baudrate > kilo)
9386e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
9393eaf1285Sclaudio 		    baudrate / kilo, unit);
9406e8089a5Sclaudio 	else
9416e8089a5Sclaudio 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
9426e8089a5Sclaudio 		    baudrate, unit);
9436e8089a5Sclaudio 
9446e8089a5Sclaudio 	return (bbuf);
9456e8089a5Sclaudio }
946