xref: /openbsd/usr.sbin/bgpd/util.c (revision 368f0e94)
1*368f0e94Sbenno /*	$OpenBSD: util.c,v 1.21 2016/06/03 17:36:37 benno 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>
232ffcd4e0Sclaudio #include <netdb.h>
242ffcd4e0Sclaudio #include <stdlib.h>
252ffcd4e0Sclaudio #include <stdio.h>
262ffcd4e0Sclaudio #include <string.h>
272ffcd4e0Sclaudio 
282ffcd4e0Sclaudio #include "bgpd.h"
292ffcd4e0Sclaudio #include "rde.h"
302ffcd4e0Sclaudio 
311e590dcfSclaudio const char	*aspath_delim(u_int8_t, int);
321e590dcfSclaudio 
332ffcd4e0Sclaudio const char *
342ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr)
352ffcd4e0Sclaudio {
362ffcd4e0Sclaudio 	static char	buf[48];
37256b680eSclaudio 	char		tbuf[16];
382ffcd4e0Sclaudio 
3915d8de66Sclaudio 	switch (addr->aid) {
4015d8de66Sclaudio 	case AID_INET:
4115d8de66Sclaudio 	case AID_INET6:
4215d8de66Sclaudio 		if (inet_ntop(aid2af(addr->aid), &addr->ba, buf,
4315d8de66Sclaudio 		    sizeof(buf)) == NULL)
442ffcd4e0Sclaudio 			return ("?");
452ffcd4e0Sclaudio 		return (buf);
4615d8de66Sclaudio 	case AID_VPN_IPv4:
47256b680eSclaudio 		if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf,
48256b680eSclaudio 		    sizeof(tbuf)) == NULL)
4915d8de66Sclaudio 			return ("?");
50256b680eSclaudio 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
51256b680eSclaudio 		   tbuf);
5215d8de66Sclaudio 		return (buf);
5315d8de66Sclaudio 	}
5415d8de66Sclaudio 	return ("???");
552ffcd4e0Sclaudio }
562ffcd4e0Sclaudio 
572ffcd4e0Sclaudio const char *
582ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr)
592ffcd4e0Sclaudio {
602ffcd4e0Sclaudio 	struct sockaddr_in6	sa_in6;
612ffcd4e0Sclaudio 	u_int16_t		tmp16;
622ffcd4e0Sclaudio 
632ffcd4e0Sclaudio 	bzero(&sa_in6, sizeof(sa_in6));
642ffcd4e0Sclaudio 	sa_in6.sin6_len = sizeof(sa_in6);
652ffcd4e0Sclaudio 	sa_in6.sin6_family = AF_INET6;
662ffcd4e0Sclaudio 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
672ffcd4e0Sclaudio 
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)) {
712ffcd4e0Sclaudio 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
722ffcd4e0Sclaudio 		sa_in6.sin6_scope_id = ntohs(tmp16);
732ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[2] = 0;
742ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[3] = 0;
752ffcd4e0Sclaudio 	}
762ffcd4e0Sclaudio 
772ffcd4e0Sclaudio 	return (log_sockaddr((struct sockaddr *)&sa_in6));
782ffcd4e0Sclaudio }
792ffcd4e0Sclaudio 
802ffcd4e0Sclaudio const char *
812ffcd4e0Sclaudio log_sockaddr(struct sockaddr *sa)
822ffcd4e0Sclaudio {
832ffcd4e0Sclaudio 	static char	buf[NI_MAXHOST];
842ffcd4e0Sclaudio 
852ffcd4e0Sclaudio 	if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0,
862ffcd4e0Sclaudio 	    NI_NUMERICHOST))
872ffcd4e0Sclaudio 		return ("(unknown)");
882ffcd4e0Sclaudio 	else
892ffcd4e0Sclaudio 		return (buf);
902ffcd4e0Sclaudio }
912ffcd4e0Sclaudio 
920c88bf70Sclaudio const char *
930c88bf70Sclaudio log_as(u_int32_t as)
940c88bf70Sclaudio {
9506bcde9cSphessler 	static char	buf[11];	/* "4294967294\0" */
960c88bf70Sclaudio 
970c88bf70Sclaudio 	if (snprintf(buf, sizeof(buf), "%u", as) == -1)
980c88bf70Sclaudio 		return ("?");
9906bcde9cSphessler 
1000c88bf70Sclaudio 	return (buf);
1010c88bf70Sclaudio }
1020c88bf70Sclaudio 
103256b680eSclaudio const char *
104256b680eSclaudio log_rd(u_int64_t rd)
105256b680eSclaudio {
106256b680eSclaudio 	static char	buf[32];
107256b680eSclaudio 	struct in_addr	addr;
108256b680eSclaudio 	u_int32_t	u32;
109256b680eSclaudio 	u_int16_t	u16;
110256b680eSclaudio 
111256b680eSclaudio 	rd = betoh64(rd);
112256b680eSclaudio 	switch (rd >> 48) {
113256b680eSclaudio 	case EXT_COMMUNITY_TWO_AS:
114256b680eSclaudio 		u32 = rd & 0xffffffff;
115256b680eSclaudio 		u16 = (rd >> 32) & 0xffff;
11632ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
117256b680eSclaudio 		break;
118256b680eSclaudio 	case EXT_COMMUNITY_FOUR_AS:
119256b680eSclaudio 		u32 = (rd >> 16) & 0xffffffff;
120256b680eSclaudio 		u16 = rd & 0xffff;
12132ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
122256b680eSclaudio 		break;
123256b680eSclaudio 	case EXT_COMMUNITY_IPV4:
124256b680eSclaudio 		u32 = (rd >> 16) & 0xffffffff;
125256b680eSclaudio 		u16 = rd & 0xffff;
126256b680eSclaudio 		addr.s_addr = htonl(u32);
12732ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
128256b680eSclaudio 		break;
129256b680eSclaudio 	default:
130256b680eSclaudio 		return ("rd ?");
131256b680eSclaudio 	}
132256b680eSclaudio 	return (buf);
133256b680eSclaudio }
134256b680eSclaudio 
135256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is
136536f41e5Sclaudio  * actually valid. */
137536f41e5Sclaudio const char *
138536f41e5Sclaudio log_ext_subtype(u_int8_t subtype)
139536f41e5Sclaudio {
140536f41e5Sclaudio 	static char etype[6];
141536f41e5Sclaudio 
142536f41e5Sclaudio 	switch (subtype) {
143536f41e5Sclaudio 	case EXT_COMMUNITY_ROUTE_TGT:
144536f41e5Sclaudio 		return ("rt");	/* route target */
145e85ee6aeSsthen 	case EXT_COMMUNITY_ROUTE_ORIG:
146536f41e5Sclaudio 		return ("soo");	/* source of origin */
147536f41e5Sclaudio 	case EXT_COMMUNITY_OSPF_DOM_ID:
148536f41e5Sclaudio 		return ("odi");	/* ospf domain id */
149536f41e5Sclaudio 	case EXT_COMMUNITY_OSPF_RTR_TYPE:
150536f41e5Sclaudio 		return ("ort");	/* ospf route type */
151536f41e5Sclaudio 	case EXT_COMMUNITY_OSPF_RTR_ID:
152536f41e5Sclaudio 		return ("ori");	/* ospf router id */
153536f41e5Sclaudio 	case EXT_COMMUNITY_BGP_COLLECT:
154536f41e5Sclaudio 		return ("bdc");	/* bgp data collection */
155536f41e5Sclaudio 	default:
156d6340f7aSderaadt 		snprintf(etype, sizeof(etype), "[%u]", subtype);
157536f41e5Sclaudio 		return (etype);
158536f41e5Sclaudio 	}
159536f41e5Sclaudio }
160536f41e5Sclaudio 
1611e590dcfSclaudio const char *
1621e590dcfSclaudio aspath_delim(u_int8_t seg_type, int closing)
1631e590dcfSclaudio {
1641e590dcfSclaudio 	static char db[8];
1651e590dcfSclaudio 
1661e590dcfSclaudio 	switch (seg_type) {
1671e590dcfSclaudio 	case AS_SET:
1681e590dcfSclaudio 		if (!closing)
1691e590dcfSclaudio 			return ("{ ");
1701e590dcfSclaudio 		else
1711e590dcfSclaudio 			return (" }");
1721e590dcfSclaudio 	case AS_SEQUENCE:
1731e590dcfSclaudio 		return ("");
1741e590dcfSclaudio 	case AS_CONFED_SEQUENCE:
1751e590dcfSclaudio 		if (!closing)
1761e590dcfSclaudio 			return ("( ");
1771e590dcfSclaudio 		else
1781e590dcfSclaudio 			return (" )");
1791e590dcfSclaudio 	case AS_CONFED_SET:
1801e590dcfSclaudio 		if (!closing)
1811e590dcfSclaudio 			return ("[ ");
1821e590dcfSclaudio 		else
1831e590dcfSclaudio 			return (" ]");
1841e590dcfSclaudio 	default:
1851e590dcfSclaudio 		if (!closing)
1861e590dcfSclaudio 			snprintf(db, sizeof(db), "!%u ", seg_type);
1871e590dcfSclaudio 		else
1881e590dcfSclaudio 			snprintf(db, sizeof(db), " !%u", seg_type);
1891e590dcfSclaudio 		return (db);
1901e590dcfSclaudio 	}
1911e590dcfSclaudio }
1921e590dcfSclaudio 
1932ffcd4e0Sclaudio int
1942ffcd4e0Sclaudio aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
1952ffcd4e0Sclaudio {
1962ffcd4e0Sclaudio #define UPDATE()				\
1972ffcd4e0Sclaudio 	do {					\
1982ffcd4e0Sclaudio 		if (r == -1)			\
1992ffcd4e0Sclaudio 			return (-1);		\
2002ffcd4e0Sclaudio 		total_size += r;		\
2012ffcd4e0Sclaudio 		if ((unsigned int)r < size) {	\
2022ffcd4e0Sclaudio 			size -= r;		\
2032ffcd4e0Sclaudio 			buf += r;		\
2042ffcd4e0Sclaudio 		} else {			\
2052ffcd4e0Sclaudio 			buf += size;		\
2062ffcd4e0Sclaudio 			size = 0;		\
2072ffcd4e0Sclaudio 		}				\
2082ffcd4e0Sclaudio 	} while (0)
2092ffcd4e0Sclaudio 	u_int8_t	*seg;
2102ffcd4e0Sclaudio 	int		 r, total_size;
2112ffcd4e0Sclaudio 	u_int16_t	 seg_size;
2122ffcd4e0Sclaudio 	u_int8_t	 i, seg_type, seg_len;
2132ffcd4e0Sclaudio 
2142ffcd4e0Sclaudio 	total_size = 0;
2152ffcd4e0Sclaudio 	seg = data;
2162ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
2172ffcd4e0Sclaudio 		seg_type = seg[0];
2182ffcd4e0Sclaudio 		seg_len = seg[1];
2190c88bf70Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
2202ffcd4e0Sclaudio 
2211e590dcfSclaudio 		r = snprintf(buf, size, "%s%s",
2221e590dcfSclaudio 		    total_size != 0 ? " " : "",
2231e590dcfSclaudio 		    aspath_delim(seg_type, 0));
2242ffcd4e0Sclaudio 		UPDATE();
2252ffcd4e0Sclaudio 
2262ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
2270c88bf70Sclaudio 			r = snprintf(buf, size, "%s",
2280c88bf70Sclaudio 			    log_as(aspath_extract(seg, i)));
2292ffcd4e0Sclaudio 			UPDATE();
2302ffcd4e0Sclaudio 			if (i + 1 < seg_len) {
2312ffcd4e0Sclaudio 				r = snprintf(buf, size, " ");
2322ffcd4e0Sclaudio 				UPDATE();
2332ffcd4e0Sclaudio 			}
2342ffcd4e0Sclaudio 		}
2351e590dcfSclaudio 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
2362ffcd4e0Sclaudio 		UPDATE();
2372ffcd4e0Sclaudio 	}
23855e49665Sclaudio 	/* ensure that we have a valid C-string especially for empty as path */
2392ffcd4e0Sclaudio 	if (size > 0)
2402ffcd4e0Sclaudio 		*buf = '\0';
2412ffcd4e0Sclaudio 
2422ffcd4e0Sclaudio 	return (total_size);
2432ffcd4e0Sclaudio #undef UPDATE
2442ffcd4e0Sclaudio }
2452ffcd4e0Sclaudio 
2462ffcd4e0Sclaudio int
2472ffcd4e0Sclaudio aspath_asprint(char **ret, void *data, u_int16_t len)
2482ffcd4e0Sclaudio {
2492ffcd4e0Sclaudio 	size_t	slen;
2502ffcd4e0Sclaudio 	int	plen;
2512ffcd4e0Sclaudio 
2522ffcd4e0Sclaudio 	slen = aspath_strlen(data, len) + 1;
2532ffcd4e0Sclaudio 	*ret = malloc(slen);
2542ffcd4e0Sclaudio 	if (*ret == NULL)
2552ffcd4e0Sclaudio 		return (-1);
2562ffcd4e0Sclaudio 
2572ffcd4e0Sclaudio 	plen = aspath_snprint(*ret, slen, data, len);
2582ffcd4e0Sclaudio 	if (plen == -1) {
2592ffcd4e0Sclaudio 		free(*ret);
2602ffcd4e0Sclaudio 		*ret = NULL;
2612ffcd4e0Sclaudio 		return (-1);
2622ffcd4e0Sclaudio 	}
2632ffcd4e0Sclaudio 
2642ffcd4e0Sclaudio 	return (0);
2652ffcd4e0Sclaudio }
2662ffcd4e0Sclaudio 
2672ffcd4e0Sclaudio size_t
2682ffcd4e0Sclaudio aspath_strlen(void *data, u_int16_t len)
2692ffcd4e0Sclaudio {
2702ffcd4e0Sclaudio 	u_int8_t	*seg;
2712ffcd4e0Sclaudio 	int		 total_size;
2720c88bf70Sclaudio 	u_int32_t	 as;
2730c88bf70Sclaudio 	u_int16_t	 seg_size;
2742ffcd4e0Sclaudio 	u_int8_t	 i, seg_type, seg_len;
2752ffcd4e0Sclaudio 
2762ffcd4e0Sclaudio 	total_size = 0;
2772ffcd4e0Sclaudio 	seg = data;
2782ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
2792ffcd4e0Sclaudio 		seg_type = seg[0];
2802ffcd4e0Sclaudio 		seg_len = seg[1];
2810c88bf70Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
2822ffcd4e0Sclaudio 
2832ffcd4e0Sclaudio 		if (seg_type == AS_SET)
2842ffcd4e0Sclaudio 			if (total_size != 0)
2852ffcd4e0Sclaudio 				total_size += 3;
2862ffcd4e0Sclaudio 			else
2872ffcd4e0Sclaudio 				total_size += 2;
2882ffcd4e0Sclaudio 		else if (total_size != 0)
2892ffcd4e0Sclaudio 			total_size += 1;
2902ffcd4e0Sclaudio 
2912ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
2922ffcd4e0Sclaudio 			as = aspath_extract(seg, i);
2930c88bf70Sclaudio 
2948db4f5d2Sclaudio 			do {
2958db4f5d2Sclaudio 				total_size++;
2968db4f5d2Sclaudio 			} while ((as = as / 10) != 0);
2972ffcd4e0Sclaudio 
2982ffcd4e0Sclaudio 			if (i + 1 < seg_len)
2992ffcd4e0Sclaudio 				total_size += 1;
3002ffcd4e0Sclaudio 		}
3012ffcd4e0Sclaudio 
3022ffcd4e0Sclaudio 		if (seg_type == AS_SET)
3032ffcd4e0Sclaudio 			total_size += 2;
3042ffcd4e0Sclaudio 	}
3052ffcd4e0Sclaudio 	return (total_size);
3062ffcd4e0Sclaudio }
3072ffcd4e0Sclaudio 
308fafbb788Sclaudio /* we need to be able to search more than one as */
309fafbb788Sclaudio int
310*368f0e94Sbenno aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
311fafbb788Sclaudio {
312fafbb788Sclaudio 	u_int8_t	*seg;
313fafbb788Sclaudio 	int		 final;
314fafbb788Sclaudio 	u_int16_t	 seg_size;
315de50ed92Sclaudio 	u_int8_t	 i, seg_len;
316*368f0e94Sbenno 	u_int32_t	 as;
317fafbb788Sclaudio 
318*368f0e94Sbenno 	if (f->type == AS_EMPTY) {
319fafbb788Sclaudio 		if (len == 0)
320fafbb788Sclaudio 			return (1);
321fafbb788Sclaudio 		else
322fafbb788Sclaudio 			return (0);
323fafbb788Sclaudio 	}
324fafbb788Sclaudio 
325fafbb788Sclaudio 	seg = data;
326fafbb788Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
327fafbb788Sclaudio 		seg_len = seg[1];
328fafbb788Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
329fafbb788Sclaudio 
330fafbb788Sclaudio 		final = (len == seg_size);
331fafbb788Sclaudio 
332fafbb788Sclaudio 		/* just check the first (leftmost) AS */
333*368f0e94Sbenno 		if (f->type == AS_PEER) {
334*368f0e94Sbenno 			as = aspath_extract(seg, 0);
335*368f0e94Sbenno 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
336fafbb788Sclaudio 				return (1);
337fafbb788Sclaudio 			else
338fafbb788Sclaudio 				return (0);
339fafbb788Sclaudio 		}
340fafbb788Sclaudio 		/* just check the final (rightmost) AS */
341*368f0e94Sbenno 		if (f->type == AS_SOURCE) {
342fafbb788Sclaudio 			/* not yet in the final segment */
343fafbb788Sclaudio 			if (!final)
344fafbb788Sclaudio 				continue;
345*368f0e94Sbenno 			as = aspath_extract(seg, seg_len - 1);
346*368f0e94Sbenno 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
347fafbb788Sclaudio 				return (1);
348fafbb788Sclaudio 			else
349fafbb788Sclaudio 				return (0);
350fafbb788Sclaudio 		}
351fafbb788Sclaudio 		/* AS_TRANSIT or AS_ALL */
352fafbb788Sclaudio 		for (i = 0; i < seg_len; i++) {
353fafbb788Sclaudio 			/*
354fafbb788Sclaudio 			 * the source (rightmost) AS is excluded from
355fafbb788Sclaudio 			 * AS_TRANSIT matches.
356fafbb788Sclaudio 			 */
357*368f0e94Sbenno 			if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
358fafbb788Sclaudio 				return (0);
359*368f0e94Sbenno 			as = aspath_extract(seg, i);
360*368f0e94Sbenno 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
361fafbb788Sclaudio 				return (1);
362fafbb788Sclaudio 		}
363fafbb788Sclaudio 	}
364*368f0e94Sbenno 	return (0);
365fafbb788Sclaudio }
366*368f0e94Sbenno 
367*368f0e94Sbenno int
368*368f0e94Sbenno as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min,
369*368f0e94Sbenno     u_int32_t as_max)
370*368f0e94Sbenno {
371*368f0e94Sbenno 	if ((op == OP_NONE || op == OP_EQ) && as == match)
372*368f0e94Sbenno 		return (1);
373*368f0e94Sbenno 	else if (op == OP_NE && as != match)
374*368f0e94Sbenno 		return (1);
375*368f0e94Sbenno 	else if (op == OP_RANGE && as >= as_min && as <= as_max)
376*368f0e94Sbenno 		return (1);
377*368f0e94Sbenno 	else if (op == OP_XRANGE && as > as_min && as < as_max)
378*368f0e94Sbenno 		return (1);
379fafbb788Sclaudio 	return (0);
380fafbb788Sclaudio }
381fafbb788Sclaudio 
3822ffcd4e0Sclaudio /*
3832ffcd4e0Sclaudio  * Extract the asnum out of the as segment at the specified position.
3842ffcd4e0Sclaudio  * Direct access is not possible because of non-aligned reads.
385c5508ee4Sclaudio  * ATTENTION: no bounds checks are done.
3862ffcd4e0Sclaudio  */
3870c88bf70Sclaudio u_int32_t
3882ffcd4e0Sclaudio aspath_extract(const void *seg, int pos)
3892ffcd4e0Sclaudio {
3902ffcd4e0Sclaudio 	const u_char	*ptr = seg;
3910c88bf70Sclaudio 	u_int32_t	 as;
3922ffcd4e0Sclaudio 
3930c88bf70Sclaudio 	ptr += 2 + sizeof(u_int32_t) * pos;
3940c88bf70Sclaudio 	memcpy(&as, ptr, sizeof(u_int32_t));
3950c88bf70Sclaudio 	return (ntohl(as));
3962ffcd4e0Sclaudio }
39721a825c9Sclaudio 
398fafbb788Sclaudio int
399fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
400fafbb788Sclaudio     int prefixlen)
401fafbb788Sclaudio {
402fafbb788Sclaudio 	in_addr_t	mask, aa, ba;
403fafbb788Sclaudio 	int		i;
404fafbb788Sclaudio 	u_int8_t	m;
405fafbb788Sclaudio 
406fafbb788Sclaudio 	if (a->aid != b->aid)
407fafbb788Sclaudio 		return (a->aid - b->aid);
408fafbb788Sclaudio 
409fafbb788Sclaudio 	switch (a->aid) {
410fafbb788Sclaudio 	case AID_INET:
4117da59fecSclaudio 		if (prefixlen == 0)
4127da59fecSclaudio 			return (0);
413fafbb788Sclaudio 		if (prefixlen > 32)
414fafbb788Sclaudio 			fatalx("prefix_cmp: bad IPv4 prefixlen");
415fafbb788Sclaudio 		mask = htonl(prefixlen2mask(prefixlen));
416fafbb788Sclaudio 		aa = ntohl(a->v4.s_addr & mask);
417fafbb788Sclaudio 		ba = ntohl(b->v4.s_addr & mask);
418fafbb788Sclaudio 		if (aa != ba)
419fafbb788Sclaudio 			return (aa - ba);
420fafbb788Sclaudio 		return (0);
421fafbb788Sclaudio 	case AID_INET6:
4227da59fecSclaudio 		if (prefixlen == 0)
4237da59fecSclaudio 			return (0);
424fafbb788Sclaudio 		if (prefixlen > 128)
425fafbb788Sclaudio 			fatalx("prefix_cmp: bad IPv6 prefixlen");
426fafbb788Sclaudio 		for (i = 0; i < prefixlen / 8; i++)
427fafbb788Sclaudio 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
428fafbb788Sclaudio 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
429fafbb788Sclaudio 		i = prefixlen % 8;
430fafbb788Sclaudio 		if (i) {
431fafbb788Sclaudio 			m = 0xff00 >> i;
432fafbb788Sclaudio 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
433fafbb788Sclaudio 			    (b->v6.s6_addr[prefixlen / 8] & m))
434fafbb788Sclaudio 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
435fafbb788Sclaudio 				    (b->v6.s6_addr[prefixlen / 8] & m));
436fafbb788Sclaudio 		}
437fafbb788Sclaudio 		return (0);
438fafbb788Sclaudio 	case AID_VPN_IPv4:
439fafbb788Sclaudio 		if (prefixlen > 32)
440fafbb788Sclaudio 			fatalx("prefix_cmp: bad IPv4 VPN prefixlen");
441fafbb788Sclaudio 		if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
442fafbb788Sclaudio 			return (1);
443fafbb788Sclaudio 		if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd))
444fafbb788Sclaudio 			return (-1);
445fafbb788Sclaudio 		mask = htonl(prefixlen2mask(prefixlen));
446fafbb788Sclaudio 		aa = ntohl(a->vpn4.addr.s_addr & mask);
447fafbb788Sclaudio 		ba = ntohl(b->vpn4.addr.s_addr & mask);
448fafbb788Sclaudio 		if (aa != ba)
449fafbb788Sclaudio 			return (aa - ba);
450fafbb788Sclaudio 		if (a->vpn4.labellen > b->vpn4.labellen)
451fafbb788Sclaudio 			return (1);
452fafbb788Sclaudio 		if (a->vpn4.labellen < b->vpn4.labellen)
453fafbb788Sclaudio 			return (-1);
454fafbb788Sclaudio 		return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
455fafbb788Sclaudio 		    a->vpn4.labellen));
456fafbb788Sclaudio 	default:
457fafbb788Sclaudio 		fatalx("prefix_cmp: unknown af");
458fafbb788Sclaudio 	}
459fafbb788Sclaudio 	return (-1);
460fafbb788Sclaudio }
461fafbb788Sclaudio 
46221a825c9Sclaudio in_addr_t
46321a825c9Sclaudio prefixlen2mask(u_int8_t prefixlen)
46421a825c9Sclaudio {
46521a825c9Sclaudio 	if (prefixlen == 0)
46621a825c9Sclaudio 		return (0);
46721a825c9Sclaudio 
46821a825c9Sclaudio 	return (0xffffffff << (32 - prefixlen));
46921a825c9Sclaudio }
47021a825c9Sclaudio 
47121a825c9Sclaudio void
47221a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
47321a825c9Sclaudio {
47421a825c9Sclaudio 	struct in6_addr	mask;
47521a825c9Sclaudio 	int		i;
47621a825c9Sclaudio 
47721a825c9Sclaudio 	bzero(&mask, sizeof(mask));
47821a825c9Sclaudio 	for (i = 0; i < prefixlen / 8; i++)
47921a825c9Sclaudio 		mask.s6_addr[i] = 0xff;
48021a825c9Sclaudio 	i = prefixlen % 8;
48121a825c9Sclaudio 	if (i)
48221a825c9Sclaudio 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
48321a825c9Sclaudio 
48421a825c9Sclaudio 	for (i = 0; i < 16; i++)
48521a825c9Sclaudio 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
48621a825c9Sclaudio }
487d6c2e4e8Sclaudio 
488d6c2e4e8Sclaudio /* address family translation functions */
489d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS;
490d6c2e4e8Sclaudio 
49186729c90Sclaudio const char *
49286729c90Sclaudio aid2str(u_int8_t aid)
49386729c90Sclaudio {
49486729c90Sclaudio 	if (aid < AID_MAX)
49586729c90Sclaudio 		return (aid_vals[aid].name);
49686729c90Sclaudio 	return ("unknown AID");
49786729c90Sclaudio }
49886729c90Sclaudio 
499d6c2e4e8Sclaudio int
500d6c2e4e8Sclaudio aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
501d6c2e4e8Sclaudio {
502d6c2e4e8Sclaudio 	if (aid < AID_MAX) {
503d6c2e4e8Sclaudio 		*afi = aid_vals[aid].afi;
504d6c2e4e8Sclaudio 		*safi = aid_vals[aid].safi;
505d6c2e4e8Sclaudio 		return (0);
506d6c2e4e8Sclaudio 	}
507d6c2e4e8Sclaudio 	return (-1);
508d6c2e4e8Sclaudio }
509d6c2e4e8Sclaudio 
510d6c2e4e8Sclaudio int
511d6c2e4e8Sclaudio afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
512d6c2e4e8Sclaudio {
513d6c2e4e8Sclaudio 	u_int8_t i;
514d6c2e4e8Sclaudio 
515d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
516d6c2e4e8Sclaudio 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
517d6c2e4e8Sclaudio 			*aid = i;
518d6c2e4e8Sclaudio 			return (0);
519d6c2e4e8Sclaudio 		}
520d6c2e4e8Sclaudio 
521d6c2e4e8Sclaudio 	return (-1);
522d6c2e4e8Sclaudio }
523d6c2e4e8Sclaudio 
524d6c2e4e8Sclaudio sa_family_t
525d6c2e4e8Sclaudio aid2af(u_int8_t aid)
526d6c2e4e8Sclaudio {
527d6c2e4e8Sclaudio 	if (aid < AID_MAX)
528d6c2e4e8Sclaudio 		return (aid_vals[aid].af);
529d6c2e4e8Sclaudio 	return (AF_UNSPEC);
530d6c2e4e8Sclaudio }
531d6c2e4e8Sclaudio 
532d6c2e4e8Sclaudio int
533d6c2e4e8Sclaudio af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
534d6c2e4e8Sclaudio {
535d6c2e4e8Sclaudio 	u_int8_t i;
536d6c2e4e8Sclaudio 
537d6c2e4e8Sclaudio 	if (safi == 0) /* default to unicast subclass */
538d6c2e4e8Sclaudio 		safi = SAFI_UNICAST;
539d6c2e4e8Sclaudio 
540d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
541d6c2e4e8Sclaudio 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
542d6c2e4e8Sclaudio 			*aid = i;
543d6c2e4e8Sclaudio 			return (0);
544d6c2e4e8Sclaudio 		}
545d6c2e4e8Sclaudio 
546d6c2e4e8Sclaudio 	return (-1);
547d6c2e4e8Sclaudio }
548d6c2e4e8Sclaudio 
549d6c2e4e8Sclaudio struct sockaddr *
550d6c2e4e8Sclaudio addr2sa(struct bgpd_addr *addr, u_int16_t port)
551d6c2e4e8Sclaudio {
552d6c2e4e8Sclaudio 	static struct sockaddr_storage	 ss;
553d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
554d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
555d6c2e4e8Sclaudio 
556d6c2e4e8Sclaudio 	if (addr->aid == AID_UNSPEC)
557d6c2e4e8Sclaudio 		return (NULL);
558d6c2e4e8Sclaudio 
559d6c2e4e8Sclaudio 	bzero(&ss, sizeof(ss));
560d6c2e4e8Sclaudio 	switch (addr->aid) {
561d6c2e4e8Sclaudio 	case AID_INET:
562d6c2e4e8Sclaudio 		sa_in->sin_family = AF_INET;
563d6c2e4e8Sclaudio 		sa_in->sin_len = sizeof(struct sockaddr_in);
564d6c2e4e8Sclaudio 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
565d6c2e4e8Sclaudio 		sa_in->sin_port = htons(port);
566d6c2e4e8Sclaudio 		break;
567d6c2e4e8Sclaudio 	case AID_INET6:
568d6c2e4e8Sclaudio 		sa_in6->sin6_family = AF_INET6;
569d6c2e4e8Sclaudio 		sa_in6->sin6_len = sizeof(struct sockaddr_in6);
570d6c2e4e8Sclaudio 		memcpy(&sa_in6->sin6_addr, &addr->v6,
571d6c2e4e8Sclaudio 		    sizeof(sa_in6->sin6_addr));
572d6c2e4e8Sclaudio 		sa_in6->sin6_port = htons(port);
573d6c2e4e8Sclaudio 		sa_in6->sin6_scope_id = addr->scope_id;
574d6c2e4e8Sclaudio 		break;
575d6c2e4e8Sclaudio 	}
576d6c2e4e8Sclaudio 
577d6c2e4e8Sclaudio 	return ((struct sockaddr *)&ss);
578d6c2e4e8Sclaudio }
579d6c2e4e8Sclaudio 
580d6c2e4e8Sclaudio void
581d6c2e4e8Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr)
582d6c2e4e8Sclaudio {
583d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
584d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
585d6c2e4e8Sclaudio 
586d6c2e4e8Sclaudio 	bzero(addr, sizeof(*addr));
587d6c2e4e8Sclaudio 	switch (sa->sa_family) {
588d6c2e4e8Sclaudio 	case AF_INET:
589d6c2e4e8Sclaudio 		addr->aid = AID_INET;
590d6c2e4e8Sclaudio 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
591d6c2e4e8Sclaudio 		break;
592d6c2e4e8Sclaudio 	case AF_INET6:
593d6c2e4e8Sclaudio 		addr->aid = AID_INET6;
594d6c2e4e8Sclaudio 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
595d6c2e4e8Sclaudio 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
596d6c2e4e8Sclaudio 		break;
597d6c2e4e8Sclaudio 	}
598d6c2e4e8Sclaudio }
599