1135446Strhodes/* 2262706Serwin * Copyright (C) 2004, 2005, 2007, 2010-2012, 2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2002 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id$ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdio.h> 25135446Strhodes 26135446Strhodes#include <isc/buffer.h> 27135446Strhodes#include <isc/msgs.h> 28135446Strhodes#include <isc/net.h> 29135446Strhodes#include <isc/netaddr.h> 30135446Strhodes#include <isc/print.h> 31135446Strhodes#include <isc/sockaddr.h> 32135446Strhodes#include <isc/string.h> 33135446Strhodes#include <isc/util.h> 34135446Strhodes 35135446Strhodesisc_boolean_t 36135446Strhodesisc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) { 37135446Strhodes REQUIRE(a != NULL && b != NULL); 38135446Strhodes 39135446Strhodes if (a->family != b->family) 40135446Strhodes return (ISC_FALSE); 41135446Strhodes 42135446Strhodes if (a->zone != b->zone) 43135446Strhodes return (ISC_FALSE); 44135446Strhodes 45135446Strhodes switch (a->family) { 46135446Strhodes case AF_INET: 47135446Strhodes if (a->type.in.s_addr != b->type.in.s_addr) 48135446Strhodes return (ISC_FALSE); 49135446Strhodes break; 50135446Strhodes case AF_INET6: 51135446Strhodes if (memcmp(&a->type.in6, &b->type.in6, 52135446Strhodes sizeof(a->type.in6)) != 0 || 53135446Strhodes a->zone != b->zone) 54135446Strhodes return (ISC_FALSE); 55135446Strhodes break; 56170222Sdougb#ifdef ISC_PLATFORM_HAVESYSUNH 57170222Sdougb case AF_UNIX: 58170222Sdougb if (strcmp(a->type.un, b->type.un) != 0) 59170222Sdougb return (ISC_FALSE); 60170222Sdougb break; 61170222Sdougb#endif 62135446Strhodes default: 63135446Strhodes return (ISC_FALSE); 64135446Strhodes } 65135446Strhodes return (ISC_TRUE); 66135446Strhodes} 67135446Strhodes 68135446Strhodesisc_boolean_t 69135446Strhodesisc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b, 70135446Strhodes unsigned int prefixlen) 71135446Strhodes{ 72225361Sdougb const unsigned char *pa = NULL, *pb = NULL; 73225361Sdougb unsigned int ipabytes = 0; /* Length of whole IP address in bytes */ 74225361Sdougb unsigned int nbytes; /* Number of significant whole bytes */ 75225361Sdougb unsigned int nbits; /* Number of significant leftover bits */ 76135446Strhodes 77135446Strhodes REQUIRE(a != NULL && b != NULL); 78135446Strhodes 79135446Strhodes if (a->family != b->family) 80135446Strhodes return (ISC_FALSE); 81135446Strhodes 82193149Sdougb if (a->zone != b->zone && b->zone != 0) 83135446Strhodes return (ISC_FALSE); 84135446Strhodes 85135446Strhodes switch (a->family) { 86135446Strhodes case AF_INET: 87135446Strhodes pa = (const unsigned char *) &a->type.in; 88135446Strhodes pb = (const unsigned char *) &b->type.in; 89135446Strhodes ipabytes = 4; 90135446Strhodes break; 91135446Strhodes case AF_INET6: 92135446Strhodes pa = (const unsigned char *) &a->type.in6; 93135446Strhodes pb = (const unsigned char *) &b->type.in6; 94135446Strhodes ipabytes = 16; 95135446Strhodes break; 96135446Strhodes default: 97135446Strhodes return (ISC_FALSE); 98135446Strhodes } 99135446Strhodes 100135446Strhodes /* 101135446Strhodes * Don't crash if we get a pattern like 10.0.0.1/9999999. 102135446Strhodes */ 103135446Strhodes if (prefixlen > ipabytes * 8) 104135446Strhodes prefixlen = ipabytes * 8; 105135446Strhodes 106135446Strhodes nbytes = prefixlen / 8; 107135446Strhodes nbits = prefixlen % 8; 108135446Strhodes 109135446Strhodes if (nbytes > 0) { 110135446Strhodes if (memcmp(pa, pb, nbytes) != 0) 111135446Strhodes return (ISC_FALSE); 112135446Strhodes } 113135446Strhodes if (nbits > 0) { 114135446Strhodes unsigned int bytea, byteb, mask; 115135446Strhodes INSIST(nbytes < ipabytes); 116135446Strhodes INSIST(nbits < 8); 117135446Strhodes bytea = pa[nbytes]; 118135446Strhodes byteb = pb[nbytes]; 119135446Strhodes mask = (0xFF << (8-nbits)) & 0xFF; 120135446Strhodes if ((bytea & mask) != (byteb & mask)) 121135446Strhodes return (ISC_FALSE); 122135446Strhodes } 123135446Strhodes return (ISC_TRUE); 124135446Strhodes} 125135446Strhodes 126135446Strhodesisc_result_t 127135446Strhodesisc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) { 128135446Strhodes char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; 129135446Strhodes char zbuf[sizeof("%4294967295")]; 130135446Strhodes unsigned int alen; 131135446Strhodes int zlen; 132135446Strhodes const char *r; 133135446Strhodes const void *type; 134135446Strhodes 135135446Strhodes REQUIRE(netaddr != NULL); 136135446Strhodes 137135446Strhodes switch (netaddr->family) { 138135446Strhodes case AF_INET: 139135446Strhodes type = &netaddr->type.in; 140135446Strhodes break; 141135446Strhodes case AF_INET6: 142135446Strhodes type = &netaddr->type.in6; 143135446Strhodes break; 144170222Sdougb#ifdef ISC_PLATFORM_HAVESYSUNH 145170222Sdougb case AF_UNIX: 146170222Sdougb alen = strlen(netaddr->type.un); 147170222Sdougb if (alen > isc_buffer_availablelength(target)) 148170222Sdougb return (ISC_R_NOSPACE); 149170222Sdougb isc_buffer_putmem(target, 150170222Sdougb (const unsigned char *)(netaddr->type.un), 151170222Sdougb alen); 152170222Sdougb return (ISC_R_SUCCESS); 153170222Sdougb#endif 154135446Strhodes default: 155135446Strhodes return (ISC_R_FAILURE); 156135446Strhodes } 157135446Strhodes r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf)); 158135446Strhodes if (r == NULL) 159135446Strhodes return (ISC_R_FAILURE); 160135446Strhodes 161135446Strhodes alen = strlen(abuf); 162135446Strhodes INSIST(alen < sizeof(abuf)); 163135446Strhodes 164135446Strhodes zlen = 0; 165135446Strhodes if (netaddr->family == AF_INET6 && netaddr->zone != 0) { 166135446Strhodes zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone); 167135446Strhodes if (zlen < 0) 168135446Strhodes return (ISC_R_FAILURE); 169135446Strhodes INSIST((unsigned int)zlen < sizeof(zbuf)); 170135446Strhodes } 171135446Strhodes 172135446Strhodes if (alen + zlen > isc_buffer_availablelength(target)) 173135446Strhodes return (ISC_R_NOSPACE); 174135446Strhodes 175135446Strhodes isc_buffer_putmem(target, (unsigned char *)abuf, alen); 176135446Strhodes isc_buffer_putmem(target, (unsigned char *)zbuf, zlen); 177135446Strhodes 178135446Strhodes return (ISC_R_SUCCESS); 179135446Strhodes} 180135446Strhodes 181135446Strhodesvoid 182135446Strhodesisc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) { 183135446Strhodes isc_result_t result; 184135446Strhodes isc_buffer_t buf; 185135446Strhodes 186135446Strhodes isc_buffer_init(&buf, array, size); 187135446Strhodes result = isc_netaddr_totext(na, &buf); 188135446Strhodes 189225361Sdougb if (size == 0) 190225361Sdougb return; 191225361Sdougb 192135446Strhodes /* 193135446Strhodes * Null terminate. 194135446Strhodes */ 195135446Strhodes if (result == ISC_R_SUCCESS) { 196135446Strhodes if (isc_buffer_availablelength(&buf) >= 1) 197135446Strhodes isc_buffer_putuint8(&buf, 0); 198135446Strhodes else 199135446Strhodes result = ISC_R_NOSPACE; 200135446Strhodes } 201135446Strhodes 202135446Strhodes if (result != ISC_R_SUCCESS) { 203135446Strhodes snprintf(array, size, 204135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR, 205135446Strhodes ISC_MSG_UNKNOWNADDR, 206135446Strhodes "<unknown address, family %u>"), 207135446Strhodes na->family); 208135446Strhodes array[size - 1] = '\0'; 209135446Strhodes } 210135446Strhodes} 211135446Strhodes 212170222Sdougb 213135446Strhodesisc_result_t 214170222Sdougbisc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { 215170222Sdougb static const unsigned char zeros[16]; 216225361Sdougb unsigned int nbits, nbytes, ipbytes = 0; 217170222Sdougb const unsigned char *p; 218170222Sdougb 219170222Sdougb switch (na->family) { 220170222Sdougb case AF_INET: 221170222Sdougb p = (const unsigned char *) &na->type.in; 222170222Sdougb ipbytes = 4; 223170222Sdougb if (prefixlen > 32) 224170222Sdougb return (ISC_R_RANGE); 225170222Sdougb break; 226170222Sdougb case AF_INET6: 227170222Sdougb p = (const unsigned char *) &na->type.in6; 228170222Sdougb ipbytes = 16; 229170222Sdougb if (prefixlen > 128) 230170222Sdougb return (ISC_R_RANGE); 231170222Sdougb break; 232170222Sdougb default: 233170222Sdougb return (ISC_R_NOTIMPLEMENTED); 234170222Sdougb } 235170222Sdougb nbytes = prefixlen / 8; 236170222Sdougb nbits = prefixlen % 8; 237170222Sdougb if (nbits != 0) { 238170222Sdougb if ((p[nbytes] & (0xff>>nbits)) != 0U) 239170222Sdougb return (ISC_R_FAILURE); 240170222Sdougb nbytes++; 241170222Sdougb } 242170222Sdougb if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) 243170222Sdougb return (ISC_R_FAILURE); 244170222Sdougb return (ISC_R_SUCCESS); 245170222Sdougb} 246170222Sdougb 247170222Sdougbisc_result_t 248135446Strhodesisc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) { 249225361Sdougb unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i; 250135446Strhodes const unsigned char *p; 251135446Strhodes 252135446Strhodes switch (s->family) { 253135446Strhodes case AF_INET: 254135446Strhodes p = (const unsigned char *) &s->type.in; 255135446Strhodes ipbytes = 4; 256135446Strhodes break; 257135446Strhodes case AF_INET6: 258135446Strhodes p = (const unsigned char *) &s->type.in6; 259135446Strhodes ipbytes = 16; 260135446Strhodes break; 261135446Strhodes default: 262135446Strhodes return (ISC_R_NOTIMPLEMENTED); 263135446Strhodes } 264135446Strhodes for (i = 0; i < ipbytes; i++) { 265135446Strhodes if (p[i] != 0xFF) 266135446Strhodes break; 267135446Strhodes } 268135446Strhodes nbytes = i; 269135446Strhodes if (i < ipbytes) { 270135446Strhodes unsigned int c = p[nbytes]; 271135446Strhodes while ((c & 0x80) != 0 && nbits < 8) { 272135446Strhodes c <<= 1; nbits++; 273135446Strhodes } 274135446Strhodes if ((c & 0xFF) != 0) 275135446Strhodes return (ISC_R_MASKNONCONTIG); 276135446Strhodes i++; 277135446Strhodes } 278135446Strhodes for (; i < ipbytes; i++) { 279135446Strhodes if (p[i] != 0) 280135446Strhodes return (ISC_R_MASKNONCONTIG); 281135446Strhodes i++; 282135446Strhodes } 283135446Strhodes *lenp = nbytes * 8 + nbits; 284135446Strhodes return (ISC_R_SUCCESS); 285135446Strhodes} 286135446Strhodes 287135446Strhodesvoid 288135446Strhodesisc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) { 289135446Strhodes memset(netaddr, 0, sizeof(*netaddr)); 290135446Strhodes netaddr->family = AF_INET; 291135446Strhodes netaddr->type.in = *ina; 292135446Strhodes} 293135446Strhodes 294135446Strhodesvoid 295135446Strhodesisc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) { 296135446Strhodes memset(netaddr, 0, sizeof(*netaddr)); 297135446Strhodes netaddr->family = AF_INET6; 298135446Strhodes netaddr->type.in6 = *ina6; 299135446Strhodes} 300135446Strhodes 301170222Sdougbisc_result_t 302170222Sdougbisc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) { 303170222Sdougb#ifdef ISC_PLATFORM_HAVESYSUNH 304224092Sdougb if (strlen(path) > sizeof(netaddr->type.un) - 1) 305224092Sdougb return (ISC_R_NOSPACE); 306170222Sdougb 307224092Sdougb memset(netaddr, 0, sizeof(*netaddr)); 308224092Sdougb netaddr->family = AF_UNIX; 309224092Sdougb strcpy(netaddr->type.un, path); 310224092Sdougb netaddr->zone = 0; 311224092Sdougb return (ISC_R_SUCCESS); 312224092Sdougb#else 313170222Sdougb UNUSED(netaddr); 314170222Sdougb UNUSED(path); 315224092Sdougb return (ISC_R_NOTIMPLEMENTED); 316170222Sdougb#endif 317170222Sdougb} 318170222Sdougb 319170222Sdougb 320135446Strhodesvoid 321135446Strhodesisc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) { 322135446Strhodes /* we currently only support AF_INET6. */ 323135446Strhodes REQUIRE(netaddr->family == AF_INET6); 324135446Strhodes 325135446Strhodes netaddr->zone = zone; 326135446Strhodes} 327135446Strhodes 328135446Strhodesisc_uint32_t 329135446Strhodesisc_netaddr_getzone(const isc_netaddr_t *netaddr) { 330135446Strhodes return (netaddr->zone); 331135446Strhodes} 332135446Strhodes 333135446Strhodesvoid 334135446Strhodesisc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) { 335135446Strhodes int family = s->type.sa.sa_family; 336135446Strhodes t->family = family; 337135446Strhodes switch (family) { 338135446Strhodes case AF_INET: 339135446Strhodes t->type.in = s->type.sin.sin_addr; 340135446Strhodes t->zone = 0; 341135446Strhodes break; 342135446Strhodes case AF_INET6: 343262706Serwin memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16); 344135446Strhodes#ifdef ISC_PLATFORM_HAVESCOPEID 345135446Strhodes t->zone = s->type.sin6.sin6_scope_id; 346135446Strhodes#else 347135446Strhodes t->zone = 0; 348135446Strhodes#endif 349135446Strhodes break; 350170222Sdougb#ifdef ISC_PLATFORM_HAVESYSUNH 351170222Sdougb case AF_UNIX: 352262706Serwin memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un)); 353170222Sdougb t->zone = 0; 354170222Sdougb break; 355170222Sdougb#endif 356135446Strhodes default: 357135446Strhodes INSIST(0); 358135446Strhodes } 359135446Strhodes} 360135446Strhodes 361135446Strhodesvoid 362135446Strhodesisc_netaddr_any(isc_netaddr_t *netaddr) { 363135446Strhodes memset(netaddr, 0, sizeof(*netaddr)); 364135446Strhodes netaddr->family = AF_INET; 365135446Strhodes netaddr->type.in.s_addr = INADDR_ANY; 366135446Strhodes} 367135446Strhodes 368135446Strhodesvoid 369135446Strhodesisc_netaddr_any6(isc_netaddr_t *netaddr) { 370135446Strhodes memset(netaddr, 0, sizeof(*netaddr)); 371135446Strhodes netaddr->family = AF_INET6; 372135446Strhodes netaddr->type.in6 = in6addr_any; 373135446Strhodes} 374135446Strhodes 375135446Strhodesisc_boolean_t 376135446Strhodesisc_netaddr_ismulticast(isc_netaddr_t *na) { 377135446Strhodes switch (na->family) { 378135446Strhodes case AF_INET: 379135446Strhodes return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr))); 380135446Strhodes case AF_INET6: 381135446Strhodes return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6))); 382135446Strhodes default: 383135446Strhodes return (ISC_FALSE); /* XXXMLG ? */ 384135446Strhodes } 385135446Strhodes} 386135446Strhodes 387135446Strhodesisc_boolean_t 388135446Strhodesisc_netaddr_isexperimental(isc_netaddr_t *na) { 389135446Strhodes switch (na->family) { 390135446Strhodes case AF_INET: 391135446Strhodes return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr))); 392135446Strhodes default: 393135446Strhodes return (ISC_FALSE); /* XXXMLG ? */ 394135446Strhodes } 395135446Strhodes} 396135446Strhodes 397135446Strhodesisc_boolean_t 398135446Strhodesisc_netaddr_islinklocal(isc_netaddr_t *na) { 399135446Strhodes switch (na->family) { 400135446Strhodes case AF_INET: 401135446Strhodes return (ISC_FALSE); 402135446Strhodes case AF_INET6: 403135446Strhodes return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6))); 404135446Strhodes default: 405135446Strhodes return (ISC_FALSE); 406135446Strhodes } 407135446Strhodes} 408135446Strhodes 409135446Strhodesisc_boolean_t 410135446Strhodesisc_netaddr_issitelocal(isc_netaddr_t *na) { 411135446Strhodes switch (na->family) { 412135446Strhodes case AF_INET: 413135446Strhodes return (ISC_FALSE); 414135446Strhodes case AF_INET6: 415135446Strhodes return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6))); 416135446Strhodes default: 417135446Strhodes return (ISC_FALSE); 418135446Strhodes } 419135446Strhodes} 420135446Strhodes 421135446Strhodesvoid 422135446Strhodesisc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) { 423135446Strhodes isc_netaddr_t *src; 424135446Strhodes 425135446Strhodes DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */ 426135446Strhodes 427135446Strhodes REQUIRE(s->family == AF_INET6); 428135446Strhodes REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6)); 429135446Strhodes 430135446Strhodes memset(t, 0, sizeof(*t)); 431135446Strhodes t->family = AF_INET; 432262706Serwin memmove(&t->type.in, (char *)&src->type.in6 + 12, 4); 433135446Strhodes return; 434135446Strhodes} 435