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