xref: /openbsd-src/usr.sbin/eigrpd/util.c (revision 3a50f0a93a2072911d0ba6ababa815fb04bf9a71)
1*3a50f0a9Sjmc /*	$OpenBSD: util.c,v 1.12 2022/12/28 21:30:16 jmc Exp $ */
243509a12Srenato 
343509a12Srenato /*
443509a12Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
543509a12Srenato  * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org>
643509a12Srenato  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
743509a12Srenato  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
843509a12Srenato  *
943509a12Srenato  * Permission to use, copy, modify, and distribute this software for any
1043509a12Srenato  * purpose with or without fee is hereby granted, provided that the above
1143509a12Srenato  * copyright notice and this permission notice appear in all copies.
1243509a12Srenato  *
1343509a12Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1443509a12Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1543509a12Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1643509a12Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1743509a12Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1843509a12Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1943509a12Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2043509a12Srenato  */
2143509a12Srenato 
228072de9bSrenato #include <sys/types.h>
238072de9bSrenato 
2443509a12Srenato #include <string.h>
2543509a12Srenato 
2643509a12Srenato #include "eigrpd.h"
2743509a12Srenato #include "log.h"
2843509a12Srenato 
2943509a12Srenato uint8_t
mask2prefixlen(in_addr_t ina)3043509a12Srenato mask2prefixlen(in_addr_t ina)
3143509a12Srenato {
3243509a12Srenato 	if (ina == 0)
3343509a12Srenato 		return (0);
3443509a12Srenato 	else
3543509a12Srenato 		return (33 - ffs(ntohl(ina)));
3643509a12Srenato }
3743509a12Srenato 
3843509a12Srenato uint8_t
mask2prefixlen6(struct sockaddr_in6 * sa_in6)3943509a12Srenato mask2prefixlen6(struct sockaddr_in6 *sa_in6)
4043509a12Srenato {
41884600caSclaudio 	unsigned int l = 0;
42884600caSclaudio 	uint8_t *ap, *ep;
4343509a12Srenato 
4443509a12Srenato 	/*
45*3a50f0a9Sjmc 	 * sin6_len is the size of the sockaddr so subtract the offset of
4643509a12Srenato 	 * the possibly truncated sin6_addr struct.
4743509a12Srenato 	 */
4843509a12Srenato 	ap = (uint8_t *)&sa_in6->sin6_addr;
4943509a12Srenato 	ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
5043509a12Srenato 	for (; ap < ep; ap++) {
5143509a12Srenato 		/* this "beauty" is adopted from sbin/route/show.c ... */
5243509a12Srenato 		switch (*ap) {
5343509a12Srenato 		case 0xff:
5443509a12Srenato 			l += 8;
5543509a12Srenato 			break;
5643509a12Srenato 		case 0xfe:
5743509a12Srenato 			l += 7;
58884600caSclaudio 			goto done;
5943509a12Srenato 		case 0xfc:
6043509a12Srenato 			l += 6;
61884600caSclaudio 			goto done;
6243509a12Srenato 		case 0xf8:
6343509a12Srenato 			l += 5;
64884600caSclaudio 			goto done;
6543509a12Srenato 		case 0xf0:
6643509a12Srenato 			l += 4;
67884600caSclaudio 			goto done;
6843509a12Srenato 		case 0xe0:
6943509a12Srenato 			l += 3;
70884600caSclaudio 			goto done;
7143509a12Srenato 		case 0xc0:
7243509a12Srenato 			l += 2;
73884600caSclaudio 			goto done;
7443509a12Srenato 		case 0x80:
7543509a12Srenato 			l += 1;
76884600caSclaudio 			goto done;
7743509a12Srenato 		case 0x00:
78884600caSclaudio 			goto done;
7943509a12Srenato 		default:
8043509a12Srenato 			fatalx("non contiguous inet6 netmask");
8143509a12Srenato 		}
8243509a12Srenato 	}
8343509a12Srenato 
84884600caSclaudio done:
85884600caSclaudio 	if (l > sizeof(struct in6_addr) * 8)
86884600caSclaudio 		fatalx("inet6 prefixlen out of bound");
8743509a12Srenato 	return (l);
8843509a12Srenato }
8943509a12Srenato 
9043509a12Srenato in_addr_t
prefixlen2mask(uint8_t prefixlen)9143509a12Srenato prefixlen2mask(uint8_t prefixlen)
9243509a12Srenato {
9343509a12Srenato 	if (prefixlen == 0)
9443509a12Srenato 		return (0);
9543509a12Srenato 
9643509a12Srenato 	return (htonl(0xffffffff << (32 - prefixlen)));
9743509a12Srenato }
9843509a12Srenato 
9943509a12Srenato struct in6_addr *
prefixlen2mask6(uint8_t prefixlen)10043509a12Srenato prefixlen2mask6(uint8_t prefixlen)
10143509a12Srenato {
10243509a12Srenato 	static struct in6_addr	mask;
10343509a12Srenato 	int			i;
10443509a12Srenato 
10543509a12Srenato 	memset(&mask, 0, sizeof(mask));
10643509a12Srenato 	for (i = 0; i < prefixlen / 8; i++)
10743509a12Srenato 		mask.s6_addr[i] = 0xff;
10843509a12Srenato 	i = prefixlen % 8;
10943509a12Srenato 	if (i)
11043509a12Srenato 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
11143509a12Srenato 
11243509a12Srenato 	return (&mask);
11343509a12Srenato }
11443509a12Srenato 
11543509a12Srenato void
eigrp_applymask(int af,union eigrpd_addr * dest,const union eigrpd_addr * src,int prefixlen)11643509a12Srenato eigrp_applymask(int af, union eigrpd_addr *dest, const union eigrpd_addr *src,
11743509a12Srenato     int prefixlen)
11843509a12Srenato {
11943509a12Srenato 	struct in6_addr	mask;
12043509a12Srenato 	int		i;
12143509a12Srenato 
12243509a12Srenato 	switch (af) {
12343509a12Srenato 	case AF_INET:
12443509a12Srenato 		dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen);
12543509a12Srenato 		break;
12643509a12Srenato 	case AF_INET6:
12743509a12Srenato 		memset(&mask, 0, sizeof(mask));
12843509a12Srenato 		for (i = 0; i < prefixlen / 8; i++)
12943509a12Srenato 			mask.s6_addr[i] = 0xff;
13043509a12Srenato 		i = prefixlen % 8;
13143509a12Srenato 		if (i)
13243509a12Srenato 			mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
13343509a12Srenato 
13443509a12Srenato 		for (i = 0; i < 16; i++)
13543509a12Srenato 			dest->v6.s6_addr[i] = src->v6.s6_addr[i] &
13643509a12Srenato 			    mask.s6_addr[i];
13743509a12Srenato 		break;
13843509a12Srenato 	default:
1393c8071b0Srenato 		fatalx("eigrp_applymask: unknown af");
14043509a12Srenato 	}
14143509a12Srenato }
14243509a12Srenato 
14343509a12Srenato int
eigrp_addrcmp(int af,const union eigrpd_addr * a,const union eigrpd_addr * b)14437212791Srenato eigrp_addrcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b)
14543509a12Srenato {
14643509a12Srenato 	switch (af) {
14743509a12Srenato 	case AF_INET:
148e8918803Srenato 		if (a->v4.s_addr == b->v4.s_addr)
149e8918803Srenato 			return (0);
150e8918803Srenato 		return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1);
15143509a12Srenato 	case AF_INET6:
152e8918803Srenato 		return (!!memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
15343509a12Srenato 	default:
1543c8071b0Srenato 		fatalx("eigrp_addrcmp: unknown af");
15543509a12Srenato 	}
15643509a12Srenato }
15743509a12Srenato 
15843509a12Srenato int
eigrp_addrisset(int af,const union eigrpd_addr * addr)15937212791Srenato eigrp_addrisset(int af, const union eigrpd_addr *addr)
16043509a12Srenato {
16143509a12Srenato 	switch (af) {
1623c8071b0Srenato 	case AF_UNSPEC:
1633c8071b0Srenato 		return (0);
16443509a12Srenato 	case AF_INET:
16543509a12Srenato 		if (addr->v4.s_addr != INADDR_ANY)
16643509a12Srenato 			return (1);
16743509a12Srenato 		break;
16843509a12Srenato 	case AF_INET6:
16943509a12Srenato 		if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
17043509a12Srenato 			return (1);
17143509a12Srenato 		break;
17243509a12Srenato 	default:
1733c8071b0Srenato 		fatalx("eigrp_addrisset: unknown af");
17443509a12Srenato 	}
17543509a12Srenato 
17643509a12Srenato 	return (0);
17743509a12Srenato }
17843509a12Srenato 
179bc6e1915Srenato int
eigrp_prefixcmp(int af,const union eigrpd_addr * a,const union eigrpd_addr * b,uint8_t prefixlen)180bc6e1915Srenato eigrp_prefixcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b,
181bc6e1915Srenato     uint8_t prefixlen)
182bc6e1915Srenato {
183bc6e1915Srenato 	in_addr_t	mask, aa, ba;
184bc6e1915Srenato 	int		i;
185bc6e1915Srenato 	uint8_t		m;
186bc6e1915Srenato 
187bc6e1915Srenato 	switch (af) {
188bc6e1915Srenato 	case AF_INET:
189bc6e1915Srenato 		if (prefixlen == 0)
190bc6e1915Srenato 			return (0);
191bc6e1915Srenato 		if (prefixlen > 32)
192bc6e1915Srenato 			fatalx("eigrp_prefixcmp: bad IPv4 prefixlen");
193bc6e1915Srenato 		mask = htonl(prefixlen2mask(prefixlen));
194bc6e1915Srenato 		aa = htonl(a->v4.s_addr) & mask;
195bc6e1915Srenato 		ba = htonl(b->v4.s_addr) & mask;
196bc6e1915Srenato 		return (aa - ba);
197bc6e1915Srenato 	case AF_INET6:
198bc6e1915Srenato 		if (prefixlen == 0)
199bc6e1915Srenato 			return (0);
200bc6e1915Srenato 		if (prefixlen > 128)
201bc6e1915Srenato 			fatalx("eigrp_prefixcmp: bad IPv6 prefixlen");
202bc6e1915Srenato 		for (i = 0; i < prefixlen / 8; i++)
203bc6e1915Srenato 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
204bc6e1915Srenato 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
205bc6e1915Srenato 		i = prefixlen % 8;
206bc6e1915Srenato 		if (i) {
207bc6e1915Srenato 			m = 0xff00 >> i;
208bc6e1915Srenato 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
209bc6e1915Srenato 			    (b->v6.s6_addr[prefixlen / 8] & m))
210bc6e1915Srenato 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
211bc6e1915Srenato 				    (b->v6.s6_addr[prefixlen / 8] & m));
212bc6e1915Srenato 		}
213bc6e1915Srenato 		return (0);
214bc6e1915Srenato 	default:
215bc6e1915Srenato 		fatalx("eigrp_prefixcmp: unknown af");
216bc6e1915Srenato 	}
217bc6e1915Srenato 	return (-1);
218bc6e1915Srenato }
219bc6e1915Srenato 
2206c428d2eSrenato int
bad_addr_v4(struct in_addr addr)2216c428d2eSrenato bad_addr_v4(struct in_addr addr)
2226c428d2eSrenato {
2236c428d2eSrenato 	uint32_t	 a = ntohl(addr.s_addr);
2246c428d2eSrenato 
2256c428d2eSrenato 	if (((a >> IN_CLASSA_NSHIFT) == 0) ||
2266c428d2eSrenato 	    ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) ||
227ef8f8f93Sclaudio 	    IN_MULTICAST(a))
2286c428d2eSrenato 		return (1);
2296c428d2eSrenato 
2306c428d2eSrenato 	return (0);
2316c428d2eSrenato }
2326c428d2eSrenato 
2336c428d2eSrenato int
bad_addr_v6(struct in6_addr * addr)2346c428d2eSrenato bad_addr_v6(struct in6_addr *addr)
2356c428d2eSrenato {
2366c428d2eSrenato 	if (IN6_IS_ADDR_UNSPECIFIED(addr) ||
2376c428d2eSrenato 	    IN6_IS_ADDR_LOOPBACK(addr) ||
2386c428d2eSrenato 	    IN6_IS_ADDR_MULTICAST(addr) ||
2396c428d2eSrenato 	    IN6_IS_ADDR_SITELOCAL(addr) ||
2406c428d2eSrenato 	    IN6_IS_ADDR_V4MAPPED(addr) ||
2416c428d2eSrenato 	    IN6_IS_ADDR_V4COMPAT(addr))
2426c428d2eSrenato 		return (1);
2436c428d2eSrenato 
2446c428d2eSrenato 	return (0);
2456c428d2eSrenato }
2466c428d2eSrenato 
2476c428d2eSrenato int
bad_addr(int af,union eigrpd_addr * addr)2486c428d2eSrenato bad_addr(int af, union eigrpd_addr *addr)
2496c428d2eSrenato {
2506c428d2eSrenato 	switch (af) {
2516c428d2eSrenato 	case AF_INET:
2526c428d2eSrenato 		return (bad_addr_v4(addr->v4));
2536c428d2eSrenato 	case AF_INET6:
2546c428d2eSrenato 		return (bad_addr_v6(&addr->v6));
2556c428d2eSrenato 	default:
2566c428d2eSrenato 		fatalx("bad_addr: unknown af");
2576c428d2eSrenato 	}
2586c428d2eSrenato }
25943509a12Srenato 
26043509a12Srenato void
embedscope(struct sockaddr_in6 * sin6)26143509a12Srenato embedscope(struct sockaddr_in6 *sin6)
26243509a12Srenato {
26343509a12Srenato 	uint16_t	 tmp16;
26443509a12Srenato 
26543509a12Srenato 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
26643509a12Srenato 		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
26743509a12Srenato 		if (tmp16 != 0) {
268*3a50f0a9Sjmc 			log_warnx("%s: address %s already has embedded scope %u",
26943509a12Srenato 			    __func__, log_sockaddr(sin6), ntohs(tmp16));
27043509a12Srenato 		}
27143509a12Srenato 		tmp16 = htons(sin6->sin6_scope_id);
27243509a12Srenato 		memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
27343509a12Srenato 		sin6->sin6_scope_id = 0;
27443509a12Srenato 	}
27543509a12Srenato }
27643509a12Srenato 
27743509a12Srenato void
recoverscope(struct sockaddr_in6 * sin6)27843509a12Srenato recoverscope(struct sockaddr_in6 *sin6)
27943509a12Srenato {
28043509a12Srenato 	uint16_t	 tmp16;
28143509a12Srenato 
28244faa115Srenato 	if (sin6->sin6_scope_id != 0)
28343509a12Srenato 		log_warnx("%s: address %s already has scope id %u",
28443509a12Srenato 		    __func__, log_sockaddr(sin6), sin6->sin6_scope_id);
28543509a12Srenato 
28643509a12Srenato 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
28743509a12Srenato 		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
28843509a12Srenato 		sin6->sin6_scope_id = ntohs(tmp16);
28943509a12Srenato 		sin6->sin6_addr.s6_addr[2] = 0;
29043509a12Srenato 		sin6->sin6_addr.s6_addr[3] = 0;
29143509a12Srenato 	}
29243509a12Srenato }
29343509a12Srenato 
29443509a12Srenato void
addscope(struct sockaddr_in6 * sin6,uint32_t id)29543509a12Srenato addscope(struct sockaddr_in6 *sin6, uint32_t id)
29643509a12Srenato {
29744faa115Srenato 	if (sin6->sin6_scope_id != 0)
29843509a12Srenato 		log_warnx("%s: address %s already has scope id %u", __func__,
29943509a12Srenato 		    log_sockaddr(sin6), sin6->sin6_scope_id);
30043509a12Srenato 
30144faa115Srenato 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr))
30243509a12Srenato 		sin6->sin6_scope_id = id;
30343509a12Srenato }
30443509a12Srenato 
30543509a12Srenato void
clearscope(struct in6_addr * in6)30643509a12Srenato clearscope(struct in6_addr *in6)
30743509a12Srenato {
30843509a12Srenato 	if (IN6_IS_SCOPE_EMBED(in6)) {
30943509a12Srenato 		in6->s6_addr[2] = 0;
31043509a12Srenato 		in6->s6_addr[3] = 0;
31143509a12Srenato 	}
31243509a12Srenato }
313414c2f5bSrenato 
314414c2f5bSrenato void
sa2addr(struct sockaddr * sa,int * af,union eigrpd_addr * addr)315414c2f5bSrenato sa2addr(struct sockaddr *sa, int *af, union eigrpd_addr *addr)
316414c2f5bSrenato {
317414c2f5bSrenato 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
318414c2f5bSrenato 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
319414c2f5bSrenato 
320414c2f5bSrenato 	memset(addr, 0, sizeof(*addr));
321414c2f5bSrenato 	switch (sa->sa_family) {
322414c2f5bSrenato 	case AF_INET:
323414c2f5bSrenato 		*af = AF_INET;
324414c2f5bSrenato 		addr->v4 = sa_in->sin_addr;
325414c2f5bSrenato 		break;
326414c2f5bSrenato 	case AF_INET6:
327414c2f5bSrenato 		*af = AF_INET6;
328414c2f5bSrenato 		addr->v6 = sa_in6->sin6_addr;
329414c2f5bSrenato 		break;
330414c2f5bSrenato 	default:
331414c2f5bSrenato 		fatalx("sa2addr: unknown af");
332414c2f5bSrenato 	}
333414c2f5bSrenato }
334