xref: /openbsd-src/usr.sbin/ldpd/util.c (revision 3a50f0a93a2072911d0ba6ababa815fb04bf9a71)
1*3a50f0a9Sjmc /*	$OpenBSD: util.c,v 1.7 2022/12/28 21:30:17 jmc Exp $ */
2ac5a809bSrenato 
3ac5a809bSrenato /*
4ac5a809bSrenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5ac5a809bSrenato  * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org>
6ac5a809bSrenato  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7ac5a809bSrenato  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8ac5a809bSrenato  *
9ac5a809bSrenato  * Permission to use, copy, modify, and distribute this software for any
10ac5a809bSrenato  * purpose with or without fee is hereby granted, provided that the above
11ac5a809bSrenato  * copyright notice and this permission notice appear in all copies.
12ac5a809bSrenato  *
13ac5a809bSrenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14ac5a809bSrenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15ac5a809bSrenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16ac5a809bSrenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17ac5a809bSrenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18ac5a809bSrenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19ac5a809bSrenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20ac5a809bSrenato  */
21ac5a809bSrenato 
22ac5a809bSrenato #include <sys/types.h>
2319fce358Srenato #include <string.h>
24ac5a809bSrenato 
25ac5a809bSrenato #include "ldpd.h"
26ac5a809bSrenato #include "log.h"
27ac5a809bSrenato 
2819fce358Srenato uint8_t
mask2prefixlen(in_addr_t ina)2919fce358Srenato mask2prefixlen(in_addr_t ina)
3019fce358Srenato {
3119fce358Srenato 	if (ina == 0)
3219fce358Srenato 		return (0);
3319fce358Srenato 	else
3419fce358Srenato 		return (33 - ffs(ntohl(ina)));
3519fce358Srenato }
3619fce358Srenato 
37a8c39dc0Srenato uint8_t
mask2prefixlen6(struct sockaddr_in6 * sa_in6)38a8c39dc0Srenato mask2prefixlen6(struct sockaddr_in6 *sa_in6)
39a8c39dc0Srenato {
40884600caSclaudio 	unsigned int l = 0;
41884600caSclaudio 	uint8_t *ap, *ep;
42a8c39dc0Srenato 
43a8c39dc0Srenato 	/*
44*3a50f0a9Sjmc 	 * sin6_len is the size of the sockaddr so subtract the offset of
45a8c39dc0Srenato 	 * the possibly truncated sin6_addr struct.
46a8c39dc0Srenato 	 */
47a8c39dc0Srenato 	ap = (uint8_t *)&sa_in6->sin6_addr;
48a8c39dc0Srenato 	ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
49a8c39dc0Srenato 	for (; ap < ep; ap++) {
50a8c39dc0Srenato 		/* this "beauty" is adopted from sbin/route/show.c ... */
51a8c39dc0Srenato 		switch (*ap) {
52a8c39dc0Srenato 		case 0xff:
53a8c39dc0Srenato 			l += 8;
54a8c39dc0Srenato 			break;
55a8c39dc0Srenato 		case 0xfe:
56a8c39dc0Srenato 			l += 7;
57884600caSclaudio 			goto done;
58a8c39dc0Srenato 		case 0xfc:
59a8c39dc0Srenato 			l += 6;
60884600caSclaudio 			goto done;
61a8c39dc0Srenato 		case 0xf8:
62a8c39dc0Srenato 			l += 5;
63884600caSclaudio 			goto done;
64a8c39dc0Srenato 		case 0xf0:
65a8c39dc0Srenato 			l += 4;
66884600caSclaudio 			goto done;
67a8c39dc0Srenato 		case 0xe0:
68a8c39dc0Srenato 			l += 3;
69884600caSclaudio 			goto done;
70a8c39dc0Srenato 		case 0xc0:
71a8c39dc0Srenato 			l += 2;
72884600caSclaudio 			goto done;
73a8c39dc0Srenato 		case 0x80:
74a8c39dc0Srenato 			l += 1;
75884600caSclaudio 			goto done;
76a8c39dc0Srenato 		case 0x00:
77884600caSclaudio 			goto done;
78a8c39dc0Srenato 		default:
79a8c39dc0Srenato 			fatalx("non contiguous inet6 netmask");
80a8c39dc0Srenato 		}
81a8c39dc0Srenato 	}
82a8c39dc0Srenato 
83884600caSclaudio done:
84884600caSclaudio 	if (l > sizeof(struct in6_addr) * 8)
85884600caSclaudio 		fatalx("inet6 prefixlen out of bound");
86a8c39dc0Srenato 	return (l);
87a8c39dc0Srenato }
88a8c39dc0Srenato 
8919fce358Srenato in_addr_t
prefixlen2mask(uint8_t prefixlen)9019fce358Srenato prefixlen2mask(uint8_t prefixlen)
9119fce358Srenato {
9219fce358Srenato 	if (prefixlen == 0)
9319fce358Srenato 		return (0);
9419fce358Srenato 
9519fce358Srenato 	return (htonl(0xffffffff << (32 - prefixlen)));
9619fce358Srenato }
9719fce358Srenato 
98a8c39dc0Srenato struct in6_addr *
prefixlen2mask6(uint8_t prefixlen)99a8c39dc0Srenato prefixlen2mask6(uint8_t prefixlen)
100a8c39dc0Srenato {
101a8c39dc0Srenato 	static struct in6_addr	mask;
102a8c39dc0Srenato 	int			i;
103a8c39dc0Srenato 
104a8c39dc0Srenato 	memset(&mask, 0, sizeof(mask));
105a8c39dc0Srenato 	for (i = 0; i < prefixlen / 8; i++)
106a8c39dc0Srenato 		mask.s6_addr[i] = 0xff;
107a8c39dc0Srenato 	i = prefixlen % 8;
108a8c39dc0Srenato 	if (i)
109a8c39dc0Srenato 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
110a8c39dc0Srenato 
111a8c39dc0Srenato 	return (&mask);
112a8c39dc0Srenato }
113a8c39dc0Srenato 
114a8c39dc0Srenato void
ldp_applymask(int af,union ldpd_addr * dest,const union ldpd_addr * src,int prefixlen)115a8c39dc0Srenato ldp_applymask(int af, union ldpd_addr *dest, const union ldpd_addr *src,
116a8c39dc0Srenato     int prefixlen)
117a8c39dc0Srenato {
118a8c39dc0Srenato 	struct in6_addr	mask;
119a8c39dc0Srenato 	int		i;
120a8c39dc0Srenato 
121a8c39dc0Srenato 	switch (af) {
122a8c39dc0Srenato 	case AF_INET:
123a8c39dc0Srenato 		dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen);
124a8c39dc0Srenato 		break;
125a8c39dc0Srenato 	case AF_INET6:
126a8c39dc0Srenato 		memset(&mask, 0, sizeof(mask));
127a8c39dc0Srenato 		for (i = 0; i < prefixlen / 8; i++)
128a8c39dc0Srenato 			mask.s6_addr[i] = 0xff;
129a8c39dc0Srenato 		i = prefixlen % 8;
130a8c39dc0Srenato 		if (i)
131a8c39dc0Srenato 			mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
132a8c39dc0Srenato 
133a8c39dc0Srenato 		for (i = 0; i < 16; i++)
134a8c39dc0Srenato 			dest->v6.s6_addr[i] = src->v6.s6_addr[i] &
135a8c39dc0Srenato 			    mask.s6_addr[i];
136a8c39dc0Srenato 		break;
137a8c39dc0Srenato 	default:
138a8c39dc0Srenato 		fatalx("ldp_applymask: unknown af");
139a8c39dc0Srenato 	}
140a8c39dc0Srenato }
141a8c39dc0Srenato 
142ac5a809bSrenato int
ldp_addrcmp(int af,const union ldpd_addr * a,const union ldpd_addr * b)143a8c39dc0Srenato ldp_addrcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b)
144a8c39dc0Srenato {
145a8c39dc0Srenato 	switch (af) {
146a8c39dc0Srenato 	case AF_INET:
147a8c39dc0Srenato 		if (a->v4.s_addr == b->v4.s_addr)
148a8c39dc0Srenato 			return (0);
149a8c39dc0Srenato 		return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1);
150a8c39dc0Srenato 	case AF_INET6:
151a8c39dc0Srenato 		return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
152a8c39dc0Srenato 	default:
153a8c39dc0Srenato 		fatalx("ldp_addrcmp: unknown af");
154a8c39dc0Srenato 	}
155a8c39dc0Srenato }
156a8c39dc0Srenato 
157a8c39dc0Srenato int
ldp_addrisset(int af,const union ldpd_addr * addr)158a8c39dc0Srenato ldp_addrisset(int af, const union ldpd_addr *addr)
159a8c39dc0Srenato {
160a8c39dc0Srenato 	switch (af) {
161a8c39dc0Srenato 	case AF_UNSPEC:
162a8c39dc0Srenato 		return (0);
163a8c39dc0Srenato 	case AF_INET:
164a8c39dc0Srenato 		if (addr->v4.s_addr != INADDR_ANY)
165a8c39dc0Srenato 			return (1);
166a8c39dc0Srenato 		break;
167a8c39dc0Srenato 	case AF_INET6:
168a8c39dc0Srenato 		if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
169a8c39dc0Srenato 			return (1);
170a8c39dc0Srenato 		break;
171a8c39dc0Srenato 	default:
172a8c39dc0Srenato 		fatalx("ldp_addrisset: unknown af");
173a8c39dc0Srenato 	}
174a8c39dc0Srenato 
175a8c39dc0Srenato 	return (0);
176a8c39dc0Srenato }
177a8c39dc0Srenato 
178a8c39dc0Srenato int
ldp_prefixcmp(int af,const union ldpd_addr * a,const union ldpd_addr * b,uint8_t prefixlen)179a8c39dc0Srenato ldp_prefixcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b,
180a8c39dc0Srenato     uint8_t prefixlen)
181a8c39dc0Srenato {
182a8c39dc0Srenato 	in_addr_t	mask, aa, ba;
183a8c39dc0Srenato 	int		i;
184a8c39dc0Srenato 	uint8_t		m;
185a8c39dc0Srenato 
186a8c39dc0Srenato 	switch (af) {
187a8c39dc0Srenato 	case AF_INET:
188a8c39dc0Srenato 		if (prefixlen == 0)
189a8c39dc0Srenato 			return (0);
190a8c39dc0Srenato 		if (prefixlen > 32)
191a8c39dc0Srenato 			fatalx("ldp_prefixcmp: bad IPv4 prefixlen");
192a8c39dc0Srenato 		mask = htonl(prefixlen2mask(prefixlen));
193a8c39dc0Srenato 		aa = htonl(a->v4.s_addr) & mask;
194a8c39dc0Srenato 		ba = htonl(b->v4.s_addr) & mask;
195a8c39dc0Srenato 		return (aa - ba);
196a8c39dc0Srenato 	case AF_INET6:
197a8c39dc0Srenato 		if (prefixlen == 0)
198a8c39dc0Srenato 			return (0);
199a8c39dc0Srenato 		if (prefixlen > 128)
200a8c39dc0Srenato 			fatalx("ldp_prefixcmp: bad IPv6 prefixlen");
201a8c39dc0Srenato 		for (i = 0; i < prefixlen / 8; i++)
202a8c39dc0Srenato 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
203a8c39dc0Srenato 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
204a8c39dc0Srenato 		i = prefixlen % 8;
205a8c39dc0Srenato 		if (i) {
206a8c39dc0Srenato 			m = 0xff00 >> i;
207a8c39dc0Srenato 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
208a8c39dc0Srenato 			    (b->v6.s6_addr[prefixlen / 8] & m))
209a8c39dc0Srenato 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
210a8c39dc0Srenato 				    (b->v6.s6_addr[prefixlen / 8] & m));
211a8c39dc0Srenato 		}
212a8c39dc0Srenato 		return (0);
213a8c39dc0Srenato 	default:
214a8c39dc0Srenato 		fatalx("ldp_prefixcmp: unknown af");
215a8c39dc0Srenato 	}
216a8c39dc0Srenato 	return (-1);
217a8c39dc0Srenato }
218a8c39dc0Srenato 
219a8c39dc0Srenato int
bad_addr_v4(struct in_addr addr)220a8c39dc0Srenato bad_addr_v4(struct in_addr addr)
221ac5a809bSrenato {
222ac5a809bSrenato 	uint32_t	 a = ntohl(addr.s_addr);
223ac5a809bSrenato 
224ac5a809bSrenato 	if (((a >> IN_CLASSA_NSHIFT) == 0) ||
225ac5a809bSrenato 	    ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) ||
226ef8f8f93Sclaudio 	    IN_MULTICAST(a))
227ac5a809bSrenato 		return (1);
228ac5a809bSrenato 
229ac5a809bSrenato 	return (0);
230ac5a809bSrenato }
231a8c39dc0Srenato 
232a8c39dc0Srenato int
bad_addr_v6(struct in6_addr * addr)233a8c39dc0Srenato bad_addr_v6(struct in6_addr *addr)
234a8c39dc0Srenato {
235a8c39dc0Srenato 	if (IN6_IS_ADDR_UNSPECIFIED(addr) ||
236a8c39dc0Srenato 	    IN6_IS_ADDR_LOOPBACK(addr) ||
237a8c39dc0Srenato 	    IN6_IS_ADDR_MULTICAST(addr) ||
238a8c39dc0Srenato 	    IN6_IS_ADDR_SITELOCAL(addr) ||
239a8c39dc0Srenato 	    IN6_IS_ADDR_V4MAPPED(addr) ||
240a8c39dc0Srenato 	    IN6_IS_ADDR_V4COMPAT(addr))
241a8c39dc0Srenato 		return (1);
242a8c39dc0Srenato 
243a8c39dc0Srenato 	return (0);
244a8c39dc0Srenato }
245a8c39dc0Srenato 
246a8c39dc0Srenato int
bad_addr(int af,union ldpd_addr * addr)247a8c39dc0Srenato bad_addr(int af, union ldpd_addr *addr)
248a8c39dc0Srenato {
249a8c39dc0Srenato 	switch (af) {
250a8c39dc0Srenato 	case AF_INET:
251a8c39dc0Srenato 		return (bad_addr_v4(addr->v4));
252a8c39dc0Srenato 	case AF_INET6:
253a8c39dc0Srenato 		return (bad_addr_v6(&addr->v6));
254a8c39dc0Srenato 	default:
255a8c39dc0Srenato 		fatalx("bad_addr: unknown af");
256a8c39dc0Srenato 	}
257a8c39dc0Srenato }
258a8c39dc0Srenato 
259a8c39dc0Srenato void
embedscope(struct sockaddr_in6 * sin6)260a8c39dc0Srenato embedscope(struct sockaddr_in6 *sin6)
261a8c39dc0Srenato {
262a8c39dc0Srenato 	uint16_t	 tmp16;
263a8c39dc0Srenato 
264a8c39dc0Srenato 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
265a8c39dc0Srenato 		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
266a8c39dc0Srenato 		if (tmp16 != 0) {
267*3a50f0a9Sjmc 			log_warnx("%s: address %s already has embedded scope %u",
268a8c39dc0Srenato 			    __func__, log_sockaddr(sin6), ntohs(tmp16));
269a8c39dc0Srenato 		}
270a8c39dc0Srenato 		tmp16 = htons(sin6->sin6_scope_id);
271a8c39dc0Srenato 		memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
272a8c39dc0Srenato 		sin6->sin6_scope_id = 0;
273a8c39dc0Srenato 	}
274a8c39dc0Srenato }
275a8c39dc0Srenato 
276a8c39dc0Srenato void
recoverscope(struct sockaddr_in6 * sin6)277a8c39dc0Srenato recoverscope(struct sockaddr_in6 *sin6)
278a8c39dc0Srenato {
279a8c39dc0Srenato 	uint16_t	 tmp16;
280a8c39dc0Srenato 
281a8c39dc0Srenato 	if (sin6->sin6_scope_id != 0)
282a8c39dc0Srenato 		log_warnx("%s: address %s already has scope id %u",
283a8c39dc0Srenato 		    __func__, log_sockaddr(sin6), sin6->sin6_scope_id);
284a8c39dc0Srenato 
285a8c39dc0Srenato 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
286a8c39dc0Srenato 		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
287a8c39dc0Srenato 		sin6->sin6_scope_id = ntohs(tmp16);
288a8c39dc0Srenato 		sin6->sin6_addr.s6_addr[2] = 0;
289a8c39dc0Srenato 		sin6->sin6_addr.s6_addr[3] = 0;
290a8c39dc0Srenato 	}
291a8c39dc0Srenato }
292a8c39dc0Srenato 
293a8c39dc0Srenato void
addscope(struct sockaddr_in6 * sin6,uint32_t id)294a8c39dc0Srenato addscope(struct sockaddr_in6 *sin6, uint32_t id)
295a8c39dc0Srenato {
296a8c39dc0Srenato 	if (sin6->sin6_scope_id != 0)
297a8c39dc0Srenato 		log_warnx("%s: address %s already has scope id %u", __func__,
298a8c39dc0Srenato 		    log_sockaddr(sin6), sin6->sin6_scope_id);
299a8c39dc0Srenato 
300a8c39dc0Srenato 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr))
301a8c39dc0Srenato 		sin6->sin6_scope_id = id;
302a8c39dc0Srenato }
303a8c39dc0Srenato 
304a8c39dc0Srenato void
clearscope(struct in6_addr * in6)305a8c39dc0Srenato clearscope(struct in6_addr *in6)
306a8c39dc0Srenato {
307a8c39dc0Srenato 	if (IN6_IS_SCOPE_EMBED(in6)) {
308a8c39dc0Srenato 		in6->s6_addr[2] = 0;
309a8c39dc0Srenato 		in6->s6_addr[3] = 0;
310a8c39dc0Srenato 	}
311a8c39dc0Srenato }
312a8c39dc0Srenato 
313a8c39dc0Srenato struct sockaddr *
addr2sa(int af,union ldpd_addr * addr,uint16_t port)314a8c39dc0Srenato addr2sa(int af, union ldpd_addr *addr, uint16_t port)
315a8c39dc0Srenato {
316a8c39dc0Srenato 	static struct sockaddr_storage	 ss;
317a8c39dc0Srenato 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
318a8c39dc0Srenato 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
319a8c39dc0Srenato 
320a8c39dc0Srenato 	memset(&ss, 0, sizeof(ss));
321a8c39dc0Srenato 	switch (af) {
322a8c39dc0Srenato 	case AF_INET:
323a8c39dc0Srenato 		sa_in->sin_family = AF_INET;
324a8c39dc0Srenato 		sa_in->sin_len = sizeof(struct sockaddr_in);
325a8c39dc0Srenato 		sa_in->sin_addr = addr->v4;
326a8c39dc0Srenato 		sa_in->sin_port = htons(port);
327a8c39dc0Srenato 		break;
328a8c39dc0Srenato 	case AF_INET6:
329a8c39dc0Srenato 		sa_in6->sin6_family = AF_INET6;
330a8c39dc0Srenato 		sa_in6->sin6_len = sizeof(struct sockaddr_in6);
331a8c39dc0Srenato 		sa_in6->sin6_addr = addr->v6;
332a8c39dc0Srenato 		sa_in6->sin6_port = htons(port);
333a8c39dc0Srenato 		break;
334a8c39dc0Srenato 	default:
335a8c39dc0Srenato 		fatalx("addr2sa: unknown af");
336a8c39dc0Srenato 	}
337a8c39dc0Srenato 
338a8c39dc0Srenato 	return ((struct sockaddr *)&ss);
339a8c39dc0Srenato }
340a8c39dc0Srenato 
341a8c39dc0Srenato void
sa2addr(struct sockaddr * sa,int * af,union ldpd_addr * addr)342a8c39dc0Srenato sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr)
343a8c39dc0Srenato {
344a8c39dc0Srenato 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
345a8c39dc0Srenato 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
346a8c39dc0Srenato 
347a8c39dc0Srenato 	memset(addr, 0, sizeof(*addr));
348a8c39dc0Srenato 	switch (sa->sa_family) {
349a8c39dc0Srenato 	case AF_INET:
350a8c39dc0Srenato 		*af = AF_INET;
351a8c39dc0Srenato 		addr->v4 = sa_in->sin_addr;
352a8c39dc0Srenato 		break;
353a8c39dc0Srenato 	case AF_INET6:
354a8c39dc0Srenato 		*af = AF_INET6;
355a8c39dc0Srenato 		addr->v6 = sa_in6->sin6_addr;
356a8c39dc0Srenato 		break;
357a8c39dc0Srenato 	default:
358a8c39dc0Srenato 		fatalx("sa2addr: unknown af");
359a8c39dc0Srenato 	}
360a8c39dc0Srenato }
361