Import dhcpcd-10.0.7 with the following changes:
[dragonfly.git] / contrib / dhcpcd / src / sa.c
blob05009d3bae7669e39ee0e4ba5f6fc4acae8fdf95
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
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.
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.
29 #include <sys/socket.h>
30 #include <sys/types.h>
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
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>
47 #include "config.h"
48 #include "common.h"
49 #include "sa.h"
51 #ifndef NDEBUG
52 static bool sa_inprefix;
53 #endif
55 socklen_t
56 sa_addroffset(const struct sockaddr *sa)
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;
77 socklen_t
78 sa_addrlen(const struct sockaddr *sa)
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;
97 #ifndef HAVE_SA_LEN
98 socklen_t
99 sa_len(const struct sockaddr *sa)
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);
119 #endif
121 bool
122 sa_is_unspecified(const struct sockaddr *sa)
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;
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
151 bool
152 sa_is_allones(const struct sockaddr *sa)
155 assert(sa != NULL);
156 switch(sa->sa_family) {
157 case AF_UNSPEC:
158 return false;
159 #ifdef INET
160 case AF_INET:
162 const struct sockaddr_in *sin;
164 sin = satocsin(sa);
165 return sin->sin_addr.s_addr == INADDR_BROADCAST;
167 #endif /* INET */
168 #ifdef INET6
169 case AF_INET6:
171 const struct sockaddr_in6 *sin6;
173 sin6 = satocsin6(sa);
174 return IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6allones);
176 #endif /* INET6 */
177 default:
178 errno = EAFNOSUPPORT;
179 return false;
183 bool
184 sa_is_loopback(const struct sockaddr *sa)
187 assert(sa != NULL);
188 switch(sa->sa_family) {
189 case AF_UNSPEC:
190 return false;
191 #ifdef INET
192 case AF_INET:
194 const struct sockaddr_in *sin;
196 sin = satocsin(sa);
197 return sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
199 #endif /* INET */
200 #ifdef INET6
201 case AF_INET6:
203 const struct sockaddr_in6 *sin6;
205 sin6 = satocsin6(sa);
206 return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
208 #endif /* INET6 */
209 default:
210 errno = EAFNOSUPPORT;
211 return false;
216 sa_toprefix(const struct sockaddr *sa)
218 int prefix;
220 assert(sa != NULL);
221 switch(sa->sa_family) {
222 #ifdef INET
223 case AF_INET:
225 const struct sockaddr_in *sin;
226 uint32_t mask;
228 sin = satocsin(sa);
229 if (sin->sin_addr.s_addr == INADDR_ANY) {
230 prefix = 0;
231 break;
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 */
242 break;
244 #endif
245 #ifdef INET6
246 case AF_INET6:
248 const struct sockaddr_in6 *sin6;
249 int x, y;
250 const uint8_t *lim, *p;
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;
259 y = 0;
260 if (p < lim) {
261 for (y = 0; y < NBBY; y++) {
262 if ((*p & (0x80 >> y)) == 0)
263 break;
268 * when the limit pointer is given, do a stricter check on the
269 * remaining bits.
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;
279 prefix = x * NBBY + y;
280 break;
282 #endif
283 default:
284 errno = EAFNOSUPPORT;
285 return -1;
288 #ifndef NDEBUG
289 /* Ensure the calculation is correct */
290 if (!sa_inprefix) {
291 union sa_ss ss = { .sa = { .sa_family = sa->sa_family } };
293 sa_inprefix = true;
294 sa_fromprefix(&ss.sa, prefix);
295 assert(sa_cmp(sa, &ss.sa) == 0);
296 sa_inprefix = false;
298 #endif
300 return prefix;
303 static void
304 ipbytes_fromprefix(uint8_t *ap, int prefix, int max_prefix)
306 int bytes, bits, i;
308 bytes = prefix / NBBY;
309 bits = prefix % NBBY;
311 for (i = 0; i < bytes; i++)
312 *ap++ = 0xff;
313 if (bits) {
314 uint8_t a;
316 a = 0xff;
317 a = (uint8_t)(a << (8 - bits));
318 *ap++ = a;
320 bytes = (max_prefix - prefix) / NBBY;
321 for (i = 0; i < bytes; i++)
322 *ap++ = 0x00;
325 void
326 in6_addr_fromprefix(struct in6_addr *addr, int prefix)
328 ipbytes_fromprefix((uint8_t *)addr, prefix, 128);
332 sa_fromprefix(struct sockaddr *sa, int prefix)
334 uint8_t *ap;
335 int max_prefix;
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;
359 ap = (uint8_t *)sa + sa_addroffset(sa);
360 ipbytes_fromprefix(ap, prefix, max_prefix);
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;
369 #endif
370 return 0;
373 /* inet_ntop, but for sockaddr. */
374 const char *
375 sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
377 const void *addr;
379 assert(buf != NULL);
380 assert(len > 0);
382 if (sa->sa_family == 0) {
383 *buf = '\0';
384 return NULL;
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;
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;
400 return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
402 #elif defined(AF_PACKET)
403 if (sa->sa_family == AF_PACKET) {
404 const struct sockaddr_ll *sll;
406 sll = (const void *)sa;
407 return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len);
409 #endif
410 addr = (const char *)sa + sa_addroffset(sa);
411 return inet_ntop(sa->sa_family, addr, buf, len);
415 sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
417 socklen_t offset, len;
419 assert(sa1 != NULL);
420 assert(sa2 != NULL);
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;
427 if (sa1->sa_family != sa2->sa_family)
428 return sa1->sa_family - sa2->sa_family;
430 #ifdef HAVE_SA_LEN
431 len = MIN(sa1->sa_len, sa2->sa_len);
432 #endif
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;
465 return memcmp((const char *)sa1 + offset,
466 (const char *)sa2 + offset,
467 len);
470 #ifdef INET
471 void
472 sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
474 struct sockaddr_in *sin;
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;
485 #endif
487 #ifdef INET6
488 void
489 sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
491 struct sockaddr_in6 *sin6;
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));
503 #endif