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
52static bool sa_inprefix;
53#endif
54
55socklen_t
56sa_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
77socklen_t
78sa_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
98socklen_t
99sa_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
121bool
122sa_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
148static const struct in6_addr in6allones = IN6MASK128;
149#endif
150
151bool
152sa_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
183bool
184sa_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
215int
216sa_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
303static void
304ipbytes_fromprefix(uint8_t *ap, int prefix, int max_prefix)
305{
306	int bytes, bits, i;
307
308	bytes = prefix / NBBY;
309	bits = prefix % NBBY;
310
311	for (i = 0; i < bytes; i++)
312		*ap++ = 0xff;
313	if (bits) {
314		uint8_t a;
315
316		a = 0xff;
317		a  = (uint8_t)(a << (8 - bits));
318		*ap++ = a;
319	}
320	bytes = (max_prefix - prefix) / NBBY;
321	for (i = 0; i < bytes; i++)
322		*ap++ = 0x00;
323}
324
325void
326in6_addr_fromprefix(struct in6_addr *addr, int prefix)
327{
328	ipbytes_fromprefix((uint8_t *)addr, prefix, 128);
329}
330
331int
332sa_fromprefix(struct sockaddr *sa, int prefix)
333{
334	uint8_t *ap;
335	int max_prefix;
336
337	switch (sa->sa_family) {
338#ifdef INET
339	case AF_INET:
340		max_prefix = 32;
341#ifdef HAVE_SA_LEN
342		sa->sa_len = sizeof(struct sockaddr_in);
343#endif
344		break;
345#endif
346#ifdef INET6
347	case AF_INET6:
348		max_prefix = 128;
349#ifdef HAVE_SA_LEN
350		sa->sa_len = sizeof(struct sockaddr_in6);
351#endif
352		break;
353#endif
354	default:
355		errno = EAFNOSUPPORT;
356		return -1;
357	}
358
359	ap = (uint8_t *)sa + sa_addroffset(sa);
360	ipbytes_fromprefix(ap, prefix, max_prefix);
361
362#ifndef NDEBUG
363	/* Ensure the calculation is correct */
364	if (!sa_inprefix) {
365		sa_inprefix = true;
366		assert(sa_toprefix(sa) == prefix);
367		sa_inprefix = false;
368	}
369#endif
370	return 0;
371}
372
373/* inet_ntop, but for sockaddr. */
374const char *
375sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
376{
377	const void *addr;
378
379	assert(buf != NULL);
380	assert(len > 0);
381
382	if (sa->sa_family == 0) {
383		*buf = '\0';
384		return NULL;
385	}
386
387#ifdef AF_LINK
388#ifndef CLLADDR
389#define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
390#endif
391	if (sa->sa_family == AF_LINK) {
392		const struct sockaddr_dl *sdl;
393
394		sdl = (const void *)sa;
395		if (sdl->sdl_alen == 0) {
396			if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1)
397				return NULL;
398			return buf;
399		}
400		return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
401	}
402#elif defined(AF_PACKET)
403	if (sa->sa_family == AF_PACKET) {
404		const struct sockaddr_ll *sll;
405
406		sll = (const void *)sa;
407		return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len);
408	}
409#endif
410	addr = (const char *)sa + sa_addroffset(sa);
411	return inet_ntop(sa->sa_family, addr, buf, len);
412}
413
414int
415sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
416{
417	socklen_t offset, len;
418
419	assert(sa1 != NULL);
420	assert(sa2 != NULL);
421
422	/* Treat AF_UNSPEC as the unspecified address. */
423	if ((sa1->sa_family == AF_UNSPEC || sa2->sa_family == AF_UNSPEC) &&
424	    sa_is_unspecified(sa1) && sa_is_unspecified(sa2))
425		return 0;
426
427	if (sa1->sa_family != sa2->sa_family)
428		return sa1->sa_family - sa2->sa_family;
429
430#ifdef HAVE_SA_LEN
431	len = MIN(sa1->sa_len, sa2->sa_len);
432#endif
433
434	switch (sa1->sa_family) {
435#ifdef INET
436	case AF_INET:
437		offset = offsetof(struct sockaddr_in, sin_addr);
438#ifdef HAVE_SA_LEN
439		len -= offset;
440		len = MIN(len, sizeof(struct in_addr));
441#else
442		len = sizeof(struct in_addr);
443#endif
444		break;
445#endif
446#ifdef INET6
447	case AF_INET6:
448		offset = offsetof(struct sockaddr_in6, sin6_addr);
449#ifdef HAVE_SA_LEN
450		len -= offset;
451		len = MIN(len, sizeof(struct in6_addr));
452#else
453		len = sizeof(struct in6_addr);
454#endif
455		break;
456#endif
457	default:
458		offset = 0;
459#ifndef HAVE_SA_LEN
460		len = sizeof(struct sockaddr);
461#endif
462		break;
463	}
464
465	return memcmp((const char *)sa1 + offset,
466	    (const char *)sa2 + offset,
467	    len);
468}
469
470#ifdef INET
471void
472sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
473{
474	struct sockaddr_in *sin;
475
476	assert(sa != NULL);
477	assert(addr != NULL);
478	sin = satosin(sa);
479	sin->sin_family = AF_INET;
480#ifdef HAVE_SA_LEN
481	sin->sin_len = sizeof(*sin);
482#endif
483	sin->sin_addr.s_addr = addr->s_addr;
484}
485#endif
486
487#ifdef INET6
488void
489sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
490{
491	struct sockaddr_in6 *sin6;
492
493	assert(sa != NULL);
494	assert(addr != NULL);
495	sin6 = satosin6(sa);
496	sin6->sin6_family = AF_INET6;
497#ifdef HAVE_SA_LEN
498	sin6->sin6_len = sizeof(*sin6);
499#endif
500	memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr,
501	    sizeof(sin6->sin6_addr.s6_addr));
502}
503#endif
504