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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "apr_arch_networkio.h"
18 #include "apr_strings.h"
21 #include "apr_strings.h"
22 #include "apr_private.h"
28 #define APR_WANT_STRFUNC
31 struct apr_ipsubnet_t {
34 apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
42 #if !defined(NETWARE) && !defined(WIN32)
43 #ifdef HAVE_SET_H_ERRNO
44 #define SET_H_ERRNO(newval) set_h_errno(newval)
46 #define SET_H_ERRNO(newval) h_errno = (newval)
49 #define SET_H_ERRNO(newval)
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.
58 #define GETHOSTBYNAME_BUFLEN 512
62 /* XXX: BS solution. Need an HAVE_GETSERVBYNAME and actually
63 * do something here, to provide the obvious proto mappings.
65 static void *getservbyname(const char *name, const char *proto)
71 static apr_status_t get_local_addr(apr_socket_t *sock)
73 sock->local_addr->salen = sizeof(sock->local_addr->sa);
74 if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa,
75 &sock->local_addr->salen) < 0) {
76 return apr_get_netos_error();
79 sock->local_port_unknown = sock->local_interface_unknown = 0;
80 /* XXX assumes sin_port and sin6_port at same offset */
81 sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port);
86 static apr_status_t get_remote_addr(apr_socket_t *sock)
88 sock->remote_addr->salen = sizeof(sock->remote_addr->sa);
89 if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa,
90 &sock->remote_addr->salen) < 0) {
91 return apr_get_netos_error();
94 sock->remote_addr_unknown = 0;
95 /* XXX assumes sin_port and sin6_port at same offset */
96 sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port);
101 APR_DECLARE(apr_status_t) apr_sockaddr_port_set(apr_sockaddr_t *sockaddr,
104 sockaddr->port = port;
105 /* XXX IPv6: assumes sin_port and sin6_port at same offset */
106 sockaddr->sa.sin.sin_port = htons(port);
110 /* XXX assumes IPv4... I don't think this function is needed anyway
111 * since we have apr_sockaddr_info_get(), but we need to clean up Apache's
112 * listen.c a bit more first.
114 APR_DECLARE(apr_status_t) apr_sockaddr_ip_set(apr_sockaddr_t *sockaddr,
119 if (!strcmp(addr, APR_ANYADDR)) {
120 sockaddr->sa.sin.sin_addr.s_addr = htonl(INADDR_ANY);
124 ipaddr = inet_addr(addr);
125 if (ipaddr == (apr_uint32_t)-1) {
127 return WSAEADDRNOTAVAIL;
133 sockaddr->sa.sin.sin_addr.s_addr = ipaddr;
137 APR_DECLARE(apr_status_t) apr_sockaddr_port_get(apr_port_t *port,
138 apr_sockaddr_t *sockaddr)
140 *port = sockaddr->port;
144 APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr,
145 apr_sockaddr_t *sockaddr)
147 *addr = apr_palloc(sockaddr->pool, sockaddr->addr_str_len);
148 apr_inet_ntop(sockaddr->family,
149 sockaddr->ipaddr_ptr,
151 sockaddr->addr_str_len);
153 if (sockaddr->family == AF_INET6 &&
154 IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sockaddr->ipaddr_ptr)) {
155 /* This is an IPv4-mapped IPv6 address; drop the leading
156 * part of the address string so we're left with the familiar
159 *addr += strlen("::ffff:");
165 void apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port)
167 addr->family = family;
168 addr->sa.sin.sin_family = family;
170 /* XXX IPv6: assumes sin_port and sin6_port at same offset */
171 addr->sa.sin.sin_port = htons(port);
175 if (family == APR_INET) {
176 addr->salen = sizeof(struct sockaddr_in);
177 addr->addr_str_len = 16;
178 addr->ipaddr_ptr = &(addr->sa.sin.sin_addr);
179 addr->ipaddr_len = sizeof(struct in_addr);
182 else if (family == APR_INET6) {
183 addr->salen = sizeof(struct sockaddr_in6);
184 addr->addr_str_len = 46;
185 addr->ipaddr_ptr = &(addr->sa.sin6.sin6_addr);
186 addr->ipaddr_len = sizeof(struct in6_addr);
191 APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa,
192 apr_interface_e which,
195 if (which == APR_LOCAL) {
196 if (sock->local_interface_unknown || sock->local_port_unknown) {
197 apr_status_t rv = get_local_addr(sock);
199 if (rv != APR_SUCCESS) {
203 *sa = sock->local_addr;
205 else if (which == APR_REMOTE) {
206 if (sock->remote_addr_unknown) {
207 apr_status_t rv = get_remote_addr(sock);
209 if (rv != APR_SUCCESS) {
213 *sa = sock->remote_addr;
222 APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr,
228 const char *ch, *lastchar;
232 *addr = NULL; /* assume not specified */
233 *scope_id = NULL; /* assume not specified */
234 *port = 0; /* assume not specified */
236 /* First handle the optional port number. That may be all that
237 * is specified in the string.
239 ch = lastchar = str + strlen(str) - 1;
240 while (ch >= str && apr_isdigit(*ch)) {
244 if (ch < str) { /* Entire string is the port. */
245 big_port = atoi(str);
246 if (big_port < 1 || big_port > 65535) {
253 if (*ch == ':' && ch < lastchar) { /* host and port number specified */
254 if (ch == str) { /* string starts with ':' -- bad */
257 big_port = atoi(ch + 1);
258 if (big_port < 1 || big_port > 65535) {
265 /* now handle the hostname */
266 addrlen = lastchar - str + 1;
268 /* XXX we don't really have to require APR_HAVE_IPV6 for this;
269 * just pass char[] for ipaddr (so we don't depend on struct in6_addr)
270 * and always define APR_INET6
274 const char *end_bracket = memchr(str, ']', addrlen);
275 struct in6_addr ipaddr;
276 const char *scope_delim;
278 if (!end_bracket || end_bracket != lastchar) {
283 /* handle scope id; this is the only context where it is allowed */
284 scope_delim = memchr(str, '%', addrlen);
286 if (scope_delim == end_bracket - 1) { /* '%' without scope id */
290 addrlen = scope_delim - str - 1;
291 *scope_id = apr_palloc(p, end_bracket - scope_delim);
292 memcpy(*scope_id, scope_delim + 1, end_bracket - scope_delim - 1);
293 (*scope_id)[end_bracket - scope_delim - 1] = '\0';
296 addrlen = addrlen - 2; /* minus 2 for '[' and ']' */
299 *addr = apr_palloc(p, addrlen + 1);
303 (*addr)[addrlen] = '\0';
304 if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) {
314 /* XXX If '%' is not a valid char in a DNS name, we *could* check
315 * for bogus scope ids first.
317 *addr = apr_palloc(p, addrlen + 1);
318 memcpy(*addr, str, addrlen);
319 (*addr)[addrlen] = '\0';
324 #if defined(HAVE_GETADDRINFO)
326 static apr_status_t call_resolver(apr_sockaddr_t **sa,
327 const char *hostname, apr_int32_t family,
328 apr_port_t port, apr_int32_t flags,
331 struct addrinfo hints, *ai, *ai_list;
332 apr_sockaddr_t *prev_sa;
334 char *servname = NULL;
336 memset(&hints, 0, sizeof(hints));
337 hints.ai_family = family;
338 hints.ai_socktype = SOCK_STREAM;
339 if(hostname == NULL) {
341 /* If hostname is NULL, assume we are trying to bind to all
343 hints.ai_flags |= AI_PASSIVE;
345 /* getaddrinfo according to RFC 2553 must have either hostname
346 * or servname non-NULL.
349 /* But current AIX getaddrinfo() doesn't like servname = "0";
350 * the "1" won't hurt since we use the port parameter to fill
351 * in the returned socket addresses later
358 servname = apr_itoa(p, port);
360 error = getaddrinfo(hostname, servname, &hints, &ai_list);
363 if (error == EAI_SYSTEM) {
369 /* issues with representing this with APR's error scheme:
370 * glibc uses negative values for these numbers, perhaps so
371 * they don't conflict with h_errno values... Tru64 uses
372 * positive values which conflict with h_errno values
374 #if defined(NEGATIVE_EAI)
377 return error + APR_OS_START_EAIERR;
383 while (ai) { /* while more addresses to report */
384 apr_sockaddr_t *new_sa;
386 /* Ignore anything bogus: getaddrinfo in some old versions of
387 * glibc will return AF_UNIX entries for AF_UNSPEC+AI_PASSIVE
389 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
394 new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
397 memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen);
398 apr_sockaddr_vars_set(new_sa, ai->ai_family, port);
400 if (!prev_sa) { /* first element in new list */
402 new_sa->hostname = apr_pstrdup(p, hostname);
407 new_sa->hostname = prev_sa->hostname;
408 prev_sa->next = new_sa;
414 freeaddrinfo(ai_list);
418 static apr_status_t find_addresses(apr_sockaddr_t **sa,
419 const char *hostname, apr_int32_t family,
420 apr_port_t port, apr_int32_t flags,
423 if (flags & APR_IPV4_ADDR_OK) {
424 apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p);
428 family = AF_INET6; /* try again */
435 else if (flags & APR_IPV6_ADDR_OK) {
436 apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p);
439 family = AF_INET; /* try again */
447 return call_resolver(sa, hostname, family, port, flags, p);
450 #else /* end of HAVE_GETADDRINFO code */
452 static apr_status_t find_addresses(apr_sockaddr_t **sa,
453 const char *hostname, apr_int32_t family,
454 apr_port_t port, apr_int32_t flags,
458 apr_sockaddr_t *prev_sa;
460 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
461 defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS)
462 #ifdef GETHOSTBYNAME_R_HOSTENT_DATA
463 struct hostent_data hd;
465 /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be
467 char tmp[GETHOSTBYNAME_BUFLEN];
472 struct in_addr ipaddr;
474 const char *orig_hostname = hostname;
476 if (hostname == NULL) {
477 /* if we are given a NULL hostname, assume '0.0.0.0' */
478 hostname = "0.0.0.0";
481 if (*hostname >= '0' && *hostname <= '9' &&
482 strspn(hostname, "0123456789.") == strlen(hostname)) {
484 ipaddr.s_addr = inet_addr(hostname);
485 addr_list[0] = (char *)&ipaddr;
486 addr_list[1] = NULL; /* just one IP in list */
487 hs.h_addr_list = (char **)addr_list;
491 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
492 defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS)
493 #if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
494 /* AIX, HP/UX, D/UX et alia */
495 gethostbyname_r(hostname, &hs, &hd);
498 #if defined(GETHOSTBYNAME_R_GLIBC2)
500 gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1,
503 /* Solaris, Irix et alia */
504 hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1,
506 #endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
508 return (hosterror + APR_OS_START_SYSERR);
510 #endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
512 hp = gethostbyname(hostname);
517 return apr_get_netos_error();
519 return (h_errno + APR_OS_START_SYSERR);
526 while (hp->h_addr_list[curaddr]) {
527 apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
530 new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr];
531 apr_sockaddr_vars_set(new_sa, AF_INET, port);
533 if (!prev_sa) { /* first element in new list */
535 new_sa->hostname = apr_pstrdup(p, orig_hostname);
540 new_sa->hostname = prev_sa->hostname;
541 prev_sa->next = new_sa;
551 #endif /* end of !HAVE_GETADDRINFO code */
553 APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa,
554 const char *hostname,
555 apr_int32_t family, apr_port_t port,
556 apr_int32_t flags, apr_pool_t *p)
561 if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) {
563 family != AF_UNSPEC ||
564 masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) {
568 if (flags & APR_IPV6_ADDR_OK) {
574 /* What may happen is that APR is not IPv6-enabled, but we're still
575 * going to call getaddrinfo(), so we have to tell the OS we only
576 * want IPv4 addresses back since we won't know what to do with
579 if (family == APR_UNSPEC) {
584 return find_addresses(sa, hostname, family, port, flags, p);
587 APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname,
588 apr_sockaddr_t *sockaddr,
591 #if defined(HAVE_GETNAMEINFO)
593 #if defined(NI_MAXHOST)
594 char tmphostname[NI_MAXHOST];
596 char tmphostname[256];
599 /* don't know if it is portable for getnameinfo() to set h_errno;
600 * clear it then see if it was set */
603 /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return
604 * a numeric address string if it fails to resolve the host name;
605 * that is *not* what we want here
607 * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling
608 * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc).
611 if (sockaddr->family == AF_INET6 &&
612 IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) {
613 struct sockaddr_in tmpsa;
614 tmpsa.sin_family = AF_INET;
616 tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];
618 tmpsa.sin_len = sizeof(tmpsa);
621 rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),
622 tmphostname, sizeof(tmphostname), NULL, 0,
623 flags != 0 ? flags : NI_NAMEREQD);
627 rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
628 tmphostname, sizeof(tmphostname), NULL, 0,
629 flags != 0 ? flags : NI_NAMEREQD);
634 /* something went wrong. Look at the EAI_ error code */
635 if (rc == EAI_SYSTEM) {
636 /* EAI_SYSTEM System error returned in errno. */
637 /* IMHO, Implementations that set h_errno a simply broken. */
638 if (h_errno) { /* for broken implementations which set h_errno */
639 return h_errno + APR_OS_START_SYSERR;
641 else { /* "normal" case */
642 return errno + APR_OS_START_SYSERR;
648 #if defined(NEGATIVE_EAI)
649 if (rc < 0) rc = -rc;
651 return rc + APR_OS_START_EAIERR; /* return the EAI_ error */
654 *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool,
658 #if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \
659 defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS)
660 #ifdef GETHOSTBYNAME_R_HOSTENT_DATA
661 struct hostent_data hd;
663 char tmp[GETHOSTBYNAME_BUFLEN];
666 struct hostent hs, *hptr;
668 #if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
669 /* AIX, HP/UX, D/UX et alia */
670 gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr,
671 sizeof(struct in_addr), AF_INET, &hs, &hd);
674 #if defined(GETHOSTBYNAME_R_GLIBC2)
676 gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr,
677 sizeof(struct in_addr), AF_INET,
678 &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror);
680 /* Solaris, Irix et alia */
681 hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr,
682 sizeof(struct in_addr), AF_INET,
683 &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror);
684 #endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
687 return hosterror + APR_OS_START_SYSERR;
689 #endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
691 struct hostent *hptr;
692 hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr,
693 sizeof(struct in_addr), AF_INET);
697 *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name);
702 return apr_get_netos_error();
706 return h_errno + APR_OS_START_SYSERR;
711 APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr,
712 const char *servname)
716 if (servname == NULL)
719 if ((se = getservbyname(servname, NULL)) != NULL){
720 sockaddr->port = htons(se->s_port);
721 sockaddr->servname = apr_pstrdup(sockaddr->pool, servname);
722 sockaddr->sa.sin.sin_port = se->s_port;
728 #define V4MAPPED_EQUAL(a,b) \
729 ((a)->sa.sin.sin_family == AF_INET && \
730 (b)->sa.sin.sin_family == AF_INET6 && \
731 IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) && \
732 !memcmp((a)->ipaddr_ptr, \
733 &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12], \
736 APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1,
737 const apr_sockaddr_t *addr2)
739 if (addr1->ipaddr_len == addr2->ipaddr_len &&
740 !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len)) {
744 if (V4MAPPED_EQUAL(addr1, addr2)) {
747 if (V4MAPPED_EQUAL(addr2, addr1)) {
751 return 0; /* not equal */
754 static apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network)
756 /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */
760 char buf[sizeof "255.255.255.255"];
762 if (strlen(network) < sizeof buf) {
763 strcpy(buf, network);
769 /* parse components */
776 if (!apr_isdigit(*t)) {
779 while (apr_isdigit(*t)) {
792 if (octet < 0 || octet > 255) {
795 ipsub->sub[0] |= octet << shift;
796 ipsub->mask[0] |= 0xFFUL << shift;
800 ipsub->sub[0] = ntohl(ipsub->sub[0]);
801 ipsub->mask[0] = ntohl(ipsub->mask[0]);
802 ipsub->family = AF_INET;
807 * APR_EINVAL not an IP address; caller should see if it is something else
808 * APR_BADIP IP address portion is is not valid
809 * APR_BADMASK mask portion is not valid
812 static apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed)
814 /* supported flavors of IP:
816 * . IPv6 numeric address string (e.g., "fe80::1")
818 * IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address.
820 * . IPv4 numeric address string (e.g., "127.0.0.1")
822 * . IPv4 network string (e.g., "9.67")
824 * IMPORTANT: This network form is only allowed if network_allowed is on.
829 rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub);
831 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) {
832 /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6
833 * addresses; this of course forces the user to specify IPv4 addresses
834 * in a.b.c.d style instead of ::ffff:a.b.c.d style.
838 ipsub->family = AF_INET6;
843 rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub);
845 ipsub->family = AF_INET;
849 if (network_allowed) {
850 return parse_network(ipsub, ipstr);
859 static int looks_like_ip(const char *ipstr)
861 if (strchr(ipstr, ':')) {
862 /* definitely not a hostname; assume it is intended to be an IPv6 address */
866 /* simple IPv4 address string check */
867 while ((*ipstr == '.') || apr_isdigit(*ipstr))
869 return (*ipstr == '\0');
872 static void fix_subnet(apr_ipsubnet_t *ipsub)
874 /* in case caller specified more bits in network address than are
875 * valid according to the mask, turn off the extra bits
879 for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) {
880 ipsub->sub[i] &= ipsub->mask[i];
884 /* be sure not to store any IPv4 address as a v4-mapped IPv6 address */
885 APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr,
886 const char *mask_or_numbits, apr_pool_t *p)
890 long bits, maxbits = 32;
892 /* filter out stuff which doesn't look remotely like an IP address; this helps
893 * callers like mod_access which have a syntax allowing hostname or IP address;
894 * APR_EINVAL tells the caller that it was probably not intended to be an IP
897 if (!looks_like_ip(ipstr)) {
901 *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t));
903 /* assume ipstr is an individual IP address, not a subnet */
904 memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask);
906 rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL);
907 if (rv != APR_SUCCESS) {
911 if (mask_or_numbits) {
913 if ((*ipsub)->family == AF_INET6) {
917 bits = strtol(mask_or_numbits, &endptr, 10);
918 if (*endptr == '\0' && bits > 0 && bits <= maxbits) {
919 /* valid num-bits string; fill in mask appropriately */
921 apr_int32_t cur_bit_value;
923 memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask);
925 (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */
929 cur_bit_value = 0x80000000;
931 (*ipsub)->mask[cur_entry] |= cur_bit_value;
935 (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]);
937 else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 &&
938 (*ipsub)->family == AF_INET) {
939 /* valid IPv4 netmask */
951 APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa)
954 /* XXX This line will segv on Win32 build with APR_HAVE_IPV6,
955 * but without the IPV6 drivers installed.
957 if (sa->sa.sin.sin_family == AF_INET) {
958 if (ipsub->family == AF_INET &&
959 ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) {
963 else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) {
964 if (ipsub->family == AF_INET &&
965 (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) {
970 apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr;
972 if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] &&
973 (addr[1] & ipsub->mask[1]) == ipsub->sub[1] &&
974 (addr[2] & ipsub->mask[2]) == ipsub->sub[2] &&
975 (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) {
980 if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) {
983 #endif /* APR_HAVE_IPV6 */
984 return 0; /* no match */