1*eabc0478Schristos /* $NetBSD: netaddr.c,v 1.2 2024/08/18 20:47:14 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos /* 4897be3a4Schristos * Copyright (C) 2004, 2005, 2007, 2010-2012 Internet Systems Consortium, Inc. ("ISC") 5897be3a4Schristos * Copyright (C) 1999-2002 Internet Software Consortium. 6897be3a4Schristos * 7897be3a4Schristos * Permission to use, copy, modify, and/or distribute this software for any 8897be3a4Schristos * purpose with or without fee is hereby granted, provided that the above 9897be3a4Schristos * copyright notice and this permission notice appear in all copies. 10897be3a4Schristos * 11897be3a4Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12897be3a4Schristos * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13897be3a4Schristos * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14897be3a4Schristos * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15897be3a4Schristos * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16897be3a4Schristos * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17897be3a4Schristos * PERFORMANCE OF THIS SOFTWARE. 18897be3a4Schristos */ 19897be3a4Schristos 20897be3a4Schristos /* Id */ 21897be3a4Schristos 22897be3a4Schristos /*! \file */ 23897be3a4Schristos 24897be3a4Schristos #include <config.h> 25897be3a4Schristos 26897be3a4Schristos #include <stdio.h> 27897be3a4Schristos 28897be3a4Schristos #include <isc/buffer.h> 29897be3a4Schristos #include <isc/msgs.h> 30897be3a4Schristos #include <isc/net.h> 31897be3a4Schristos #include <isc/netaddr.h> 32897be3a4Schristos #include <isc/print.h> 33897be3a4Schristos #include <isc/sockaddr.h> 34897be3a4Schristos #include <isc/string.h> 35897be3a4Schristos #include <isc/util.h> 36897be3a4Schristos #include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ 37897be3a4Schristos 38897be3a4Schristos isc_boolean_t 39897be3a4Schristos isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) { 40897be3a4Schristos REQUIRE(a != NULL && b != NULL); 41897be3a4Schristos 42897be3a4Schristos if (a->family != b->family) 43897be3a4Schristos return (ISC_FALSE); 44897be3a4Schristos 45897be3a4Schristos if (a->zone != b->zone) 46897be3a4Schristos return (ISC_FALSE); 47897be3a4Schristos 48897be3a4Schristos switch (a->family) { 49897be3a4Schristos case AF_INET: 50897be3a4Schristos if (a->type.in.s_addr != b->type.in.s_addr) 51897be3a4Schristos return (ISC_FALSE); 52897be3a4Schristos break; 53897be3a4Schristos case AF_INET6: 54897be3a4Schristos if (memcmp(&a->type.in6, &b->type.in6, 55897be3a4Schristos sizeof(a->type.in6)) != 0 || 56897be3a4Schristos a->zone != b->zone) 57897be3a4Schristos return (ISC_FALSE); 58897be3a4Schristos break; 59897be3a4Schristos #ifdef ISC_PLATFORM_HAVESYSUNH 60897be3a4Schristos case AF_UNIX: 61897be3a4Schristos if (strcmp(a->type.un, b->type.un) != 0) 62897be3a4Schristos return (ISC_FALSE); 63897be3a4Schristos break; 64897be3a4Schristos #endif 65897be3a4Schristos default: 66897be3a4Schristos return (ISC_FALSE); 67897be3a4Schristos } 68897be3a4Schristos return (ISC_TRUE); 69897be3a4Schristos } 70897be3a4Schristos 71897be3a4Schristos isc_boolean_t 72897be3a4Schristos isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b, 73897be3a4Schristos unsigned int prefixlen) 74897be3a4Schristos { 75897be3a4Schristos const unsigned char *pa = NULL, *pb = NULL; 76897be3a4Schristos unsigned int ipabytes = 0; /* Length of whole IP address in bytes */ 77897be3a4Schristos unsigned int nbytes; /* Number of significant whole bytes */ 78897be3a4Schristos unsigned int nbits; /* Number of significant leftover bits */ 79897be3a4Schristos 80897be3a4Schristos REQUIRE(a != NULL && b != NULL); 81897be3a4Schristos 82897be3a4Schristos if (a->family != b->family) 83897be3a4Schristos return (ISC_FALSE); 84897be3a4Schristos 85897be3a4Schristos if (a->zone != b->zone && b->zone != 0) 86897be3a4Schristos return (ISC_FALSE); 87897be3a4Schristos 88897be3a4Schristos switch (a->family) { 89897be3a4Schristos case AF_INET: 90897be3a4Schristos pa = (const unsigned char *) &a->type.in; 91897be3a4Schristos pb = (const unsigned char *) &b->type.in; 92897be3a4Schristos ipabytes = 4; 93897be3a4Schristos break; 94897be3a4Schristos case AF_INET6: 95897be3a4Schristos pa = (const unsigned char *) &a->type.in6; 96897be3a4Schristos pb = (const unsigned char *) &b->type.in6; 97897be3a4Schristos ipabytes = 16; 98897be3a4Schristos break; 99897be3a4Schristos default: 100897be3a4Schristos return (ISC_FALSE); 101897be3a4Schristos } 102897be3a4Schristos 103897be3a4Schristos /* 104897be3a4Schristos * Don't crash if we get a pattern like 10.0.0.1/9999999. 105897be3a4Schristos */ 106897be3a4Schristos if (prefixlen > ipabytes * 8) 107897be3a4Schristos prefixlen = ipabytes * 8; 108897be3a4Schristos 109897be3a4Schristos nbytes = prefixlen / 8; 110897be3a4Schristos nbits = prefixlen % 8; 111897be3a4Schristos 112897be3a4Schristos if (nbytes > 0) { 113897be3a4Schristos if (memcmp(pa, pb, nbytes) != 0) 114897be3a4Schristos return (ISC_FALSE); 115897be3a4Schristos } 116897be3a4Schristos if (nbits > 0) { 117897be3a4Schristos unsigned int bytea, byteb, mask; 118897be3a4Schristos INSIST(nbytes < ipabytes); 119897be3a4Schristos INSIST(nbits < 8); 120897be3a4Schristos bytea = pa[nbytes]; 121897be3a4Schristos byteb = pb[nbytes]; 122897be3a4Schristos mask = (0xFF << (8-nbits)) & 0xFF; 123897be3a4Schristos if ((bytea & mask) != (byteb & mask)) 124897be3a4Schristos return (ISC_FALSE); 125897be3a4Schristos } 126897be3a4Schristos return (ISC_TRUE); 127897be3a4Schristos } 128897be3a4Schristos 129897be3a4Schristos isc_result_t 130897be3a4Schristos isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) { 131897be3a4Schristos char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; 132897be3a4Schristos char zbuf[sizeof("%4294967295")]; 133897be3a4Schristos unsigned int alen; 134897be3a4Schristos int zlen; 135897be3a4Schristos const char *r; 136897be3a4Schristos const void *type; 137897be3a4Schristos 138897be3a4Schristos REQUIRE(netaddr != NULL); 139897be3a4Schristos 140897be3a4Schristos switch (netaddr->family) { 141897be3a4Schristos case AF_INET: 142897be3a4Schristos type = &netaddr->type.in; 143897be3a4Schristos break; 144897be3a4Schristos case AF_INET6: 145897be3a4Schristos type = &netaddr->type.in6; 146897be3a4Schristos break; 147897be3a4Schristos #ifdef ISC_PLATFORM_HAVESYSUNH 148897be3a4Schristos case AF_UNIX: 149897be3a4Schristos alen = strlen(netaddr->type.un); 150897be3a4Schristos if (alen > isc_buffer_availablelength(target)) 151897be3a4Schristos return (ISC_R_NOSPACE); 152897be3a4Schristos isc_buffer_putmem(target, 153897be3a4Schristos (const unsigned char *)(netaddr->type.un), 154897be3a4Schristos alen); 155897be3a4Schristos return (ISC_R_SUCCESS); 156897be3a4Schristos #endif 157897be3a4Schristos default: 158897be3a4Schristos return (ISC_R_FAILURE); 159897be3a4Schristos } 160897be3a4Schristos r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf)); 161897be3a4Schristos if (r == NULL) 162897be3a4Schristos return (ISC_R_FAILURE); 163897be3a4Schristos 164897be3a4Schristos alen = (unsigned int)strlen(abuf); /* no overflow possible */ 165897be3a4Schristos INSIST(alen < sizeof(abuf)); 166897be3a4Schristos 167897be3a4Schristos zlen = 0; 168897be3a4Schristos if (netaddr->family == AF_INET6 && netaddr->zone != 0) { 169897be3a4Schristos zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone); 170897be3a4Schristos if (zlen < 0) 171897be3a4Schristos return (ISC_R_FAILURE); 172897be3a4Schristos INSIST((unsigned int)zlen < sizeof(zbuf)); 173897be3a4Schristos } 174897be3a4Schristos 175897be3a4Schristos if (alen + zlen > isc_buffer_availablelength(target)) 176897be3a4Schristos return (ISC_R_NOSPACE); 177897be3a4Schristos 178897be3a4Schristos isc_buffer_putmem(target, (unsigned char *)abuf, alen); 179897be3a4Schristos isc_buffer_putmem(target, (unsigned char *)zbuf, zlen); 180897be3a4Schristos 181897be3a4Schristos return (ISC_R_SUCCESS); 182897be3a4Schristos } 183897be3a4Schristos 184897be3a4Schristos void 185897be3a4Schristos isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) { 186897be3a4Schristos isc_result_t result; 187897be3a4Schristos isc_buffer_t buf; 188897be3a4Schristos 189897be3a4Schristos isc_buffer_init(&buf, array, size); 190897be3a4Schristos result = isc_netaddr_totext(na, &buf); 191897be3a4Schristos 192897be3a4Schristos if (size == 0) 193897be3a4Schristos return; 194897be3a4Schristos 195897be3a4Schristos /* 196897be3a4Schristos * Null terminate. 197897be3a4Schristos */ 198897be3a4Schristos if (result == ISC_R_SUCCESS) { 199897be3a4Schristos if (isc_buffer_availablelength(&buf) >= 1) 200897be3a4Schristos isc_buffer_putuint8(&buf, 0); 201897be3a4Schristos else 202897be3a4Schristos result = ISC_R_NOSPACE; 203897be3a4Schristos } 204897be3a4Schristos 205897be3a4Schristos if (result != ISC_R_SUCCESS) { 206897be3a4Schristos snprintf(array, size, 207897be3a4Schristos "<%s %u>", 208897be3a4Schristos isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR, 209897be3a4Schristos ISC_MSG_UNKNOWNADDR, 210897be3a4Schristos "unknown address, family"), 211897be3a4Schristos na->family); 212897be3a4Schristos array[size - 1] = '\0'; 213897be3a4Schristos } 214897be3a4Schristos } 215897be3a4Schristos 216897be3a4Schristos 217897be3a4Schristos isc_result_t 218897be3a4Schristos isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { 219897be3a4Schristos static const unsigned char zeros[16] = { 0 }; 220897be3a4Schristos unsigned int nbits, nbytes, ipbytes = 0; 221897be3a4Schristos const unsigned char *p; 222897be3a4Schristos 223897be3a4Schristos switch (na->family) { 224897be3a4Schristos case AF_INET: 225897be3a4Schristos p = (const unsigned char *) &na->type.in; 226897be3a4Schristos ipbytes = 4; 227897be3a4Schristos if (prefixlen > 32) 228897be3a4Schristos return (ISC_R_RANGE); 229897be3a4Schristos break; 230897be3a4Schristos case AF_INET6: 231897be3a4Schristos p = (const unsigned char *) &na->type.in6; 232897be3a4Schristos ipbytes = 16; 233897be3a4Schristos if (prefixlen > 128) 234897be3a4Schristos return (ISC_R_RANGE); 235897be3a4Schristos break; 236897be3a4Schristos default: 237897be3a4Schristos return (ISC_R_NOTIMPLEMENTED); 238897be3a4Schristos } 239897be3a4Schristos nbytes = prefixlen / 8; 240897be3a4Schristos nbits = prefixlen % 8; 241897be3a4Schristos if (nbits != 0) { 242897be3a4Schristos if ((p[nbytes] & (0xff>>nbits)) != 0U) 243897be3a4Schristos return (ISC_R_FAILURE); 244897be3a4Schristos nbytes++; 245897be3a4Schristos } 246897be3a4Schristos if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) 247897be3a4Schristos return (ISC_R_FAILURE); 248897be3a4Schristos return (ISC_R_SUCCESS); 249897be3a4Schristos } 250897be3a4Schristos 251897be3a4Schristos isc_result_t 252897be3a4Schristos isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) { 253897be3a4Schristos unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i; 254897be3a4Schristos const unsigned char *p; 255897be3a4Schristos 256897be3a4Schristos switch (s->family) { 257897be3a4Schristos case AF_INET: 258897be3a4Schristos p = (const unsigned char *) &s->type.in; 259897be3a4Schristos ipbytes = 4; 260897be3a4Schristos break; 261897be3a4Schristos case AF_INET6: 262897be3a4Schristos p = (const unsigned char *) &s->type.in6; 263897be3a4Schristos ipbytes = 16; 264897be3a4Schristos break; 265897be3a4Schristos default: 266897be3a4Schristos return (ISC_R_NOTIMPLEMENTED); 267897be3a4Schristos } 268897be3a4Schristos for (i = 0; i < ipbytes; i++) { 269897be3a4Schristos if (p[i] != 0xFF) 270897be3a4Schristos break; 271897be3a4Schristos } 272897be3a4Schristos nbytes = i; 273897be3a4Schristos if (i < ipbytes) { 274897be3a4Schristos unsigned int c = p[nbytes]; 275897be3a4Schristos while ((c & 0x80) != 0 && nbits < 8) { 276897be3a4Schristos c <<= 1; nbits++; 277897be3a4Schristos } 278897be3a4Schristos if ((c & 0xFF) != 0) 279897be3a4Schristos return (ISC_R_MASKNONCONTIG); 280897be3a4Schristos i++; 281897be3a4Schristos } 282897be3a4Schristos for (; i < ipbytes; i++) { 283897be3a4Schristos if (p[i] != 0) 284897be3a4Schristos return (ISC_R_MASKNONCONTIG); 285897be3a4Schristos } 286897be3a4Schristos *lenp = nbytes * 8 + nbits; 287897be3a4Schristos return (ISC_R_SUCCESS); 288897be3a4Schristos } 289897be3a4Schristos 290897be3a4Schristos void 291897be3a4Schristos isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) { 292897be3a4Schristos memset(netaddr, 0, sizeof(*netaddr)); 293897be3a4Schristos netaddr->family = AF_INET; 294897be3a4Schristos netaddr->type.in = *ina; 295897be3a4Schristos } 296897be3a4Schristos 297897be3a4Schristos void 298897be3a4Schristos isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) { 299897be3a4Schristos memset(netaddr, 0, sizeof(*netaddr)); 300897be3a4Schristos netaddr->family = AF_INET6; 301897be3a4Schristos netaddr->type.in6 = *ina6; 302897be3a4Schristos } 303897be3a4Schristos 304897be3a4Schristos isc_result_t 305897be3a4Schristos isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) { 306897be3a4Schristos #ifdef ISC_PLATFORM_HAVESYSUNH 307897be3a4Schristos if (strlen(path) > sizeof(netaddr->type.un) - 1) 308897be3a4Schristos return (ISC_R_NOSPACE); 309897be3a4Schristos 310897be3a4Schristos memset(netaddr, 0, sizeof(*netaddr)); 311897be3a4Schristos netaddr->family = AF_UNIX; 312897be3a4Schristos strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un)); 313897be3a4Schristos netaddr->zone = 0; 314897be3a4Schristos return (ISC_R_SUCCESS); 315897be3a4Schristos #else 316897be3a4Schristos UNUSED(netaddr); 317897be3a4Schristos UNUSED(path); 318897be3a4Schristos return (ISC_R_NOTIMPLEMENTED); 319897be3a4Schristos #endif 320897be3a4Schristos } 321897be3a4Schristos 322897be3a4Schristos 323897be3a4Schristos void 324897be3a4Schristos isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) { 325897be3a4Schristos /* we currently only support AF_INET6. */ 326897be3a4Schristos REQUIRE(netaddr->family == AF_INET6); 327897be3a4Schristos 328897be3a4Schristos netaddr->zone = zone; 329897be3a4Schristos } 330897be3a4Schristos 331897be3a4Schristos isc_uint32_t 332897be3a4Schristos isc_netaddr_getzone(const isc_netaddr_t *netaddr) { 333897be3a4Schristos return (netaddr->zone); 334897be3a4Schristos } 335897be3a4Schristos 336897be3a4Schristos void 337897be3a4Schristos isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) { 338897be3a4Schristos int family = s->type.sa.sa_family; 339897be3a4Schristos t->family = family; 340897be3a4Schristos switch (family) { 341897be3a4Schristos case AF_INET: 342897be3a4Schristos t->type.in = s->type.sin.sin_addr; 343897be3a4Schristos t->zone = 0; 344897be3a4Schristos break; 345897be3a4Schristos case AF_INET6: 346897be3a4Schristos memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16); 347897be3a4Schristos #ifdef ISC_PLATFORM_HAVESCOPEID 348897be3a4Schristos t->zone = s->type.sin6.sin6_scope_id; 349897be3a4Schristos #else 350897be3a4Schristos t->zone = 0; 351897be3a4Schristos #endif 352897be3a4Schristos break; 353897be3a4Schristos #ifdef ISC_PLATFORM_HAVESYSUNH 354897be3a4Schristos case AF_UNIX: 355897be3a4Schristos memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un)); 356897be3a4Schristos t->zone = 0; 357897be3a4Schristos break; 358897be3a4Schristos #endif 359897be3a4Schristos default: 360897be3a4Schristos INSIST(0); 361897be3a4Schristos } 362897be3a4Schristos } 363897be3a4Schristos 364897be3a4Schristos void 365897be3a4Schristos isc_netaddr_any(isc_netaddr_t *netaddr) { 366897be3a4Schristos memset(netaddr, 0, sizeof(*netaddr)); 367897be3a4Schristos netaddr->family = AF_INET; 368897be3a4Schristos netaddr->type.in.s_addr = INADDR_ANY; 369897be3a4Schristos } 370897be3a4Schristos 371897be3a4Schristos void 372897be3a4Schristos isc_netaddr_any6(isc_netaddr_t *netaddr) { 373897be3a4Schristos memset(netaddr, 0, sizeof(*netaddr)); 374897be3a4Schristos netaddr->family = AF_INET6; 375897be3a4Schristos netaddr->type.in6 = in6addr_any; 376897be3a4Schristos } 377897be3a4Schristos 378897be3a4Schristos isc_boolean_t 379897be3a4Schristos isc_netaddr_ismulticast(isc_netaddr_t *na) { 380897be3a4Schristos switch (na->family) { 381897be3a4Schristos case AF_INET: 382897be3a4Schristos return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr))); 383897be3a4Schristos case AF_INET6: 384897be3a4Schristos return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6))); 385897be3a4Schristos default: 386897be3a4Schristos return (ISC_FALSE); /* XXXMLG ? */ 387897be3a4Schristos } 388897be3a4Schristos } 389897be3a4Schristos 390897be3a4Schristos isc_boolean_t 391897be3a4Schristos isc_netaddr_isexperimental(isc_netaddr_t *na) { 392897be3a4Schristos switch (na->family) { 393897be3a4Schristos case AF_INET: 394897be3a4Schristos return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr))); 395897be3a4Schristos default: 396897be3a4Schristos return (ISC_FALSE); /* XXXMLG ? */ 397897be3a4Schristos } 398897be3a4Schristos } 399897be3a4Schristos 400897be3a4Schristos isc_boolean_t 401897be3a4Schristos isc_netaddr_islinklocal(isc_netaddr_t *na) { 402897be3a4Schristos switch (na->family) { 403897be3a4Schristos case AF_INET: 404897be3a4Schristos return (ISC_FALSE); 405897be3a4Schristos case AF_INET6: 406897be3a4Schristos return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6))); 407897be3a4Schristos default: 408897be3a4Schristos return (ISC_FALSE); 409897be3a4Schristos } 410897be3a4Schristos } 411897be3a4Schristos 412897be3a4Schristos isc_boolean_t 413897be3a4Schristos isc_netaddr_issitelocal(isc_netaddr_t *na) { 414897be3a4Schristos switch (na->family) { 415897be3a4Schristos case AF_INET: 416897be3a4Schristos return (ISC_FALSE); 417897be3a4Schristos case AF_INET6: 418897be3a4Schristos return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6))); 419897be3a4Schristos default: 420897be3a4Schristos return (ISC_FALSE); 421897be3a4Schristos } 422897be3a4Schristos } 423897be3a4Schristos 424897be3a4Schristos void 425897be3a4Schristos isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) { 426897be3a4Schristos isc_netaddr_t *src; 427897be3a4Schristos 428897be3a4Schristos DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */ 429897be3a4Schristos 430897be3a4Schristos REQUIRE(s->family == AF_INET6); 431897be3a4Schristos REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6)); 432897be3a4Schristos 433897be3a4Schristos memset(t, 0, sizeof(*t)); 434897be3a4Schristos t->family = AF_INET; 435897be3a4Schristos memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4); 436897be3a4Schristos return; 437897be3a4Schristos } 438