1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * Socket Address handling for dhcpcd
4 * Copyright (c) 2015-2019 Roy Marples <roy@marples.name>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
29 #include <sys/socket.h>
30 #include <sys/types.h>
32 #include <arpa/inet.h>
34 #include <net/if_dl.h>
36 #include <linux/if_packet.h>
52 static bool sa_inprefix;
56 sa_addroffset(const struct sockaddr *sa)
60 switch(sa->sa_family) {
63 return offsetof(struct sockaddr_in, sin_addr) +
64 offsetof(struct in_addr, s_addr);
68 return offsetof(struct sockaddr_in6, sin6_addr) +
69 offsetof(struct in6_addr, s6_addr);
78 sa_addrlen(const struct sockaddr *sa)
80 #define membersize(type, member) sizeof(((type *)0)->member)
82 switch(sa->sa_family) {
85 return membersize(struct in_addr, s_addr);
89 return membersize(struct in6_addr, s6_addr);
99 sa_len(const struct sockaddr *sa)
102 switch (sa->sa_family) {
105 return sizeof(struct sockaddr_dl);
109 return sizeof(struct sockaddr_ll);
112 return sizeof(struct sockaddr_in);
114 return sizeof(struct sockaddr_in6);
116 return sizeof(struct sockaddr);
122 sa_is_unspecified(const struct sockaddr *sa)
126 switch(sa->sa_family) {
131 return satocsin(sa)->sin_addr.s_addr == INADDR_ANY;
135 return IN6_IS_ADDR_UNSPECIFIED(&satocsin6(sa)->sin6_addr);
138 errno = EAFNOSUPPORT;
145 #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
146 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
148 static const struct in6_addr in6allones = IN6MASK128;
152 sa_is_allones(const struct sockaddr *sa)
156 switch(sa->sa_family) {
162 const struct sockaddr_in *sin;
165 return sin->sin_addr.s_addr == INADDR_BROADCAST;
171 const struct sockaddr_in6 *sin6;
173 sin6 = satocsin6(sa);
174 return IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6allones);
178 errno = EAFNOSUPPORT;
184 sa_is_loopback(const struct sockaddr *sa)
188 switch(sa->sa_family) {
194 const struct sockaddr_in *sin;
197 return sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
203 const struct sockaddr_in6 *sin6;
205 sin6 = satocsin6(sa);
206 return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
210 errno = EAFNOSUPPORT;
216 sa_toprefix(const struct sockaddr *sa)
221 switch(sa->sa_family) {
225 const struct sockaddr_in *sin;
229 if (sin->sin_addr.s_addr == INADDR_ANY) {
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) {
239 return -1; /* noncontig, no pfxlen */
248 const struct sockaddr_in6 *sin6;
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++) {
261 for (y = 0; y < NBBY; y++) {
262 if ((*p & (0x80 >> y)) == 0)
268 * when the limit pointer is given, do a stricter check on the
272 if (y != 0 && (*p & (0x00ff >> y)) != 0)
274 for (p = p + 1; p < lim; p++)
279 prefix = x * NBBY + y;
284 errno = EAFNOSUPPORT;
289 /* Ensure the calculation is correct */
291 union sa_ss ss = { .sa.sa_family = sa->sa_family };
294 sa_fromprefix(&ss.sa, prefix);
295 assert(sa_cmp(sa, &ss.sa) == 0);
304 sa_fromprefix(struct sockaddr *sa, int prefix)
307 int max_prefix, bytes, bits, i;
309 switch (sa->sa_family) {
314 sa->sa_len = sizeof(struct sockaddr_in);
322 sa->sa_len = sizeof(struct sockaddr_in6);
327 errno = EAFNOSUPPORT;
331 bytes = prefix / NBBY;
332 bits = prefix % NBBY;
334 ap = (uint8_t *)sa + sa_addroffset(sa);
335 for (i = 0; i < bytes; i++)
341 a = (uint8_t)(a << (8 - bits));
344 bytes = (max_prefix - prefix) / NBBY;
345 for (i = 0; i < bytes; i++)
349 /* Ensure the calculation is correct */
352 assert(sa_toprefix(sa) == prefix);
359 /* inet_ntop, but for sockaddr. */
361 sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
368 if (sa->sa_family == 0) {
375 #define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
377 if (sa->sa_family == AF_LINK) {
378 const struct sockaddr_dl *sdl;
380 sdl = (const void *)sa;
381 if (sdl->sdl_alen == 0) {
382 if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1)
386 return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
389 if (sa->sa_family == AF_PACKET) {
390 const struct sockaddr_ll *sll;
392 sll = (const void *)sa;
393 return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len);
396 addr = (const char *)sa + sa_addroffset(sa);
397 return inet_ntop(sa->sa_family, addr, buf, len);
401 sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
403 socklen_t offset, len;
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))
413 if (sa1->sa_family != sa2->sa_family)
414 return sa1->sa_family - sa2->sa_family;
417 len = MIN(sa1->sa_len, sa2->sa_len);
420 switch (sa1->sa_family) {
423 offset = offsetof(struct sockaddr_in, sin_addr);
426 len = MIN(len, sizeof(struct in_addr));
428 len = sizeof(struct in_addr);
434 offset = offsetof(struct sockaddr_in6, sin6_addr);
437 len = MIN(len, sizeof(struct in6_addr));
439 len = sizeof(struct in6_addr);
446 len = sizeof(struct sockaddr);
451 return memcmp((const char *)sa1 + offset,
452 (const char *)sa2 + offset,
458 sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
460 struct sockaddr_in *sin;
463 assert(addr != NULL);
465 sin->sin_family = AF_INET;
467 sin->sin_len = sizeof(*sin);
469 sin->sin_addr.s_addr = addr->s_addr;
475 sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
477 struct sockaddr_in6 *sin6;
480 assert(addr != NULL);
482 sin6->sin6_family = AF_INET6;
484 sin6->sin6_len = sizeof(*sin6);
486 memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr,
487 sizeof(sin6->sin6_addr.s6_addr));