1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr_arch_networkio.h" 18251875Speter#include "apr_strings.h" 19251875Speter#include "apr.h" 20251875Speter#include "apr_lib.h" 21251875Speter#include "apr_strings.h" 22251875Speter#include "apr_private.h" 23251875Speter 24251875Speter#if APR_HAVE_STDLIB_H 25251875Speter#include <stdlib.h> 26251875Speter#endif 27251875Speter 28251875Speter#define APR_WANT_STRFUNC 29251875Speter#include "apr_want.h" 30251875Speter 31251875Speterstruct apr_ipsubnet_t { 32251875Speter int family; 33251875Speter#if APR_HAVE_IPV6 34251875Speter apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */ 35251875Speter apr_uint32_t mask[4]; 36251875Speter#else 37251875Speter apr_uint32_t sub[1]; 38251875Speter apr_uint32_t mask[1]; 39251875Speter#endif 40251875Speter}; 41251875Speter 42251875Speter#if !defined(NETWARE) && !defined(WIN32) 43251875Speter#ifdef HAVE_SET_H_ERRNO 44251875Speter#define SET_H_ERRNO(newval) set_h_errno(newval) 45251875Speter#else 46251875Speter#define SET_H_ERRNO(newval) h_errno = (newval) 47251875Speter#endif 48251875Speter#else 49251875Speter#define SET_H_ERRNO(newval) 50251875Speter#endif 51251875Speter 52251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 53251875Speter defined(HAVE_GETHOSTBYNAME_R) 54251875Speter/* This is the maximum size that may be returned from the reentrant 55251875Speter * gethostbyname_r function. If the system tries to use more, it 56251875Speter * should return ERANGE. 57251875Speter */ 58251875Speter#define GETHOSTBYNAME_BUFLEN 512 59251875Speter#endif 60251875Speter 61251875Speter#ifdef _AIX 62251875Speter/* Some levels of AIX getaddrinfo() don't like servname = "0", so 63251875Speter * set servname to "1" when port is 0 and fix it up later. 64251875Speter */ 65251875Speter#define AIX_SERVNAME_HACK 1 66251875Speter#else 67251875Speter#define AIX_SERVNAME_HACK 0 68251875Speter#endif 69251875Speter 70251875Speter#ifdef _WIN32_WCE 71251875Speter/* XXX: BS solution. Need an HAVE_GETSERVBYNAME and actually 72251875Speter * do something here, to provide the obvious proto mappings. 73251875Speter */ 74251875Speterstatic void *getservbyname(const char *name, const char *proto) 75251875Speter{ 76251875Speter return NULL; 77251875Speter} 78251875Speter#endif 79251875Speter 80251875Speterstatic apr_status_t get_local_addr(apr_socket_t *sock) 81251875Speter{ 82251875Speter sock->local_addr->salen = sizeof(sock->local_addr->sa); 83251875Speter if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa, 84251875Speter &sock->local_addr->salen) < 0) { 85251875Speter return apr_get_netos_error(); 86251875Speter } 87251875Speter else { 88251875Speter sock->local_port_unknown = sock->local_interface_unknown = 0; 89251875Speter /* XXX assumes sin_port and sin6_port at same offset */ 90251875Speter sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port); 91251875Speter return APR_SUCCESS; 92251875Speter } 93251875Speter} 94251875Speter 95251875Speterstatic apr_status_t get_remote_addr(apr_socket_t *sock) 96251875Speter{ 97251875Speter sock->remote_addr->salen = sizeof(sock->remote_addr->sa); 98251875Speter if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa, 99251875Speter &sock->remote_addr->salen) < 0) { 100251875Speter return apr_get_netos_error(); 101251875Speter } 102251875Speter else { 103251875Speter sock->remote_addr_unknown = 0; 104251875Speter /* XXX assumes sin_port and sin6_port at same offset */ 105251875Speter sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port); 106251875Speter return APR_SUCCESS; 107251875Speter } 108251875Speter} 109251875Speter 110251875SpeterAPR_DECLARE(apr_status_t) apr_sockaddr_ip_getbuf(char *buf, apr_size_t buflen, 111251875Speter apr_sockaddr_t *sockaddr) 112251875Speter{ 113251875Speter if (!apr_inet_ntop(sockaddr->family, sockaddr->ipaddr_ptr, buf, buflen)) { 114251875Speter return APR_ENOSPC; 115251875Speter } 116251875Speter 117251875Speter#if APR_HAVE_IPV6 118251875Speter if (sockaddr->family == AF_INET6 119251875Speter && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sockaddr->ipaddr_ptr) 120251875Speter && buflen > strlen("::ffff:")) { 121251875Speter /* This is an IPv4-mapped IPv6 address; drop the leading 122251875Speter * part of the address string so we're left with the familiar 123251875Speter * IPv4 format. 124251875Speter */ 125251875Speter memmove(buf, buf + strlen("::ffff:"), 126251875Speter strlen(buf + strlen("::ffff:"))+1); 127251875Speter } 128251875Speter#endif 129251875Speter /* ensure NUL termination if the buffer is too short */ 130251875Speter buf[buflen-1] = '\0'; 131251875Speter return APR_SUCCESS; 132251875Speter} 133251875Speter 134251875SpeterAPR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr, 135251875Speter apr_sockaddr_t *sockaddr) 136251875Speter{ 137251875Speter *addr = apr_palloc(sockaddr->pool, sockaddr->addr_str_len); 138251875Speter return apr_sockaddr_ip_getbuf(*addr, sockaddr->addr_str_len, sockaddr); 139251875Speter} 140251875Speter 141251875Spetervoid apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port) 142251875Speter{ 143251875Speter addr->family = family; 144251875Speter addr->sa.sin.sin_family = family; 145251875Speter if (port) { 146251875Speter /* XXX IPv6: assumes sin_port and sin6_port at same offset */ 147251875Speter addr->sa.sin.sin_port = htons(port); 148251875Speter addr->port = port; 149251875Speter } 150251875Speter#if AIX_SERVNAME_HACK 151251875Speter else { 152251875Speter addr->sa.sin.sin_port = htons(port); 153251875Speter } 154251875Speter#endif 155251875Speter 156251875Speter if (family == APR_INET) { 157251875Speter addr->salen = sizeof(struct sockaddr_in); 158251875Speter addr->addr_str_len = 16; 159251875Speter addr->ipaddr_ptr = &(addr->sa.sin.sin_addr); 160251875Speter addr->ipaddr_len = sizeof(struct in_addr); 161251875Speter } 162251875Speter#if APR_HAVE_IPV6 163251875Speter else if (family == APR_INET6) { 164251875Speter addr->salen = sizeof(struct sockaddr_in6); 165251875Speter addr->addr_str_len = 46; 166251875Speter addr->ipaddr_ptr = &(addr->sa.sin6.sin6_addr); 167251875Speter addr->ipaddr_len = sizeof(struct in6_addr); 168251875Speter } 169251875Speter#endif 170251875Speter} 171251875Speter 172251875SpeterAPR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa, 173251875Speter apr_interface_e which, 174251875Speter apr_socket_t *sock) 175251875Speter{ 176251875Speter if (which == APR_LOCAL) { 177251875Speter if (sock->local_interface_unknown || sock->local_port_unknown) { 178251875Speter apr_status_t rv = get_local_addr(sock); 179251875Speter 180251875Speter if (rv != APR_SUCCESS) { 181251875Speter return rv; 182251875Speter } 183251875Speter } 184251875Speter *sa = sock->local_addr; 185251875Speter } 186251875Speter else if (which == APR_REMOTE) { 187251875Speter if (sock->remote_addr_unknown) { 188251875Speter apr_status_t rv = get_remote_addr(sock); 189251875Speter 190251875Speter if (rv != APR_SUCCESS) { 191251875Speter return rv; 192251875Speter } 193251875Speter } 194251875Speter *sa = sock->remote_addr; 195251875Speter } 196251875Speter else { 197251875Speter *sa = NULL; 198251875Speter return APR_EINVAL; 199251875Speter } 200251875Speter return APR_SUCCESS; 201251875Speter} 202251875Speter 203251875SpeterAPR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr, 204251875Speter char **scope_id, 205251875Speter apr_port_t *port, 206251875Speter const char *str, 207251875Speter apr_pool_t *p) 208251875Speter{ 209251875Speter const char *ch, *lastchar; 210251875Speter int big_port; 211251875Speter apr_size_t addrlen; 212251875Speter 213251875Speter *addr = NULL; /* assume not specified */ 214251875Speter *scope_id = NULL; /* assume not specified */ 215251875Speter *port = 0; /* assume not specified */ 216251875Speter 217251875Speter /* First handle the optional port number. That may be all that 218251875Speter * is specified in the string. 219251875Speter */ 220251875Speter ch = lastchar = str + strlen(str) - 1; 221251875Speter while (ch >= str && apr_isdigit(*ch)) { 222251875Speter --ch; 223251875Speter } 224251875Speter 225251875Speter if (ch < str) { /* Entire string is the port. */ 226251875Speter big_port = atoi(str); 227251875Speter if (big_port < 1 || big_port > 65535) { 228251875Speter return APR_EINVAL; 229251875Speter } 230251875Speter *port = big_port; 231251875Speter return APR_SUCCESS; 232251875Speter } 233251875Speter 234251875Speter if (*ch == ':' && ch < lastchar) { /* host and port number specified */ 235251875Speter if (ch == str) { /* string starts with ':' -- bad */ 236251875Speter return APR_EINVAL; 237251875Speter } 238251875Speter big_port = atoi(ch + 1); 239251875Speter if (big_port < 1 || big_port > 65535) { 240251875Speter return APR_EINVAL; 241251875Speter } 242251875Speter *port = big_port; 243251875Speter lastchar = ch - 1; 244251875Speter } 245251875Speter 246251875Speter /* now handle the hostname */ 247251875Speter addrlen = lastchar - str + 1; 248251875Speter 249251875Speter/* XXX we don't really have to require APR_HAVE_IPV6 for this; 250251875Speter * just pass char[] for ipaddr (so we don't depend on struct in6_addr) 251251875Speter * and always define APR_INET6 252251875Speter */ 253251875Speter#if APR_HAVE_IPV6 254251875Speter if (*str == '[') { 255251875Speter const char *end_bracket = memchr(str, ']', addrlen); 256251875Speter struct in6_addr ipaddr; 257251875Speter const char *scope_delim; 258251875Speter 259251875Speter if (!end_bracket || end_bracket != lastchar) { 260251875Speter *port = 0; 261251875Speter return APR_EINVAL; 262251875Speter } 263251875Speter 264251875Speter /* handle scope id; this is the only context where it is allowed */ 265251875Speter scope_delim = memchr(str, '%', addrlen); 266251875Speter if (scope_delim) { 267251875Speter if (scope_delim == end_bracket - 1) { /* '%' without scope id */ 268251875Speter *port = 0; 269251875Speter return APR_EINVAL; 270251875Speter } 271251875Speter addrlen = scope_delim - str - 1; 272251875Speter *scope_id = apr_palloc(p, end_bracket - scope_delim); 273251875Speter memcpy(*scope_id, scope_delim + 1, end_bracket - scope_delim - 1); 274251875Speter (*scope_id)[end_bracket - scope_delim - 1] = '\0'; 275251875Speter } 276251875Speter else { 277251875Speter addrlen = addrlen - 2; /* minus 2 for '[' and ']' */ 278251875Speter } 279251875Speter 280251875Speter *addr = apr_palloc(p, addrlen + 1); 281251875Speter memcpy(*addr, 282251875Speter str + 1, 283251875Speter addrlen); 284251875Speter (*addr)[addrlen] = '\0'; 285251875Speter if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) { 286251875Speter *addr = NULL; 287251875Speter *scope_id = NULL; 288251875Speter *port = 0; 289251875Speter return APR_EINVAL; 290251875Speter } 291251875Speter } 292251875Speter else 293251875Speter#endif 294251875Speter { 295251875Speter /* XXX If '%' is not a valid char in a DNS name, we *could* check 296251875Speter * for bogus scope ids first. 297251875Speter */ 298251875Speter *addr = apr_palloc(p, addrlen + 1); 299251875Speter memcpy(*addr, str, addrlen); 300251875Speter (*addr)[addrlen] = '\0'; 301251875Speter } 302251875Speter return APR_SUCCESS; 303251875Speter} 304251875Speter 305251875Speter#if defined(HAVE_GETADDRINFO) 306251875Speter 307251875Speterstatic apr_status_t call_resolver(apr_sockaddr_t **sa, 308251875Speter const char *hostname, apr_int32_t family, 309251875Speter apr_port_t port, apr_int32_t flags, 310251875Speter apr_pool_t *p) 311251875Speter{ 312251875Speter struct addrinfo hints, *ai, *ai_list; 313251875Speter apr_sockaddr_t *prev_sa; 314251875Speter int error; 315251875Speter char *servname = NULL; 316251875Speter 317251875Speter memset(&hints, 0, sizeof(hints)); 318251875Speter hints.ai_family = family; 319251875Speter hints.ai_socktype = SOCK_STREAM; 320251875Speter#ifdef HAVE_GAI_ADDRCONFIG 321251875Speter if (family == APR_UNSPEC) { 322251875Speter /* By default, only look up addresses using address types for 323251875Speter * which a local interface is configured, i.e. no IPv6 if no 324251875Speter * IPv6 interfaces configured. */ 325251875Speter hints.ai_flags = AI_ADDRCONFIG; 326251875Speter } 327251875Speter#endif 328289166Speter 329289166Speter#ifdef __MVS__ 330289166Speter /* z/OS will not return IPv4 address under AF_UNSPEC if any IPv6 results 331289166Speter * are returned, w/o AI_ALL. 332289166Speter */ 333289166Speter if (family == APR_UNSPEC) { 334289166Speter hints.ai_flags |= AI_ALL; 335289166Speter } 336289166Speter#endif 337289166Speter 338251875Speter if(hostname == NULL) { 339251875Speter#ifdef AI_PASSIVE 340251875Speter /* If hostname is NULL, assume we are trying to bind to all 341251875Speter * interfaces. */ 342251875Speter hints.ai_flags |= AI_PASSIVE; 343251875Speter#endif 344251875Speter /* getaddrinfo according to RFC 2553 must have either hostname 345251875Speter * or servname non-NULL. 346251875Speter */ 347251875Speter#ifdef OSF1 348251875Speter /* The Tru64 5.0 getaddrinfo() can only resolve services given 349251875Speter * by the name listed in /etc/services; a numeric or unknown 350251875Speter * servname gets an EAI_SERVICE error. So just resolve the 351251875Speter * appropriate anyaddr and fill in the port later. */ 352251875Speter hostname = family == AF_INET6 ? "::" : "0.0.0.0"; 353251875Speter servname = NULL; 354251875Speter#ifdef AI_NUMERICHOST 355251875Speter hints.ai_flags |= AI_NUMERICHOST; 356251875Speter#endif 357251875Speter#else 358251875Speter#if AIX_SERVNAME_HACK 359251875Speter if (!port) { 360251875Speter servname = "1"; 361251875Speter } 362251875Speter else 363251875Speter#endif /* AIX_SERVNAME_HACK */ 364251875Speter servname = apr_itoa(p, port); 365251875Speter#endif /* OSF1 */ 366251875Speter } 367251875Speter error = getaddrinfo(hostname, servname, &hints, &ai_list); 368251875Speter#ifdef HAVE_GAI_ADDRCONFIG 369253734Speter /* 370253734Speter * Using AI_ADDRCONFIG involves some unfortunate guesswork because it 371253734Speter * does not consider loopback addresses when trying to determine if 372253734Speter * IPv4 or IPv6 is configured on a system (see RFC 3493). 373253734Speter * This is a problem if one actually wants to listen on or connect to 374253734Speter * the loopback address of a protocol family that is not otherwise 375253734Speter * configured on the system. See PR 52709. 376253734Speter * To work around some of the problems, retry without AI_ADDRCONFIG 377253734Speter * in case of EAI_ADDRFAMILY. 378253734Speter * XXX: apr_sockaddr_info_get() should really accept a flag to determine 379253734Speter * XXX: if AI_ADDRCONFIG's guesswork is wanted and if the address is 380253734Speter * XXX: to be used for listen() or connect(). 381253734Speter * 382253734Speter * In case of EAI_BADFLAGS, AI_ADDRCONFIG is not supported. 383253734Speter */ 384253734Speter if ((family == APR_UNSPEC) && (error == EAI_BADFLAGS 385253734Speter#ifdef EAI_ADDRFAMILY 386253734Speter || error == EAI_ADDRFAMILY 387253734Speter#endif 388253734Speter )) { 389253734Speter hints.ai_flags &= ~AI_ADDRCONFIG; 390251875Speter error = getaddrinfo(hostname, servname, &hints, &ai_list); 391251875Speter } 392251875Speter#endif 393251875Speter if (error) { 394251875Speter#if defined(WIN32) 395251875Speter return apr_get_netos_error(); 396251875Speter#else 397251875Speter if (error == EAI_SYSTEM) { 398253734Speter return errno ? errno : APR_EGENERAL; 399251875Speter } 400251875Speter else 401251875Speter { 402251875Speter /* issues with representing this with APR's error scheme: 403251875Speter * glibc uses negative values for these numbers, perhaps so 404251875Speter * they don't conflict with h_errno values... Tru64 uses 405251875Speter * positive values which conflict with h_errno values 406251875Speter */ 407251875Speter#if defined(NEGATIVE_EAI) 408251875Speter error = -error; 409251875Speter#endif 410251875Speter return error + APR_OS_START_EAIERR; 411251875Speter } 412251875Speter#endif /* WIN32 */ 413251875Speter } 414251875Speter 415251875Speter prev_sa = NULL; 416251875Speter ai = ai_list; 417251875Speter while (ai) { /* while more addresses to report */ 418251875Speter apr_sockaddr_t *new_sa; 419251875Speter 420251875Speter /* Ignore anything bogus: getaddrinfo in some old versions of 421251875Speter * glibc will return AF_UNIX entries for APR_UNSPEC+AI_PASSIVE 422251875Speter * lookups. */ 423251875Speter#if APR_HAVE_IPV6 424251875Speter if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { 425251875Speter#else 426251875Speter if (ai->ai_family != AF_INET) { 427251875Speter#endif 428251875Speter ai = ai->ai_next; 429251875Speter continue; 430251875Speter } 431251875Speter 432251875Speter new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 433251875Speter 434251875Speter new_sa->pool = p; 435251875Speter memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen); 436251875Speter apr_sockaddr_vars_set(new_sa, ai->ai_family, port); 437251875Speter 438251875Speter if (!prev_sa) { /* first element in new list */ 439251875Speter if (hostname) { 440251875Speter new_sa->hostname = apr_pstrdup(p, hostname); 441251875Speter } 442251875Speter *sa = new_sa; 443251875Speter } 444251875Speter else { 445251875Speter new_sa->hostname = prev_sa->hostname; 446251875Speter prev_sa->next = new_sa; 447251875Speter } 448251875Speter 449251875Speter prev_sa = new_sa; 450251875Speter ai = ai->ai_next; 451251875Speter } 452251875Speter freeaddrinfo(ai_list); 453253734Speter 454253734Speter if (prev_sa == NULL) { 455253734Speter /* 456253734Speter * getaddrinfo returned only useless entries and *sa is still empty. 457253734Speter * This should be treated as an error. 458253734Speter */ 459253734Speter return APR_EGENERAL; 460253734Speter } 461253734Speter 462251875Speter return APR_SUCCESS; 463251875Speter} 464251875Speter 465251875Speterstatic apr_status_t find_addresses(apr_sockaddr_t **sa, 466251875Speter const char *hostname, apr_int32_t family, 467251875Speter apr_port_t port, apr_int32_t flags, 468251875Speter apr_pool_t *p) 469251875Speter{ 470251875Speter if (flags & APR_IPV4_ADDR_OK) { 471251875Speter apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p); 472251875Speter 473251875Speter#if APR_HAVE_IPV6 474251875Speter if (error) { 475251875Speter family = AF_INET6; /* try again */ 476251875Speter } 477251875Speter else 478251875Speter#endif 479251875Speter return error; 480251875Speter } 481251875Speter#if APR_HAVE_IPV6 482251875Speter else if (flags & APR_IPV6_ADDR_OK) { 483251875Speter apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p); 484251875Speter 485251875Speter if (error) { 486251875Speter family = AF_INET; /* try again */ 487251875Speter } 488251875Speter else { 489251875Speter return APR_SUCCESS; 490251875Speter } 491251875Speter } 492251875Speter#endif 493251875Speter 494251875Speter return call_resolver(sa, hostname, family, port, flags, p); 495251875Speter} 496251875Speter 497251875Speter#else /* end of HAVE_GETADDRINFO code */ 498251875Speter 499251875Speterstatic apr_status_t find_addresses(apr_sockaddr_t **sa, 500251875Speter const char *hostname, apr_int32_t family, 501251875Speter apr_port_t port, apr_int32_t flags, 502251875Speter apr_pool_t *p) 503251875Speter{ 504251875Speter struct hostent *hp; 505251875Speter apr_sockaddr_t *prev_sa; 506251875Speter int curaddr; 507251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 508251875Speter defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) 509251875Speter#ifdef GETHOSTBYNAME_R_HOSTENT_DATA 510251875Speter struct hostent_data hd; 511251875Speter#else 512251875Speter /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be 513251875Speter * bumped. */ 514251875Speter char tmp[GETHOSTBYNAME_BUFLEN]; 515251875Speter#endif 516251875Speter int hosterror; 517251875Speter#endif 518251875Speter struct hostent hs; 519251875Speter struct in_addr ipaddr; 520251875Speter char *addr_list[2]; 521251875Speter const char *orig_hostname = hostname; 522251875Speter 523251875Speter if (hostname == NULL) { 524251875Speter /* if we are given a NULL hostname, assume '0.0.0.0' */ 525251875Speter hostname = "0.0.0.0"; 526251875Speter } 527251875Speter 528251875Speter if (*hostname >= '0' && *hostname <= '9' && 529251875Speter strspn(hostname, "0123456789.") == strlen(hostname)) { 530251875Speter 531251875Speter ipaddr.s_addr = inet_addr(hostname); 532251875Speter addr_list[0] = (char *)&ipaddr; 533251875Speter addr_list[1] = NULL; /* just one IP in list */ 534251875Speter hs.h_addr_list = (char **)addr_list; 535251875Speter hp = &hs; 536251875Speter } 537251875Speter else { 538251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 539251875Speter defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) 540251875Speter#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) 541251875Speter /* AIX, HP/UX, D/UX et alia */ 542251875Speter gethostbyname_r(hostname, &hs, &hd); 543251875Speter hp = &hs; 544251875Speter#else 545251875Speter#if defined(GETHOSTBYNAME_R_GLIBC2) 546251875Speter /* Linux glibc2+ */ 547251875Speter gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 548251875Speter &hp, &hosterror); 549251875Speter#else 550251875Speter /* Solaris, Irix et alia */ 551251875Speter hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 552251875Speter &hosterror); 553251875Speter#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ 554251875Speter if (!hp) { 555251875Speter return (hosterror + APR_OS_START_SYSERR); 556251875Speter } 557251875Speter#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ 558251875Speter#else 559251875Speter hp = gethostbyname(hostname); 560251875Speter#endif 561251875Speter 562251875Speter if (!hp) { 563251875Speter#ifdef WIN32 564251875Speter return apr_get_netos_error(); 565251875Speter#else 566251875Speter return (h_errno + APR_OS_START_SYSERR); 567251875Speter#endif 568251875Speter } 569251875Speter } 570251875Speter 571251875Speter prev_sa = NULL; 572251875Speter curaddr = 0; 573251875Speter while (hp->h_addr_list[curaddr]) { 574251875Speter apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 575251875Speter 576251875Speter new_sa->pool = p; 577251875Speter new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr]; 578251875Speter apr_sockaddr_vars_set(new_sa, AF_INET, port); 579251875Speter 580251875Speter if (!prev_sa) { /* first element in new list */ 581251875Speter if (orig_hostname) { 582251875Speter new_sa->hostname = apr_pstrdup(p, orig_hostname); 583251875Speter } 584251875Speter *sa = new_sa; 585251875Speter } 586251875Speter else { 587251875Speter new_sa->hostname = prev_sa->hostname; 588251875Speter prev_sa->next = new_sa; 589251875Speter } 590251875Speter 591251875Speter prev_sa = new_sa; 592251875Speter ++curaddr; 593251875Speter } 594251875Speter 595253734Speter if (prev_sa == NULL) { 596253734Speter /* this should not happen but no result should be treated as error */ 597253734Speter return APR_EGENERAL; 598253734Speter } 599253734Speter 600251875Speter return APR_SUCCESS; 601251875Speter} 602251875Speter 603251875Speter#endif /* end of !HAVE_GETADDRINFO code */ 604251875Speter 605251875SpeterAPR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, 606251875Speter const char *hostname, 607251875Speter apr_int32_t family, apr_port_t port, 608251875Speter apr_int32_t flags, apr_pool_t *p) 609251875Speter{ 610251875Speter apr_int32_t masked; 611251875Speter *sa = NULL; 612251875Speter 613251875Speter if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { 614251875Speter if (!hostname || 615251875Speter family != APR_UNSPEC || 616251875Speter masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) { 617251875Speter return APR_EINVAL; 618251875Speter } 619251875Speter#if !APR_HAVE_IPV6 620251875Speter if (flags & APR_IPV6_ADDR_OK) { 621251875Speter return APR_ENOTIMPL; 622251875Speter } 623251875Speter#endif 624251875Speter } 625251875Speter#if !APR_HAVE_IPV6 626251875Speter /* What may happen is that APR is not IPv6-enabled, but we're still 627251875Speter * going to call getaddrinfo(), so we have to tell the OS we only 628251875Speter * want IPv4 addresses back since we won't know what to do with 629251875Speter * IPv6 addresses. 630251875Speter */ 631251875Speter if (family == APR_UNSPEC) { 632251875Speter family = APR_INET; 633251875Speter } 634251875Speter#endif 635251875Speter 636251875Speter return find_addresses(sa, hostname, family, port, flags, p); 637251875Speter} 638251875Speter 639251875SpeterAPR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, 640251875Speter apr_sockaddr_t *sockaddr, 641251875Speter apr_int32_t flags) 642251875Speter{ 643251875Speter#if defined(HAVE_GETNAMEINFO) 644251875Speter int rc; 645251875Speter#if defined(NI_MAXHOST) 646251875Speter char tmphostname[NI_MAXHOST]; 647251875Speter#else 648251875Speter char tmphostname[256]; 649251875Speter#endif 650251875Speter 651251875Speter /* don't know if it is portable for getnameinfo() to set h_errno; 652251875Speter * clear it then see if it was set */ 653251875Speter SET_H_ERRNO(0); 654251875Speter 655251875Speter /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return 656251875Speter * a numeric address string if it fails to resolve the host name; 657251875Speter * that is *not* what we want here 658251875Speter * 659251875Speter * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling 660251875Speter * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc). 661251875Speter */ 662251875Speter#if APR_HAVE_IPV6 663251875Speter if (sockaddr->family == AF_INET6 && 664251875Speter IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) { 665251875Speter struct sockaddr_in tmpsa; 666251875Speter tmpsa.sin_family = AF_INET; 667251875Speter tmpsa.sin_port = 0; 668251875Speter tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3]; 669251875Speter#ifdef SIN6_LEN 670251875Speter tmpsa.sin_len = sizeof(tmpsa); 671251875Speter#endif 672251875Speter 673251875Speter rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa), 674251875Speter tmphostname, sizeof(tmphostname), NULL, 0, 675251875Speter flags != 0 ? flags : NI_NAMEREQD); 676251875Speter } 677251875Speter else 678251875Speter#endif 679251875Speter rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen, 680251875Speter tmphostname, sizeof(tmphostname), NULL, 0, 681251875Speter flags != 0 ? flags : NI_NAMEREQD); 682251875Speter if (rc != 0) { 683251875Speter *hostname = NULL; 684251875Speter 685251875Speter#ifndef WIN32 686251875Speter /* something went wrong. Look at the EAI_ error code */ 687251875Speter if (rc == EAI_SYSTEM) { 688251875Speter /* EAI_SYSTEM System error returned in errno. */ 689251875Speter /* IMHO, Implementations that set h_errno a simply broken. */ 690251875Speter if (h_errno) { /* for broken implementations which set h_errno */ 691251875Speter return h_errno + APR_OS_START_SYSERR; 692251875Speter } 693251875Speter else { /* "normal" case */ 694251875Speter return errno + APR_OS_START_SYSERR; 695251875Speter } 696251875Speter } 697251875Speter else 698251875Speter#endif 699251875Speter { 700251875Speter#if defined(NEGATIVE_EAI) 701251875Speter if (rc < 0) rc = -rc; 702251875Speter#endif 703251875Speter return rc + APR_OS_START_EAIERR; /* return the EAI_ error */ 704251875Speter } 705251875Speter } 706251875Speter *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, 707251875Speter tmphostname); 708251875Speter return APR_SUCCESS; 709251875Speter#else 710251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \ 711251875Speter defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS) 712251875Speter#ifdef GETHOSTBYNAME_R_HOSTENT_DATA 713251875Speter struct hostent_data hd; 714251875Speter#else 715251875Speter char tmp[GETHOSTBYNAME_BUFLEN]; 716251875Speter#endif 717251875Speter int hosterror; 718251875Speter struct hostent hs, *hptr; 719251875Speter 720251875Speter#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) 721251875Speter /* AIX, HP/UX, D/UX et alia */ 722251875Speter gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 723251875Speter sizeof(struct in_addr), AF_INET, &hs, &hd); 724251875Speter hptr = &hs; 725251875Speter#else 726251875Speter#if defined(GETHOSTBYNAME_R_GLIBC2) 727251875Speter /* Linux glibc2+ */ 728251875Speter gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 729251875Speter sizeof(struct in_addr), AF_INET, 730251875Speter &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror); 731251875Speter#else 732251875Speter /* Solaris, Irix et alia */ 733251875Speter hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 734251875Speter sizeof(struct in_addr), AF_INET, 735251875Speter &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror); 736251875Speter#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ 737251875Speter if (!hptr) { 738251875Speter *hostname = NULL; 739251875Speter return hosterror + APR_OS_START_SYSERR; 740251875Speter } 741251875Speter#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ 742251875Speter#else 743251875Speter struct hostent *hptr; 744251875Speter hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, 745251875Speter sizeof(struct in_addr), AF_INET); 746251875Speter#endif 747251875Speter 748251875Speter if (hptr) { 749251875Speter *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name); 750251875Speter return APR_SUCCESS; 751251875Speter } 752251875Speter *hostname = NULL; 753251875Speter#if defined(WIN32) 754251875Speter return apr_get_netos_error(); 755251875Speter#elif defined(OS2) 756251875Speter return h_errno; 757251875Speter#else 758251875Speter return h_errno + APR_OS_START_SYSERR; 759251875Speter#endif 760251875Speter#endif 761251875Speter} 762251875Speter 763251875SpeterAPR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, 764251875Speter const char *servname) 765251875Speter{ 766251875Speter#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ 767251875Speter defined(HAVE_GETSERVBYNAME_R) && \ 768251875Speter (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ 769251875Speter defined(GETSERVBYNAME_R_OSF1)) 770251875Speter struct servent se; 771251875Speter#if defined(GETSERVBYNAME_R_OSF1) 772251875Speter struct servent_data sed; 773251875Speter 774251875Speter memset(&sed, 0, sizeof(sed)); /* must zero fill before use */ 775251875Speter#else 776251875Speter#if defined(GETSERVBYNAME_R_GLIBC2) 777251875Speter struct servent *res; 778251875Speter#endif 779251875Speter char buf[1024]; 780251875Speter#endif 781251875Speter#else 782251875Speter struct servent *se; 783251875Speter#endif 784251875Speter 785251875Speter if (servname == NULL) 786251875Speter return APR_EINVAL; 787251875Speter 788251875Speter#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ 789251875Speter defined(HAVE_GETSERVBYNAME_R) && \ 790251875Speter (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ 791251875Speter defined(GETSERVBYNAME_R_OSF1)) 792251875Speter#if defined(GETSERVBYNAME_R_GLIBC2) 793251875Speter if (getservbyname_r(servname, NULL, 794251875Speter &se, buf, sizeof(buf), &res) == 0 && res != NULL) { 795251875Speter sockaddr->port = ntohs(res->s_port); 796251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 797251875Speter sockaddr->sa.sin.sin_port = res->s_port; 798251875Speter return APR_SUCCESS; 799251875Speter } 800251875Speter#elif defined(GETSERVBYNAME_R_SOLARIS) 801251875Speter if (getservbyname_r(servname, NULL, &se, buf, sizeof(buf)) != NULL) { 802251875Speter sockaddr->port = ntohs(se.s_port); 803251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 804251875Speter sockaddr->sa.sin.sin_port = se.s_port; 805251875Speter return APR_SUCCESS; 806251875Speter } 807251875Speter#elif defined(GETSERVBYNAME_R_OSF1) 808251875Speter if (getservbyname_r(servname, NULL, &se, &sed) == 0) { 809251875Speter sockaddr->port = ntohs(se.s_port); 810251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 811251875Speter sockaddr->sa.sin.sin_port = se.s_port; 812251875Speter return APR_SUCCESS; 813251875Speter } 814251875Speter#endif 815251875Speter#else 816251875Speter if ((se = getservbyname(servname, NULL)) != NULL){ 817251875Speter sockaddr->port = ntohs(se->s_port); 818251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 819251875Speter sockaddr->sa.sin.sin_port = se->s_port; 820251875Speter return APR_SUCCESS; 821251875Speter } 822251875Speter#endif 823251875Speter return APR_ENOENT; 824251875Speter} 825251875Speter 826251875Speter#define V4MAPPED_EQUAL(a,b) \ 827251875Speter((a)->sa.sin.sin_family == AF_INET && \ 828251875Speter (b)->sa.sin.sin_family == AF_INET6 && \ 829251875Speter IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) && \ 830251875Speter !memcmp((a)->ipaddr_ptr, \ 831251875Speter &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12], \ 832251875Speter (a)->ipaddr_len)) 833251875Speter 834251875SpeterAPR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, 835251875Speter const apr_sockaddr_t *addr2) 836251875Speter{ 837251875Speter if (addr1->ipaddr_len == addr2->ipaddr_len && 838251875Speter !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len)) { 839251875Speter return 1; 840251875Speter } 841251875Speter#if APR_HAVE_IPV6 842251875Speter if (V4MAPPED_EQUAL(addr1, addr2)) { 843251875Speter return 1; 844251875Speter } 845251875Speter if (V4MAPPED_EQUAL(addr2, addr1)) { 846251875Speter return 1; 847251875Speter } 848251875Speter#endif 849251875Speter return 0; /* not equal */ 850251875Speter} 851251875Speter 852269847SpeterAPR_DECLARE(int) apr_sockaddr_is_wildcard(const apr_sockaddr_t *addr) 853269847Speter{ 854269847Speter static const char inaddr_any[ 855269847Speter#if APR_HAVE_IPV6 856269847Speter sizeof(struct in6_addr) 857269847Speter#else 858269847Speter sizeof(struct in_addr) 859269847Speter#endif 860269847Speter ] = {0}; 861269847Speter 862269847Speter if (addr->ipaddr_ptr /* IP address initialized */ 863269847Speter && addr->ipaddr_len <= sizeof inaddr_any) { /* else bug elsewhere? */ 864269847Speter if (!memcmp(inaddr_any, addr->ipaddr_ptr, addr->ipaddr_len)) { 865269847Speter return 1; 866269847Speter } 867269847Speter#if APR_HAVE_IPV6 868269847Speter if (addr->family == AF_INET6 869269847Speter && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr)) { 870269847Speter struct in_addr *v4 = (struct in_addr *)&((apr_uint32_t *)addr->ipaddr_ptr)[3]; 871269847Speter 872269847Speter if (!memcmp(inaddr_any, v4, sizeof *v4)) { 873269847Speter return 1; 874269847Speter } 875269847Speter } 876269847Speter#endif 877269847Speter } 878269847Speter return 0; 879269847Speter} 880269847Speter 881251875Speterstatic apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network) 882251875Speter{ 883251875Speter /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */ 884251875Speter int shift; 885251875Speter char *s, *t; 886251875Speter int octet; 887251875Speter char buf[sizeof "255.255.255.255"]; 888251875Speter 889251875Speter if (strlen(network) < sizeof buf) { 890251875Speter strcpy(buf, network); 891251875Speter } 892251875Speter else { 893251875Speter return APR_EBADIP; 894251875Speter } 895251875Speter 896251875Speter /* parse components */ 897251875Speter s = buf; 898251875Speter ipsub->sub[0] = 0; 899251875Speter ipsub->mask[0] = 0; 900251875Speter shift = 24; 901251875Speter while (*s) { 902251875Speter t = s; 903251875Speter if (!apr_isdigit(*t)) { 904251875Speter return APR_EBADIP; 905251875Speter } 906251875Speter while (apr_isdigit(*t)) { 907251875Speter ++t; 908251875Speter } 909251875Speter if (*t == '.') { 910251875Speter *t++ = 0; 911251875Speter } 912251875Speter else if (*t) { 913251875Speter return APR_EBADIP; 914251875Speter } 915251875Speter if (shift < 0) { 916251875Speter return APR_EBADIP; 917251875Speter } 918251875Speter octet = atoi(s); 919251875Speter if (octet < 0 || octet > 255) { 920251875Speter return APR_EBADIP; 921251875Speter } 922251875Speter ipsub->sub[0] |= octet << shift; 923251875Speter ipsub->mask[0] |= 0xFFUL << shift; 924251875Speter s = t; 925251875Speter shift -= 8; 926251875Speter } 927251875Speter ipsub->sub[0] = ntohl(ipsub->sub[0]); 928251875Speter ipsub->mask[0] = ntohl(ipsub->mask[0]); 929251875Speter ipsub->family = AF_INET; 930251875Speter return APR_SUCCESS; 931251875Speter} 932251875Speter 933251875Speter/* return values: 934251875Speter * APR_EINVAL not an IP address; caller should see if it is something else 935251875Speter * APR_BADIP IP address portion is is not valid 936251875Speter * APR_BADMASK mask portion is not valid 937251875Speter */ 938251875Speter 939251875Speterstatic apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed) 940251875Speter{ 941251875Speter /* supported flavors of IP: 942251875Speter * 943251875Speter * . IPv6 numeric address string (e.g., "fe80::1") 944251875Speter * 945251875Speter * IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address. 946251875Speter * 947251875Speter * . IPv4 numeric address string (e.g., "127.0.0.1") 948251875Speter * 949251875Speter * . IPv4 network string (e.g., "9.67") 950251875Speter * 951251875Speter * IMPORTANT: This network form is only allowed if network_allowed is on. 952251875Speter */ 953251875Speter int rc; 954251875Speter 955251875Speter#if APR_HAVE_IPV6 956251875Speter rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub); 957251875Speter if (rc == 1) { 958251875Speter if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) { 959251875Speter /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6 960251875Speter * addresses; this of course forces the user to specify IPv4 addresses 961251875Speter * in a.b.c.d style instead of ::ffff:a.b.c.d style. 962251875Speter */ 963251875Speter return APR_EBADIP; 964251875Speter } 965251875Speter ipsub->family = AF_INET6; 966251875Speter } 967251875Speter else 968251875Speter#endif 969251875Speter { 970251875Speter rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub); 971251875Speter if (rc == 1) { 972251875Speter ipsub->family = AF_INET; 973251875Speter } 974251875Speter } 975251875Speter if (rc != 1) { 976251875Speter if (network_allowed) { 977251875Speter return parse_network(ipsub, ipstr); 978251875Speter } 979251875Speter else { 980251875Speter return APR_EBADIP; 981251875Speter } 982251875Speter } 983251875Speter return APR_SUCCESS; 984251875Speter} 985251875Speter 986251875Speterstatic int looks_like_ip(const char *ipstr) 987251875Speter{ 988251875Speter if (strchr(ipstr, ':')) { 989251875Speter /* definitely not a hostname; assume it is intended to be an IPv6 address */ 990251875Speter return 1; 991251875Speter } 992251875Speter 993251875Speter /* simple IPv4 address string check */ 994251875Speter while ((*ipstr == '.') || apr_isdigit(*ipstr)) 995251875Speter ipstr++; 996251875Speter return (*ipstr == '\0'); 997251875Speter} 998251875Speter 999251875Speterstatic void fix_subnet(apr_ipsubnet_t *ipsub) 1000251875Speter{ 1001251875Speter /* in case caller specified more bits in network address than are 1002251875Speter * valid according to the mask, turn off the extra bits 1003251875Speter */ 1004251875Speter int i; 1005251875Speter 1006251875Speter for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) { 1007251875Speter ipsub->sub[i] &= ipsub->mask[i]; 1008251875Speter } 1009251875Speter} 1010251875Speter 1011251875Speter/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */ 1012251875SpeterAPR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, 1013251875Speter const char *mask_or_numbits, apr_pool_t *p) 1014251875Speter{ 1015251875Speter apr_status_t rv; 1016251875Speter char *endptr; 1017251875Speter long bits, maxbits = 32; 1018251875Speter 1019251875Speter /* filter out stuff which doesn't look remotely like an IP address; this helps 1020251875Speter * callers like mod_access which have a syntax allowing hostname or IP address; 1021251875Speter * APR_EINVAL tells the caller that it was probably not intended to be an IP 1022251875Speter * address 1023251875Speter */ 1024251875Speter if (!looks_like_ip(ipstr)) { 1025251875Speter return APR_EINVAL; 1026251875Speter } 1027251875Speter 1028251875Speter *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t)); 1029251875Speter 1030251875Speter /* assume ipstr is an individual IP address, not a subnet */ 1031251875Speter memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask); 1032251875Speter 1033251875Speter rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL); 1034251875Speter if (rv != APR_SUCCESS) { 1035251875Speter return rv; 1036251875Speter } 1037251875Speter 1038251875Speter if (mask_or_numbits) { 1039251875Speter#if APR_HAVE_IPV6 1040251875Speter if ((*ipsub)->family == AF_INET6) { 1041251875Speter maxbits = 128; 1042251875Speter } 1043251875Speter#endif 1044251875Speter bits = strtol(mask_or_numbits, &endptr, 10); 1045251875Speter if (*endptr == '\0' && bits > 0 && bits <= maxbits) { 1046251875Speter /* valid num-bits string; fill in mask appropriately */ 1047251875Speter int cur_entry = 0; 1048251875Speter apr_int32_t cur_bit_value; 1049251875Speter 1050251875Speter memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask); 1051251875Speter while (bits > 32) { 1052251875Speter (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */ 1053251875Speter bits -= 32; 1054251875Speter ++cur_entry; 1055251875Speter } 1056251875Speter cur_bit_value = 0x80000000; 1057251875Speter while (bits) { 1058251875Speter (*ipsub)->mask[cur_entry] |= cur_bit_value; 1059251875Speter --bits; 1060251875Speter cur_bit_value /= 2; 1061251875Speter } 1062251875Speter (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]); 1063251875Speter } 1064251875Speter else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 && 1065251875Speter (*ipsub)->family == AF_INET) { 1066251875Speter /* valid IPv4 netmask */ 1067251875Speter } 1068251875Speter else { 1069251875Speter return APR_EBADMASK; 1070251875Speter } 1071251875Speter } 1072251875Speter 1073251875Speter fix_subnet(*ipsub); 1074251875Speter 1075251875Speter return APR_SUCCESS; 1076251875Speter} 1077251875Speter 1078251875SpeterAPR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa) 1079251875Speter{ 1080251875Speter#if APR_HAVE_IPV6 1081251875Speter /* XXX This line will segv on Win32 build with APR_HAVE_IPV6, 1082251875Speter * but without the IPV6 drivers installed. 1083251875Speter */ 1084253734Speter if (sa->family == AF_INET) { 1085251875Speter if (ipsub->family == AF_INET && 1086251875Speter ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) { 1087251875Speter return 1; 1088251875Speter } 1089251875Speter } 1090251875Speter else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) { 1091251875Speter if (ipsub->family == AF_INET && 1092251875Speter (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) { 1093251875Speter return 1; 1094251875Speter } 1095251875Speter } 1096253734Speter else if (sa->family == AF_INET6 && ipsub->family == AF_INET6) { 1097251875Speter apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr; 1098251875Speter 1099251875Speter if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] && 1100251875Speter (addr[1] & ipsub->mask[1]) == ipsub->sub[1] && 1101251875Speter (addr[2] & ipsub->mask[2]) == ipsub->sub[2] && 1102251875Speter (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) { 1103251875Speter return 1; 1104251875Speter } 1105251875Speter } 1106251875Speter#else 1107251875Speter if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) { 1108251875Speter return 1; 1109251875Speter } 1110251875Speter#endif /* APR_HAVE_IPV6 */ 1111251875Speter return 0; /* no match */ 1112251875Speter} 1113