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