xref: /dragonfly/contrib/dhcpcd/src/sa.c (revision f984587a)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Socket Address handling for dhcpcd
4  * Copyright (c) 2015-2023 Roy Marples <roy@marples.name>
5  * All rights reserved
6 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 
32 #include <arpa/inet.h>
33 #ifdef AF_LINK
34 #include <net/if_dl.h>
35 #elif defined(AF_PACKET)
36 #include <linux/if_packet.h>
37 #endif
38 
39 #include <assert.h>
40 #include <errno.h>
41 #include <stdbool.h>
42 #include <stddef.h>
43 #include <stdio.h>
44 #include <stdint.h>
45 #include <string.h>
46 
47 #include "config.h"
48 #include "common.h"
49 #include "sa.h"
50 
51 #ifndef NDEBUG
52 static bool sa_inprefix;
53 #endif
54 
55 socklen_t
56 sa_addroffset(const struct sockaddr *sa)
57 {
58 
59 	assert(sa != NULL);
60 	switch(sa->sa_family) {
61 #ifdef INET
62 	case AF_INET:
63 		return offsetof(struct sockaddr_in, sin_addr) +
64 		       offsetof(struct in_addr, s_addr);
65 #endif /* INET */
66 #ifdef INET6
67 	case AF_INET6:
68 		return offsetof(struct sockaddr_in6, sin6_addr) +
69 		       offsetof(struct in6_addr, s6_addr);
70 #endif /* INET6 */
71 	default:
72 		errno = EAFNOSUPPORT;
73 		return 0;
74 	}
75 }
76 
77 socklen_t
78 sa_addrlen(const struct sockaddr *sa)
79 {
80 #define membersize(type, member) sizeof(((type *)0)->member)
81 	assert(sa != NULL);
82 	switch(sa->sa_family) {
83 #ifdef INET
84 	case AF_INET:
85 		return membersize(struct in_addr, s_addr);
86 #endif /* INET */
87 #ifdef INET6
88 	case AF_INET6:
89 		return membersize(struct in6_addr, s6_addr);
90 #endif /* INET6 */
91 	default:
92 		errno = EAFNOSUPPORT;
93 		return 0;
94 	}
95 }
96 
97 #ifndef HAVE_SA_LEN
98 socklen_t
99 sa_len(const struct sockaddr *sa)
100 {
101 
102 	switch (sa->sa_family) {
103 #ifdef AF_LINK
104 	case AF_LINK:
105 		return sizeof(struct sockaddr_dl);
106 #endif
107 #ifdef AF_PACKET
108 	case AF_PACKET:
109 		return sizeof(struct sockaddr_ll);
110 #endif
111 	case AF_INET:
112 		return sizeof(struct sockaddr_in);
113 	case AF_INET6:
114 		return sizeof(struct sockaddr_in6);
115 	default:
116 		return sizeof(struct sockaddr);
117 	}
118 }
119 #endif
120 
121 bool
122 sa_is_unspecified(const struct sockaddr *sa)
123 {
124 
125 	assert(sa != NULL);
126 	switch(sa->sa_family) {
127 	case AF_UNSPEC:
128 		return true;
129 #ifdef INET
130 	case AF_INET:
131 		return satocsin(sa)->sin_addr.s_addr == INADDR_ANY;
132 #endif /* INET */
133 #ifdef INET6
134 	case AF_INET6:
135 		return IN6_IS_ADDR_UNSPECIFIED(&satocsin6(sa)->sin6_addr);
136 #endif /* INET6 */
137 	default:
138 		errno = EAFNOSUPPORT;
139 		return false;
140 	}
141 }
142 
143 #ifdef INET6
144 #ifndef IN6MASK128
145 #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
146 		       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
147 #endif
148 static const struct in6_addr in6allones = IN6MASK128;
149 #endif
150 
151 bool
152 sa_is_allones(const struct sockaddr *sa)
153 {
154 
155 	assert(sa != NULL);
156 	switch(sa->sa_family) {
157 	case AF_UNSPEC:
158 		return false;
159 #ifdef INET
160 	case AF_INET:
161 	{
162 		const struct sockaddr_in *sin;
163 
164 		sin = satocsin(sa);
165 		return sin->sin_addr.s_addr == INADDR_BROADCAST;
166 	}
167 #endif /* INET */
168 #ifdef INET6
169 	case AF_INET6:
170 	{
171 		const struct sockaddr_in6 *sin6;
172 
173 		sin6 = satocsin6(sa);
174 		return IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6allones);
175 	}
176 #endif /* INET6 */
177 	default:
178 		errno = EAFNOSUPPORT;
179 		return false;
180 	}
181 }
182 
183 bool
184 sa_is_loopback(const struct sockaddr *sa)
185 {
186 
187 	assert(sa != NULL);
188 	switch(sa->sa_family) {
189 	case AF_UNSPEC:
190 		return false;
191 #ifdef INET
192 	case AF_INET:
193 	{
194 		const struct sockaddr_in *sin;
195 
196 		sin = satocsin(sa);
197 		return sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
198 	}
199 #endif /* INET */
200 #ifdef INET6
201 	case AF_INET6:
202 	{
203 		const struct sockaddr_in6 *sin6;
204 
205 		sin6 = satocsin6(sa);
206 		return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
207 	}
208 #endif /* INET6 */
209 	default:
210 		errno = EAFNOSUPPORT;
211 		return false;
212 	}
213 }
214 
215 int
216 sa_toprefix(const struct sockaddr *sa)
217 {
218 	int prefix;
219 
220 	assert(sa != NULL);
221 	switch(sa->sa_family) {
222 #ifdef INET
223 	case AF_INET:
224 	{
225 		const struct sockaddr_in *sin;
226 		uint32_t mask;
227 
228 		sin = satocsin(sa);
229 		if (sin->sin_addr.s_addr == INADDR_ANY) {
230 			prefix = 0;
231 			break;
232 		}
233 		mask = ntohl(sin->sin_addr.s_addr);
234 		prefix = 33 - ffs((int)mask);	/* 33 - (1 .. 32) -> 32 .. 1 */
235 		if (prefix < 32) {		/* more than 1 bit in mask */
236 			/* check for non-contig netmask */
237 			if ((mask^(((1U << prefix)-1) << (32 - prefix))) != 0) {
238 				errno = EINVAL;
239 				return -1;	/* noncontig, no pfxlen */
240 			}
241 		}
242 		break;
243 	}
244 #endif
245 #ifdef INET6
246 	case AF_INET6:
247 	{
248 		const struct sockaddr_in6 *sin6;
249 		int x, y;
250 		const uint8_t *lim, *p;
251 
252 		sin6 = satocsin6(sa);
253 		p = (const uint8_t *)sin6->sin6_addr.s6_addr;
254 		lim = p + sizeof(sin6->sin6_addr.s6_addr);
255 		for (x = 0; p < lim; x++, p++) {
256 			if (*p != 0xff)
257 				break;
258 		}
259 		y = 0;
260 		if (p < lim) {
261 			for (y = 0; y < NBBY; y++) {
262 				if ((*p & (0x80 >> y)) == 0)
263 					break;
264 			}
265 		}
266 
267 		/*
268 		 * when the limit pointer is given, do a stricter check on the
269 		 * remaining bits.
270 		 */
271 		if (p < lim) {
272 			if (y != 0 && (*p & (0x00ff >> y)) != 0)
273 				return 0;
274 			for (p = p + 1; p < lim; p++)
275 				if (*p != 0)
276 					return 0;
277 		}
278 
279 		prefix = x * NBBY + y;
280 		break;
281 	}
282 #endif
283 	default:
284 		errno = EAFNOSUPPORT;
285 		return -1;
286 	}
287 
288 #ifndef NDEBUG
289 	/* Ensure the calculation is correct */
290 	if (!sa_inprefix) {
291 		union sa_ss ss = { .sa = { .sa_family = sa->sa_family } };
292 
293 		sa_inprefix = true;
294 		sa_fromprefix(&ss.sa, prefix);
295 		assert(sa_cmp(sa, &ss.sa) == 0);
296 		sa_inprefix = false;
297 	}
298 #endif
299 
300 	return prefix;
301 }
302 
303 int
304 sa_fromprefix(struct sockaddr *sa, int prefix)
305 {
306 	uint8_t *ap;
307 	int max_prefix, bytes, bits, i;
308 
309 	switch (sa->sa_family) {
310 #ifdef INET
311 	case AF_INET:
312 		max_prefix = 32;
313 #ifdef HAVE_SA_LEN
314 		sa->sa_len = sizeof(struct sockaddr_in);
315 #endif
316 		break;
317 #endif
318 #ifdef INET6
319 	case AF_INET6:
320 		max_prefix = 128;
321 #ifdef HAVE_SA_LEN
322 		sa->sa_len = sizeof(struct sockaddr_in6);
323 #endif
324 		break;
325 #endif
326 	default:
327 		errno = EAFNOSUPPORT;
328 		return -1;
329 	}
330 
331 	bytes = prefix / NBBY;
332 	bits = prefix % NBBY;
333 
334 	ap = (uint8_t *)sa + sa_addroffset(sa);
335 	for (i = 0; i < bytes; i++)
336 		*ap++ = 0xff;
337 	if (bits) {
338 		uint8_t a;
339 
340 		a = 0xff;
341 		a  = (uint8_t)(a << (8 - bits));
342 		*ap++ = a;
343 	}
344 	bytes = (max_prefix - prefix) / NBBY;
345 	for (i = 0; i < bytes; i++)
346 		*ap++ = 0x00;
347 
348 #ifndef NDEBUG
349 	/* Ensure the calculation is correct */
350 	if (!sa_inprefix) {
351 		sa_inprefix = true;
352 		assert(sa_toprefix(sa) == prefix);
353 		sa_inprefix = false;
354 	}
355 #endif
356 	return 0;
357 }
358 
359 /* inet_ntop, but for sockaddr. */
360 const char *
361 sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
362 {
363 	const void *addr;
364 
365 	assert(buf != NULL);
366 	assert(len > 0);
367 
368 	if (sa->sa_family == 0) {
369 		*buf = '\0';
370 		return NULL;
371 	}
372 
373 #ifdef AF_LINK
374 #ifndef CLLADDR
375 #define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
376 #endif
377 	if (sa->sa_family == AF_LINK) {
378 		const struct sockaddr_dl *sdl;
379 
380 		sdl = (const void *)sa;
381 		if (sdl->sdl_alen == 0) {
382 			if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1)
383 				return NULL;
384 			return buf;
385 		}
386 		return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
387 	}
388 #elif defined(AF_PACKET)
389 	if (sa->sa_family == AF_PACKET) {
390 		const struct sockaddr_ll *sll;
391 
392 		sll = (const void *)sa;
393 		return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len);
394 	}
395 #endif
396 	addr = (const char *)sa + sa_addroffset(sa);
397 	return inet_ntop(sa->sa_family, addr, buf, len);
398 }
399 
400 int
401 sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
402 {
403 	socklen_t offset, len;
404 
405 	assert(sa1 != NULL);
406 	assert(sa2 != NULL);
407 
408 	/* Treat AF_UNSPEC as the unspecified address. */
409 	if ((sa1->sa_family == AF_UNSPEC || sa2->sa_family == AF_UNSPEC) &&
410 	    sa_is_unspecified(sa1) && sa_is_unspecified(sa2))
411 		return 0;
412 
413 	if (sa1->sa_family != sa2->sa_family)
414 		return sa1->sa_family - sa2->sa_family;
415 
416 #ifdef HAVE_SA_LEN
417 	len = MIN(sa1->sa_len, sa2->sa_len);
418 #endif
419 
420 	switch (sa1->sa_family) {
421 #ifdef INET
422 	case AF_INET:
423 		offset = offsetof(struct sockaddr_in, sin_addr);
424 #ifdef HAVE_SA_LEN
425 		len -= offset;
426 		len = MIN(len, sizeof(struct in_addr));
427 #else
428 		len = sizeof(struct in_addr);
429 #endif
430 		break;
431 #endif
432 #ifdef INET6
433 	case AF_INET6:
434 		offset = offsetof(struct sockaddr_in6, sin6_addr);
435 #ifdef HAVE_SA_LEN
436 		len -= offset;
437 		len = MIN(len, sizeof(struct in6_addr));
438 #else
439 		len = sizeof(struct in6_addr);
440 #endif
441 		break;
442 #endif
443 	default:
444 		offset = 0;
445 #ifndef HAVE_SA_LEN
446 		len = sizeof(struct sockaddr);
447 #endif
448 		break;
449 	}
450 
451 	return memcmp((const char *)sa1 + offset,
452 	    (const char *)sa2 + offset,
453 	    len);
454 }
455 
456 #ifdef INET
457 void
458 sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
459 {
460 	struct sockaddr_in *sin;
461 
462 	assert(sa != NULL);
463 	assert(addr != NULL);
464 	sin = satosin(sa);
465 	sin->sin_family = AF_INET;
466 #ifdef HAVE_SA_LEN
467 	sin->sin_len = sizeof(*sin);
468 #endif
469 	sin->sin_addr.s_addr = addr->s_addr;
470 }
471 #endif
472 
473 #ifdef INET6
474 void
475 sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
476 {
477 	struct sockaddr_in6 *sin6;
478 
479 	assert(sa != NULL);
480 	assert(addr != NULL);
481 	sin6 = satosin6(sa);
482 	sin6->sin6_family = AF_INET6;
483 #ifdef HAVE_SA_LEN
484 	sin6->sin6_len = sizeof(*sin6);
485 #endif
486 	memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr,
487 	    sizeof(sin6->sin6_addr.s6_addr));
488 }
489 #endif
490