xref: /openbsd/usr.sbin/bgpd/util.c (revision 5e3f6f95)
1*5e3f6f95Sbenno /*	$OpenBSD: util.c,v 1.24 2017/01/24 04:22:42 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>
270561b344Sphessler #include <vis.h>
282ffcd4e0Sclaudio 
292ffcd4e0Sclaudio #include "bgpd.h"
302ffcd4e0Sclaudio #include "rde.h"
31*5e3f6f95Sbenno #include "log.h"
322ffcd4e0Sclaudio 
331e590dcfSclaudio const char	*aspath_delim(u_int8_t, int);
341e590dcfSclaudio 
352ffcd4e0Sclaudio const char *
362ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr)
372ffcd4e0Sclaudio {
382ffcd4e0Sclaudio 	static char	buf[48];
39256b680eSclaudio 	char		tbuf[16];
402ffcd4e0Sclaudio 
4115d8de66Sclaudio 	switch (addr->aid) {
4215d8de66Sclaudio 	case AID_INET:
4315d8de66Sclaudio 	case AID_INET6:
4415d8de66Sclaudio 		if (inet_ntop(aid2af(addr->aid), &addr->ba, buf,
4515d8de66Sclaudio 		    sizeof(buf)) == NULL)
462ffcd4e0Sclaudio 			return ("?");
472ffcd4e0Sclaudio 		return (buf);
4815d8de66Sclaudio 	case AID_VPN_IPv4:
49256b680eSclaudio 		if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf,
50256b680eSclaudio 		    sizeof(tbuf)) == NULL)
5115d8de66Sclaudio 			return ("?");
52256b680eSclaudio 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
53256b680eSclaudio 		   tbuf);
5415d8de66Sclaudio 		return (buf);
5515d8de66Sclaudio 	}
5615d8de66Sclaudio 	return ("???");
572ffcd4e0Sclaudio }
582ffcd4e0Sclaudio 
592ffcd4e0Sclaudio const char *
602ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr)
612ffcd4e0Sclaudio {
622ffcd4e0Sclaudio 	struct sockaddr_in6	sa_in6;
632ffcd4e0Sclaudio 	u_int16_t		tmp16;
642ffcd4e0Sclaudio 
652ffcd4e0Sclaudio 	bzero(&sa_in6, sizeof(sa_in6));
662ffcd4e0Sclaudio 	sa_in6.sin6_len = sizeof(sa_in6);
672ffcd4e0Sclaudio 	sa_in6.sin6_family = AF_INET6;
682ffcd4e0Sclaudio 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
692ffcd4e0Sclaudio 
702ffcd4e0Sclaudio 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
712ffcd4e0Sclaudio 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
722ffcd4e0Sclaudio 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
732ffcd4e0Sclaudio 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
742ffcd4e0Sclaudio 		sa_in6.sin6_scope_id = ntohs(tmp16);
752ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[2] = 0;
762ffcd4e0Sclaudio 		sa_in6.sin6_addr.s6_addr[3] = 0;
772ffcd4e0Sclaudio 	}
782ffcd4e0Sclaudio 
792ffcd4e0Sclaudio 	return (log_sockaddr((struct sockaddr *)&sa_in6));
802ffcd4e0Sclaudio }
812ffcd4e0Sclaudio 
822ffcd4e0Sclaudio const char *
832ffcd4e0Sclaudio log_sockaddr(struct sockaddr *sa)
842ffcd4e0Sclaudio {
852ffcd4e0Sclaudio 	static char	buf[NI_MAXHOST];
862ffcd4e0Sclaudio 
872ffcd4e0Sclaudio 	if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0,
882ffcd4e0Sclaudio 	    NI_NUMERICHOST))
892ffcd4e0Sclaudio 		return ("(unknown)");
902ffcd4e0Sclaudio 	else
912ffcd4e0Sclaudio 		return (buf);
922ffcd4e0Sclaudio }
932ffcd4e0Sclaudio 
940c88bf70Sclaudio const char *
950c88bf70Sclaudio log_as(u_int32_t as)
960c88bf70Sclaudio {
9706bcde9cSphessler 	static char	buf[11];	/* "4294967294\0" */
980c88bf70Sclaudio 
990c88bf70Sclaudio 	if (snprintf(buf, sizeof(buf), "%u", as) == -1)
1000c88bf70Sclaudio 		return ("?");
10106bcde9cSphessler 
1020c88bf70Sclaudio 	return (buf);
1030c88bf70Sclaudio }
1040c88bf70Sclaudio 
105256b680eSclaudio const char *
106256b680eSclaudio log_rd(u_int64_t rd)
107256b680eSclaudio {
108256b680eSclaudio 	static char	buf[32];
109256b680eSclaudio 	struct in_addr	addr;
110256b680eSclaudio 	u_int32_t	u32;
111256b680eSclaudio 	u_int16_t	u16;
112256b680eSclaudio 
113256b680eSclaudio 	rd = betoh64(rd);
114256b680eSclaudio 	switch (rd >> 48) {
115256b680eSclaudio 	case EXT_COMMUNITY_TWO_AS:
116256b680eSclaudio 		u32 = rd & 0xffffffff;
117256b680eSclaudio 		u16 = (rd >> 32) & 0xffff;
11832ecd2d8Sderaadt 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
119256b680eSclaudio 		break;
120256b680eSclaudio 	case EXT_COMMUNITY_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;
125256b680eSclaudio 	case EXT_COMMUNITY_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 
137256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is
138536f41e5Sclaudio  * actually valid. */
139536f41e5Sclaudio const char *
140536f41e5Sclaudio log_ext_subtype(u_int8_t subtype)
141536f41e5Sclaudio {
142536f41e5Sclaudio 	static char etype[6];
143536f41e5Sclaudio 
144536f41e5Sclaudio 	switch (subtype) {
145536f41e5Sclaudio 	case EXT_COMMUNITY_ROUTE_TGT:
146536f41e5Sclaudio 		return ("rt");	/* route target */
147e85ee6aeSsthen 	case EXT_COMMUNITY_ROUTE_ORIG:
148536f41e5Sclaudio 		return ("soo");	/* source of origin */
149536f41e5Sclaudio 	case EXT_COMMUNITY_OSPF_DOM_ID:
150536f41e5Sclaudio 		return ("odi");	/* ospf domain id */
151536f41e5Sclaudio 	case EXT_COMMUNITY_OSPF_RTR_TYPE:
152536f41e5Sclaudio 		return ("ort");	/* ospf route type */
153536f41e5Sclaudio 	case EXT_COMMUNITY_OSPF_RTR_ID:
154536f41e5Sclaudio 		return ("ori");	/* ospf router id */
155536f41e5Sclaudio 	case EXT_COMMUNITY_BGP_COLLECT:
156536f41e5Sclaudio 		return ("bdc");	/* bgp data collection */
157536f41e5Sclaudio 	default:
158d6340f7aSderaadt 		snprintf(etype, sizeof(etype), "[%u]", subtype);
159536f41e5Sclaudio 		return (etype);
160536f41e5Sclaudio 	}
161536f41e5Sclaudio }
162536f41e5Sclaudio 
1631e590dcfSclaudio const char *
1640561b344Sphessler log_shutcomm(const char *communication) {
1650561b344Sphessler 	static char buf[(SHUT_COMM_LEN - 1) * 4 + 1];
1660561b344Sphessler 
1670561b344Sphessler 	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
1680561b344Sphessler 
1690561b344Sphessler 	return buf;
1700561b344Sphessler }
1710561b344Sphessler 
1720561b344Sphessler const char *
1731e590dcfSclaudio aspath_delim(u_int8_t seg_type, int closing)
1741e590dcfSclaudio {
1751e590dcfSclaudio 	static char db[8];
1761e590dcfSclaudio 
1771e590dcfSclaudio 	switch (seg_type) {
1781e590dcfSclaudio 	case AS_SET:
1791e590dcfSclaudio 		if (!closing)
1801e590dcfSclaudio 			return ("{ ");
1811e590dcfSclaudio 		else
1821e590dcfSclaudio 			return (" }");
1831e590dcfSclaudio 	case AS_SEQUENCE:
1841e590dcfSclaudio 		return ("");
1851e590dcfSclaudio 	case AS_CONFED_SEQUENCE:
1861e590dcfSclaudio 		if (!closing)
1871e590dcfSclaudio 			return ("( ");
1881e590dcfSclaudio 		else
1891e590dcfSclaudio 			return (" )");
1901e590dcfSclaudio 	case AS_CONFED_SET:
1911e590dcfSclaudio 		if (!closing)
1921e590dcfSclaudio 			return ("[ ");
1931e590dcfSclaudio 		else
1941e590dcfSclaudio 			return (" ]");
1951e590dcfSclaudio 	default:
1961e590dcfSclaudio 		if (!closing)
1971e590dcfSclaudio 			snprintf(db, sizeof(db), "!%u ", seg_type);
1981e590dcfSclaudio 		else
1991e590dcfSclaudio 			snprintf(db, sizeof(db), " !%u", seg_type);
2001e590dcfSclaudio 		return (db);
2011e590dcfSclaudio 	}
2021e590dcfSclaudio }
2031e590dcfSclaudio 
2042ffcd4e0Sclaudio int
2052ffcd4e0Sclaudio aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
2062ffcd4e0Sclaudio {
2072ffcd4e0Sclaudio #define UPDATE()				\
2082ffcd4e0Sclaudio 	do {					\
2092ffcd4e0Sclaudio 		if (r == -1)			\
2102ffcd4e0Sclaudio 			return (-1);		\
2112ffcd4e0Sclaudio 		total_size += r;		\
2122ffcd4e0Sclaudio 		if ((unsigned int)r < size) {	\
2132ffcd4e0Sclaudio 			size -= r;		\
2142ffcd4e0Sclaudio 			buf += r;		\
2152ffcd4e0Sclaudio 		} else {			\
2162ffcd4e0Sclaudio 			buf += size;		\
2172ffcd4e0Sclaudio 			size = 0;		\
2182ffcd4e0Sclaudio 		}				\
2192ffcd4e0Sclaudio 	} while (0)
2202ffcd4e0Sclaudio 	u_int8_t	*seg;
2212ffcd4e0Sclaudio 	int		 r, total_size;
2222ffcd4e0Sclaudio 	u_int16_t	 seg_size;
2232ffcd4e0Sclaudio 	u_int8_t	 i, seg_type, seg_len;
2242ffcd4e0Sclaudio 
2252ffcd4e0Sclaudio 	total_size = 0;
2262ffcd4e0Sclaudio 	seg = data;
2272ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
2282ffcd4e0Sclaudio 		seg_type = seg[0];
2292ffcd4e0Sclaudio 		seg_len = seg[1];
2300c88bf70Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
2312ffcd4e0Sclaudio 
2321e590dcfSclaudio 		r = snprintf(buf, size, "%s%s",
2331e590dcfSclaudio 		    total_size != 0 ? " " : "",
2341e590dcfSclaudio 		    aspath_delim(seg_type, 0));
2352ffcd4e0Sclaudio 		UPDATE();
2362ffcd4e0Sclaudio 
2372ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
2380c88bf70Sclaudio 			r = snprintf(buf, size, "%s",
2390c88bf70Sclaudio 			    log_as(aspath_extract(seg, i)));
2402ffcd4e0Sclaudio 			UPDATE();
2412ffcd4e0Sclaudio 			if (i + 1 < seg_len) {
2422ffcd4e0Sclaudio 				r = snprintf(buf, size, " ");
2432ffcd4e0Sclaudio 				UPDATE();
2442ffcd4e0Sclaudio 			}
2452ffcd4e0Sclaudio 		}
2461e590dcfSclaudio 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
2472ffcd4e0Sclaudio 		UPDATE();
2482ffcd4e0Sclaudio 	}
24955e49665Sclaudio 	/* ensure that we have a valid C-string especially for empty as path */
2502ffcd4e0Sclaudio 	if (size > 0)
2512ffcd4e0Sclaudio 		*buf = '\0';
2522ffcd4e0Sclaudio 
2532ffcd4e0Sclaudio 	return (total_size);
2542ffcd4e0Sclaudio #undef UPDATE
2552ffcd4e0Sclaudio }
2562ffcd4e0Sclaudio 
2572ffcd4e0Sclaudio int
2582ffcd4e0Sclaudio aspath_asprint(char **ret, void *data, u_int16_t len)
2592ffcd4e0Sclaudio {
2602ffcd4e0Sclaudio 	size_t	slen;
2612ffcd4e0Sclaudio 	int	plen;
2622ffcd4e0Sclaudio 
2632ffcd4e0Sclaudio 	slen = aspath_strlen(data, len) + 1;
2642ffcd4e0Sclaudio 	*ret = malloc(slen);
2652ffcd4e0Sclaudio 	if (*ret == NULL)
2662ffcd4e0Sclaudio 		return (-1);
2672ffcd4e0Sclaudio 
2682ffcd4e0Sclaudio 	plen = aspath_snprint(*ret, slen, data, len);
2692ffcd4e0Sclaudio 	if (plen == -1) {
2702ffcd4e0Sclaudio 		free(*ret);
2712ffcd4e0Sclaudio 		*ret = NULL;
2722ffcd4e0Sclaudio 		return (-1);
2732ffcd4e0Sclaudio 	}
2742ffcd4e0Sclaudio 
2752ffcd4e0Sclaudio 	return (0);
2762ffcd4e0Sclaudio }
2772ffcd4e0Sclaudio 
2782ffcd4e0Sclaudio size_t
2792ffcd4e0Sclaudio aspath_strlen(void *data, u_int16_t len)
2802ffcd4e0Sclaudio {
2812ffcd4e0Sclaudio 	u_int8_t	*seg;
2822ffcd4e0Sclaudio 	int		 total_size;
2830c88bf70Sclaudio 	u_int32_t	 as;
2840c88bf70Sclaudio 	u_int16_t	 seg_size;
2852ffcd4e0Sclaudio 	u_int8_t	 i, seg_type, seg_len;
2862ffcd4e0Sclaudio 
2872ffcd4e0Sclaudio 	total_size = 0;
2882ffcd4e0Sclaudio 	seg = data;
2892ffcd4e0Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
2902ffcd4e0Sclaudio 		seg_type = seg[0];
2912ffcd4e0Sclaudio 		seg_len = seg[1];
2920c88bf70Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
2932ffcd4e0Sclaudio 
2942ffcd4e0Sclaudio 		if (seg_type == AS_SET)
2952ffcd4e0Sclaudio 			if (total_size != 0)
2962ffcd4e0Sclaudio 				total_size += 3;
2972ffcd4e0Sclaudio 			else
2982ffcd4e0Sclaudio 				total_size += 2;
2992ffcd4e0Sclaudio 		else if (total_size != 0)
3002ffcd4e0Sclaudio 			total_size += 1;
3012ffcd4e0Sclaudio 
3022ffcd4e0Sclaudio 		for (i = 0; i < seg_len; i++) {
3032ffcd4e0Sclaudio 			as = aspath_extract(seg, i);
3040c88bf70Sclaudio 
3058db4f5d2Sclaudio 			do {
3068db4f5d2Sclaudio 				total_size++;
3078db4f5d2Sclaudio 			} while ((as = as / 10) != 0);
3082ffcd4e0Sclaudio 
3092ffcd4e0Sclaudio 			if (i + 1 < seg_len)
3102ffcd4e0Sclaudio 				total_size += 1;
3112ffcd4e0Sclaudio 		}
3122ffcd4e0Sclaudio 
3132ffcd4e0Sclaudio 		if (seg_type == AS_SET)
3142ffcd4e0Sclaudio 			total_size += 2;
3152ffcd4e0Sclaudio 	}
3162ffcd4e0Sclaudio 	return (total_size);
3172ffcd4e0Sclaudio }
3182ffcd4e0Sclaudio 
319fafbb788Sclaudio /* we need to be able to search more than one as */
320fafbb788Sclaudio int
321368f0e94Sbenno aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
322fafbb788Sclaudio {
323fafbb788Sclaudio 	u_int8_t	*seg;
324fafbb788Sclaudio 	int		 final;
325fafbb788Sclaudio 	u_int16_t	 seg_size;
326de50ed92Sclaudio 	u_int8_t	 i, seg_len;
327368f0e94Sbenno 	u_int32_t	 as;
328fafbb788Sclaudio 
329368f0e94Sbenno 	if (f->type == AS_EMPTY) {
330fafbb788Sclaudio 		if (len == 0)
331fafbb788Sclaudio 			return (1);
332fafbb788Sclaudio 		else
333fafbb788Sclaudio 			return (0);
334fafbb788Sclaudio 	}
335fafbb788Sclaudio 
336fafbb788Sclaudio 	seg = data;
337fafbb788Sclaudio 	for (; len > 0; len -= seg_size, seg += seg_size) {
338fafbb788Sclaudio 		seg_len = seg[1];
339fafbb788Sclaudio 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
340fafbb788Sclaudio 
341fafbb788Sclaudio 		final = (len == seg_size);
342fafbb788Sclaudio 
343fafbb788Sclaudio 		/* just check the first (leftmost) AS */
344368f0e94Sbenno 		if (f->type == AS_PEER) {
345368f0e94Sbenno 			as = aspath_extract(seg, 0);
346368f0e94Sbenno 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
347fafbb788Sclaudio 				return (1);
348fafbb788Sclaudio 			else
349fafbb788Sclaudio 				return (0);
350fafbb788Sclaudio 		}
351fafbb788Sclaudio 		/* just check the final (rightmost) AS */
352368f0e94Sbenno 		if (f->type == AS_SOURCE) {
353fafbb788Sclaudio 			/* not yet in the final segment */
354fafbb788Sclaudio 			if (!final)
355fafbb788Sclaudio 				continue;
356368f0e94Sbenno 			as = aspath_extract(seg, seg_len - 1);
357368f0e94Sbenno 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
358fafbb788Sclaudio 				return (1);
359fafbb788Sclaudio 			else
360fafbb788Sclaudio 				return (0);
361fafbb788Sclaudio 		}
362fafbb788Sclaudio 		/* AS_TRANSIT or AS_ALL */
363fafbb788Sclaudio 		for (i = 0; i < seg_len; i++) {
364fafbb788Sclaudio 			/*
365fafbb788Sclaudio 			 * the source (rightmost) AS is excluded from
366fafbb788Sclaudio 			 * AS_TRANSIT matches.
367fafbb788Sclaudio 			 */
368368f0e94Sbenno 			if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
369fafbb788Sclaudio 				return (0);
370368f0e94Sbenno 			as = aspath_extract(seg, i);
371368f0e94Sbenno 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
372fafbb788Sclaudio 				return (1);
373fafbb788Sclaudio 		}
374fafbb788Sclaudio 	}
375368f0e94Sbenno 	return (0);
376fafbb788Sclaudio }
377368f0e94Sbenno 
378368f0e94Sbenno int
379368f0e94Sbenno as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min,
380368f0e94Sbenno     u_int32_t as_max)
381368f0e94Sbenno {
382368f0e94Sbenno 	if ((op == OP_NONE || op == OP_EQ) && as == match)
383368f0e94Sbenno 		return (1);
384368f0e94Sbenno 	else if (op == OP_NE && as != match)
385368f0e94Sbenno 		return (1);
386368f0e94Sbenno 	else if (op == OP_RANGE && as >= as_min && as <= as_max)
387368f0e94Sbenno 		return (1);
388368f0e94Sbenno 	else if (op == OP_XRANGE && as > as_min && as < as_max)
389368f0e94Sbenno 		return (1);
390fafbb788Sclaudio 	return (0);
391fafbb788Sclaudio }
392fafbb788Sclaudio 
3932ffcd4e0Sclaudio /*
3942ffcd4e0Sclaudio  * Extract the asnum out of the as segment at the specified position.
3952ffcd4e0Sclaudio  * Direct access is not possible because of non-aligned reads.
396c5508ee4Sclaudio  * ATTENTION: no bounds checks are done.
3972ffcd4e0Sclaudio  */
3980c88bf70Sclaudio u_int32_t
3992ffcd4e0Sclaudio aspath_extract(const void *seg, int pos)
4002ffcd4e0Sclaudio {
4012ffcd4e0Sclaudio 	const u_char	*ptr = seg;
4020c88bf70Sclaudio 	u_int32_t	 as;
4032ffcd4e0Sclaudio 
4040c88bf70Sclaudio 	ptr += 2 + sizeof(u_int32_t) * pos;
4050c88bf70Sclaudio 	memcpy(&as, ptr, sizeof(u_int32_t));
4060c88bf70Sclaudio 	return (ntohl(as));
4072ffcd4e0Sclaudio }
40821a825c9Sclaudio 
409de5c2eedSclaudio /*
410de5c2eedSclaudio  * This function will have undefined behaviour if the passed in prefixlen is
411de5c2eedSclaudio  * to large for the respective bgpd_addr address family.
412de5c2eedSclaudio  */
413fafbb788Sclaudio int
414fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
415fafbb788Sclaudio     int prefixlen)
416fafbb788Sclaudio {
417fafbb788Sclaudio 	in_addr_t	mask, aa, ba;
418fafbb788Sclaudio 	int		i;
419fafbb788Sclaudio 	u_int8_t	m;
420fafbb788Sclaudio 
421fafbb788Sclaudio 	if (a->aid != b->aid)
422fafbb788Sclaudio 		return (a->aid - b->aid);
423fafbb788Sclaudio 
424fafbb788Sclaudio 	switch (a->aid) {
425fafbb788Sclaudio 	case AID_INET:
4267da59fecSclaudio 		if (prefixlen == 0)
4277da59fecSclaudio 			return (0);
428fafbb788Sclaudio 		if (prefixlen > 32)
429de5c2eedSclaudio 			return (-1);
430fafbb788Sclaudio 		mask = htonl(prefixlen2mask(prefixlen));
431fafbb788Sclaudio 		aa = ntohl(a->v4.s_addr & mask);
432fafbb788Sclaudio 		ba = ntohl(b->v4.s_addr & mask);
433fafbb788Sclaudio 		if (aa != ba)
434fafbb788Sclaudio 			return (aa - ba);
435fafbb788Sclaudio 		return (0);
436fafbb788Sclaudio 	case AID_INET6:
4377da59fecSclaudio 		if (prefixlen == 0)
4387da59fecSclaudio 			return (0);
439fafbb788Sclaudio 		if (prefixlen > 128)
440de5c2eedSclaudio 			return (-1);
441fafbb788Sclaudio 		for (i = 0; i < prefixlen / 8; i++)
442fafbb788Sclaudio 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
443fafbb788Sclaudio 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
444fafbb788Sclaudio 		i = prefixlen % 8;
445fafbb788Sclaudio 		if (i) {
446fafbb788Sclaudio 			m = 0xff00 >> i;
447fafbb788Sclaudio 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
448fafbb788Sclaudio 			    (b->v6.s6_addr[prefixlen / 8] & m))
449fafbb788Sclaudio 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
450fafbb788Sclaudio 				    (b->v6.s6_addr[prefixlen / 8] & m));
451fafbb788Sclaudio 		}
452fafbb788Sclaudio 		return (0);
453fafbb788Sclaudio 	case AID_VPN_IPv4:
454fafbb788Sclaudio 		if (prefixlen > 32)
455de5c2eedSclaudio 			return (-1);
456fafbb788Sclaudio 		if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
457fafbb788Sclaudio 			return (1);
458fafbb788Sclaudio 		if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd))
459fafbb788Sclaudio 			return (-1);
460fafbb788Sclaudio 		mask = htonl(prefixlen2mask(prefixlen));
461fafbb788Sclaudio 		aa = ntohl(a->vpn4.addr.s_addr & mask);
462fafbb788Sclaudio 		ba = ntohl(b->vpn4.addr.s_addr & mask);
463fafbb788Sclaudio 		if (aa != ba)
464fafbb788Sclaudio 			return (aa - ba);
465fafbb788Sclaudio 		if (a->vpn4.labellen > b->vpn4.labellen)
466fafbb788Sclaudio 			return (1);
467fafbb788Sclaudio 		if (a->vpn4.labellen < b->vpn4.labellen)
468fafbb788Sclaudio 			return (-1);
469fafbb788Sclaudio 		return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
470fafbb788Sclaudio 		    a->vpn4.labellen));
471fafbb788Sclaudio 	}
472fafbb788Sclaudio 	return (-1);
473fafbb788Sclaudio }
474fafbb788Sclaudio 
47521a825c9Sclaudio in_addr_t
47621a825c9Sclaudio prefixlen2mask(u_int8_t prefixlen)
47721a825c9Sclaudio {
47821a825c9Sclaudio 	if (prefixlen == 0)
47921a825c9Sclaudio 		return (0);
48021a825c9Sclaudio 
48121a825c9Sclaudio 	return (0xffffffff << (32 - prefixlen));
48221a825c9Sclaudio }
48321a825c9Sclaudio 
48421a825c9Sclaudio void
48521a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
48621a825c9Sclaudio {
48721a825c9Sclaudio 	struct in6_addr	mask;
48821a825c9Sclaudio 	int		i;
48921a825c9Sclaudio 
49021a825c9Sclaudio 	bzero(&mask, sizeof(mask));
49121a825c9Sclaudio 	for (i = 0; i < prefixlen / 8; i++)
49221a825c9Sclaudio 		mask.s6_addr[i] = 0xff;
49321a825c9Sclaudio 	i = prefixlen % 8;
49421a825c9Sclaudio 	if (i)
49521a825c9Sclaudio 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
49621a825c9Sclaudio 
49721a825c9Sclaudio 	for (i = 0; i < 16; i++)
49821a825c9Sclaudio 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
49921a825c9Sclaudio }
500d6c2e4e8Sclaudio 
501d6c2e4e8Sclaudio /* address family translation functions */
502d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS;
503d6c2e4e8Sclaudio 
50486729c90Sclaudio const char *
50586729c90Sclaudio aid2str(u_int8_t aid)
50686729c90Sclaudio {
50786729c90Sclaudio 	if (aid < AID_MAX)
50886729c90Sclaudio 		return (aid_vals[aid].name);
50986729c90Sclaudio 	return ("unknown AID");
51086729c90Sclaudio }
51186729c90Sclaudio 
512d6c2e4e8Sclaudio int
513d6c2e4e8Sclaudio aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
514d6c2e4e8Sclaudio {
515d6c2e4e8Sclaudio 	if (aid < AID_MAX) {
516d6c2e4e8Sclaudio 		*afi = aid_vals[aid].afi;
517d6c2e4e8Sclaudio 		*safi = aid_vals[aid].safi;
518d6c2e4e8Sclaudio 		return (0);
519d6c2e4e8Sclaudio 	}
520d6c2e4e8Sclaudio 	return (-1);
521d6c2e4e8Sclaudio }
522d6c2e4e8Sclaudio 
523d6c2e4e8Sclaudio int
524d6c2e4e8Sclaudio afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
525d6c2e4e8Sclaudio {
526d6c2e4e8Sclaudio 	u_int8_t i;
527d6c2e4e8Sclaudio 
528d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
529d6c2e4e8Sclaudio 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
530d6c2e4e8Sclaudio 			*aid = i;
531d6c2e4e8Sclaudio 			return (0);
532d6c2e4e8Sclaudio 		}
533d6c2e4e8Sclaudio 
534d6c2e4e8Sclaudio 	return (-1);
535d6c2e4e8Sclaudio }
536d6c2e4e8Sclaudio 
537d6c2e4e8Sclaudio sa_family_t
538d6c2e4e8Sclaudio aid2af(u_int8_t aid)
539d6c2e4e8Sclaudio {
540d6c2e4e8Sclaudio 	if (aid < AID_MAX)
541d6c2e4e8Sclaudio 		return (aid_vals[aid].af);
542d6c2e4e8Sclaudio 	return (AF_UNSPEC);
543d6c2e4e8Sclaudio }
544d6c2e4e8Sclaudio 
545d6c2e4e8Sclaudio int
546d6c2e4e8Sclaudio af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
547d6c2e4e8Sclaudio {
548d6c2e4e8Sclaudio 	u_int8_t i;
549d6c2e4e8Sclaudio 
550d6c2e4e8Sclaudio 	if (safi == 0) /* default to unicast subclass */
551d6c2e4e8Sclaudio 		safi = SAFI_UNICAST;
552d6c2e4e8Sclaudio 
553d6c2e4e8Sclaudio 	for (i = 0; i < AID_MAX; i++)
554d6c2e4e8Sclaudio 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
555d6c2e4e8Sclaudio 			*aid = i;
556d6c2e4e8Sclaudio 			return (0);
557d6c2e4e8Sclaudio 		}
558d6c2e4e8Sclaudio 
559d6c2e4e8Sclaudio 	return (-1);
560d6c2e4e8Sclaudio }
561d6c2e4e8Sclaudio 
562d6c2e4e8Sclaudio struct sockaddr *
563d6c2e4e8Sclaudio addr2sa(struct bgpd_addr *addr, u_int16_t port)
564d6c2e4e8Sclaudio {
565d6c2e4e8Sclaudio 	static struct sockaddr_storage	 ss;
566d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
567d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
568d6c2e4e8Sclaudio 
569d6c2e4e8Sclaudio 	if (addr->aid == AID_UNSPEC)
570d6c2e4e8Sclaudio 		return (NULL);
571d6c2e4e8Sclaudio 
572d6c2e4e8Sclaudio 	bzero(&ss, sizeof(ss));
573d6c2e4e8Sclaudio 	switch (addr->aid) {
574d6c2e4e8Sclaudio 	case AID_INET:
575d6c2e4e8Sclaudio 		sa_in->sin_family = AF_INET;
576d6c2e4e8Sclaudio 		sa_in->sin_len = sizeof(struct sockaddr_in);
577d6c2e4e8Sclaudio 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
578d6c2e4e8Sclaudio 		sa_in->sin_port = htons(port);
579d6c2e4e8Sclaudio 		break;
580d6c2e4e8Sclaudio 	case AID_INET6:
581d6c2e4e8Sclaudio 		sa_in6->sin6_family = AF_INET6;
582d6c2e4e8Sclaudio 		sa_in6->sin6_len = sizeof(struct sockaddr_in6);
583d6c2e4e8Sclaudio 		memcpy(&sa_in6->sin6_addr, &addr->v6,
584d6c2e4e8Sclaudio 		    sizeof(sa_in6->sin6_addr));
585d6c2e4e8Sclaudio 		sa_in6->sin6_port = htons(port);
586d6c2e4e8Sclaudio 		sa_in6->sin6_scope_id = addr->scope_id;
587d6c2e4e8Sclaudio 		break;
588d6c2e4e8Sclaudio 	}
589d6c2e4e8Sclaudio 
590d6c2e4e8Sclaudio 	return ((struct sockaddr *)&ss);
591d6c2e4e8Sclaudio }
592d6c2e4e8Sclaudio 
593d6c2e4e8Sclaudio void
594d6c2e4e8Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr)
595d6c2e4e8Sclaudio {
596d6c2e4e8Sclaudio 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
597d6c2e4e8Sclaudio 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
598d6c2e4e8Sclaudio 
599d6c2e4e8Sclaudio 	bzero(addr, sizeof(*addr));
600d6c2e4e8Sclaudio 	switch (sa->sa_family) {
601d6c2e4e8Sclaudio 	case AF_INET:
602d6c2e4e8Sclaudio 		addr->aid = AID_INET;
603d6c2e4e8Sclaudio 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
604d6c2e4e8Sclaudio 		break;
605d6c2e4e8Sclaudio 	case AF_INET6:
606d6c2e4e8Sclaudio 		addr->aid = AID_INET6;
607d6c2e4e8Sclaudio 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
608d6c2e4e8Sclaudio 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
609d6c2e4e8Sclaudio 		break;
610d6c2e4e8Sclaudio 	}
611d6c2e4e8Sclaudio }
612