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