Home | History | Annotate | Line # | Download | only in src
      1 /* SPDX-License-Identifier: BSD-2-Clause */
      2 /*
      3  * Socket Address handling for dhcpcd
      4  * Copyright (c) 2015-2025 Roy Marples <roy (at) 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 static void
    304 ipbytes_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 
    325 void
    326 in6_addr_fromprefix(struct in6_addr *addr, int prefix)
    327 {
    328 	ipbytes_fromprefix((uint8_t *)addr, prefix, 128);
    329 }
    330 
    331 int
    332 sa_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. */
    374 const char *
    375 sa_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 
    414 int
    415 sa_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 	if (sa1->sa_family != sa2->sa_family)
    423 		return sa1->sa_family - sa2->sa_family;
    424 
    425 #ifdef HAVE_SA_LEN
    426 	len = MIN(sa1->sa_len, sa2->sa_len);
    427 #endif
    428 
    429 	switch (sa1->sa_family) {
    430 #ifdef INET
    431 	case AF_INET:
    432 		offset = offsetof(struct sockaddr_in, sin_addr);
    433 #ifdef HAVE_SA_LEN
    434 		len -= offset;
    435 		len = MIN(len, sizeof(struct in_addr));
    436 #else
    437 		len = sizeof(struct in_addr);
    438 #endif
    439 		break;
    440 #endif
    441 #ifdef INET6
    442 	case AF_INET6:
    443 		offset = offsetof(struct sockaddr_in6, sin6_addr);
    444 #ifdef HAVE_SA_LEN
    445 		len -= offset;
    446 		len = MIN(len, sizeof(struct in6_addr));
    447 #else
    448 		len = sizeof(struct in6_addr);
    449 #endif
    450 		break;
    451 #endif
    452 	default:
    453 		offset = 0;
    454 #ifndef HAVE_SA_LEN
    455 		len = sizeof(struct sockaddr);
    456 #endif
    457 		break;
    458 	}
    459 
    460 	return memcmp((const char *)sa1 + offset,
    461 	    (const char *)sa2 + offset,
    462 	    len);
    463 }
    464 
    465 #ifdef INET
    466 void
    467 sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
    468 {
    469 	struct sockaddr_in *sin;
    470 
    471 	assert(sa != NULL);
    472 	assert(addr != NULL);
    473 	sin = satosin(sa);
    474 	sin->sin_family = AF_INET;
    475 #ifdef HAVE_SA_LEN
    476 	sin->sin_len = sizeof(*sin);
    477 #endif
    478 	sin->sin_addr.s_addr = addr->s_addr;
    479 }
    480 #endif
    481 
    482 #ifdef INET6
    483 void
    484 sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
    485 {
    486 	struct sockaddr_in6 *sin6;
    487 
    488 	assert(sa != NULL);
    489 	assert(addr != NULL);
    490 	sin6 = satosin6(sa);
    491 	sin6->sin6_family = AF_INET6;
    492 #ifdef HAVE_SA_LEN
    493 	sin6->sin6_len = sizeof(*sin6);
    494 #endif
    495 	memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr,
    496 	    sizeof(sin6->sin6_addr.s6_addr));
    497 }
    498 #endif
    499