1 /* $NetBSD: netaddr.c,v 1.6 2014/12/10 04:37:59 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2010-2012, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2002 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <stdio.h> 27 28 #include <isc/buffer.h> 29 #include <isc/msgs.h> 30 #include <isc/net.h> 31 #include <isc/netaddr.h> 32 #include <isc/print.h> 33 #include <isc/sockaddr.h> 34 #include <isc/string.h> 35 #include <isc/util.h> 36 37 isc_boolean_t 38 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) { 39 REQUIRE(a != NULL && b != NULL); 40 41 if (a->family != b->family) 42 return (ISC_FALSE); 43 44 if (a->zone != b->zone) 45 return (ISC_FALSE); 46 47 switch (a->family) { 48 case AF_INET: 49 if (a->type.in.s_addr != b->type.in.s_addr) 50 return (ISC_FALSE); 51 break; 52 case AF_INET6: 53 if (memcmp(&a->type.in6, &b->type.in6, 54 sizeof(a->type.in6)) != 0 || 55 a->zone != b->zone) 56 return (ISC_FALSE); 57 break; 58 #ifdef ISC_PLATFORM_HAVESYSUNH 59 case AF_UNIX: 60 if (strcmp(a->type.un, b->type.un) != 0) 61 return (ISC_FALSE); 62 break; 63 #endif 64 default: 65 return (ISC_FALSE); 66 } 67 return (ISC_TRUE); 68 } 69 70 isc_boolean_t 71 isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b, 72 unsigned int prefixlen) 73 { 74 const unsigned char *pa = NULL, *pb = NULL; 75 unsigned int ipabytes = 0; /* Length of whole IP address in bytes */ 76 unsigned int nbytes; /* Number of significant whole bytes */ 77 unsigned int nbits; /* Number of significant leftover bits */ 78 79 REQUIRE(a != NULL && b != NULL); 80 81 if (a->family != b->family) 82 return (ISC_FALSE); 83 84 if (a->zone != b->zone && b->zone != 0) 85 return (ISC_FALSE); 86 87 switch (a->family) { 88 case AF_INET: 89 pa = (const unsigned char *) &a->type.in; 90 pb = (const unsigned char *) &b->type.in; 91 ipabytes = 4; 92 break; 93 case AF_INET6: 94 pa = (const unsigned char *) &a->type.in6; 95 pb = (const unsigned char *) &b->type.in6; 96 ipabytes = 16; 97 break; 98 default: 99 return (ISC_FALSE); 100 } 101 102 /* 103 * Don't crash if we get a pattern like 10.0.0.1/9999999. 104 */ 105 if (prefixlen > ipabytes * 8) 106 prefixlen = ipabytes * 8; 107 108 nbytes = prefixlen / 8; 109 nbits = prefixlen % 8; 110 111 if (nbytes > 0) { 112 if (memcmp(pa, pb, nbytes) != 0) 113 return (ISC_FALSE); 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 (ISC_FALSE); 124 } 125 return (ISC_TRUE); 126 } 127 128 isc_result_t 129 isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) { 130 char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; 131 char zbuf[sizeof("%4294967295")]; 132 unsigned int alen; 133 int zlen; 134 const char *r; 135 const void *type; 136 137 REQUIRE(netaddr != NULL); 138 139 switch (netaddr->family) { 140 case AF_INET: 141 type = &netaddr->type.in; 142 break; 143 case AF_INET6: 144 type = &netaddr->type.in6; 145 break; 146 #ifdef ISC_PLATFORM_HAVESYSUNH 147 case AF_UNIX: 148 alen = strlen(netaddr->type.un); 149 if (alen > isc_buffer_availablelength(target)) 150 return (ISC_R_NOSPACE); 151 isc_buffer_putmem(target, 152 (const unsigned char *)(netaddr->type.un), 153 alen); 154 return (ISC_R_SUCCESS); 155 #endif 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 alen = strlen(abuf); 164 INSIST(alen < sizeof(abuf)); 165 166 zlen = 0; 167 if (netaddr->family == AF_INET6 && netaddr->zone != 0) { 168 zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone); 169 if (zlen < 0) 170 return (ISC_R_FAILURE); 171 INSIST((unsigned int)zlen < sizeof(zbuf)); 172 } 173 174 if (alen + zlen > isc_buffer_availablelength(target)) 175 return (ISC_R_NOSPACE); 176 177 isc_buffer_putmem(target, (unsigned char *)abuf, alen); 178 isc_buffer_putmem(target, (unsigned char *)zbuf, zlen); 179 180 return (ISC_R_SUCCESS); 181 } 182 183 void 184 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) { 185 isc_result_t result; 186 isc_buffer_t buf; 187 188 isc_buffer_init(&buf, array, size); 189 result = isc_netaddr_totext(na, &buf); 190 191 if (size == 0) 192 return; 193 194 /* 195 * Null terminate. 196 */ 197 if (result == ISC_R_SUCCESS) { 198 if (isc_buffer_availablelength(&buf) >= 1) 199 isc_buffer_putuint8(&buf, 0); 200 else 201 result = ISC_R_NOSPACE; 202 } 203 204 if (result != ISC_R_SUCCESS) { 205 snprintf(array, size, 206 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR, 207 ISC_MSG_UNKNOWNADDR, 208 "<unknown address, family %u>"), 209 na->family); 210 array[size - 1] = '\0'; 211 } 212 } 213 214 215 isc_result_t 216 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { 217 static const unsigned char zeros[16]; 218 unsigned int nbits, nbytes, ipbytes = 0; 219 const unsigned char *p; 220 221 switch (na->family) { 222 case AF_INET: 223 p = (const unsigned char *) &na->type.in; 224 ipbytes = 4; 225 if (prefixlen > 32) 226 return (ISC_R_RANGE); 227 break; 228 case AF_INET6: 229 p = (const unsigned char *) &na->type.in6; 230 ipbytes = 16; 231 if (prefixlen > 128) 232 return (ISC_R_RANGE); 233 break; 234 default: 235 return (ISC_R_NOTIMPLEMENTED); 236 } 237 nbytes = prefixlen / 8; 238 nbits = prefixlen % 8; 239 if (nbits != 0) { 240 INSIST(nbytes < ipbytes); 241 if ((p[nbytes] & (0xff>>nbits)) != 0U) 242 return (ISC_R_FAILURE); 243 nbytes++; 244 } 245 if (nbytes < ipbytes && memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) 246 return (ISC_R_FAILURE); 247 return (ISC_R_SUCCESS); 248 } 249 250 isc_result_t 251 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) { 252 unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i; 253 const unsigned char *p; 254 255 switch (s->family) { 256 case AF_INET: 257 p = (const unsigned char *) &s->type.in; 258 ipbytes = 4; 259 break; 260 case AF_INET6: 261 p = (const unsigned char *) &s->type.in6; 262 ipbytes = 16; 263 break; 264 default: 265 return (ISC_R_NOTIMPLEMENTED); 266 } 267 for (i = 0; i < ipbytes; i++) { 268 if (p[i] != 0xFF) 269 break; 270 } 271 nbytes = i; 272 if (i < ipbytes) { 273 unsigned int c = p[nbytes]; 274 while ((c & 0x80) != 0 && nbits < 8) { 275 c <<= 1; nbits++; 276 } 277 if ((c & 0xFF) != 0) 278 return (ISC_R_MASKNONCONTIG); 279 i++; 280 } 281 for (; i < ipbytes; i++) { 282 if (p[i] != 0) 283 return (ISC_R_MASKNONCONTIG); 284 i++; 285 } 286 *lenp = nbytes * 8 + nbits; 287 return (ISC_R_SUCCESS); 288 } 289 290 void 291 isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) { 292 memset(netaddr, 0, sizeof(*netaddr)); 293 netaddr->family = AF_INET; 294 netaddr->type.in = *ina; 295 } 296 297 void 298 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) { 299 memset(netaddr, 0, sizeof(*netaddr)); 300 netaddr->family = AF_INET6; 301 netaddr->type.in6 = *ina6; 302 } 303 304 isc_result_t 305 isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) { 306 #ifdef ISC_PLATFORM_HAVESYSUNH 307 if (strlen(path) > sizeof(netaddr->type.un) - 1) 308 return (ISC_R_NOSPACE); 309 310 memset(netaddr, 0, sizeof(*netaddr)); 311 netaddr->family = AF_UNIX; 312 strcpy(netaddr->type.un, path); 313 netaddr->zone = 0; 314 return (ISC_R_SUCCESS); 315 #else 316 UNUSED(netaddr); 317 UNUSED(path); 318 return (ISC_R_NOTIMPLEMENTED); 319 #endif 320 } 321 322 323 void 324 isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) { 325 /* we currently only support AF_INET6. */ 326 REQUIRE(netaddr->family == AF_INET6); 327 328 netaddr->zone = zone; 329 } 330 331 isc_uint32_t 332 isc_netaddr_getzone(const isc_netaddr_t *netaddr) { 333 return (netaddr->zone); 334 } 335 336 void 337 isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) { 338 int family = s->type.sa.sa_family; 339 t->family = family; 340 switch (family) { 341 case AF_INET: 342 t->type.in = s->type.sin.sin_addr; 343 t->zone = 0; 344 break; 345 case AF_INET6: 346 memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16); 347 #ifdef ISC_PLATFORM_HAVESCOPEID 348 t->zone = s->type.sin6.sin6_scope_id; 349 #else 350 t->zone = 0; 351 #endif 352 break; 353 #ifdef ISC_PLATFORM_HAVESYSUNH 354 case AF_UNIX: 355 memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un)); 356 t->zone = 0; 357 break; 358 #endif 359 default: 360 INSIST(0); 361 } 362 } 363 364 void 365 isc_netaddr_any(isc_netaddr_t *netaddr) { 366 memset(netaddr, 0, sizeof(*netaddr)); 367 netaddr->family = AF_INET; 368 netaddr->type.in.s_addr = INADDR_ANY; 369 } 370 371 void 372 isc_netaddr_any6(isc_netaddr_t *netaddr) { 373 memset(netaddr, 0, sizeof(*netaddr)); 374 netaddr->family = AF_INET6; 375 netaddr->type.in6 = in6addr_any; 376 } 377 378 isc_boolean_t 379 isc_netaddr_ismulticast(isc_netaddr_t *na) { 380 switch (na->family) { 381 case AF_INET: 382 return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr))); 383 case AF_INET6: 384 return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6))); 385 default: 386 return (ISC_FALSE); /* XXXMLG ? */ 387 } 388 } 389 390 isc_boolean_t 391 isc_netaddr_isexperimental(isc_netaddr_t *na) { 392 switch (na->family) { 393 case AF_INET: 394 return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr))); 395 default: 396 return (ISC_FALSE); /* XXXMLG ? */ 397 } 398 } 399 400 isc_boolean_t 401 isc_netaddr_islinklocal(isc_netaddr_t *na) { 402 switch (na->family) { 403 case AF_INET: 404 return (ISC_FALSE); 405 case AF_INET6: 406 return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6))); 407 default: 408 return (ISC_FALSE); 409 } 410 } 411 412 isc_boolean_t 413 isc_netaddr_issitelocal(isc_netaddr_t *na) { 414 switch (na->family) { 415 case AF_INET: 416 return (ISC_FALSE); 417 case AF_INET6: 418 return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6))); 419 default: 420 return (ISC_FALSE); 421 } 422 } 423 424 void 425 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) { 426 isc_netaddr_t *src; 427 428 DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */ 429 430 REQUIRE(s->family == AF_INET6); 431 REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6)); 432 433 memset(t, 0, sizeof(*t)); 434 t->family = AF_INET; 435 memmove(&t->type.in, (char *)&src->type.in6 + 12, 4); 436 return; 437 } 438