sockaddr.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2010-2012, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  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/hash.h>
00028 #include <isc/msgs.h>
00029 #include <isc/netaddr.h>
00030 #include <isc/print.h>
00031 #include <isc/region.h>
00032 #include <isc/sockaddr.h>
00033 #include <isc/string.h>
00034 #include <isc/util.h>
00035 
00036 isc_boolean_t
00037 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
00038         return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
00039                                            ISC_SOCKADDR_CMPPORT|
00040                                            ISC_SOCKADDR_CMPSCOPE));
00041 }
00042 
00043 isc_boolean_t
00044 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
00045         return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
00046                                            ISC_SOCKADDR_CMPSCOPE));
00047 }
00048 
00049 isc_boolean_t
00050 isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
00051                      unsigned int flags)
00052 {
00053         REQUIRE(a != NULL && b != NULL);
00054 
00055         if (a->length != b->length)
00056                 return (ISC_FALSE);
00057 
00058         /*
00059          * We don't just memcmp because the sin_zero field isn't always
00060          * zero.
00061          */
00062 
00063         if (a->type.sa.sa_family != b->type.sa.sa_family)
00064                 return (ISC_FALSE);
00065         switch (a->type.sa.sa_family) {
00066         case AF_INET:
00067                 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
00068                     memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
00069                            sizeof(a->type.sin.sin_addr)) != 0)
00070                         return (ISC_FALSE);
00071                 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
00072                     a->type.sin.sin_port != b->type.sin.sin_port)
00073                         return (ISC_FALSE);
00074                 break;
00075         case AF_INET6:
00076                 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
00077                     memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
00078                            sizeof(a->type.sin6.sin6_addr)) != 0)
00079                         return (ISC_FALSE);
00080 #ifdef ISC_PLATFORM_HAVESCOPEID
00081                 /*
00082                  * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
00083                  * ISC_FALSE if one of the scopes in zero.
00084                  */
00085                 if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
00086                     a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
00087                     ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
00088                       (a->type.sin6.sin6_scope_id != 0 &&
00089                        b->type.sin6.sin6_scope_id != 0)))
00090                         return (ISC_FALSE);
00091 #endif
00092                 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
00093                     a->type.sin6.sin6_port != b->type.sin6.sin6_port)
00094                         return (ISC_FALSE);
00095                 break;
00096         default:
00097                 if (memcmp(&a->type, &b->type, a->length) != 0)
00098                         return (ISC_FALSE);
00099         }
00100         return (ISC_TRUE);
00101 }
00102 
00103 isc_boolean_t
00104 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
00105                           unsigned int prefixlen)
00106 {
00107         isc_netaddr_t na, nb;
00108         isc_netaddr_fromsockaddr(&na, a);
00109         isc_netaddr_fromsockaddr(&nb, b);
00110         return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
00111 }
00112 
00113 isc_result_t
00114 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
00115         isc_result_t result;
00116         isc_netaddr_t netaddr;
00117         char pbuf[sizeof("65000")];
00118         unsigned int plen;
00119         isc_region_t avail;
00120 
00121         REQUIRE(sockaddr != NULL);
00122 
00123         /*
00124          * Do the port first, giving us the opportunity to check for
00125          * unsupported address families before calling
00126          * isc_netaddr_fromsockaddr().
00127          */
00128         switch (sockaddr->type.sa.sa_family) {
00129         case AF_INET:
00130                 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
00131                 break;
00132         case AF_INET6:
00133                 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
00134                 break;
00135 #ifdef ISC_PLAFORM_HAVESYSUNH
00136         case AF_UNIX:
00137                 plen = strlen(sockaddr->type.sunix.sun_path);
00138                 if (plen >= isc_buffer_availablelength(target))
00139                         return (ISC_R_NOSPACE);
00140 
00141                 isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
00142 
00143                 /*
00144                  * Null terminate after used region.
00145                  */
00146                 isc_buffer_availableregion(target, &avail);
00147                 INSIST(avail.length >= 1);
00148                 avail.base[0] = '\0';
00149 
00150                 return (ISC_R_SUCCESS);
00151 #endif
00152         default:
00153                 return (ISC_R_FAILURE);
00154         }
00155 
00156         plen = strlen(pbuf);
00157         INSIST(plen < sizeof(pbuf));
00158 
00159         isc_netaddr_fromsockaddr(&netaddr, sockaddr);
00160         result = isc_netaddr_totext(&netaddr, target);
00161         if (result != ISC_R_SUCCESS)
00162                 return (result);
00163 
00164         if (1 + plen + 1 > isc_buffer_availablelength(target))
00165                 return (ISC_R_NOSPACE);
00166 
00167         isc_buffer_putmem(target, (const unsigned char *)"#", 1);
00168         isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
00169 
00170         /*
00171          * Null terminate after used region.
00172          */
00173         isc_buffer_availableregion(target, &avail);
00174         INSIST(avail.length >= 1);
00175         avail.base[0] = '\0';
00176 
00177         return (ISC_R_SUCCESS);
00178 }
00179 
00180 void
00181 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
00182         isc_result_t result;
00183         isc_buffer_t buf;
00184 
00185         if (size == 0U)
00186                 return;
00187 
00188         isc_buffer_init(&buf, array, size);
00189         result = isc_sockaddr_totext(sa, &buf);
00190         if (result != ISC_R_SUCCESS) {
00191                 /*
00192                  * The message is the same as in netaddr.c.
00193                  */
00194                 snprintf(array, size,
00195                          isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
00196                                         ISC_MSG_UNKNOWNADDR,
00197                                         "<unknown address, family %u>"),
00198                          sa->type.sa.sa_family);
00199                 array[size - 1] = '\0';
00200         }
00201 }
00202 
00203 unsigned int
00204 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
00205         unsigned int length = 0;
00206         const unsigned char *s = NULL;
00207         unsigned int h = 0;
00208         unsigned int g;
00209         unsigned int p = 0;
00210         const struct in6_addr *in6;
00211 
00212         REQUIRE(sockaddr != NULL);
00213 
00214         switch (sockaddr->type.sa.sa_family) {
00215         case AF_INET:
00216                 s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
00217                 p = ntohs(sockaddr->type.sin.sin_port);
00218                 length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
00219                 break;
00220         case AF_INET6:
00221                 in6 = &sockaddr->type.sin6.sin6_addr;
00222                 s = (const unsigned char *)in6;
00223                 if (IN6_IS_ADDR_V4MAPPED(in6)) {
00224                         s += 12;
00225                         length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
00226                 } else
00227                         length = sizeof(sockaddr->type.sin6.sin6_addr);
00228                 p = ntohs(sockaddr->type.sin6.sin6_port);
00229                 break;
00230         default:
00231                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00232                                  isc_msgcat_get(isc_msgcat,
00233                                                 ISC_MSGSET_SOCKADDR,
00234                                                 ISC_MSG_UNKNOWNFAMILY,
00235                                                 "unknown address family: %d"),
00236                                              (int)sockaddr->type.sa.sa_family);
00237                 s = (const unsigned char *)&sockaddr->type;
00238                 length = sockaddr->length;
00239                 p = 0;
00240         }
00241 
00242         h = isc_hash_calc(s, length, ISC_TRUE);
00243         if (!address_only) {
00244                 g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
00245                                   ISC_TRUE);
00246                 h = h ^ g; /* XXX: we should concatenate h and p first */
00247         }
00248 
00249         return (h);
00250 }
00251 
00252 void
00253 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
00254 {
00255         memset(sockaddr, 0, sizeof(*sockaddr));
00256         sockaddr->type.sin.sin_family = AF_INET;
00257 #ifdef ISC_PLATFORM_HAVESALEN
00258         sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
00259 #endif
00260         sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
00261         sockaddr->type.sin.sin_port = 0;
00262         sockaddr->length = sizeof(sockaddr->type.sin);
00263         ISC_LINK_INIT(sockaddr, link);
00264 }
00265 
00266 void
00267 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
00268 {
00269         memset(sockaddr, 0, sizeof(*sockaddr));
00270         sockaddr->type.sin6.sin6_family = AF_INET6;
00271 #ifdef ISC_PLATFORM_HAVESALEN
00272         sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
00273 #endif
00274         sockaddr->type.sin6.sin6_addr = in6addr_any;
00275         sockaddr->type.sin6.sin6_port = 0;
00276         sockaddr->length = sizeof(sockaddr->type.sin6);
00277         ISC_LINK_INIT(sockaddr, link);
00278 }
00279 
00280 void
00281 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
00282                     in_port_t port)
00283 {
00284         memset(sockaddr, 0, sizeof(*sockaddr));
00285         sockaddr->type.sin.sin_family = AF_INET;
00286 #ifdef ISC_PLATFORM_HAVESALEN
00287         sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
00288 #endif
00289         sockaddr->type.sin.sin_addr = *ina;
00290         sockaddr->type.sin.sin_port = htons(port);
00291         sockaddr->length = sizeof(sockaddr->type.sin);
00292         ISC_LINK_INIT(sockaddr, link);
00293 }
00294 
00295 void
00296 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
00297      switch (pf) {
00298      case AF_INET:
00299              isc_sockaddr_any(sockaddr);
00300              break;
00301      case AF_INET6:
00302              isc_sockaddr_any6(sockaddr);
00303              break;
00304      default:
00305              INSIST(0);
00306      }
00307 }
00308 
00309 void
00310 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
00311                      in_port_t port)
00312 {
00313         memset(sockaddr, 0, sizeof(*sockaddr));
00314         sockaddr->type.sin6.sin6_family = AF_INET6;
00315 #ifdef ISC_PLATFORM_HAVESALEN
00316         sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
00317 #endif
00318         sockaddr->type.sin6.sin6_addr = *ina6;
00319         sockaddr->type.sin6.sin6_port = htons(port);
00320         sockaddr->length = sizeof(sockaddr->type.sin6);
00321         ISC_LINK_INIT(sockaddr, link);
00322 }
00323 
00324 void
00325 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
00326                       in_port_t port)
00327 {
00328         memset(sockaddr, 0, sizeof(*sockaddr));
00329         sockaddr->type.sin6.sin6_family = AF_INET6;
00330 #ifdef ISC_PLATFORM_HAVESALEN
00331         sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
00332 #endif
00333         sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
00334         sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
00335         memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
00336         sockaddr->type.sin6.sin6_port = htons(port);
00337         sockaddr->length = sizeof(sockaddr->type.sin6);
00338         ISC_LINK_INIT(sockaddr, link);
00339 }
00340 
00341 int
00342 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
00343 
00344         /*
00345          * Get the protocol family of 'sockaddr'.
00346          */
00347 
00348 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
00349         /*
00350          * Assume that PF_xxx == AF_xxx for all AF and PF.
00351          */
00352         return (sockaddr->type.sa.sa_family);
00353 #else
00354         switch (sockaddr->type.sa.sa_family) {
00355         case AF_INET:
00356                 return (PF_INET);
00357         case AF_INET6:
00358                 return (PF_INET6);
00359         default:
00360                 FATAL_ERROR(__FILE__, __LINE__,
00361                             isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
00362                                            ISC_MSG_UNKNOWNFAMILY,
00363                                            "unknown address family: %d"),
00364                             (int)sockaddr->type.sa.sa_family);
00365         }
00366 #endif
00367 }
00368 
00369 void
00370 isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
00371                     in_port_t port)
00372 {
00373         memset(sockaddr, 0, sizeof(*sockaddr));
00374         sockaddr->type.sin.sin_family = na->family;
00375         switch (na->family) {
00376         case AF_INET:
00377                 sockaddr->length = sizeof(sockaddr->type.sin);
00378 #ifdef ISC_PLATFORM_HAVESALEN
00379                 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
00380 #endif
00381                 sockaddr->type.sin.sin_addr = na->type.in;
00382                 sockaddr->type.sin.sin_port = htons(port);
00383                 break;
00384         case AF_INET6:
00385                 sockaddr->length = sizeof(sockaddr->type.sin6);
00386 #ifdef ISC_PLATFORM_HAVESALEN
00387                 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
00388 #endif
00389                 memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
00390 #ifdef ISC_PLATFORM_HAVESCOPEID
00391                 sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
00392 #endif
00393                 sockaddr->type.sin6.sin6_port = htons(port);
00394                 break;
00395         default:
00396                 INSIST(0);
00397         }
00398         ISC_LINK_INIT(sockaddr, link);
00399 }
00400 
00401 void
00402 isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
00403         switch (sockaddr->type.sa.sa_family) {
00404         case AF_INET:
00405                 sockaddr->type.sin.sin_port = htons(port);
00406                 break;
00407         case AF_INET6:
00408                 sockaddr->type.sin6.sin6_port = htons(port);
00409                 break;
00410         default:
00411                 FATAL_ERROR(__FILE__, __LINE__,
00412                             isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
00413                                            ISC_MSG_UNKNOWNFAMILY,
00414                                            "unknown address family: %d"),
00415                             (int)sockaddr->type.sa.sa_family);
00416         }
00417 }
00418 
00419 in_port_t
00420 isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
00421         in_port_t port = 0;
00422 
00423         switch (sockaddr->type.sa.sa_family) {
00424         case AF_INET:
00425                 port = ntohs(sockaddr->type.sin.sin_port);
00426                 break;
00427         case AF_INET6:
00428                 port = ntohs(sockaddr->type.sin6.sin6_port);
00429                 break;
00430         default:
00431                 FATAL_ERROR(__FILE__, __LINE__,
00432                             isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
00433                                            ISC_MSG_UNKNOWNFAMILY,
00434                                            "unknown address family: %d"),
00435                             (int)sockaddr->type.sa.sa_family);
00436         }
00437 
00438         return (port);
00439 }
00440 
00441 isc_boolean_t
00442 isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
00443         isc_netaddr_t netaddr;
00444 
00445         if (sockaddr->type.sa.sa_family == AF_INET ||
00446             sockaddr->type.sa.sa_family == AF_INET6) {
00447                 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
00448                 return (isc_netaddr_ismulticast(&netaddr));
00449         }
00450         return (ISC_FALSE);
00451 }
00452 
00453 isc_boolean_t
00454 isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
00455         isc_netaddr_t netaddr;
00456 
00457         if (sockaddr->type.sa.sa_family == AF_INET) {
00458                 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
00459                 return (isc_netaddr_isexperimental(&netaddr));
00460         }
00461         return (ISC_FALSE);
00462 }
00463 
00464 isc_boolean_t
00465 isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
00466         isc_netaddr_t netaddr;
00467 
00468         if (sockaddr->type.sa.sa_family == AF_INET6) {
00469                 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
00470                 return (isc_netaddr_issitelocal(&netaddr));
00471         }
00472         return (ISC_FALSE);
00473 }
00474 
00475 isc_boolean_t
00476 isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
00477         isc_netaddr_t netaddr;
00478 
00479         if (sockaddr->type.sa.sa_family == AF_INET6) {
00480                 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
00481                 return (isc_netaddr_islinklocal(&netaddr));
00482         }
00483         return (ISC_FALSE);
00484 }
00485 
00486 isc_result_t
00487 isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
00488 #ifdef ISC_PLATFORM_HAVESYSUNH
00489         if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
00490                 return (ISC_R_NOSPACE);
00491         memset(sockaddr, 0, sizeof(*sockaddr));
00492         sockaddr->length = sizeof(sockaddr->type.sunix);
00493         sockaddr->type.sunix.sun_family = AF_UNIX;
00494 #ifdef ISC_PLATFORM_HAVESALEN
00495         sockaddr->type.sunix.sun_len =
00496                         (unsigned char)sizeof(sockaddr->type.sunix);
00497 #endif
00498         strcpy(sockaddr->type.sunix.sun_path, path);
00499         return (ISC_R_SUCCESS);
00500 #else
00501         UNUSED(sockaddr);
00502         UNUSED(path);
00503         return (ISC_R_NOTIMPLEMENTED);
00504 #endif
00505 }

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