netaddr.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2010-2012, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <stdio.h>
00025 
00026 #include <isc/buffer.h>
00027 #include <isc/msgs.h>
00028 #include <isc/net.h>
00029 #include <isc/netaddr.h>
00030 #include <isc/print.h>
00031 #include <isc/sockaddr.h>
00032 #include <isc/string.h>
00033 #include <isc/util.h>
00034 
00035 isc_boolean_t
00036 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
00037         REQUIRE(a != NULL && b != NULL);
00038 
00039         if (a->family != b->family)
00040                 return (ISC_FALSE);
00041 
00042         if (a->zone != b->zone)
00043                 return (ISC_FALSE);
00044 
00045         switch (a->family) {
00046         case AF_INET:
00047                 if (a->type.in.s_addr != b->type.in.s_addr)
00048                         return (ISC_FALSE);
00049                 break;
00050         case AF_INET6:
00051                 if (memcmp(&a->type.in6, &b->type.in6,
00052                            sizeof(a->type.in6)) != 0 ||
00053                     a->zone != b->zone)
00054                         return (ISC_FALSE);
00055                 break;
00056 #ifdef ISC_PLATFORM_HAVESYSUNH
00057         case AF_UNIX:
00058                 if (strcmp(a->type.un, b->type.un) != 0)
00059                         return (ISC_FALSE);
00060                 break;
00061 #endif
00062         default:
00063                 return (ISC_FALSE);
00064         }
00065         return (ISC_TRUE);
00066 }
00067 
00068 isc_boolean_t
00069 isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
00070                      unsigned int prefixlen)
00071 {
00072         const unsigned char *pa = NULL, *pb = NULL;
00073         unsigned int ipabytes = 0; /* Length of whole IP address in bytes */
00074         unsigned int nbytes;       /* Number of significant whole bytes */
00075         unsigned int nbits;        /* Number of significant leftover bits */
00076 
00077         REQUIRE(a != NULL && b != NULL);
00078 
00079         if (a->family != b->family)
00080                 return (ISC_FALSE);
00081 
00082         if (a->zone != b->zone && b->zone != 0)
00083                 return (ISC_FALSE);
00084 
00085         switch (a->family) {
00086         case AF_INET:
00087                 pa = (const unsigned char *) &a->type.in;
00088                 pb = (const unsigned char *) &b->type.in;
00089                 ipabytes = 4;
00090                 break;
00091         case AF_INET6:
00092                 pa = (const unsigned char *) &a->type.in6;
00093                 pb = (const unsigned char *) &b->type.in6;
00094                 ipabytes = 16;
00095                 break;
00096         default:
00097                 return (ISC_FALSE);
00098         }
00099 
00100         /*
00101          * Don't crash if we get a pattern like 10.0.0.1/9999999.
00102          */
00103         if (prefixlen > ipabytes * 8)
00104                 prefixlen = ipabytes * 8;
00105 
00106         nbytes = prefixlen / 8;
00107         nbits = prefixlen % 8;
00108 
00109         if (nbytes > 0) {
00110                 if (memcmp(pa, pb, nbytes) != 0)
00111                         return (ISC_FALSE);
00112         }
00113         if (nbits > 0) {
00114                 unsigned int bytea, byteb, mask;
00115                 INSIST(nbytes < ipabytes);
00116                 INSIST(nbits < 8);
00117                 bytea = pa[nbytes];
00118                 byteb = pb[nbytes];
00119                 mask = (0xFF << (8-nbits)) & 0xFF;
00120                 if ((bytea & mask) != (byteb & mask))
00121                         return (ISC_FALSE);
00122         }
00123         return (ISC_TRUE);
00124 }
00125 
00126 isc_result_t
00127 isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
00128         char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
00129         char zbuf[sizeof("%4294967295")];
00130         unsigned int alen;
00131         int zlen;
00132         const char *r;
00133         const void *type;
00134 
00135         REQUIRE(netaddr != NULL);
00136 
00137         switch (netaddr->family) {
00138         case AF_INET:
00139                 type = &netaddr->type.in;
00140                 break;
00141         case AF_INET6:
00142                 type = &netaddr->type.in6;
00143                 break;
00144 #ifdef ISC_PLATFORM_HAVESYSUNH
00145         case AF_UNIX:
00146                 alen = strlen(netaddr->type.un);
00147                 if (alen > isc_buffer_availablelength(target))
00148                         return (ISC_R_NOSPACE);
00149                 isc_buffer_putmem(target,
00150                                   (const unsigned char *)(netaddr->type.un),
00151                                   alen);
00152                 return (ISC_R_SUCCESS);
00153 #endif
00154         default:
00155                 return (ISC_R_FAILURE);
00156         }
00157         r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
00158         if (r == NULL)
00159                 return (ISC_R_FAILURE);
00160 
00161         alen = strlen(abuf);
00162         INSIST(alen < sizeof(abuf));
00163 
00164         zlen = 0;
00165         if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
00166                 zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
00167                 if (zlen < 0)
00168                         return (ISC_R_FAILURE);
00169                 INSIST((unsigned int)zlen < sizeof(zbuf));
00170         }
00171 
00172         if (alen + zlen > isc_buffer_availablelength(target))
00173                 return (ISC_R_NOSPACE);
00174 
00175         isc_buffer_putmem(target, (unsigned char *)abuf, alen);
00176         isc_buffer_putmem(target, (unsigned char *)zbuf, zlen);
00177 
00178         return (ISC_R_SUCCESS);
00179 }
00180 
00181 void
00182 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
00183         isc_result_t result;
00184         isc_buffer_t buf;
00185 
00186         isc_buffer_init(&buf, array, size);
00187         result = isc_netaddr_totext(na, &buf);
00188 
00189         if (size == 0)
00190                 return;
00191 
00192         /*
00193          * Null terminate.
00194          */
00195         if (result == ISC_R_SUCCESS) {
00196                 if (isc_buffer_availablelength(&buf) >= 1)
00197                         isc_buffer_putuint8(&buf, 0);
00198                 else
00199                         result = ISC_R_NOSPACE;
00200         }
00201 
00202         if (result != ISC_R_SUCCESS) {
00203                 snprintf(array, size,
00204                          isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
00205                                         ISC_MSG_UNKNOWNADDR,
00206                                         "<unknown address, family %u>"),
00207                          na->family);
00208                 array[size - 1] = '\0';
00209         }
00210 }
00211 
00212 
00213 isc_result_t
00214 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
00215         static const unsigned char zeros[16];
00216         unsigned int nbits, nbytes, ipbytes = 0;
00217         const unsigned char *p;
00218 
00219         switch (na->family) {
00220         case AF_INET:
00221                 p = (const unsigned char *) &na->type.in;
00222                 ipbytes = 4;
00223                 if (prefixlen > 32)
00224                         return (ISC_R_RANGE);
00225                 break;
00226         case AF_INET6:
00227                 p = (const unsigned char *) &na->type.in6;
00228                 ipbytes = 16;
00229                 if (prefixlen > 128)
00230                         return (ISC_R_RANGE);
00231                 break;
00232         default:
00233                 return (ISC_R_NOTIMPLEMENTED);
00234         }
00235         nbytes = prefixlen / 8;
00236         nbits = prefixlen % 8;
00237         if (nbits != 0) {
00238                 INSIST(nbytes < ipbytes);
00239                 if ((p[nbytes] & (0xff>>nbits)) != 0U)
00240                         return (ISC_R_FAILURE);
00241                 nbytes++;
00242         }
00243         if (nbytes < ipbytes && memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
00244                 return (ISC_R_FAILURE);
00245         return (ISC_R_SUCCESS);
00246 }
00247 
00248 isc_result_t
00249 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
00250         unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
00251         const unsigned char *p;
00252 
00253         switch (s->family) {
00254         case AF_INET:
00255                 p = (const unsigned char *) &s->type.in;
00256                 ipbytes = 4;
00257                 break;
00258         case AF_INET6:
00259                 p = (const unsigned char *) &s->type.in6;
00260                 ipbytes = 16;
00261                 break;
00262         default:
00263                 return (ISC_R_NOTIMPLEMENTED);
00264         }
00265         for (i = 0; i < ipbytes; i++) {
00266                 if (p[i] != 0xFF)
00267                         break;
00268         }
00269         nbytes = i;
00270         if (i < ipbytes) {
00271                 unsigned int c = p[nbytes];
00272                 while ((c & 0x80) != 0 && nbits < 8) {
00273                         c <<= 1; nbits++;
00274                 }
00275                 if ((c & 0xFF) != 0)
00276                         return (ISC_R_MASKNONCONTIG);
00277                 i++;
00278         }
00279         for (; i < ipbytes; i++) {
00280                 if (p[i] != 0)
00281                         return (ISC_R_MASKNONCONTIG);
00282                 i++;
00283         }
00284         *lenp = nbytes * 8 + nbits;
00285         return (ISC_R_SUCCESS);
00286 }
00287 
00288 void
00289 isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
00290         memset(netaddr, 0, sizeof(*netaddr));
00291         netaddr->family = AF_INET;
00292         netaddr->type.in = *ina;
00293 }
00294 
00295 void
00296 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
00297         memset(netaddr, 0, sizeof(*netaddr));
00298         netaddr->family = AF_INET6;
00299         netaddr->type.in6 = *ina6;
00300 }
00301 
00302 isc_result_t
00303 isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
00304 #ifdef ISC_PLATFORM_HAVESYSUNH
00305         if (strlen(path) > sizeof(netaddr->type.un) - 1)
00306                 return (ISC_R_NOSPACE);
00307 
00308         memset(netaddr, 0, sizeof(*netaddr));
00309         netaddr->family = AF_UNIX;
00310         strcpy(netaddr->type.un, path);
00311         netaddr->zone = 0;
00312         return (ISC_R_SUCCESS);
00313 #else
00314         UNUSED(netaddr);
00315         UNUSED(path);
00316         return (ISC_R_NOTIMPLEMENTED);
00317 #endif
00318 }
00319 
00320 
00321 void
00322 isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) {
00323         /* we currently only support AF_INET6. */
00324         REQUIRE(netaddr->family == AF_INET6);
00325 
00326         netaddr->zone = zone;
00327 }
00328 
00329 isc_uint32_t
00330 isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
00331         return (netaddr->zone);
00332 }
00333 
00334 void
00335 isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
00336         int family = s->type.sa.sa_family;
00337         t->family = family;
00338         switch (family) {
00339         case AF_INET:
00340                 t->type.in = s->type.sin.sin_addr;
00341                 t->zone = 0;
00342                 break;
00343         case AF_INET6:
00344                 memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16);
00345 #ifdef ISC_PLATFORM_HAVESCOPEID
00346                 t->zone = s->type.sin6.sin6_scope_id;
00347 #else
00348                 t->zone = 0;
00349 #endif
00350                 break;
00351 #ifdef ISC_PLATFORM_HAVESYSUNH
00352         case AF_UNIX:
00353                 memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
00354                 t->zone = 0;
00355                 break;
00356 #endif
00357         default:
00358                 INSIST(0);
00359         }
00360 }
00361 
00362 void
00363 isc_netaddr_any(isc_netaddr_t *netaddr) {
00364         memset(netaddr, 0, sizeof(*netaddr));
00365         netaddr->family = AF_INET;
00366         netaddr->type.in.s_addr = INADDR_ANY;
00367 }
00368 
00369 void
00370 isc_netaddr_any6(isc_netaddr_t *netaddr) {
00371         memset(netaddr, 0, sizeof(*netaddr));
00372         netaddr->family = AF_INET6;
00373         netaddr->type.in6 = in6addr_any;
00374 }
00375 
00376 isc_boolean_t
00377 isc_netaddr_ismulticast(isc_netaddr_t *na) {
00378         switch (na->family) {
00379         case AF_INET:
00380                 return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr)));
00381         case AF_INET6:
00382                 return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6)));
00383         default:
00384                 return (ISC_FALSE);  /* XXXMLG ? */
00385         }
00386 }
00387 
00388 isc_boolean_t
00389 isc_netaddr_isexperimental(isc_netaddr_t *na) {
00390         switch (na->family) {
00391         case AF_INET:
00392                 return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr)));
00393         default:
00394                 return (ISC_FALSE);  /* XXXMLG ? */
00395         }
00396 }
00397 
00398 isc_boolean_t
00399 isc_netaddr_islinklocal(isc_netaddr_t *na) {
00400         switch (na->family) {
00401         case AF_INET:
00402                 return (ISC_FALSE);
00403         case AF_INET6:
00404                 return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6)));
00405         default:
00406                 return (ISC_FALSE);
00407         }
00408 }
00409 
00410 isc_boolean_t
00411 isc_netaddr_issitelocal(isc_netaddr_t *na) {
00412         switch (na->family) {
00413         case AF_INET:
00414                 return (ISC_FALSE);
00415         case AF_INET6:
00416                 return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6)));
00417         default:
00418                 return (ISC_FALSE);
00419         }
00420 }
00421 
00422 void
00423 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
00424         isc_netaddr_t *src;
00425 
00426         DE_CONST(s, src);       /* Must come before IN6_IS_ADDR_V4MAPPED. */
00427 
00428         REQUIRE(s->family == AF_INET6);
00429         REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
00430 
00431         memset(t, 0, sizeof(*t));
00432         t->family = AF_INET;
00433         memmove(&t->type.in, (char *)&src->type.in6 + 12, 4);
00434         return;
00435 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha