1/* $NetBSD: netaddr.c,v 1.9 2024/02/21 22:52:28 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16/*! \file */ 17 18#include <inttypes.h> 19#include <stdbool.h> 20#include <stdio.h> 21 22#include <isc/buffer.h> 23#include <isc/net.h> 24#include <isc/netaddr.h> 25#include <isc/print.h> 26#include <isc/sockaddr.h> 27#include <isc/string.h> 28#include <isc/util.h> 29 30bool 31isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) { 32 REQUIRE(a != NULL && b != NULL); 33 34 if (a->family != b->family) { 35 return (false); 36 } 37 38 if (a->zone != b->zone) { 39 return (false); 40 } 41 42 switch (a->family) { 43 case AF_INET: 44 if (a->type.in.s_addr != b->type.in.s_addr) { 45 return (false); 46 } 47 break; 48 case AF_INET6: 49 if (memcmp(&a->type.in6, &b->type.in6, sizeof(a->type.in6)) != 50 0 || 51 a->zone != b->zone) 52 { 53 return (false); 54 } 55 break; 56 case AF_UNIX: 57 if (strcmp(a->type.un, b->type.un) != 0) { 58 return (false); 59 } 60 break; 61 default: 62 return (false); 63 } 64 return (true); 65} 66 67bool 68isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b, 69 unsigned int prefixlen) { 70 const unsigned char *pa = NULL, *pb = NULL; 71 unsigned int ipabytes = 0; /* Length of whole IP address in bytes */ 72 unsigned int nbytes; /* Number of significant whole bytes */ 73 unsigned int nbits; /* Number of significant leftover bits */ 74 75 REQUIRE(a != NULL && b != NULL); 76 77 if (a->family != b->family) { 78 return (false); 79 } 80 81 if (a->zone != b->zone && b->zone != 0) { 82 return (false); 83 } 84 85 switch (a->family) { 86 case AF_INET: 87 pa = (const unsigned char *)&a->type.in; 88 pb = (const unsigned char *)&b->type.in; 89 ipabytes = 4; 90 break; 91 case AF_INET6: 92 pa = (const unsigned char *)&a->type.in6; 93 pb = (const unsigned char *)&b->type.in6; 94 ipabytes = 16; 95 break; 96 default: 97 return (false); 98 } 99 100 /* 101 * Don't crash if we get a pattern like 10.0.0.1/9999999. 102 */ 103 if (prefixlen > ipabytes * 8) { 104 prefixlen = ipabytes * 8; 105 } 106 107 nbytes = prefixlen / 8; 108 nbits = prefixlen % 8; 109 110 if (nbytes > 0) { 111 if (memcmp(pa, pb, nbytes) != 0) { 112 return (false); 113 } 114 } 115 if (nbits > 0) { 116 unsigned int bytea, byteb, mask; 117 INSIST(nbytes < ipabytes); 118 INSIST(nbits < 8); 119 bytea = pa[nbytes]; 120 byteb = pb[nbytes]; 121 mask = (0xFF << (8 - nbits)) & 0xFF; 122 if ((bytea & mask) != (byteb & mask)) { 123 return (false); 124 } 125 } 126 return (true); 127} 128 129isc_result_t 130isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) { 131 char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; 132 char zbuf[sizeof("%4294967295")]; 133 unsigned int alen; 134 int zlen; 135 const char *r; 136 const void *type; 137 138 REQUIRE(netaddr != NULL); 139 140 switch (netaddr->family) { 141 case AF_INET: 142 type = &netaddr->type.in; 143 break; 144 case AF_INET6: 145 type = &netaddr->type.in6; 146 break; 147 case AF_UNIX: 148 alen = strlen(netaddr->type.un); 149 if (alen > isc_buffer_availablelength(target)) { 150 return (ISC_R_NOSPACE); 151 } 152 isc_buffer_putmem(target, 153 (const unsigned char *)(netaddr->type.un), 154 alen); 155 return (ISC_R_SUCCESS); 156 default: 157 return (ISC_R_FAILURE); 158 } 159 r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf)); 160 if (r == NULL) { 161 return (ISC_R_FAILURE); 162 } 163 164 alen = strlen(abuf); 165 INSIST(alen < sizeof(abuf)); 166 167 zlen = 0; 168 if (netaddr->family == AF_INET6 && netaddr->zone != 0) { 169 zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone); 170 if (zlen < 0) { 171 return (ISC_R_FAILURE); 172 } 173 INSIST((unsigned int)zlen < sizeof(zbuf)); 174 } 175 176 if (alen + zlen > isc_buffer_availablelength(target)) { 177 return (ISC_R_NOSPACE); 178 } 179 180 isc_buffer_putmem(target, (unsigned char *)abuf, alen); 181 isc_buffer_putmem(target, (unsigned char *)zbuf, (unsigned int)zlen); 182 183 return (ISC_R_SUCCESS); 184} 185 186void 187isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) { 188 isc_result_t result; 189 isc_buffer_t buf; 190 191 isc_buffer_init(&buf, array, size); 192 result = isc_netaddr_totext(na, &buf); 193 194 if (size == 0) { 195 return; 196 } 197 198 /* 199 * Null terminate. 200 */ 201 if (result == ISC_R_SUCCESS) { 202 if (isc_buffer_availablelength(&buf) >= 1) { 203 isc_buffer_putuint8(&buf, 0); 204 } else { 205 result = ISC_R_NOSPACE; 206 } 207 } 208 209 if (result != ISC_R_SUCCESS) { 210 snprintf(array, size, "<unknown address, family %u>", 211 na->family); 212 array[size - 1] = '\0'; 213 } 214} 215 216isc_result_t 217isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { 218 static const unsigned char zeros[16]; 219 unsigned int nbits, nbytes, ipbytes = 0; 220 const unsigned char *p; 221 222 switch (na->family) { 223 case AF_INET: 224 p = (const unsigned char *)&na->type.in; 225 ipbytes = 4; 226 if (prefixlen > 32) { 227 return (ISC_R_RANGE); 228 } 229 break; 230 case AF_INET6: 231 p = (const unsigned char *)&na->type.in6; 232 ipbytes = 16; 233 if (prefixlen > 128) { 234 return (ISC_R_RANGE); 235 } 236 break; 237 default: 238 return (ISC_R_NOTIMPLEMENTED); 239 } 240 nbytes = prefixlen / 8; 241 nbits = prefixlen % 8; 242 if (nbits != 0) { 243 INSIST(nbytes < ipbytes); 244 if ((p[nbytes] & (0xff >> nbits)) != 0U) { 245 return (ISC_R_FAILURE); 246 } 247 nbytes++; 248 } 249 if (nbytes < ipbytes && 250 memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) 251 { 252 return (ISC_R_FAILURE); 253 } 254 return (ISC_R_SUCCESS); 255} 256 257isc_result_t 258isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) { 259 unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i; 260 const unsigned char *p; 261 262 switch (s->family) { 263 case AF_INET: 264 p = (const unsigned char *)&s->type.in; 265 ipbytes = 4; 266 break; 267 case AF_INET6: 268 p = (const unsigned char *)&s->type.in6; 269 ipbytes = 16; 270 break; 271 default: 272 return (ISC_R_NOTIMPLEMENTED); 273 } 274 for (i = 0; i < ipbytes; i++) { 275 if (p[i] != 0xFF) { 276 break; 277 } 278 } 279 nbytes = i; 280 if (i < ipbytes) { 281 unsigned int c = p[nbytes]; 282 while ((c & 0x80) != 0 && nbits < 8) { 283 c <<= 1; 284 nbits++; 285 } 286 if ((c & 0xFF) != 0) { 287 return (ISC_R_MASKNONCONTIG); 288 } 289 i++; 290 } 291 for (; i < ipbytes; i++) { 292 if (p[i] != 0) { 293 return (ISC_R_MASKNONCONTIG); 294 } 295 } 296 *lenp = nbytes * 8 + nbits; 297 return (ISC_R_SUCCESS); 298} 299 300void 301isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) { 302 memset(netaddr, 0, sizeof(*netaddr)); 303 netaddr->family = AF_INET; 304 netaddr->type.in = *ina; 305} 306 307void 308isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) { 309 memset(netaddr, 0, sizeof(*netaddr)); 310 netaddr->family = AF_INET6; 311 netaddr->type.in6 = *ina6; 312} 313 314isc_result_t 315isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) { 316 if (strlen(path) > sizeof(netaddr->type.un) - 1) { 317 return (ISC_R_NOSPACE); 318 } 319 320 memset(netaddr, 0, sizeof(*netaddr)); 321 netaddr->family = AF_UNIX; 322 strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un)); 323 netaddr->zone = 0; 324 return (ISC_R_SUCCESS); 325} 326 327void 328isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone) { 329 /* we currently only support AF_INET6. */ 330 REQUIRE(netaddr->family == AF_INET6); 331 332 netaddr->zone = zone; 333} 334 335uint32_t 336isc_netaddr_getzone(const isc_netaddr_t *netaddr) { 337 return (netaddr->zone); 338} 339 340void 341isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) { 342 int family = s->type.sa.sa_family; 343 t->family = family; 344 switch (family) { 345 case AF_INET: 346 t->type.in = s->type.sin.sin_addr; 347 t->zone = 0; 348 break; 349 case AF_INET6: 350 memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16); 351 t->zone = s->type.sin6.sin6_scope_id; 352 break; 353 case AF_UNIX: 354 memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un)); 355 t->zone = 0; 356 break; 357 default: 358 UNREACHABLE(); 359 } 360} 361 362void 363isc_netaddr_any(isc_netaddr_t *netaddr) { 364 memset(netaddr, 0, sizeof(*netaddr)); 365 netaddr->family = AF_INET; 366 netaddr->type.in.s_addr = INADDR_ANY; 367} 368 369void 370isc_netaddr_any6(isc_netaddr_t *netaddr) { 371 memset(netaddr, 0, sizeof(*netaddr)); 372 netaddr->family = AF_INET6; 373 netaddr->type.in6 = in6addr_any; 374} 375 376void 377isc_netaddr_unspec(isc_netaddr_t *netaddr) { 378 memset(netaddr, 0, sizeof(*netaddr)); 379 netaddr->family = AF_UNSPEC; 380} 381 382bool 383isc_netaddr_ismulticast(const isc_netaddr_t *na) { 384 switch (na->family) { 385 case AF_INET: 386 return (ISC_IPADDR_ISMULTICAST(na->type.in.s_addr)); 387 case AF_INET6: 388 return (IN6_IS_ADDR_MULTICAST(&na->type.in6)); 389 default: 390 return (false); /* XXXMLG ? */ 391 } 392} 393 394bool 395isc_netaddr_isexperimental(const isc_netaddr_t *na) { 396 switch (na->family) { 397 case AF_INET: 398 return (ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr)); 399 default: 400 return (false); /* XXXMLG ? */ 401 } 402} 403 404bool 405isc_netaddr_islinklocal(const isc_netaddr_t *na) { 406 switch (na->family) { 407 case AF_INET: 408 return (false); 409 case AF_INET6: 410 return (IN6_IS_ADDR_LINKLOCAL(&na->type.in6)); 411 default: 412 return (false); 413 } 414} 415 416bool 417isc_netaddr_issitelocal(const isc_netaddr_t *na) { 418 switch (na->family) { 419 case AF_INET: 420 return (false); 421 case AF_INET6: 422 return (IN6_IS_ADDR_SITELOCAL(&na->type.in6)); 423 default: 424 return (false); 425 } 426} 427 428#define ISC_IPADDR_ISNETZERO(i) \ 429 (((uint32_t)(i) & ISC__IPADDR(0xff000000)) == ISC__IPADDR(0x00000000)) 430 431bool 432isc_netaddr_isnetzero(const isc_netaddr_t *na) { 433 switch (na->family) { 434 case AF_INET: 435 return (ISC_IPADDR_ISNETZERO(na->type.in.s_addr)); 436 case AF_INET6: 437 return (false); 438 default: 439 return (false); 440 } 441} 442 443void 444isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) { 445 isc_netaddr_t *src; 446 447 DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */ 448 449 REQUIRE(s->family == AF_INET6); 450 REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6)); 451 452 memset(t, 0, sizeof(*t)); 453 t->family = AF_INET; 454 memmove(&t->type.in, (char *)&src->type.in6 + 12, 4); 455 return; 456} 457 458bool 459isc_netaddr_isloopback(const isc_netaddr_t *na) { 460 switch (na->family) { 461 case AF_INET: 462 return (((ntohl(na->type.in.s_addr) & 0xff000000U) == 463 0x7f000000U)); 464 case AF_INET6: 465 return (IN6_IS_ADDR_LOOPBACK(&na->type.in6)); 466 default: 467 return (false); 468 } 469} 470