1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * Socket Address handling for dhcpcd
4 * Copyright (c) 2015-2023 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>
35 #elif defined(AF_PACKET)
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 ipbytes_fromprefix(uint8_t *ap
, int prefix
, int max_prefix
)
308 bytes
= prefix
/ NBBY
;
309 bits
= prefix
% NBBY
;
311 for (i
= 0; i
< bytes
; i
++)
317 a
= (uint8_t)(a
<< (8 - bits
));
320 bytes
= (max_prefix
- prefix
) / NBBY
;
321 for (i
= 0; i
< bytes
; i
++)
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
)
337 switch (sa
->sa_family
) {
342 sa
->sa_len
= sizeof(struct sockaddr_in
);
350 sa
->sa_len
= sizeof(struct sockaddr_in6
);
355 errno
= EAFNOSUPPORT
;
359 ap
= (uint8_t *)sa
+ sa_addroffset(sa
);
360 ipbytes_fromprefix(ap
, prefix
, max_prefix
);
363 /* Ensure the calculation is correct */
366 assert(sa_toprefix(sa
) == prefix
);
373 /* inet_ntop, but for sockaddr. */
375 sa_addrtop(const struct sockaddr
*sa
, char *buf
, socklen_t len
)
382 if (sa
->sa_family
== 0) {
389 #define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
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)
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
);
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
;
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
))
427 if (sa1
->sa_family
!= sa2
->sa_family
)
428 return sa1
->sa_family
- sa2
->sa_family
;
431 len
= MIN(sa1
->sa_len
, sa2
->sa_len
);
434 switch (sa1
->sa_family
) {
437 offset
= offsetof(struct sockaddr_in
, sin_addr
);
440 len
= MIN(len
, sizeof(struct in_addr
));
442 len
= sizeof(struct in_addr
);
448 offset
= offsetof(struct sockaddr_in6
, sin6_addr
);
451 len
= MIN(len
, sizeof(struct in6_addr
));
453 len
= sizeof(struct in6_addr
);
460 len
= sizeof(struct sockaddr
);
465 return memcmp((const char *)sa1
+ offset
,
466 (const char *)sa2
+ offset
,
472 sa_in_init(struct sockaddr
*sa
, const struct in_addr
*addr
)
474 struct sockaddr_in
*sin
;
477 assert(addr
!= NULL
);
479 sin
->sin_family
= AF_INET
;
481 sin
->sin_len
= sizeof(*sin
);
483 sin
->sin_addr
.s_addr
= addr
->s_addr
;
489 sa_in6_init(struct sockaddr
*sa
, const struct in6_addr
*addr
)
491 struct sockaddr_in6
*sin6
;
494 assert(addr
!= NULL
);
496 sin6
->sin6_family
= AF_INET6
;
498 sin6
->sin6_len
= sizeof(*sin6
);
500 memcpy(&sin6
->sin6_addr
.s6_addr
, &addr
->s6_addr
,
501 sizeof(sin6
->sin6_addr
.s6_addr
));