1 1.2 christos /* $NetBSD: addr.c,v 1.8 2025/04/09 15:49:31 christos Exp $ */ 2 1.8 christos /* $OpenBSD: addr.c,v 1.9 2024/10/18 04:30:09 djm Exp $ */ 3 1.1 christos 4 1.1 christos /* 5 1.1 christos * Copyright (c) 2004-2008 Damien Miller <djm (at) mindrot.org> 6 1.1 christos * 7 1.1 christos * Permission to use, copy, modify, and distribute this software for any 8 1.1 christos * purpose with or without fee is hereby granted, provided that the above 9 1.1 christos * copyright notice and this permission notice appear in all copies. 10 1.1 christos * 11 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 1.1 christos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 1.1 christos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 1.1 christos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 1.1 christos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 1.1 christos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 1.1 christos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 1.1 christos */ 19 1.1 christos 20 1.2 christos #include "includes.h" 21 1.2 christos __RCSID("$NetBSD: addr.c,v 1.8 2025/04/09 15:49:31 christos Exp $"); 22 1.2 christos 23 1.1 christos #include <sys/types.h> 24 1.1 christos #include <sys/socket.h> 25 1.1 christos #include <netinet/in.h> 26 1.1 christos #include <arpa/inet.h> 27 1.1 christos 28 1.1 christos #include <netdb.h> 29 1.1 christos #include <string.h> 30 1.1 christos #include <stdlib.h> 31 1.1 christos #include <stdio.h> 32 1.7 christos #include <limits.h> 33 1.1 christos 34 1.1 christos #include "addr.h" 35 1.1 christos 36 1.1 christos #define _SA(x) ((struct sockaddr *)(x)) 37 1.1 christos 38 1.8 christos static int 39 1.1 christos addr_unicast_masklen(int af) 40 1.1 christos { 41 1.1 christos switch (af) { 42 1.1 christos case AF_INET: 43 1.1 christos return 32; 44 1.1 christos case AF_INET6: 45 1.1 christos return 128; 46 1.1 christos default: 47 1.1 christos return -1; 48 1.1 christos } 49 1.1 christos } 50 1.1 christos 51 1.1 christos static inline int 52 1.1 christos masklen_valid(int af, u_int masklen) 53 1.1 christos { 54 1.1 christos switch (af) { 55 1.1 christos case AF_INET: 56 1.1 christos return masklen <= 32 ? 0 : -1; 57 1.1 christos case AF_INET6: 58 1.1 christos return masklen <= 128 ? 0 : -1; 59 1.1 christos default: 60 1.1 christos return -1; 61 1.1 christos } 62 1.1 christos } 63 1.1 christos 64 1.8 christos static int 65 1.1 christos addr_xaddr_to_sa(const struct xaddr *xa, struct sockaddr *sa, socklen_t *len, 66 1.1 christos u_int16_t port) 67 1.1 christos { 68 1.1 christos struct sockaddr_in *in4 = (struct sockaddr_in *)sa; 69 1.1 christos struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 70 1.1 christos 71 1.1 christos if (xa == NULL || sa == NULL || len == NULL) 72 1.1 christos return -1; 73 1.1 christos 74 1.1 christos switch (xa->af) { 75 1.1 christos case AF_INET: 76 1.1 christos if (*len < sizeof(*in4)) 77 1.1 christos return -1; 78 1.1 christos memset(sa, '\0', sizeof(*in4)); 79 1.1 christos *len = sizeof(*in4); 80 1.1 christos #ifdef SOCK_HAS_LEN 81 1.1 christos in4->sin_len = sizeof(*in4); 82 1.1 christos #endif 83 1.1 christos in4->sin_family = AF_INET; 84 1.1 christos in4->sin_port = htons(port); 85 1.1 christos memcpy(&in4->sin_addr, &xa->v4, sizeof(in4->sin_addr)); 86 1.1 christos break; 87 1.1 christos case AF_INET6: 88 1.1 christos if (*len < sizeof(*in6)) 89 1.1 christos return -1; 90 1.1 christos memset(sa, '\0', sizeof(*in6)); 91 1.1 christos *len = sizeof(*in6); 92 1.1 christos #ifdef SOCK_HAS_LEN 93 1.1 christos in6->sin6_len = sizeof(*in6); 94 1.1 christos #endif 95 1.1 christos in6->sin6_family = AF_INET6; 96 1.1 christos in6->sin6_port = htons(port); 97 1.1 christos memcpy(&in6->sin6_addr, &xa->v6, sizeof(in6->sin6_addr)); 98 1.1 christos in6->sin6_scope_id = xa->scope_id; 99 1.1 christos break; 100 1.1 christos default: 101 1.1 christos return -1; 102 1.1 christos } 103 1.1 christos return 0; 104 1.1 christos } 105 1.1 christos 106 1.1 christos /* 107 1.1 christos * Convert struct sockaddr to struct xaddr 108 1.1 christos * Returns 0 on success, -1 on failure. 109 1.1 christos */ 110 1.1 christos int 111 1.1 christos addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa) 112 1.1 christos { 113 1.1 christos struct sockaddr_in *in4 = (struct sockaddr_in *)sa; 114 1.1 christos struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 115 1.1 christos 116 1.1 christos memset(xa, '\0', sizeof(*xa)); 117 1.1 christos 118 1.1 christos switch (sa->sa_family) { 119 1.1 christos case AF_INET: 120 1.1 christos if (slen < (socklen_t)sizeof(*in4)) 121 1.1 christos return -1; 122 1.1 christos xa->af = AF_INET; 123 1.1 christos memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4)); 124 1.1 christos break; 125 1.1 christos case AF_INET6: 126 1.1 christos if (slen < (socklen_t)sizeof(*in6)) 127 1.1 christos return -1; 128 1.1 christos xa->af = AF_INET6; 129 1.1 christos memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6)); 130 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 131 1.1 christos xa->scope_id = in6->sin6_scope_id; 132 1.1 christos #endif 133 1.1 christos break; 134 1.1 christos default: 135 1.1 christos return -1; 136 1.1 christos } 137 1.1 christos 138 1.1 christos return 0; 139 1.1 christos } 140 1.1 christos 141 1.8 christos static int 142 1.1 christos addr_invert(struct xaddr *n) 143 1.1 christos { 144 1.1 christos int i; 145 1.1 christos 146 1.1 christos if (n == NULL) 147 1.1 christos return -1; 148 1.1 christos 149 1.1 christos switch (n->af) { 150 1.1 christos case AF_INET: 151 1.1 christos n->v4.s_addr = ~n->v4.s_addr; 152 1.1 christos return 0; 153 1.1 christos case AF_INET6: 154 1.1 christos for (i = 0; i < 4; i++) 155 1.1 christos n->addr32[i] = ~n->addr32[i]; 156 1.1 christos return 0; 157 1.1 christos default: 158 1.1 christos return -1; 159 1.1 christos } 160 1.1 christos } 161 1.1 christos 162 1.1 christos /* 163 1.1 christos * Calculate a netmask of length 'l' for address family 'af' and 164 1.1 christos * store it in 'n'. 165 1.1 christos * Returns 0 on success, -1 on failure. 166 1.1 christos */ 167 1.1 christos int 168 1.1 christos addr_netmask(int af, u_int l, struct xaddr *n) 169 1.1 christos { 170 1.1 christos int i; 171 1.1 christos 172 1.1 christos if (masklen_valid(af, l) != 0 || n == NULL) 173 1.1 christos return -1; 174 1.1 christos 175 1.1 christos memset(n, '\0', sizeof(*n)); 176 1.1 christos switch (af) { 177 1.1 christos case AF_INET: 178 1.1 christos n->af = AF_INET; 179 1.1 christos if (l == 0) 180 1.1 christos return 0; 181 1.1 christos n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff); 182 1.1 christos return 0; 183 1.1 christos case AF_INET6: 184 1.1 christos n->af = AF_INET6; 185 1.1 christos for (i = 0; i < 4 && l >= 32; i++, l -= 32) 186 1.1 christos n->addr32[i] = 0xffffffffU; 187 1.1 christos if (i < 4 && l != 0) 188 1.1 christos n->addr32[i] = htonl((0xffffffff << (32 - l)) & 189 1.1 christos 0xffffffff); 190 1.1 christos return 0; 191 1.1 christos default: 192 1.1 christos return -1; 193 1.1 christos } 194 1.1 christos } 195 1.1 christos 196 1.8 christos static int 197 1.1 christos addr_hostmask(int af, u_int l, struct xaddr *n) 198 1.1 christos { 199 1.1 christos if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1) 200 1.1 christos return -1; 201 1.1 christos return 0; 202 1.1 christos } 203 1.1 christos 204 1.1 christos /* 205 1.1 christos * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'. 206 1.1 christos * Returns 0 on success, -1 on failure. 207 1.1 christos */ 208 1.1 christos int 209 1.1 christos addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b) 210 1.1 christos { 211 1.1 christos int i; 212 1.1 christos 213 1.1 christos if (dst == NULL || a == NULL || b == NULL || a->af != b->af) 214 1.1 christos return -1; 215 1.1 christos 216 1.1 christos memcpy(dst, a, sizeof(*dst)); 217 1.1 christos switch (a->af) { 218 1.1 christos case AF_INET: 219 1.1 christos dst->v4.s_addr &= b->v4.s_addr; 220 1.1 christos return 0; 221 1.1 christos case AF_INET6: 222 1.1 christos dst->scope_id = a->scope_id; 223 1.1 christos for (i = 0; i < 4; i++) 224 1.1 christos dst->addr32[i] &= b->addr32[i]; 225 1.1 christos return 0; 226 1.1 christos default: 227 1.1 christos return -1; 228 1.1 christos } 229 1.1 christos } 230 1.1 christos 231 1.8 christos static int 232 1.5 christos addr_or(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b) 233 1.5 christos { 234 1.5 christos int i; 235 1.5 christos 236 1.5 christos if (dst == NULL || a == NULL || b == NULL || a->af != b->af) 237 1.5 christos return (-1); 238 1.5 christos 239 1.5 christos memcpy(dst, a, sizeof(*dst)); 240 1.5 christos switch (a->af) { 241 1.5 christos case AF_INET: 242 1.5 christos dst->v4.s_addr |= b->v4.s_addr; 243 1.5 christos return (0); 244 1.5 christos case AF_INET6: 245 1.5 christos for (i = 0; i < 4; i++) 246 1.5 christos dst->addr32[i] |= b->addr32[i]; 247 1.5 christos return (0); 248 1.5 christos default: 249 1.5 christos return (-1); 250 1.5 christos } 251 1.5 christos } 252 1.5 christos 253 1.5 christos int 254 1.1 christos addr_cmp(const struct xaddr *a, const struct xaddr *b) 255 1.1 christos { 256 1.1 christos int i; 257 1.1 christos 258 1.1 christos if (a->af != b->af) 259 1.1 christos return (a->af == AF_INET6 ? 1 : -1); 260 1.1 christos 261 1.1 christos switch (a->af) { 262 1.1 christos case AF_INET: 263 1.1 christos /* 264 1.1 christos * Can't just subtract here as 255.255.255.255 - 0.0.0.0 is 265 1.1 christos * too big to fit into a signed int 266 1.1 christos */ 267 1.1 christos if (a->v4.s_addr == b->v4.s_addr) 268 1.1 christos return 0; 269 1.1 christos return (ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1); 270 1.3 christos case AF_INET6: 271 1.1 christos /* 272 1.1 christos * Do this a byte at a time to avoid the above issue and 273 1.1 christos * any endian problems 274 1.1 christos */ 275 1.1 christos for (i = 0; i < 16; i++) 276 1.1 christos if (a->addr8[i] - b->addr8[i] != 0) 277 1.1 christos return (a->addr8[i] - b->addr8[i]); 278 1.1 christos if (a->scope_id == b->scope_id) 279 1.1 christos return (0); 280 1.1 christos return (a->scope_id > b->scope_id ? 1 : -1); 281 1.1 christos default: 282 1.1 christos return (-1); 283 1.1 christos } 284 1.1 christos } 285 1.1 christos 286 1.8 christos static int 287 1.1 christos addr_is_all0s(const struct xaddr *a) 288 1.1 christos { 289 1.1 christos int i; 290 1.1 christos 291 1.1 christos switch (a->af) { 292 1.1 christos case AF_INET: 293 1.1 christos return (a->v4.s_addr == 0 ? 0 : -1); 294 1.3 christos case AF_INET6: 295 1.1 christos for (i = 0; i < 4; i++) 296 1.1 christos if (a->addr32[i] != 0) 297 1.1 christos return -1; 298 1.1 christos return 0; 299 1.1 christos default: 300 1.1 christos return -1; 301 1.1 christos } 302 1.1 christos } 303 1.1 christos 304 1.5 christos /* Increment the specified address. Note, does not do overflow checking */ 305 1.5 christos void 306 1.5 christos addr_increment(struct xaddr *a) 307 1.5 christos { 308 1.5 christos int i; 309 1.5 christos uint32_t n; 310 1.5 christos 311 1.5 christos switch (a->af) { 312 1.5 christos case AF_INET: 313 1.5 christos a->v4.s_addr = htonl(ntohl(a->v4.s_addr) + 1); 314 1.5 christos break; 315 1.5 christos case AF_INET6: 316 1.5 christos for (i = 0; i < 4; i++) { 317 1.5 christos /* Increment with carry */ 318 1.5 christos n = ntohl(a->addr32[3 - i]) + 1; 319 1.5 christos a->addr32[3 - i] = htonl(n); 320 1.5 christos if (n != 0) 321 1.5 christos break; 322 1.5 christos } 323 1.5 christos break; 324 1.5 christos } 325 1.5 christos } 326 1.5 christos 327 1.1 christos /* 328 1.1 christos * Test whether host portion of address 'a', as determined by 'masklen' 329 1.1 christos * is all zeros. 330 1.3 christos * Returns 0 if host portion of address is all-zeros, 331 1.1 christos * -1 if not all zeros or on failure. 332 1.1 christos */ 333 1.8 christos static int 334 1.1 christos addr_host_is_all0s(const struct xaddr *a, u_int masklen) 335 1.1 christos { 336 1.1 christos struct xaddr tmp_addr, tmp_mask, tmp_result; 337 1.1 christos 338 1.1 christos memcpy(&tmp_addr, a, sizeof(tmp_addr)); 339 1.1 christos if (addr_hostmask(a->af, masklen, &tmp_mask) == -1) 340 1.1 christos return -1; 341 1.1 christos if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1) 342 1.1 christos return -1; 343 1.1 christos return addr_is_all0s(&tmp_result); 344 1.1 christos } 345 1.1 christos 346 1.5 christos #if 0 347 1.8 christos static int 348 1.5 christos addr_host_to_all0s(struct xaddr *a, u_int masklen) 349 1.5 christos { 350 1.5 christos struct xaddr tmp_mask; 351 1.5 christos 352 1.5 christos if (addr_netmask(a->af, masklen, &tmp_mask) == -1) 353 1.5 christos return (-1); 354 1.5 christos if (addr_and(a, a, &tmp_mask) == -1) 355 1.5 christos return (-1); 356 1.5 christos return (0); 357 1.5 christos } 358 1.5 christos #endif 359 1.5 christos 360 1.5 christos int 361 1.5 christos addr_host_to_all1s(struct xaddr *a, u_int masklen) 362 1.5 christos { 363 1.5 christos struct xaddr tmp_mask; 364 1.5 christos 365 1.5 christos if (addr_hostmask(a->af, masklen, &tmp_mask) == -1) 366 1.5 christos return (-1); 367 1.5 christos if (addr_or(a, a, &tmp_mask) == -1) 368 1.5 christos return (-1); 369 1.5 christos return (0); 370 1.5 christos } 371 1.5 christos 372 1.1 christos /* 373 1.3 christos * Parse string address 'p' into 'n'. 374 1.1 christos * Returns 0 on success, -1 on failure. 375 1.1 christos */ 376 1.1 christos int 377 1.1 christos addr_pton(const char *p, struct xaddr *n) 378 1.1 christos { 379 1.1 christos struct addrinfo hints, *ai; 380 1.1 christos 381 1.1 christos memset(&hints, '\0', sizeof(hints)); 382 1.1 christos hints.ai_flags = AI_NUMERICHOST; 383 1.1 christos 384 1.1 christos if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0) 385 1.1 christos return -1; 386 1.1 christos 387 1.3 christos if (ai == NULL) 388 1.3 christos return -1; 389 1.3 christos 390 1.3 christos if (ai->ai_addr == NULL) { 391 1.3 christos freeaddrinfo(ai); 392 1.1 christos return -1; 393 1.3 christos } 394 1.1 christos 395 1.1 christos if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, 396 1.1 christos n) == -1) { 397 1.1 christos freeaddrinfo(ai); 398 1.1 christos return -1; 399 1.1 christos } 400 1.1 christos 401 1.1 christos freeaddrinfo(ai); 402 1.1 christos return 0; 403 1.1 christos } 404 1.1 christos 405 1.8 christos #if 0 406 1.8 christos static int 407 1.1 christos addr_sa_pton(const char *h, const char *s, struct sockaddr *sa, socklen_t slen) 408 1.1 christos { 409 1.1 christos struct addrinfo hints, *ai; 410 1.1 christos 411 1.1 christos memset(&hints, '\0', sizeof(hints)); 412 1.1 christos hints.ai_flags = AI_NUMERICHOST; 413 1.1 christos 414 1.1 christos if (h == NULL || getaddrinfo(h, s, &hints, &ai) != 0) 415 1.1 christos return -1; 416 1.1 christos 417 1.3 christos if (ai == NULL) 418 1.1 christos return -1; 419 1.1 christos 420 1.3 christos if (ai->ai_addr == NULL) { 421 1.3 christos freeaddrinfo(ai); 422 1.3 christos return -1; 423 1.3 christos } 424 1.3 christos 425 1.1 christos if (sa != NULL) { 426 1.3 christos if (slen < ai->ai_addrlen) { 427 1.3 christos freeaddrinfo(ai); 428 1.1 christos return -1; 429 1.3 christos } 430 1.1 christos memcpy(sa, &ai->ai_addr, ai->ai_addrlen); 431 1.1 christos } 432 1.1 christos 433 1.1 christos freeaddrinfo(ai); 434 1.1 christos return 0; 435 1.1 christos } 436 1.8 christos #endif 437 1.1 christos 438 1.1 christos int 439 1.1 christos addr_ntop(const struct xaddr *n, char *p, size_t len) 440 1.1 christos { 441 1.1 christos struct sockaddr_storage ss; 442 1.1 christos socklen_t slen = sizeof(ss); 443 1.1 christos 444 1.1 christos if (addr_xaddr_to_sa(n, _SA(&ss), &slen, 0) == -1) 445 1.1 christos return -1; 446 1.3 christos if (p == NULL || len == 0) 447 1.1 christos return -1; 448 1.1 christos if (getnameinfo(_SA(&ss), slen, p, len, NULL, 0, 449 1.6 christos NI_NUMERICHOST) != 0) 450 1.1 christos return -1; 451 1.1 christos 452 1.1 christos return 0; 453 1.1 christos } 454 1.1 christos 455 1.1 christos /* 456 1.1 christos * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z). 457 1.1 christos * Return -1 on parse error, -2 on inconsistency or 0 on success. 458 1.1 christos */ 459 1.1 christos int 460 1.1 christos addr_pton_cidr(const char *p, struct xaddr *n, u_int *l) 461 1.1 christos { 462 1.1 christos struct xaddr tmp; 463 1.7 christos u_int masklen = 999; 464 1.7 christos char addrbuf[64], *mp; 465 1.7 christos const char *errstr; 466 1.1 christos 467 1.1 christos /* Don't modify argument */ 468 1.1 christos if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf)) 469 1.1 christos return -1; 470 1.1 christos 471 1.1 christos if ((mp = strchr(addrbuf, '/')) != NULL) { 472 1.1 christos *mp = '\0'; 473 1.1 christos mp++; 474 1.7 christos masklen = (u_int)strtonum(mp, 0, INT_MAX, &errstr); 475 1.7 christos if (errstr) 476 1.1 christos return -1; 477 1.1 christos } 478 1.1 christos 479 1.1 christos if (addr_pton(addrbuf, &tmp) == -1) 480 1.1 christos return -1; 481 1.1 christos 482 1.1 christos if (mp == NULL) 483 1.1 christos masklen = addr_unicast_masklen(tmp.af); 484 1.1 christos if (masklen_valid(tmp.af, masklen) == -1) 485 1.1 christos return -2; 486 1.1 christos if (addr_host_is_all0s(&tmp, masklen) != 0) 487 1.1 christos return -2; 488 1.1 christos 489 1.1 christos if (n != NULL) 490 1.1 christos memcpy(n, &tmp, sizeof(*n)); 491 1.1 christos if (l != NULL) 492 1.1 christos *l = masklen; 493 1.1 christos 494 1.1 christos return 0; 495 1.1 christos } 496 1.1 christos 497 1.1 christos int 498 1.1 christos addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen) 499 1.1 christos { 500 1.1 christos struct xaddr tmp_mask, tmp_result; 501 1.1 christos 502 1.1 christos if (host->af != net->af) 503 1.1 christos return -1; 504 1.1 christos 505 1.1 christos if (addr_netmask(host->af, masklen, &tmp_mask) == -1) 506 1.1 christos return -1; 507 1.1 christos if (addr_and(&tmp_result, host, &tmp_mask) == -1) 508 1.1 christos return -1; 509 1.1 christos return addr_cmp(&tmp_result, net); 510 1.1 christos } 511