1 /* 2 * Socket Address handling for dhcpcd 3 * Copyright (c) 2015-2018 Roy Marples <roy@marples.name> 4 * All rights reserved 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/socket.h> 29 #include <sys/types.h> 30 31 #include <arpa/inet.h> 32 #ifdef AF_LINK 33 #include <net/if_dl.h> 34 #elif AF_PACKET 35 #include <linux/if_packet.h> 36 #endif 37 38 #include <assert.h> 39 #include <errno.h> 40 #include <stddef.h> 41 #include <stdio.h> 42 #include <stdint.h> 43 #include <string.h> 44 45 #include "config.h" 46 #include "common.h" 47 #include "sa.h" 48 49 #ifndef NDEBUG 50 static bool sa_inprefix; 51 #endif 52 53 socklen_t 54 sa_addroffset(const struct sockaddr *sa) 55 { 56 57 assert(sa != NULL); 58 switch(sa->sa_family) { 59 #ifdef INET 60 case AF_INET: 61 return offsetof(struct sockaddr_in, sin_addr) + 62 offsetof(struct in_addr, s_addr); 63 #endif /* INET */ 64 #ifdef INET6 65 case AF_INET6: 66 return offsetof(struct sockaddr_in6, sin6_addr) + 67 offsetof(struct in6_addr, s6_addr); 68 #endif /* INET6 */ 69 default: 70 errno = EAFNOSUPPORT; 71 return 0; 72 } 73 } 74 75 socklen_t 76 sa_addrlen(const struct sockaddr *sa) 77 { 78 #define membersize(type, member) sizeof(((type *)0)->member) 79 assert(sa != NULL); 80 switch(sa->sa_family) { 81 #ifdef INET 82 case AF_INET: 83 return membersize(struct in_addr, s_addr); 84 #endif /* INET */ 85 #ifdef INET6 86 case AF_INET6: 87 return membersize(struct in6_addr, s6_addr); 88 #endif /* INET6 */ 89 default: 90 errno = EAFNOSUPPORT; 91 return 0; 92 } 93 } 94 95 bool 96 sa_is_unspecified(const struct sockaddr *sa) 97 { 98 99 assert(sa != NULL); 100 switch(sa->sa_family) { 101 case AF_UNSPEC: 102 return true; 103 #ifdef INET 104 case AF_INET: 105 return satocsin(sa)->sin_addr.s_addr == INADDR_ANY; 106 #endif /* INET */ 107 #ifdef INET6 108 case AF_INET6: 109 return IN6_IS_ADDR_UNSPECIFIED(&satocsin6(sa)->sin6_addr); 110 #endif /* INET6 */ 111 default: 112 errno = EAFNOSUPPORT; 113 return false; 114 } 115 } 116 117 #ifdef INET6 118 #ifndef IN6MASK128 119 #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ 120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}} 121 #endif 122 static const struct in6_addr in6allones = IN6MASK128; 123 #endif 124 125 bool 126 sa_is_allones(const struct sockaddr *sa) 127 { 128 129 assert(sa != NULL); 130 switch(sa->sa_family) { 131 case AF_UNSPEC: 132 return false; 133 #ifdef INET 134 case AF_INET: 135 { 136 const struct sockaddr_in *sin; 137 138 sin = satocsin(sa); 139 return sin->sin_addr.s_addr == INADDR_BROADCAST; 140 } 141 #endif /* INET */ 142 #ifdef INET6 143 case AF_INET6: 144 { 145 const struct sockaddr_in6 *sin6; 146 147 sin6 = satocsin6(sa); 148 return IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6allones); 149 } 150 #endif /* INET6 */ 151 default: 152 errno = EAFNOSUPPORT; 153 return false; 154 } 155 } 156 157 bool 158 sa_is_loopback(const struct sockaddr *sa) 159 { 160 161 assert(sa != NULL); 162 switch(sa->sa_family) { 163 case AF_UNSPEC: 164 return false; 165 #ifdef INET 166 case AF_INET: 167 { 168 const struct sockaddr_in *sin; 169 170 sin = satocsin(sa); 171 return sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK); 172 } 173 #endif /* INET */ 174 #ifdef INET6 175 case AF_INET6: 176 { 177 const struct sockaddr_in6 *sin6; 178 179 sin6 = satocsin6(sa); 180 return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr); 181 } 182 #endif /* INET6 */ 183 default: 184 errno = EAFNOSUPPORT; 185 return false; 186 } 187 } 188 189 int 190 sa_toprefix(const struct sockaddr *sa) 191 { 192 int prefix; 193 194 assert(sa != NULL); 195 switch(sa->sa_family) { 196 #ifdef INET 197 case AF_INET: 198 { 199 const struct sockaddr_in *sin; 200 uint32_t mask; 201 202 sin = satocsin(sa); 203 if (sin->sin_addr.s_addr == INADDR_ANY) { 204 prefix = 0; 205 break; 206 } 207 mask = ntohl(sin->sin_addr.s_addr); 208 prefix = 33 - ffs((int)mask); /* 33 - (1 .. 32) -> 32 .. 1 */ 209 if (prefix < 32) { /* more than 1 bit in mask */ 210 /* check for non-contig netmask */ 211 if ((mask^(((1U << prefix)-1) << (32 - prefix))) != 0) { 212 errno = EINVAL; 213 return -1; /* noncontig, no pfxlen */ 214 } 215 } 216 break; 217 } 218 #endif 219 #ifdef INET6 220 case AF_INET6: 221 { 222 const struct sockaddr_in6 *sin6; 223 int x, y; 224 const uint8_t *lim, *p; 225 226 sin6 = satocsin6(sa); 227 p = (const uint8_t *)sin6->sin6_addr.s6_addr; 228 lim = p + sizeof(sin6->sin6_addr.s6_addr); 229 for (x = 0; p < lim; x++, p++) { 230 if (*p != 0xff) 231 break; 232 } 233 y = 0; 234 if (p < lim) { 235 for (y = 0; y < NBBY; y++) { 236 if ((*p & (0x80 >> y)) == 0) 237 break; 238 } 239 } 240 241 /* 242 * when the limit pointer is given, do a stricter check on the 243 * remaining bits. 244 */ 245 if (p < lim) { 246 if (y != 0 && (*p & (0x00ff >> y)) != 0) 247 return 0; 248 for (p = p + 1; p < lim; p++) 249 if (*p != 0) 250 return 0; 251 } 252 253 prefix = x * NBBY + y; 254 break; 255 } 256 #endif 257 default: 258 errno = EAFNOSUPPORT; 259 return -1; 260 } 261 262 #ifndef NDEBUG 263 /* Ensure the calculation is correct */ 264 if (!sa_inprefix) { 265 union sa_ss ss; 266 267 sa_inprefix = true; 268 memset(&ss, 0, sizeof(ss)); 269 ss.sa.sa_family = sa->sa_family; 270 sa_fromprefix(&ss.sa, prefix); 271 assert(sa_cmp(sa, &ss.sa) == 0); 272 sa_inprefix = false; 273 } 274 #endif 275 276 return prefix; 277 } 278 279 int 280 sa_fromprefix(struct sockaddr *sa, int prefix) 281 { 282 uint8_t *ap; 283 int max_prefix, bytes, bits, i; 284 285 switch (sa->sa_family) { 286 #ifdef INET 287 case AF_INET: 288 max_prefix = 32; 289 #ifdef HAVE_SA_LEN 290 sa->sa_len = sizeof(struct sockaddr_in); 291 #endif 292 break; 293 #endif 294 #ifdef INET6 295 case AF_INET6: 296 max_prefix = 128; 297 #ifdef HAVE_SA_LEN 298 sa->sa_len = sizeof(struct sockaddr_in6); 299 #endif 300 break; 301 #endif 302 default: 303 errno = EAFNOSUPPORT; 304 return -1; 305 } 306 307 bytes = prefix / NBBY; 308 bits = prefix % NBBY; 309 310 ap = (uint8_t *)sa + sa_addroffset(sa); 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 #ifndef NDEBUG 325 /* Ensure the calculation is correct */ 326 if (!sa_inprefix) { 327 sa_inprefix = true; 328 assert(sa_toprefix(sa) == prefix); 329 sa_inprefix = false; 330 } 331 #endif 332 return 0; 333 } 334 335 /* inet_ntop, but for sockaddr. */ 336 const char * 337 sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len) 338 { 339 const void *addr; 340 341 assert(buf != NULL); 342 #ifdef AF_LINK 343 #ifndef CLLADDR 344 #define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen) 345 #endif 346 if (sa->sa_family == AF_LINK) { 347 const struct sockaddr_dl *sdl; 348 349 sdl = (const void *)sa; 350 if (sdl->sdl_alen == 0) { 351 if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1) 352 return NULL; 353 return buf; 354 } 355 return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len); 356 } 357 #elif AF_PACKET 358 if (sa->sa_family == AF_PACKET) { 359 const struct sockaddr_ll *sll; 360 361 sll = (const void *)sa; 362 return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len); 363 } 364 #endif 365 addr = (const char *)sa + sa_addroffset(sa); 366 return inet_ntop(sa->sa_family, addr, buf, len); 367 } 368 369 int 370 sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2) 371 { 372 socklen_t offset, len; 373 374 assert(sa1 != NULL); 375 assert(sa2 != NULL); 376 377 /* Treat AF_UNSPEC as the unspecified address. */ 378 if ((sa1->sa_family == AF_UNSPEC || sa2->sa_family == AF_UNSPEC) && 379 sa_is_unspecified(sa1) && sa_is_unspecified(sa2)) 380 return 0; 381 382 if (sa1->sa_family != sa2->sa_family) 383 return sa1->sa_family - sa2->sa_family; 384 385 #ifdef HAVE_SA_LEN 386 len = MIN(sa1->sa_len, sa2->sa_len); 387 #endif 388 389 switch (sa1->sa_family) { 390 #ifdef INET 391 case AF_INET: 392 offset = offsetof(struct sockaddr_in, sin_addr); 393 #ifdef HAVE_SA_LEN 394 len -= offset; 395 len = MIN(len, sizeof(struct in_addr)); 396 #else 397 len = sizeof(struct in_addr); 398 #endif 399 break; 400 #endif 401 #ifdef INET6 402 case AF_INET6: 403 offset = offsetof(struct sockaddr_in6, sin6_addr); 404 #ifdef HAVE_SA_LEN 405 len -= offset; 406 len = MIN(len, sizeof(struct in6_addr)); 407 #else 408 len = sizeof(struct in6_addr); 409 #endif 410 break; 411 #endif 412 default: 413 offset = 0; 414 #ifndef HAVE_SA_LEN 415 len = sizeof(struct sockaddr); 416 #endif 417 break; 418 } 419 420 return memcmp((const char *)sa1 + offset, 421 (const char *)sa2 + offset, 422 len); 423 } 424 425 #ifdef INET 426 void 427 sa_in_init(struct sockaddr *sa, const struct in_addr *addr) 428 { 429 struct sockaddr_in *sin; 430 431 assert(sa != NULL); 432 assert(addr != NULL); 433 sin = satosin(sa); 434 sin->sin_family = AF_INET; 435 #ifdef HAVE_SA_LEN 436 sin->sin_len = sizeof(*sin); 437 #endif 438 sin->sin_addr.s_addr = addr->s_addr; 439 } 440 #endif 441 442 #ifdef INET6 443 void 444 sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr) 445 { 446 struct sockaddr_in6 *sin6; 447 448 assert(sa != NULL); 449 assert(addr != NULL); 450 sin6 = satosin6(sa); 451 sin6->sin6_family = AF_INET6; 452 #ifdef HAVE_SA_LEN 453 sin6->sin6_len = sizeof(*sin6); 454 #endif 455 memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr, 456 sizeof(sin6->sin6_addr.s6_addr)); 457 } 458 #endif 459