"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/network_io/unix/sockaddr.c" (19 Mar 2019, 39349 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sockaddr.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    1 /* Licensed to the Apache Software Foundation (ASF) under one or more
    2  * contributor license agreements.  See the NOTICE file distributed with
    3  * this work for additional information regarding copyright ownership.
    4  * The ASF licenses this file to You under the Apache License, Version 2.0
    5  * (the "License"); you may not use this file except in compliance with
    6  * the License.  You may obtain a copy of the License at
    7  *
    8  *     http://www.apache.org/licenses/LICENSE-2.0
    9  *
   10  * Unless required by applicable law or agreed to in writing, software
   11  * distributed under the License is distributed on an "AS IS" BASIS,
   12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13  * See the License for the specific language governing permissions and
   14  * limitations under the License.
   15  */
   16 
   17 #include "apr_arch_networkio.h"
   18 #include "apr_strings.h"
   19 #include "apr.h"
   20 #include "apr_lib.h"
   21 #include "apr_strings.h"
   22 #include "apr_private.h"
   23 
   24 #if APR_HAVE_STDLIB_H
   25 #include <stdlib.h>
   26 #endif
   27 
   28 #ifdef HAVE_NET_IF_H
   29 #include <net/if.h>
   30 #endif
   31 
   32 #if defined(HAVE_IF_INDEXTONAME) && defined(_MSC_VER)
   33 #include "arch/win32/apr_arch_misc.h"
   34 #endif
   35 
   36 #define APR_WANT_STRFUNC
   37 #include "apr_want.h"
   38 
   39 struct apr_ipsubnet_t {
   40     int family;
   41 #if APR_HAVE_IPV6
   42     apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
   43     apr_uint32_t mask[4];
   44 #else
   45     apr_uint32_t sub[1];
   46     apr_uint32_t mask[1];
   47 #endif
   48 };
   49 
   50 #if !defined(NETWARE) && !defined(WIN32)
   51 #ifdef HAVE_SET_H_ERRNO
   52 #define SET_H_ERRNO(newval) set_h_errno(newval)
   53 #else
   54 #define SET_H_ERRNO(newval) h_errno = (newval)
   55 #endif
   56 #else
   57 #define SET_H_ERRNO(newval)
   58 #endif
   59 
   60 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
   61     defined(HAVE_GETHOSTBYNAME_R)
   62 /* This is the maximum size that may be returned from the reentrant
   63  * gethostbyname_r function.  If the system tries to use more, it
   64  * should return ERANGE.
   65  */
   66 #define GETHOSTBYNAME_BUFLEN 512
   67 #endif
   68 
   69 #ifdef _AIX
   70 /* Some levels of AIX getaddrinfo() don't like servname = "0", so
   71  * set servname to "1" when port is 0 and fix it up later.
   72  */
   73 #define AIX_SERVNAME_HACK 1
   74 #else
   75 #define AIX_SERVNAME_HACK 0
   76 #endif
   77 
   78 #ifdef _WIN32_WCE
   79 /* XXX: BS solution.  Need an HAVE_GETSERVBYNAME and actually
   80  * do something here, to provide the obvious proto mappings.
   81  */
   82 static void *getservbyname(const char *name, const char *proto)
   83 {
   84     return NULL;
   85 }
   86 #endif
   87 
   88 static apr_status_t get_local_addr(apr_socket_t *sock)
   89 {
   90     sock->local_addr->salen = sizeof(sock->local_addr->sa);
   91     if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa,
   92                     &sock->local_addr->salen) < 0) {
   93         return apr_get_netos_error();
   94     }
   95     else {
   96         sock->local_port_unknown = sock->local_interface_unknown = 0;
   97         /* XXX assumes sin_port and sin6_port at same offset */
   98         sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port);
   99         return APR_SUCCESS;
  100     }
  101 }
  102 
  103 static apr_status_t get_remote_addr(apr_socket_t *sock)
  104 {
  105     sock->remote_addr->salen = sizeof(sock->remote_addr->sa);
  106     if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa,
  107                     &sock->remote_addr->salen) < 0) {
  108         return apr_get_netos_error();
  109     }
  110     else {
  111         sock->remote_addr_unknown = 0;
  112         /* XXX assumes sin_port and sin6_port at same offset */
  113         sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port);
  114         return APR_SUCCESS;
  115     }
  116 }
  117 
  118 APR_DECLARE(apr_status_t) apr_sockaddr_ip_getbuf(char *buf, apr_size_t buflen,
  119                                                  apr_sockaddr_t *sockaddr)
  120 {
  121     if (!apr_inet_ntop(sockaddr->family, sockaddr->ipaddr_ptr, buf, buflen)) {
  122         return APR_ENOSPC;
  123     }
  124 
  125 #if APR_HAVE_IPV6
  126     if (sockaddr->family == AF_INET6 
  127         && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sockaddr->ipaddr_ptr)
  128         && buflen > strlen("::ffff:")) {
  129         /* This is an IPv4-mapped IPv6 address; drop the leading
  130          * part of the address string so we're left with the familiar
  131          * IPv4 format.
  132          */
  133         memmove(buf, buf + strlen("::ffff:"),
  134                 strlen(buf + strlen("::ffff:"))+1);
  135     }
  136 
  137     /* ensure NUL termination if the buffer is too short */
  138     buf[buflen-1] = '\0';
  139 
  140 #ifdef HAVE_IF_INDEXTONAME
  141     /* Append scope name for link-local addresses. */
  142     if (sockaddr->family == AF_INET6
  143         && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)sockaddr->ipaddr_ptr)) {
  144         char scbuf[IF_NAMESIZE], *p = buf + strlen(buf);
  145 
  146         if (if_indextoname(sockaddr->sa.sin6.sin6_scope_id, scbuf) == scbuf) {
  147             /* Space check, need room for buf + '%' + scope + '\0'.
  148              * Assert: buflen >= strlen(buf) + strlen(scbuf) + 2
  149              * Equiv:  buflen >= (p-buf) + strlen(buf) + 2
  150              * Thus, fail in inverse condition: */
  151             if (buflen < strlen(scbuf) + (p - buf) + 2) {
  152                 return APR_ENOSPC;
  153             }
  154             *p++ = '%';
  155             memcpy(p, scbuf, strlen(scbuf) + 1);
  156         }
  157     }    
  158 #endif /* HAVE_IF_INDEXTONAME */
  159 #endif /* APR_HAVE_IPV6 */
  160 
  161     return APR_SUCCESS;
  162 }
  163 
  164 APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr,
  165                                               apr_sockaddr_t *sockaddr)
  166 {
  167     *addr = apr_palloc(sockaddr->pool, sockaddr->addr_str_len);
  168     return apr_sockaddr_ip_getbuf(*addr, sockaddr->addr_str_len, sockaddr);
  169 }
  170 
  171 void apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port)
  172 {
  173     addr->family = family;
  174     addr->sa.sin.sin_family = family;
  175     if (port) {
  176         /* XXX IPv6: assumes sin_port and sin6_port at same offset */
  177         addr->sa.sin.sin_port = htons(port);
  178         addr->port = port;
  179     }
  180 #if AIX_SERVNAME_HACK
  181     else {
  182         addr->sa.sin.sin_port = htons(port);
  183     }
  184 #endif
  185 
  186     if (family == APR_INET) {
  187         addr->salen = sizeof(struct sockaddr_in);
  188         addr->addr_str_len = 16;
  189         addr->ipaddr_ptr = &(addr->sa.sin.sin_addr);
  190         addr->ipaddr_len = sizeof(struct in_addr);
  191     }
  192 #if APR_HAVE_IPV6
  193     else if (family == APR_INET6) {
  194         addr->salen = sizeof(struct sockaddr_in6);
  195         addr->addr_str_len = 46;
  196         addr->ipaddr_ptr = &(addr->sa.sin6.sin6_addr);
  197         addr->ipaddr_len = sizeof(struct in6_addr);
  198     }
  199 #endif
  200 #if APR_HAVE_SOCKADDR_UN
  201     else if (family == APR_UNIX) {
  202         addr->salen = sizeof(struct sockaddr_un);
  203         addr->addr_str_len = sizeof(addr->sa.unx.sun_path);;
  204         addr->ipaddr_ptr = &(addr->sa.unx.sun_path);
  205         addr->ipaddr_len = addr->addr_str_len;
  206     }
  207 #endif
  208 }
  209 
  210 APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa,
  211                                            apr_interface_e which,
  212                                            apr_socket_t *sock)
  213 {
  214     if (which == APR_LOCAL) {
  215         if (sock->local_interface_unknown || sock->local_port_unknown) {
  216             apr_status_t rv = get_local_addr(sock);
  217 
  218             if (rv != APR_SUCCESS) {
  219                 return rv;
  220             }
  221         }
  222         *sa = sock->local_addr;
  223     }
  224     else if (which == APR_REMOTE) {
  225         if (sock->remote_addr_unknown) {
  226             apr_status_t rv = get_remote_addr(sock);
  227 
  228             if (rv != APR_SUCCESS) {
  229                 return rv;
  230             }
  231         }
  232         *sa = sock->remote_addr;
  233     }
  234     else {
  235         *sa = NULL;
  236         return APR_EINVAL;
  237     }
  238     return APR_SUCCESS;
  239 }
  240 
  241 APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr,
  242                                               char **scope_id,
  243                                               apr_port_t *port,
  244                                               const char *str,
  245                                               apr_pool_t *p)
  246 {
  247     const char *ch, *lastchar;
  248     int big_port;
  249     apr_size_t addrlen;
  250 
  251     *addr = NULL;         /* assume not specified */
  252     *scope_id = NULL;     /* assume not specified */
  253     *port = 0;            /* assume not specified */
  254 
  255     /* First handle the optional port number.  That may be all that
  256      * is specified in the string.
  257      */
  258     ch = lastchar = str + strlen(str) - 1;
  259     while (ch >= str && apr_isdigit(*ch)) {
  260         --ch;
  261     }
  262 
  263     if (ch < str) {       /* Entire string is the port. */
  264         big_port = atoi(str);
  265         if (big_port < 1 || big_port > 65535) {
  266             return APR_EINVAL;
  267         }
  268         *port = big_port;
  269         return APR_SUCCESS;
  270     }
  271 
  272     if (*ch == ':' && ch < lastchar) { /* host and port number specified */
  273         if (ch == str) {               /* string starts with ':' -- bad */
  274             return APR_EINVAL;
  275         }
  276         big_port = atoi(ch + 1);
  277         if (big_port < 1 || big_port > 65535) {
  278             return APR_EINVAL;
  279         }
  280         *port = big_port;
  281         lastchar = ch - 1;
  282     }
  283 
  284     /* now handle the hostname */
  285     addrlen = lastchar - str + 1;
  286 
  287 /* XXX we don't really have to require APR_HAVE_IPV6 for this; 
  288  * just pass char[] for ipaddr (so we don't depend on struct in6_addr)
  289  * and always define APR_INET6 
  290  */
  291 #if APR_HAVE_IPV6
  292     if (*str == '[') {
  293         const char *end_bracket = memchr(str, ']', addrlen);
  294         struct in6_addr ipaddr;
  295         const char *scope_delim;
  296 
  297         if (!end_bracket || end_bracket != lastchar) {
  298             *port = 0;
  299             return APR_EINVAL;
  300         }
  301 
  302         /* handle scope id; this is the only context where it is allowed */
  303         scope_delim = memchr(str, '%', addrlen);
  304         if (scope_delim) {
  305             if (scope_delim == end_bracket - 1) { /* '%' without scope id */
  306                 *port = 0;
  307                 return APR_EINVAL;
  308             }
  309             addrlen = scope_delim - str - 1;
  310             *scope_id = apr_pstrmemdup(p, scope_delim + 1, end_bracket - scope_delim - 1);
  311         }
  312         else {
  313             addrlen = addrlen - 2; /* minus 2 for '[' and ']' */
  314         }
  315 
  316         *addr = apr_pstrmemdup(p, str + 1, addrlen);
  317         if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) {
  318             *addr = NULL;
  319             *scope_id = NULL;
  320             *port = 0;
  321             return APR_EINVAL;
  322         }
  323     }
  324     else 
  325 #endif
  326     {
  327         /* XXX If '%' is not a valid char in a DNS name, we *could* check 
  328          *     for bogus scope ids first.
  329          */
  330         *addr = apr_pstrmemdup(p, str, addrlen);
  331     }
  332     return APR_SUCCESS;
  333 }
  334 
  335 #if defined(HAVE_GETADDRINFO)
  336 
  337 static apr_status_t call_resolver(apr_sockaddr_t **sa,
  338                                   const char *hostname, apr_int32_t family,
  339                                   apr_port_t port, apr_int32_t flags, 
  340                                   apr_pool_t *p)
  341 {
  342     struct addrinfo hints, *ai, *ai_list;
  343     apr_sockaddr_t *prev_sa;
  344     int error;
  345     char *servname = NULL; 
  346 
  347     memset(&hints, 0, sizeof(hints));
  348     hints.ai_family = family;
  349     hints.ai_socktype = SOCK_STREAM;
  350 #ifdef HAVE_GAI_ADDRCONFIG
  351     if (family == APR_UNSPEC) {
  352         /* By default, only look up addresses using address types for
  353          * which a local interface is configured, i.e. no IPv6 if no
  354          * IPv6 interfaces configured. */
  355         hints.ai_flags = AI_ADDRCONFIG;
  356     }
  357 #endif
  358 
  359 #ifdef __MVS__
  360     /* z/OS will not return IPv4 address under AF_UNSPEC if any IPv6 results 
  361      * are returned, w/o AI_ALL. 
  362      */
  363     if (family == APR_UNSPEC) { 
  364        hints.ai_flags |= AI_ALL;
  365     }
  366 #endif
  367 
  368     if(hostname == NULL) {
  369 #ifdef AI_PASSIVE 
  370         /* If hostname is NULL, assume we are trying to bind to all
  371          * interfaces. */
  372         hints.ai_flags |= AI_PASSIVE;
  373 #endif
  374         /* getaddrinfo according to RFC 2553 must have either hostname
  375          * or servname non-NULL.
  376          */
  377 #ifdef OSF1
  378         /* The Tru64 5.0 getaddrinfo() can only resolve services given
  379          * by the name listed in /etc/services; a numeric or unknown
  380          * servname gets an EAI_SERVICE error.  So just resolve the
  381          * appropriate anyaddr and fill in the port later. */
  382         hostname = family == AF_INET6 ? "::" : "0.0.0.0";
  383         servname = NULL;
  384 #ifdef AI_NUMERICHOST
  385         hints.ai_flags |= AI_NUMERICHOST;
  386 #endif
  387 #else
  388 #if AIX_SERVNAME_HACK
  389         if (!port) {
  390             servname = "1";
  391         }
  392         else
  393 #endif /* AIX_SERVNAME_HACK */
  394         servname = apr_itoa(p, port);
  395 #endif /* OSF1 */
  396     }
  397     error = getaddrinfo(hostname, servname, &hints, &ai_list);
  398 #ifdef HAVE_GAI_ADDRCONFIG
  399     /*
  400      * Using AI_ADDRCONFIG involves some unfortunate guesswork because it
  401      * does not consider loopback addresses when trying to determine if
  402      * IPv4 or IPv6 is configured on a system (see RFC 3493).
  403      * This is a problem if one actually wants to listen on or connect to
  404      * the loopback address of a protocol family that is not otherwise
  405      * configured on the system. See PR 52709.
  406      * To work around some of the problems, retry without AI_ADDRCONFIG
  407      * in case of EAI_ADDRFAMILY.
  408      * XXX: apr_sockaddr_info_get() should really accept a flag to determine
  409      * XXX: if AI_ADDRCONFIG's guesswork is wanted and if the address is
  410      * XXX: to be used for listen() or connect().
  411      *
  412      * In case of EAI_BADFLAGS, AI_ADDRCONFIG is not supported.
  413      */
  414     if ((family == APR_UNSPEC) && (error == EAI_BADFLAGS
  415 #ifdef EAI_ADDRFAMILY
  416                                    || error == EAI_ADDRFAMILY
  417 #endif
  418                                                              )) {
  419         hints.ai_flags &= ~AI_ADDRCONFIG;
  420         error = getaddrinfo(hostname, servname, &hints, &ai_list);
  421     }
  422 #endif
  423     if (error) {
  424 #if defined(WIN32)
  425         return apr_get_netos_error();
  426 #else
  427         if (error == EAI_SYSTEM) {
  428             return errno ? errno : APR_EGENERAL;
  429         }
  430         else 
  431         {
  432             /* issues with representing this with APR's error scheme:
  433              * glibc uses negative values for these numbers, perhaps so 
  434              * they don't conflict with h_errno values...  Tru64 uses 
  435              * positive values which conflict with h_errno values
  436              */
  437 #if defined(NEGATIVE_EAI)
  438             error = -error;
  439 #endif
  440             return error + APR_OS_START_EAIERR;
  441         }
  442 #endif /* WIN32 */
  443     }
  444 
  445     prev_sa = NULL;
  446     ai = ai_list;
  447     while (ai) { /* while more addresses to report */
  448         apr_sockaddr_t *new_sa;
  449 
  450         /* Ignore anything bogus: getaddrinfo in some old versions of
  451          * glibc will return AF_UNIX entries for APR_UNSPEC+AI_PASSIVE
  452          * lookups. */
  453 #if APR_HAVE_IPV6
  454         if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
  455 #else
  456         if (ai->ai_family != AF_INET) {
  457 #endif
  458             ai = ai->ai_next;
  459             continue;
  460         }
  461 
  462         new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
  463 
  464         new_sa->pool = p;
  465         memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen);
  466         apr_sockaddr_vars_set(new_sa, ai->ai_family, port);
  467 
  468         if (!prev_sa) { /* first element in new list */
  469             if (hostname) {
  470                 new_sa->hostname = apr_pstrdup(p, hostname);
  471             }
  472             *sa = new_sa;
  473         }
  474         else {
  475             new_sa->hostname = prev_sa->hostname;
  476             prev_sa->next = new_sa;
  477         }
  478 
  479         prev_sa = new_sa;
  480         ai = ai->ai_next;
  481     }
  482     freeaddrinfo(ai_list);
  483 
  484     if (prev_sa == NULL) {
  485         /*
  486          * getaddrinfo returned only useless entries and *sa is still empty.
  487          * This should be treated as an error.
  488          */
  489         return APR_EGENERAL;
  490     }
  491 
  492     return APR_SUCCESS;
  493 }
  494 
  495 static apr_status_t find_addresses(apr_sockaddr_t **sa, 
  496                                    const char *hostname, apr_int32_t family,
  497                                    apr_port_t port, apr_int32_t flags, 
  498                                    apr_pool_t *p)
  499 {
  500     if (flags & APR_IPV4_ADDR_OK) {
  501         apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p);
  502 
  503 #if APR_HAVE_IPV6
  504         if (error) {
  505             family = AF_INET6; /* try again */
  506         }
  507         else
  508 #endif
  509         return error;
  510     }
  511 #if APR_HAVE_IPV6
  512     else if (flags & APR_IPV6_ADDR_OK) {
  513         apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p);
  514 
  515         if (error) {
  516             family = AF_INET; /* try again */
  517         }
  518         else {
  519             return APR_SUCCESS;
  520         }
  521     }
  522 #endif
  523 
  524     return call_resolver(sa, hostname, family, port, flags, p);
  525 }
  526 
  527 #else /* end of HAVE_GETADDRINFO code */
  528 
  529 static apr_status_t find_addresses(apr_sockaddr_t **sa, 
  530                                    const char *hostname, apr_int32_t family,
  531                                    apr_port_t port, apr_int32_t flags, 
  532                                    apr_pool_t *p)
  533 {
  534     struct hostent *hp;
  535     apr_sockaddr_t *prev_sa;
  536     int curaddr;
  537 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
  538     defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS)
  539 #ifdef GETHOSTBYNAME_R_HOSTENT_DATA
  540     struct hostent_data hd;
  541 #else
  542     /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be
  543      * bumped. */
  544     char tmp[GETHOSTBYNAME_BUFLEN];
  545 #endif
  546     int hosterror;
  547 #endif
  548     struct hostent hs;
  549     struct in_addr ipaddr;
  550     char *addr_list[2];
  551     const char *orig_hostname = hostname;
  552 
  553     if (hostname == NULL) {
  554         /* if we are given a NULL hostname, assume '0.0.0.0' */
  555         hostname = "0.0.0.0";
  556     }
  557 
  558     if (*hostname >= '0' && *hostname <= '9' &&
  559         strspn(hostname, "0123456789.") == strlen(hostname)) {
  560 
  561         ipaddr.s_addr = inet_addr(hostname);
  562         addr_list[0] = (char *)&ipaddr;
  563         addr_list[1] = NULL; /* just one IP in list */
  564         hs.h_addr_list = (char **)addr_list;
  565         hp = &hs;
  566     }
  567     else {
  568 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
  569     defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS)
  570 #if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
  571         /* AIX, HP/UX, D/UX et alia */
  572         gethostbyname_r(hostname, &hs, &hd);
  573         hp = &hs;
  574 #else
  575 #if defined(GETHOSTBYNAME_R_GLIBC2)
  576         /* Linux glibc2+ */
  577         gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 
  578                         &hp, &hosterror);
  579 #else
  580         /* Solaris, Irix et alia */
  581         hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1,
  582                              &hosterror);
  583 #endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
  584         if (!hp) {
  585             return (hosterror + APR_OS_START_SYSERR);
  586         }
  587 #endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
  588 #else
  589         hp = gethostbyname(hostname);
  590 #endif
  591 
  592         if (!hp) {
  593 #ifdef WIN32
  594             return apr_get_netos_error();
  595 #else
  596             return (h_errno + APR_OS_START_SYSERR);
  597 #endif
  598         }
  599     }
  600 
  601     prev_sa = NULL;
  602     curaddr = 0;
  603     while (hp->h_addr_list[curaddr]) {
  604         apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
  605 
  606         new_sa->pool = p;
  607         new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr];
  608         apr_sockaddr_vars_set(new_sa, AF_INET, port);
  609 
  610         if (!prev_sa) { /* first element in new list */
  611             if (orig_hostname) {
  612                 new_sa->hostname = apr_pstrdup(p, orig_hostname);
  613             }
  614             *sa = new_sa;
  615         }
  616         else {
  617             new_sa->hostname = prev_sa->hostname;
  618             prev_sa->next = new_sa;
  619         }
  620 
  621         prev_sa = new_sa;
  622         ++curaddr;
  623     }
  624 
  625     if (prev_sa == NULL) {
  626         /* this should not happen but no result should be treated as error */
  627         return APR_EGENERAL;
  628     }
  629 
  630     return APR_SUCCESS;
  631 }
  632 
  633 #endif /* end of !HAVE_GETADDRINFO code */
  634 
  635 APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa,
  636                                                 const char *hostname, 
  637                                                 apr_int32_t family, apr_port_t port,
  638                                                 apr_int32_t flags, apr_pool_t *p)
  639 {
  640     apr_int32_t masked;
  641     *sa = NULL;
  642 
  643     if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) {
  644         if (!hostname ||
  645             family != APR_UNSPEC ||
  646             masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) {
  647             return APR_EINVAL;
  648         }
  649 #if !APR_HAVE_IPV6
  650         if (flags & APR_IPV6_ADDR_OK) {
  651             return APR_ENOTIMPL;
  652         }
  653 #endif
  654     }
  655     if (family == APR_UNSPEC && hostname && *hostname == '/') {
  656         family = APR_UNIX;
  657     }
  658     if (family == APR_UNIX) {
  659 #if APR_HAVE_SOCKADDR_UN
  660         if (hostname && *hostname == '/') {
  661             *sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
  662             (*sa)->pool = p;
  663             apr_cpystrn((*sa)->sa.unx.sun_path, hostname,
  664                         sizeof((*sa)->sa.unx.sun_path));
  665             (*sa)->hostname = apr_pstrdup(p, hostname);
  666             (*sa)->family = APR_UNIX;
  667             (*sa)->sa.unx.sun_family = APR_UNIX;
  668             (*sa)->salen = sizeof(struct sockaddr_un);
  669             (*sa)->addr_str_len = sizeof((*sa)->sa.unx.sun_path);
  670             (*sa)->ipaddr_ptr = &((*sa)->sa.unx.sun_path);
  671             (*sa)->ipaddr_len = (*sa)->addr_str_len;
  672 
  673             return APR_SUCCESS;
  674         }
  675         else
  676 #endif
  677         {
  678             *sa = NULL;
  679             return APR_ENOTIMPL;
  680         }
  681     }
  682 #if !APR_HAVE_IPV6
  683     /* What may happen is that APR is not IPv6-enabled, but we're still
  684      * going to call getaddrinfo(), so we have to tell the OS we only
  685      * want IPv4 addresses back since we won't know what to do with
  686      * IPv6 addresses.
  687      */
  688     if (family == APR_UNSPEC) {
  689         family = APR_INET;
  690     }
  691 #endif
  692 
  693     return find_addresses(sa, hostname, family, port, flags, p);
  694 }
  695 
  696 APR_DECLARE(apr_status_t) apr_sockaddr_info_copy(apr_sockaddr_t **dst,
  697                                                  const apr_sockaddr_t *src,
  698                                                  apr_pool_t *p)
  699 {
  700     apr_sockaddr_t *d;
  701     const apr_sockaddr_t *s;
  702 
  703     for (*dst = d = NULL, s = src; s; s = s->next) {
  704         if (!d) {
  705             *dst = d = apr_pmemdup(p, s, sizeof *s);
  706         }
  707         else {
  708             d = d->next = apr_pmemdup(p, s, sizeof *s);
  709         }
  710         if (s->hostname) {
  711             if (s == src || s->hostname != src->hostname) {
  712                 d->hostname = apr_pstrdup(p, s->hostname);
  713             }
  714             else {
  715                 d->hostname = (*dst)->hostname;
  716             }
  717         }
  718         if (s->servname) {
  719             if (s == src || s->servname != src->servname) {
  720                 d->servname = apr_pstrdup(p, s->servname);
  721             }
  722             else {
  723                 d->servname = (*dst)->servname;
  724             }
  725         }
  726         d->pool = p;
  727         apr_sockaddr_vars_set(d, s->family, s->port);
  728     }
  729     return APR_SUCCESS;
  730 }
  731 
  732 APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname,
  733                                           apr_sockaddr_t *sockaddr,
  734                                           apr_int32_t flags)
  735 {
  736 #if defined(HAVE_GETNAMEINFO)
  737     int rc;
  738 #if defined(NI_MAXHOST)
  739     char tmphostname[NI_MAXHOST];
  740 #else
  741     char tmphostname[256];
  742 #endif
  743 
  744     /* don't know if it is portable for getnameinfo() to set h_errno;
  745      * clear it then see if it was set */
  746     SET_H_ERRNO(0);
  747 
  748     /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return
  749      * a numeric address string if it fails to resolve the host name;
  750      * that is *not* what we want here
  751      *
  752      * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling
  753      * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc).
  754      */
  755 #if APR_HAVE_IPV6
  756     if (sockaddr->family == AF_INET6 &&
  757         IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) {
  758         struct sockaddr_in tmpsa;
  759         tmpsa.sin_family = AF_INET;
  760         tmpsa.sin_port = 0;
  761         tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];
  762 #ifdef SIN6_LEN
  763         tmpsa.sin_len = sizeof(tmpsa);
  764 #endif
  765 
  766         rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),
  767                          tmphostname, sizeof(tmphostname), NULL, 0,
  768                          flags != 0 ? flags : NI_NAMEREQD);
  769     }
  770 #if APR_HAVE_SOCKADDR_UN
  771     else if (sockaddr->family == APR_UNIX) {
  772         *hostname = sockaddr->hostname;
  773         return APR_SUCCESS;
  774     }
  775 #endif
  776     else
  777 #endif
  778     rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
  779                      tmphostname, sizeof(tmphostname), NULL, 0,
  780                      flags != 0 ? flags : NI_NAMEREQD);
  781     if (rc != 0) {
  782         *hostname = NULL;
  783 
  784 #ifndef WIN32
  785         /* something went wrong. Look at the EAI_ error code */
  786         if (rc == EAI_SYSTEM) {
  787             /* EAI_SYSTEM      System error returned in errno. */
  788             /* IMHO, Implementations that set h_errno a simply broken. */
  789             if (h_errno) { /* for broken implementations which set h_errno */
  790                 return h_errno + APR_OS_START_SYSERR;
  791             }
  792             else { /* "normal" case */
  793                 return errno + APR_OS_START_SYSERR;
  794             }
  795         }
  796         else 
  797 #endif
  798         {
  799 #if defined(NEGATIVE_EAI)
  800             if (rc < 0) rc = -rc;
  801 #endif
  802             return rc + APR_OS_START_EAIERR; /* return the EAI_ error */
  803         }
  804     }
  805     *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, 
  806                                                  tmphostname);
  807     return APR_SUCCESS;
  808 #else
  809 #if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \
  810     defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS)
  811 #ifdef GETHOSTBYNAME_R_HOSTENT_DATA
  812     struct hostent_data hd;
  813 #else
  814     char tmp[GETHOSTBYNAME_BUFLEN];
  815 #endif
  816     int hosterror;
  817     struct hostent hs, *hptr;
  818 
  819 #if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
  820     /* AIX, HP/UX, D/UX et alia */
  821     gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 
  822                   sizeof(struct in_addr), AF_INET, &hs, &hd);
  823     hptr = &hs;
  824 #else
  825 #if defined(GETHOSTBYNAME_R_GLIBC2)
  826     /* Linux glibc2+ */
  827     gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 
  828                     sizeof(struct in_addr), AF_INET,
  829                     &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror);
  830 #else
  831     /* Solaris, Irix et alia */
  832     hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 
  833                            sizeof(struct in_addr), AF_INET,
  834                            &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror);
  835 #endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
  836     if (!hptr) {
  837         *hostname = NULL;
  838         return hosterror + APR_OS_START_SYSERR;
  839     }
  840 #endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
  841 #else
  842     struct hostent *hptr;
  843     hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, 
  844                          sizeof(struct in_addr), AF_INET);
  845 #endif
  846 
  847     if (hptr) {
  848         *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name);
  849         return APR_SUCCESS;
  850     }
  851     *hostname = NULL;
  852 #if defined(WIN32)
  853     return apr_get_netos_error();
  854 #elif defined(OS2)
  855     return h_errno;
  856 #else
  857     return h_errno + APR_OS_START_SYSERR;
  858 #endif
  859 #endif
  860 }
  861 
  862 APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr,
  863                                             const char *servname)
  864 {
  865 #if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \
  866     defined(HAVE_GETSERVBYNAME_R) && \
  867     (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \
  868      defined(GETSERVBYNAME_R_OSF1))
  869     struct servent se;
  870 #if defined(GETSERVBYNAME_R_OSF1)
  871     struct servent_data sed;
  872 
  873     memset(&sed, 0, sizeof(sed)); /* must zero fill before use */
  874 #else
  875 #if defined(GETSERVBYNAME_R_GLIBC2)
  876     struct servent *res;
  877 #endif
  878     char buf[1024];
  879 #endif
  880 #else
  881     struct servent *se;
  882 #endif
  883 
  884     if (servname == NULL)
  885         return APR_EINVAL;
  886 
  887 #if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \
  888     defined(HAVE_GETSERVBYNAME_R) && \
  889     (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \
  890      defined(GETSERVBYNAME_R_OSF1))
  891 #if defined(GETSERVBYNAME_R_GLIBC2)
  892     if (getservbyname_r(servname, NULL,
  893                         &se, buf, sizeof(buf), &res) == 0 && res != NULL) {
  894         sockaddr->port = ntohs(res->s_port);
  895         sockaddr->servname = apr_pstrdup(sockaddr->pool, servname);
  896         sockaddr->sa.sin.sin_port = res->s_port;
  897         return APR_SUCCESS;
  898     }
  899 #elif defined(GETSERVBYNAME_R_SOLARIS)
  900     if (getservbyname_r(servname, NULL, &se, buf, sizeof(buf)) != NULL) {
  901         sockaddr->port = ntohs(se.s_port);
  902         sockaddr->servname = apr_pstrdup(sockaddr->pool, servname);
  903         sockaddr->sa.sin.sin_port = se.s_port;
  904         return APR_SUCCESS;
  905     }
  906 #elif defined(GETSERVBYNAME_R_OSF1)
  907     if (getservbyname_r(servname, NULL, &se, &sed) == 0) {
  908         sockaddr->port = ntohs(se.s_port);
  909         sockaddr->servname = apr_pstrdup(sockaddr->pool, servname);
  910         sockaddr->sa.sin.sin_port = se.s_port;
  911         return APR_SUCCESS;
  912     }
  913 #endif
  914 #else
  915     if ((se = getservbyname(servname, NULL)) != NULL){
  916         sockaddr->port = ntohs(se->s_port);
  917         sockaddr->servname = apr_pstrdup(sockaddr->pool, servname);
  918         sockaddr->sa.sin.sin_port = se->s_port;
  919         return APR_SUCCESS;
  920     }
  921 #endif
  922     return APR_ENOENT;
  923 }
  924 
  925 #define V4MAPPED_EQUAL(a,b)                                   \
  926 ((a)->sa.sin.sin_family == AF_INET &&                         \
  927  (b)->sa.sin.sin_family == AF_INET6 &&                        \
  928  IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) &&  \
  929  !memcmp((a)->ipaddr_ptr,                                     \
  930          &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12],  \
  931          (a)->ipaddr_len))
  932 
  933 #if APR_HAVE_IPV6
  934 #define SCOPE_OR_ZERO(sa_) ((sa_)->family != AF_INET6 ? 0 :   \
  935                             ((sa_)->sa.sin6.sin6_scope_id))
  936 #else
  937 #define SCOPE_OR_ZERO(sa_) (0)
  938 #endif
  939 
  940 APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1,
  941                                     const apr_sockaddr_t *addr2)
  942 {
  943     if (addr1->ipaddr_len == addr2->ipaddr_len
  944         && !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len)
  945         && SCOPE_OR_ZERO(addr1) == SCOPE_OR_ZERO(addr2)) {
  946         return 1;
  947     }
  948 #if APR_HAVE_IPV6
  949     if (V4MAPPED_EQUAL(addr1, addr2)) {
  950         return 1;
  951     }
  952     if (V4MAPPED_EQUAL(addr2, addr1)) {
  953         return 1;
  954     }
  955 #endif
  956     return 0; /* not equal */
  957 }
  958 
  959 APR_DECLARE(int) apr_sockaddr_is_wildcard(const apr_sockaddr_t *addr)
  960 {
  961     static const char inaddr_any[
  962 #if APR_HAVE_IPV6
  963         sizeof(struct in6_addr)
  964 #else
  965         sizeof(struct in_addr)
  966 #endif
  967     ] = {0};
  968 
  969     if (addr->ipaddr_ptr /* IP address initialized */
  970         && addr->ipaddr_len <= sizeof inaddr_any) { /* else bug elsewhere? */
  971         if (!memcmp(inaddr_any, addr->ipaddr_ptr, addr->ipaddr_len)) {
  972             return 1;
  973         }
  974 #if APR_HAVE_IPV6
  975     if (addr->family == AF_INET6
  976         && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr)) {
  977         struct in_addr *v4 = (struct in_addr *)&((apr_uint32_t *)addr->ipaddr_ptr)[3];
  978 
  979         if (!memcmp(inaddr_any, v4, sizeof *v4)) {
  980             return 1;
  981         }
  982     }
  983 #endif
  984     }
  985     return 0;
  986 }
  987 
  988 static apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network)
  989 {
  990     /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */
  991     int shift;
  992     char *s, *t;
  993     int octet;
  994     char buf[sizeof "255.255.255.255"];
  995 
  996     if (strlen(network) < sizeof buf) {
  997         strcpy(buf, network);
  998     }
  999     else {
 1000         return APR_EBADIP;
 1001     }
 1002 
 1003     /* parse components */
 1004     s = buf;
 1005     ipsub->sub[0] = 0;
 1006     ipsub->mask[0] = 0;
 1007     shift = 24;
 1008     while (*s) {
 1009         t = s;
 1010         if (!apr_isdigit(*t)) {
 1011             return APR_EBADIP;
 1012         }
 1013         while (apr_isdigit(*t)) {
 1014             ++t;
 1015         }
 1016         if (*t == '.') {
 1017             *t++ = 0;
 1018         }
 1019         else if (*t) {
 1020             return APR_EBADIP;
 1021         }
 1022         if (shift < 0) {
 1023             return APR_EBADIP;
 1024         }
 1025         octet = atoi(s);
 1026         if (octet < 0 || octet > 255) {
 1027             return APR_EBADIP;
 1028         }
 1029         ipsub->sub[0] |= octet << shift;
 1030         ipsub->mask[0] |= 0xFFUL << shift;
 1031         s = t;
 1032         shift -= 8;
 1033     }
 1034     ipsub->sub[0] = ntohl(ipsub->sub[0]);
 1035     ipsub->mask[0] = ntohl(ipsub->mask[0]);
 1036     ipsub->family = AF_INET;
 1037     return APR_SUCCESS;
 1038 }
 1039 
 1040 /* return values:
 1041  * APR_EINVAL     not an IP address; caller should see if it is something else
 1042  * APR_BADIP      IP address portion is is not valid
 1043  * APR_BADMASK    mask portion is not valid
 1044  */
 1045 
 1046 static apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed)
 1047 {
 1048     /* supported flavors of IP:
 1049      *
 1050      * . IPv6 numeric address string (e.g., "fe80::1")
 1051      * 
 1052      *   IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address.
 1053      *
 1054      * . IPv4 numeric address string (e.g., "127.0.0.1")
 1055      *
 1056      * . IPv4 network string (e.g., "9.67")
 1057      *
 1058      *   IMPORTANT: This network form is only allowed if network_allowed is on.
 1059      */
 1060     int rc;
 1061 
 1062 #if APR_HAVE_IPV6
 1063     rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub);
 1064     if (rc == 1) {
 1065         if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) {
 1066             /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6
 1067              * addresses; this of course forces the user to specify IPv4 addresses
 1068              * in a.b.c.d style instead of ::ffff:a.b.c.d style.
 1069              */
 1070             return APR_EBADIP;
 1071         }
 1072         ipsub->family = AF_INET6;
 1073     }
 1074     else
 1075 #endif
 1076     {
 1077         rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub);
 1078         if (rc == 1) {
 1079             ipsub->family = AF_INET;
 1080         }
 1081     }
 1082     if (rc != 1) {
 1083         if (network_allowed) {
 1084             return parse_network(ipsub, ipstr);
 1085         }
 1086         else {
 1087             return APR_EBADIP;
 1088         }
 1089     }
 1090     return APR_SUCCESS;
 1091 }
 1092 
 1093 static int looks_like_ip(const char *ipstr)
 1094 {
 1095     if (strlen(ipstr) == 0) {
 1096         return 0;
 1097     }
 1098     
 1099     if (strchr(ipstr, ':')) {
 1100         /* definitely not a hostname; assume it is intended to be an IPv6 address */
 1101         return 1;
 1102     }
 1103 
 1104     /* simple IPv4 address string check */
 1105     while ((*ipstr == '.') || apr_isdigit(*ipstr))
 1106         ipstr++;
 1107     return (*ipstr == '\0');
 1108 }
 1109 
 1110 static void fix_subnet(apr_ipsubnet_t *ipsub)
 1111 {
 1112     /* in case caller specified more bits in network address than are
 1113      * valid according to the mask, turn off the extra bits
 1114      */
 1115     int i;
 1116 
 1117     for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) {
 1118         ipsub->sub[i] &= ipsub->mask[i];
 1119     }
 1120 }
 1121 
 1122 /* be sure not to store any IPv4 address as a v4-mapped IPv6 address */
 1123 APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, 
 1124                                               const char *mask_or_numbits, apr_pool_t *p)
 1125 {
 1126     apr_status_t rv;
 1127     char *endptr;
 1128     long bits, maxbits = 32;
 1129 
 1130     /* filter out stuff which doesn't look remotely like an IP address; this helps 
 1131      * callers like mod_access which have a syntax allowing hostname or IP address;
 1132      * APR_EINVAL tells the caller that it was probably not intended to be an IP
 1133      * address
 1134      */
 1135     if (!looks_like_ip(ipstr)) {
 1136         return APR_EINVAL;
 1137     }
 1138 
 1139     *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t));
 1140 
 1141     /* assume ipstr is an individual IP address, not a subnet */
 1142     memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask);
 1143 
 1144     rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL);
 1145     if (rv != APR_SUCCESS) {
 1146         return rv;
 1147     }
 1148 
 1149     if (mask_or_numbits) {
 1150 #if APR_HAVE_IPV6
 1151         if ((*ipsub)->family == AF_INET6) {
 1152             maxbits = 128;
 1153         }
 1154 #endif
 1155         bits = strtol(mask_or_numbits, &endptr, 10);
 1156         if (*endptr == '\0' && bits > 0 && bits <= maxbits) {
 1157             /* valid num-bits string; fill in mask appropriately */
 1158             int cur_entry = 0;
 1159             apr_int32_t cur_bit_value;
 1160 
 1161             memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask);
 1162             while (bits > 32) {
 1163                 (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */
 1164                 bits -= 32;
 1165                 ++cur_entry;
 1166             }
 1167             cur_bit_value = 0x80000000;
 1168             while (bits) {
 1169                 (*ipsub)->mask[cur_entry] |= cur_bit_value;
 1170                 --bits;
 1171                 cur_bit_value /= 2;
 1172             }
 1173             (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]);
 1174         }
 1175         else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 &&
 1176             (*ipsub)->family == AF_INET) {
 1177             /* valid IPv4 netmask */
 1178         }
 1179         else {
 1180             return APR_EBADMASK;
 1181         }
 1182     }
 1183 
 1184     fix_subnet(*ipsub);
 1185 
 1186     return APR_SUCCESS;
 1187 }
 1188 
 1189 APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa)
 1190 {
 1191 #if APR_HAVE_IPV6
 1192     /* XXX This line will segv on Win32 build with APR_HAVE_IPV6,
 1193      * but without the IPV6 drivers installed.
 1194      */
 1195     if (sa->family == AF_INET) {
 1196         if (ipsub->family == AF_INET &&
 1197             ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) {
 1198             return 1;
 1199         }
 1200     }
 1201     else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) {
 1202         if (ipsub->family == AF_INET &&
 1203             (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) {
 1204             return 1;
 1205         }
 1206     }
 1207     else if (sa->family == AF_INET6 && ipsub->family == AF_INET6) {
 1208         apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr;
 1209 
 1210         if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] &&
 1211             (addr[1] & ipsub->mask[1]) == ipsub->sub[1] &&
 1212             (addr[2] & ipsub->mask[2]) == ipsub->sub[2] &&
 1213             (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) {
 1214             return 1;
 1215         }
 1216     }
 1217 #else
 1218     if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) {
 1219         return 1;
 1220     }
 1221 #endif /* APR_HAVE_IPV6 */
 1222     return 0; /* no match */
 1223 }
 1224 
 1225 APR_DECLARE(apr_status_t) apr_sockaddr_zone_set(apr_sockaddr_t *sa,
 1226                                                 const char *zone_id)
 1227 {
 1228 #if !APR_HAVE_IPV6 || !defined(HAVE_IF_NAMETOINDEX)
 1229     return APR_ENOTIMPL;
 1230 #else
 1231     unsigned int idx;
 1232     
 1233     if (sa->family != APR_INET6
 1234         || !IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)sa->ipaddr_ptr)) {
 1235         return APR_EBADIP;
 1236     }
 1237 
 1238     idx = if_nametoindex(zone_id);
 1239     if (idx) {
 1240         sa->sa.sin6.sin6_scope_id = idx;
 1241         return APR_SUCCESS;
 1242     }
 1243 
 1244     if (errno != ENODEV) {
 1245         return errno;
 1246     }
 1247     else {
 1248         char *endptr;
 1249         apr_int64_t i = apr_strtoi64(zone_id, &endptr, 10);
 1250 
 1251         if (*endptr != '\0' || errno || i < 1 || i > APR_INT16_MAX) {
 1252             return APR_EGENERAL;
 1253         }
 1254 
 1255         sa->sa.sin6.sin6_scope_id = (unsigned int) i;
 1256         return APR_SUCCESS;
 1257     }
 1258 #endif
 1259 }
 1260 
 1261 APR_DECLARE(apr_status_t) apr_sockaddr_zone_get(const apr_sockaddr_t *sa,
 1262                                                 const char **name,
 1263                                                 apr_uint32_t *id,
 1264                                                 apr_pool_t *p)
 1265 {
 1266 #if !APR_HAVE_IPV6 || !defined(HAVE_IF_INDEXTONAME)
 1267     return APR_ENOTIMPL;
 1268 #else
 1269     if (sa->family != APR_INET6 || !sa->sa.sin6.sin6_scope_id) {
 1270         return APR_EBADIP;
 1271     }        
 1272 
 1273     if (name) {
 1274         char *buf = apr_palloc(p, IF_NAMESIZE);
 1275         if (if_indextoname(sa->sa.sin6.sin6_scope_id, buf) == NULL)
 1276             return errno;
 1277         *name = buf;
 1278     }
 1279 
 1280     if (id) *id = sa->sa.sin6.sin6_scope_id;
 1281     
 1282     return APR_SUCCESS;
 1283 #endif
 1284 }