1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Socket Address handling for dhcpcd 4 * Copyright (c) 2015-2020 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 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 int 304 sa_fromprefix(struct sockaddr *sa, int prefix) 305 { 306 uint8_t *ap; 307 int max_prefix, bytes, bits, i; 308 309 switch (sa->sa_family) { 310 #ifdef INET 311 case AF_INET: 312 max_prefix = 32; 313 #ifdef HAVE_SA_LEN 314 sa->sa_len = sizeof(struct sockaddr_in); 315 #endif 316 break; 317 #endif 318 #ifdef INET6 319 case AF_INET6: 320 max_prefix = 128; 321 #ifdef HAVE_SA_LEN 322 sa->sa_len = sizeof(struct sockaddr_in6); 323 #endif 324 break; 325 #endif 326 default: 327 errno = EAFNOSUPPORT; 328 return -1; 329 } 330 331 bytes = prefix / NBBY; 332 bits = prefix % NBBY; 333 334 ap = (uint8_t *)sa + sa_addroffset(sa); 335 for (i = 0; i < bytes; i++) 336 *ap++ = 0xff; 337 if (bits) { 338 uint8_t a; 339 340 a = 0xff; 341 a = (uint8_t)(a << (8 - bits)); 342 *ap++ = a; 343 } 344 bytes = (max_prefix - prefix) / NBBY; 345 for (i = 0; i < bytes; i++) 346 *ap++ = 0x00; 347 348 #ifndef NDEBUG 349 /* Ensure the calculation is correct */ 350 if (!sa_inprefix) { 351 sa_inprefix = true; 352 assert(sa_toprefix(sa) == prefix); 353 sa_inprefix = false; 354 } 355 #endif 356 return 0; 357 } 358 359 /* inet_ntop, but for sockaddr. */ 360 const char * 361 sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len) 362 { 363 const void *addr; 364 365 assert(buf != NULL); 366 assert(len > 0); 367 368 if (sa->sa_family == 0) { 369 *buf = '\0'; 370 return NULL; 371 } 372 373 #ifdef AF_LINK 374 #ifndef CLLADDR 375 #define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen) 376 #endif 377 if (sa->sa_family == AF_LINK) { 378 const struct sockaddr_dl *sdl; 379 380 sdl = (const void *)sa; 381 if (sdl->sdl_alen == 0) { 382 if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1) 383 return NULL; 384 return buf; 385 } 386 return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len); 387 } 388 #elif defined(AF_PACKET) 389 if (sa->sa_family == AF_PACKET) { 390 const struct sockaddr_ll *sll; 391 392 sll = (const void *)sa; 393 return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len); 394 } 395 #endif 396 addr = (const char *)sa + sa_addroffset(sa); 397 return inet_ntop(sa->sa_family, addr, buf, len); 398 } 399 400 int 401 sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2) 402 { 403 socklen_t offset, len; 404 405 assert(sa1 != NULL); 406 assert(sa2 != NULL); 407 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)) 411 return 0; 412 413 if (sa1->sa_family != sa2->sa_family) 414 return sa1->sa_family - sa2->sa_family; 415 416 #ifdef HAVE_SA_LEN 417 len = MIN(sa1->sa_len, sa2->sa_len); 418 #endif 419 420 switch (sa1->sa_family) { 421 #ifdef INET 422 case AF_INET: 423 offset = offsetof(struct sockaddr_in, sin_addr); 424 #ifdef HAVE_SA_LEN 425 len -= offset; 426 len = MIN(len, sizeof(struct in_addr)); 427 #else 428 len = sizeof(struct in_addr); 429 #endif 430 break; 431 #endif 432 #ifdef INET6 433 case AF_INET6: 434 offset = offsetof(struct sockaddr_in6, sin6_addr); 435 #ifdef HAVE_SA_LEN 436 len -= offset; 437 len = MIN(len, sizeof(struct in6_addr)); 438 #else 439 len = sizeof(struct in6_addr); 440 #endif 441 break; 442 #endif 443 default: 444 offset = 0; 445 #ifndef HAVE_SA_LEN 446 len = sizeof(struct sockaddr); 447 #endif 448 break; 449 } 450 451 return memcmp((const char *)sa1 + offset, 452 (const char *)sa2 + offset, 453 len); 454 } 455 456 #ifdef INET 457 void 458 sa_in_init(struct sockaddr *sa, const struct in_addr *addr) 459 { 460 struct sockaddr_in *sin; 461 462 assert(sa != NULL); 463 assert(addr != NULL); 464 sin = satosin(sa); 465 sin->sin_family = AF_INET; 466 #ifdef HAVE_SA_LEN 467 sin->sin_len = sizeof(*sin); 468 #endif 469 sin->sin_addr.s_addr = addr->s_addr; 470 } 471 #endif 472 473 #ifdef INET6 474 void 475 sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr) 476 { 477 struct sockaddr_in6 *sin6; 478 479 assert(sa != NULL); 480 assert(addr != NULL); 481 sin6 = satosin6(sa); 482 sin6->sin6_family = AF_INET6; 483 #ifdef HAVE_SA_LEN 484 sin6->sin6_len = sizeof(*sin6); 485 #endif 486 memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr, 487 sizeof(sin6->sin6_addr.s6_addr)); 488 } 489 #endif 490