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 28362181Sdim#ifdef HAVE_NET_IF_H 29362181Sdim#include <net/if.h> 30362181Sdim#endif 31362181Sdim 32362181Sdim#if defined(HAVE_IF_INDEXTONAME) && defined(_MSC_VER) 33362181Sdim#include "arch/win32/apr_arch_misc.h" 34362181Sdim#endif 35362181Sdim 36251875Speter#define APR_WANT_STRFUNC 37251875Speter#include "apr_want.h" 38251875Speter 39251875Speterstruct apr_ipsubnet_t { 40251875Speter int family; 41251875Speter#if APR_HAVE_IPV6 42251875Speter apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */ 43251875Speter apr_uint32_t mask[4]; 44251875Speter#else 45251875Speter apr_uint32_t sub[1]; 46251875Speter apr_uint32_t mask[1]; 47251875Speter#endif 48251875Speter}; 49251875Speter 50251875Speter#if !defined(NETWARE) && !defined(WIN32) 51251875Speter#ifdef HAVE_SET_H_ERRNO 52251875Speter#define SET_H_ERRNO(newval) set_h_errno(newval) 53251875Speter#else 54251875Speter#define SET_H_ERRNO(newval) h_errno = (newval) 55251875Speter#endif 56251875Speter#else 57251875Speter#define SET_H_ERRNO(newval) 58251875Speter#endif 59251875Speter 60251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 61251875Speter defined(HAVE_GETHOSTBYNAME_R) 62251875Speter/* This is the maximum size that may be returned from the reentrant 63251875Speter * gethostbyname_r function. If the system tries to use more, it 64251875Speter * should return ERANGE. 65251875Speter */ 66251875Speter#define GETHOSTBYNAME_BUFLEN 512 67251875Speter#endif 68251875Speter 69251875Speter#ifdef _AIX 70251875Speter/* Some levels of AIX getaddrinfo() don't like servname = "0", so 71251875Speter * set servname to "1" when port is 0 and fix it up later. 72251875Speter */ 73251875Speter#define AIX_SERVNAME_HACK 1 74251875Speter#else 75251875Speter#define AIX_SERVNAME_HACK 0 76251875Speter#endif 77251875Speter 78251875Speter#ifdef _WIN32_WCE 79251875Speter/* XXX: BS solution. Need an HAVE_GETSERVBYNAME and actually 80251875Speter * do something here, to provide the obvious proto mappings. 81251875Speter */ 82251875Speterstatic void *getservbyname(const char *name, const char *proto) 83251875Speter{ 84251875Speter return NULL; 85251875Speter} 86251875Speter#endif 87251875Speter 88251875Speterstatic apr_status_t get_local_addr(apr_socket_t *sock) 89251875Speter{ 90251875Speter sock->local_addr->salen = sizeof(sock->local_addr->sa); 91251875Speter if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa, 92251875Speter &sock->local_addr->salen) < 0) { 93251875Speter return apr_get_netos_error(); 94251875Speter } 95251875Speter else { 96251875Speter sock->local_port_unknown = sock->local_interface_unknown = 0; 97251875Speter /* XXX assumes sin_port and sin6_port at same offset */ 98251875Speter sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port); 99251875Speter return APR_SUCCESS; 100251875Speter } 101251875Speter} 102251875Speter 103251875Speterstatic apr_status_t get_remote_addr(apr_socket_t *sock) 104251875Speter{ 105251875Speter sock->remote_addr->salen = sizeof(sock->remote_addr->sa); 106251875Speter if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa, 107251875Speter &sock->remote_addr->salen) < 0) { 108251875Speter return apr_get_netos_error(); 109251875Speter } 110251875Speter else { 111251875Speter sock->remote_addr_unknown = 0; 112251875Speter /* XXX assumes sin_port and sin6_port at same offset */ 113251875Speter sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port); 114251875Speter return APR_SUCCESS; 115251875Speter } 116251875Speter} 117251875Speter 118251875SpeterAPR_DECLARE(apr_status_t) apr_sockaddr_ip_getbuf(char *buf, apr_size_t buflen, 119251875Speter apr_sockaddr_t *sockaddr) 120251875Speter{ 121251875Speter if (!apr_inet_ntop(sockaddr->family, sockaddr->ipaddr_ptr, buf, buflen)) { 122251875Speter return APR_ENOSPC; 123251875Speter } 124251875Speter 125251875Speter#if APR_HAVE_IPV6 126251875Speter if (sockaddr->family == AF_INET6 127251875Speter && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sockaddr->ipaddr_ptr) 128251875Speter && buflen > strlen("::ffff:")) { 129251875Speter /* This is an IPv4-mapped IPv6 address; drop the leading 130251875Speter * part of the address string so we're left with the familiar 131251875Speter * IPv4 format. 132251875Speter */ 133251875Speter memmove(buf, buf + strlen("::ffff:"), 134251875Speter strlen(buf + strlen("::ffff:"))+1); 135251875Speter } 136362181Sdim 137251875Speter /* ensure NUL termination if the buffer is too short */ 138251875Speter buf[buflen-1] = '\0'; 139362181Sdim 140362181Sdim#ifdef HAVE_IF_INDEXTONAME 141362181Sdim /* Append scope name for link-local addresses. */ 142362181Sdim if (sockaddr->family == AF_INET6 143362181Sdim && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)sockaddr->ipaddr_ptr)) { 144362181Sdim char scbuf[IF_NAMESIZE], *p = buf + strlen(buf); 145362181Sdim 146362181Sdim if (if_indextoname(sockaddr->sa.sin6.sin6_scope_id, scbuf) == scbuf) { 147362181Sdim /* Space check, need room for buf + '%' + scope + '\0'. 148362181Sdim * Assert: buflen >= strlen(buf) + strlen(scbuf) + 2 149362181Sdim * Equiv: buflen >= (p-buf) + strlen(buf) + 2 150362181Sdim * Thus, fail in inverse condition: */ 151362181Sdim if (buflen < strlen(scbuf) + (p - buf) + 2) { 152362181Sdim return APR_ENOSPC; 153362181Sdim } 154362181Sdim *p++ = '%'; 155362181Sdim memcpy(p, scbuf, strlen(scbuf) + 1); 156362181Sdim } 157362181Sdim } 158362181Sdim#endif /* HAVE_IF_INDEXTONAME */ 159362181Sdim#endif /* APR_HAVE_IPV6 */ 160362181Sdim 161251875Speter return APR_SUCCESS; 162251875Speter} 163251875Speter 164251875SpeterAPR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr, 165251875Speter apr_sockaddr_t *sockaddr) 166251875Speter{ 167251875Speter *addr = apr_palloc(sockaddr->pool, sockaddr->addr_str_len); 168251875Speter return apr_sockaddr_ip_getbuf(*addr, sockaddr->addr_str_len, sockaddr); 169251875Speter} 170251875Speter 171251875Spetervoid apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port) 172251875Speter{ 173251875Speter addr->family = family; 174251875Speter addr->sa.sin.sin_family = family; 175251875Speter if (port) { 176251875Speter /* XXX IPv6: assumes sin_port and sin6_port at same offset */ 177251875Speter addr->sa.sin.sin_port = htons(port); 178251875Speter addr->port = port; 179251875Speter } 180251875Speter#if AIX_SERVNAME_HACK 181251875Speter else { 182251875Speter addr->sa.sin.sin_port = htons(port); 183251875Speter } 184251875Speter#endif 185251875Speter 186251875Speter if (family == APR_INET) { 187251875Speter addr->salen = sizeof(struct sockaddr_in); 188251875Speter addr->addr_str_len = 16; 189251875Speter addr->ipaddr_ptr = &(addr->sa.sin.sin_addr); 190251875Speter addr->ipaddr_len = sizeof(struct in_addr); 191251875Speter } 192251875Speter#if APR_HAVE_IPV6 193251875Speter else if (family == APR_INET6) { 194251875Speter addr->salen = sizeof(struct sockaddr_in6); 195251875Speter addr->addr_str_len = 46; 196251875Speter addr->ipaddr_ptr = &(addr->sa.sin6.sin6_addr); 197251875Speter addr->ipaddr_len = sizeof(struct in6_addr); 198251875Speter } 199251875Speter#endif 200362181Sdim#if APR_HAVE_SOCKADDR_UN 201362181Sdim else if (family == APR_UNIX) { 202362181Sdim addr->salen = sizeof(struct sockaddr_un); 203362181Sdim addr->addr_str_len = sizeof(addr->sa.unx.sun_path);; 204362181Sdim addr->ipaddr_ptr = &(addr->sa.unx.sun_path); 205362181Sdim addr->ipaddr_len = addr->addr_str_len; 206362181Sdim } 207362181Sdim#endif 208251875Speter} 209251875Speter 210251875SpeterAPR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa, 211251875Speter apr_interface_e which, 212251875Speter apr_socket_t *sock) 213251875Speter{ 214251875Speter if (which == APR_LOCAL) { 215251875Speter if (sock->local_interface_unknown || sock->local_port_unknown) { 216251875Speter apr_status_t rv = get_local_addr(sock); 217251875Speter 218251875Speter if (rv != APR_SUCCESS) { 219251875Speter return rv; 220251875Speter } 221251875Speter } 222251875Speter *sa = sock->local_addr; 223251875Speter } 224251875Speter else if (which == APR_REMOTE) { 225251875Speter if (sock->remote_addr_unknown) { 226251875Speter apr_status_t rv = get_remote_addr(sock); 227251875Speter 228251875Speter if (rv != APR_SUCCESS) { 229251875Speter return rv; 230251875Speter } 231251875Speter } 232251875Speter *sa = sock->remote_addr; 233251875Speter } 234251875Speter else { 235251875Speter *sa = NULL; 236251875Speter return APR_EINVAL; 237251875Speter } 238251875Speter return APR_SUCCESS; 239251875Speter} 240251875Speter 241251875SpeterAPR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr, 242251875Speter char **scope_id, 243251875Speter apr_port_t *port, 244251875Speter const char *str, 245251875Speter apr_pool_t *p) 246251875Speter{ 247251875Speter const char *ch, *lastchar; 248251875Speter int big_port; 249251875Speter apr_size_t addrlen; 250251875Speter 251251875Speter *addr = NULL; /* assume not specified */ 252251875Speter *scope_id = NULL; /* assume not specified */ 253251875Speter *port = 0; /* assume not specified */ 254251875Speter 255251875Speter /* First handle the optional port number. That may be all that 256251875Speter * is specified in the string. 257251875Speter */ 258251875Speter ch = lastchar = str + strlen(str) - 1; 259251875Speter while (ch >= str && apr_isdigit(*ch)) { 260251875Speter --ch; 261251875Speter } 262251875Speter 263251875Speter if (ch < str) { /* Entire string is the port. */ 264251875Speter big_port = atoi(str); 265251875Speter if (big_port < 1 || big_port > 65535) { 266251875Speter return APR_EINVAL; 267251875Speter } 268251875Speter *port = big_port; 269251875Speter return APR_SUCCESS; 270251875Speter } 271251875Speter 272251875Speter if (*ch == ':' && ch < lastchar) { /* host and port number specified */ 273251875Speter if (ch == str) { /* string starts with ':' -- bad */ 274251875Speter return APR_EINVAL; 275251875Speter } 276251875Speter big_port = atoi(ch + 1); 277251875Speter if (big_port < 1 || big_port > 65535) { 278251875Speter return APR_EINVAL; 279251875Speter } 280251875Speter *port = big_port; 281251875Speter lastchar = ch - 1; 282251875Speter } 283251875Speter 284251875Speter /* now handle the hostname */ 285251875Speter addrlen = lastchar - str + 1; 286251875Speter 287251875Speter/* XXX we don't really have to require APR_HAVE_IPV6 for this; 288251875Speter * just pass char[] for ipaddr (so we don't depend on struct in6_addr) 289251875Speter * and always define APR_INET6 290251875Speter */ 291251875Speter#if APR_HAVE_IPV6 292251875Speter if (*str == '[') { 293251875Speter const char *end_bracket = memchr(str, ']', addrlen); 294251875Speter struct in6_addr ipaddr; 295251875Speter const char *scope_delim; 296251875Speter 297251875Speter if (!end_bracket || end_bracket != lastchar) { 298251875Speter *port = 0; 299251875Speter return APR_EINVAL; 300251875Speter } 301251875Speter 302251875Speter /* handle scope id; this is the only context where it is allowed */ 303251875Speter scope_delim = memchr(str, '%', addrlen); 304251875Speter if (scope_delim) { 305251875Speter if (scope_delim == end_bracket - 1) { /* '%' without scope id */ 306251875Speter *port = 0; 307251875Speter return APR_EINVAL; 308251875Speter } 309251875Speter addrlen = scope_delim - str - 1; 310362181Sdim *scope_id = apr_pstrmemdup(p, scope_delim + 1, end_bracket - scope_delim - 1); 311251875Speter } 312251875Speter else { 313251875Speter addrlen = addrlen - 2; /* minus 2 for '[' and ']' */ 314251875Speter } 315251875Speter 316362181Sdim *addr = apr_pstrmemdup(p, str + 1, addrlen); 317251875Speter if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) { 318251875Speter *addr = NULL; 319251875Speter *scope_id = NULL; 320251875Speter *port = 0; 321251875Speter return APR_EINVAL; 322251875Speter } 323251875Speter } 324251875Speter else 325251875Speter#endif 326251875Speter { 327251875Speter /* XXX If '%' is not a valid char in a DNS name, we *could* check 328251875Speter * for bogus scope ids first. 329251875Speter */ 330362181Sdim *addr = apr_pstrmemdup(p, str, addrlen); 331251875Speter } 332251875Speter return APR_SUCCESS; 333251875Speter} 334251875Speter 335251875Speter#if defined(HAVE_GETADDRINFO) 336251875Speter 337251875Speterstatic apr_status_t call_resolver(apr_sockaddr_t **sa, 338251875Speter const char *hostname, apr_int32_t family, 339251875Speter apr_port_t port, apr_int32_t flags, 340251875Speter apr_pool_t *p) 341251875Speter{ 342251875Speter struct addrinfo hints, *ai, *ai_list; 343251875Speter apr_sockaddr_t *prev_sa; 344251875Speter int error; 345251875Speter char *servname = NULL; 346251875Speter 347251875Speter memset(&hints, 0, sizeof(hints)); 348251875Speter hints.ai_family = family; 349251875Speter hints.ai_socktype = SOCK_STREAM; 350251875Speter#ifdef HAVE_GAI_ADDRCONFIG 351251875Speter if (family == APR_UNSPEC) { 352251875Speter /* By default, only look up addresses using address types for 353251875Speter * which a local interface is configured, i.e. no IPv6 if no 354251875Speter * IPv6 interfaces configured. */ 355251875Speter hints.ai_flags = AI_ADDRCONFIG; 356251875Speter } 357251875Speter#endif 358286503Speter 359286503Speter#ifdef __MVS__ 360286503Speter /* z/OS will not return IPv4 address under AF_UNSPEC if any IPv6 results 361286503Speter * are returned, w/o AI_ALL. 362286503Speter */ 363286503Speter if (family == APR_UNSPEC) { 364286503Speter hints.ai_flags |= AI_ALL; 365286503Speter } 366286503Speter#endif 367286503Speter 368251875Speter if(hostname == NULL) { 369251875Speter#ifdef AI_PASSIVE 370251875Speter /* If hostname is NULL, assume we are trying to bind to all 371251875Speter * interfaces. */ 372251875Speter hints.ai_flags |= AI_PASSIVE; 373251875Speter#endif 374251875Speter /* getaddrinfo according to RFC 2553 must have either hostname 375251875Speter * or servname non-NULL. 376251875Speter */ 377251875Speter#ifdef OSF1 378251875Speter /* The Tru64 5.0 getaddrinfo() can only resolve services given 379251875Speter * by the name listed in /etc/services; a numeric or unknown 380251875Speter * servname gets an EAI_SERVICE error. So just resolve the 381251875Speter * appropriate anyaddr and fill in the port later. */ 382251875Speter hostname = family == AF_INET6 ? "::" : "0.0.0.0"; 383251875Speter servname = NULL; 384251875Speter#ifdef AI_NUMERICHOST 385251875Speter hints.ai_flags |= AI_NUMERICHOST; 386251875Speter#endif 387251875Speter#else 388251875Speter#if AIX_SERVNAME_HACK 389251875Speter if (!port) { 390251875Speter servname = "1"; 391251875Speter } 392251875Speter else 393251875Speter#endif /* AIX_SERVNAME_HACK */ 394251875Speter servname = apr_itoa(p, port); 395251875Speter#endif /* OSF1 */ 396251875Speter } 397251875Speter error = getaddrinfo(hostname, servname, &hints, &ai_list); 398251875Speter#ifdef HAVE_GAI_ADDRCONFIG 399253734Speter /* 400253734Speter * Using AI_ADDRCONFIG involves some unfortunate guesswork because it 401253734Speter * does not consider loopback addresses when trying to determine if 402253734Speter * IPv4 or IPv6 is configured on a system (see RFC 3493). 403253734Speter * This is a problem if one actually wants to listen on or connect to 404253734Speter * the loopback address of a protocol family that is not otherwise 405253734Speter * configured on the system. See PR 52709. 406253734Speter * To work around some of the problems, retry without AI_ADDRCONFIG 407253734Speter * in case of EAI_ADDRFAMILY. 408253734Speter * XXX: apr_sockaddr_info_get() should really accept a flag to determine 409253734Speter * XXX: if AI_ADDRCONFIG's guesswork is wanted and if the address is 410253734Speter * XXX: to be used for listen() or connect(). 411253734Speter * 412253734Speter * In case of EAI_BADFLAGS, AI_ADDRCONFIG is not supported. 413253734Speter */ 414253734Speter if ((family == APR_UNSPEC) && (error == EAI_BADFLAGS 415253734Speter#ifdef EAI_ADDRFAMILY 416253734Speter || error == EAI_ADDRFAMILY 417253734Speter#endif 418253734Speter )) { 419253734Speter hints.ai_flags &= ~AI_ADDRCONFIG; 420251875Speter error = getaddrinfo(hostname, servname, &hints, &ai_list); 421251875Speter } 422251875Speter#endif 423251875Speter if (error) { 424251875Speter#if defined(WIN32) 425251875Speter return apr_get_netos_error(); 426251875Speter#else 427251875Speter if (error == EAI_SYSTEM) { 428253734Speter return errno ? errno : APR_EGENERAL; 429251875Speter } 430251875Speter else 431251875Speter { 432251875Speter /* issues with representing this with APR's error scheme: 433251875Speter * glibc uses negative values for these numbers, perhaps so 434251875Speter * they don't conflict with h_errno values... Tru64 uses 435251875Speter * positive values which conflict with h_errno values 436251875Speter */ 437251875Speter#if defined(NEGATIVE_EAI) 438251875Speter error = -error; 439251875Speter#endif 440251875Speter return error + APR_OS_START_EAIERR; 441251875Speter } 442251875Speter#endif /* WIN32 */ 443251875Speter } 444251875Speter 445251875Speter prev_sa = NULL; 446251875Speter ai = ai_list; 447251875Speter while (ai) { /* while more addresses to report */ 448251875Speter apr_sockaddr_t *new_sa; 449251875Speter 450251875Speter /* Ignore anything bogus: getaddrinfo in some old versions of 451251875Speter * glibc will return AF_UNIX entries for APR_UNSPEC+AI_PASSIVE 452251875Speter * lookups. */ 453251875Speter#if APR_HAVE_IPV6 454251875Speter if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { 455251875Speter#else 456251875Speter if (ai->ai_family != AF_INET) { 457251875Speter#endif 458251875Speter ai = ai->ai_next; 459251875Speter continue; 460251875Speter } 461251875Speter 462251875Speter new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 463251875Speter 464251875Speter new_sa->pool = p; 465251875Speter memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen); 466251875Speter apr_sockaddr_vars_set(new_sa, ai->ai_family, port); 467251875Speter 468251875Speter if (!prev_sa) { /* first element in new list */ 469251875Speter if (hostname) { 470251875Speter new_sa->hostname = apr_pstrdup(p, hostname); 471251875Speter } 472251875Speter *sa = new_sa; 473251875Speter } 474251875Speter else { 475251875Speter new_sa->hostname = prev_sa->hostname; 476251875Speter prev_sa->next = new_sa; 477251875Speter } 478251875Speter 479251875Speter prev_sa = new_sa; 480251875Speter ai = ai->ai_next; 481251875Speter } 482251875Speter freeaddrinfo(ai_list); 483253734Speter 484253734Speter if (prev_sa == NULL) { 485253734Speter /* 486253734Speter * getaddrinfo returned only useless entries and *sa is still empty. 487253734Speter * This should be treated as an error. 488253734Speter */ 489253734Speter return APR_EGENERAL; 490253734Speter } 491253734Speter 492251875Speter return APR_SUCCESS; 493251875Speter} 494251875Speter 495251875Speterstatic apr_status_t find_addresses(apr_sockaddr_t **sa, 496251875Speter const char *hostname, apr_int32_t family, 497251875Speter apr_port_t port, apr_int32_t flags, 498251875Speter apr_pool_t *p) 499251875Speter{ 500251875Speter if (flags & APR_IPV4_ADDR_OK) { 501251875Speter apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p); 502251875Speter 503251875Speter#if APR_HAVE_IPV6 504251875Speter if (error) { 505251875Speter family = AF_INET6; /* try again */ 506251875Speter } 507251875Speter else 508251875Speter#endif 509251875Speter return error; 510251875Speter } 511251875Speter#if APR_HAVE_IPV6 512251875Speter else if (flags & APR_IPV6_ADDR_OK) { 513251875Speter apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p); 514251875Speter 515251875Speter if (error) { 516251875Speter family = AF_INET; /* try again */ 517251875Speter } 518251875Speter else { 519251875Speter return APR_SUCCESS; 520251875Speter } 521251875Speter } 522251875Speter#endif 523251875Speter 524251875Speter return call_resolver(sa, hostname, family, port, flags, p); 525251875Speter} 526251875Speter 527251875Speter#else /* end of HAVE_GETADDRINFO code */ 528251875Speter 529251875Speterstatic apr_status_t find_addresses(apr_sockaddr_t **sa, 530251875Speter const char *hostname, apr_int32_t family, 531251875Speter apr_port_t port, apr_int32_t flags, 532251875Speter apr_pool_t *p) 533251875Speter{ 534251875Speter struct hostent *hp; 535251875Speter apr_sockaddr_t *prev_sa; 536251875Speter int curaddr; 537251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 538251875Speter defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) 539251875Speter#ifdef GETHOSTBYNAME_R_HOSTENT_DATA 540251875Speter struct hostent_data hd; 541251875Speter#else 542251875Speter /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be 543251875Speter * bumped. */ 544251875Speter char tmp[GETHOSTBYNAME_BUFLEN]; 545251875Speter#endif 546251875Speter int hosterror; 547251875Speter#endif 548251875Speter struct hostent hs; 549251875Speter struct in_addr ipaddr; 550251875Speter char *addr_list[2]; 551251875Speter const char *orig_hostname = hostname; 552251875Speter 553251875Speter if (hostname == NULL) { 554251875Speter /* if we are given a NULL hostname, assume '0.0.0.0' */ 555251875Speter hostname = "0.0.0.0"; 556251875Speter } 557251875Speter 558251875Speter if (*hostname >= '0' && *hostname <= '9' && 559251875Speter strspn(hostname, "0123456789.") == strlen(hostname)) { 560251875Speter 561251875Speter ipaddr.s_addr = inet_addr(hostname); 562251875Speter addr_list[0] = (char *)&ipaddr; 563251875Speter addr_list[1] = NULL; /* just one IP in list */ 564251875Speter hs.h_addr_list = (char **)addr_list; 565251875Speter hp = &hs; 566251875Speter } 567251875Speter else { 568251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 569251875Speter defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) 570251875Speter#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) 571251875Speter /* AIX, HP/UX, D/UX et alia */ 572251875Speter gethostbyname_r(hostname, &hs, &hd); 573251875Speter hp = &hs; 574251875Speter#else 575251875Speter#if defined(GETHOSTBYNAME_R_GLIBC2) 576251875Speter /* Linux glibc2+ */ 577251875Speter gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 578251875Speter &hp, &hosterror); 579251875Speter#else 580251875Speter /* Solaris, Irix et alia */ 581251875Speter hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 582251875Speter &hosterror); 583251875Speter#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ 584251875Speter if (!hp) { 585251875Speter return (hosterror + APR_OS_START_SYSERR); 586251875Speter } 587251875Speter#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ 588251875Speter#else 589251875Speter hp = gethostbyname(hostname); 590251875Speter#endif 591251875Speter 592251875Speter if (!hp) { 593251875Speter#ifdef WIN32 594251875Speter return apr_get_netos_error(); 595251875Speter#else 596251875Speter return (h_errno + APR_OS_START_SYSERR); 597251875Speter#endif 598251875Speter } 599251875Speter } 600251875Speter 601251875Speter prev_sa = NULL; 602251875Speter curaddr = 0; 603251875Speter while (hp->h_addr_list[curaddr]) { 604251875Speter apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 605251875Speter 606251875Speter new_sa->pool = p; 607251875Speter new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr]; 608251875Speter apr_sockaddr_vars_set(new_sa, AF_INET, port); 609251875Speter 610251875Speter if (!prev_sa) { /* first element in new list */ 611251875Speter if (orig_hostname) { 612251875Speter new_sa->hostname = apr_pstrdup(p, orig_hostname); 613251875Speter } 614251875Speter *sa = new_sa; 615251875Speter } 616251875Speter else { 617251875Speter new_sa->hostname = prev_sa->hostname; 618251875Speter prev_sa->next = new_sa; 619251875Speter } 620251875Speter 621251875Speter prev_sa = new_sa; 622251875Speter ++curaddr; 623251875Speter } 624251875Speter 625253734Speter if (prev_sa == NULL) { 626253734Speter /* this should not happen but no result should be treated as error */ 627253734Speter return APR_EGENERAL; 628253734Speter } 629253734Speter 630251875Speter return APR_SUCCESS; 631251875Speter} 632251875Speter 633251875Speter#endif /* end of !HAVE_GETADDRINFO code */ 634251875Speter 635251875SpeterAPR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, 636251875Speter const char *hostname, 637251875Speter apr_int32_t family, apr_port_t port, 638251875Speter apr_int32_t flags, apr_pool_t *p) 639251875Speter{ 640251875Speter apr_int32_t masked; 641251875Speter *sa = NULL; 642251875Speter 643251875Speter if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { 644251875Speter if (!hostname || 645251875Speter family != APR_UNSPEC || 646251875Speter masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) { 647251875Speter return APR_EINVAL; 648251875Speter } 649251875Speter#if !APR_HAVE_IPV6 650251875Speter if (flags & APR_IPV6_ADDR_OK) { 651251875Speter return APR_ENOTIMPL; 652251875Speter } 653251875Speter#endif 654251875Speter } 655362181Sdim if (family == APR_UNSPEC && hostname && *hostname == '/') { 656362181Sdim family = APR_UNIX; 657362181Sdim } 658362181Sdim if (family == APR_UNIX) { 659362181Sdim#if APR_HAVE_SOCKADDR_UN 660362181Sdim if (hostname && *hostname == '/') { 661362181Sdim *sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 662362181Sdim (*sa)->pool = p; 663362181Sdim apr_cpystrn((*sa)->sa.unx.sun_path, hostname, 664362181Sdim sizeof((*sa)->sa.unx.sun_path)); 665362181Sdim (*sa)->hostname = apr_pstrdup(p, hostname); 666362181Sdim (*sa)->family = APR_UNIX; 667362181Sdim (*sa)->sa.unx.sun_family = APR_UNIX; 668362181Sdim (*sa)->salen = sizeof(struct sockaddr_un); 669362181Sdim (*sa)->addr_str_len = sizeof((*sa)->sa.unx.sun_path); 670362181Sdim (*sa)->ipaddr_ptr = &((*sa)->sa.unx.sun_path); 671362181Sdim (*sa)->ipaddr_len = (*sa)->addr_str_len; 672362181Sdim 673362181Sdim return APR_SUCCESS; 674362181Sdim } 675362181Sdim else 676362181Sdim#endif 677362181Sdim { 678362181Sdim *sa = NULL; 679362181Sdim return APR_ENOTIMPL; 680362181Sdim } 681362181Sdim } 682251875Speter#if !APR_HAVE_IPV6 683251875Speter /* What may happen is that APR is not IPv6-enabled, but we're still 684251875Speter * going to call getaddrinfo(), so we have to tell the OS we only 685251875Speter * want IPv4 addresses back since we won't know what to do with 686251875Speter * IPv6 addresses. 687251875Speter */ 688251875Speter if (family == APR_UNSPEC) { 689251875Speter family = APR_INET; 690251875Speter } 691251875Speter#endif 692251875Speter 693251875Speter return find_addresses(sa, hostname, family, port, flags, p); 694251875Speter} 695251875Speter 696362181SdimAPR_DECLARE(apr_status_t) apr_sockaddr_info_copy(apr_sockaddr_t **dst, 697362181Sdim const apr_sockaddr_t *src, 698362181Sdim apr_pool_t *p) 699362181Sdim{ 700362181Sdim apr_sockaddr_t *d; 701362181Sdim const apr_sockaddr_t *s; 702362181Sdim 703362181Sdim for (*dst = d = NULL, s = src; s; s = s->next) { 704362181Sdim if (!d) { 705362181Sdim *dst = d = apr_pmemdup(p, s, sizeof *s); 706362181Sdim } 707362181Sdim else { 708362181Sdim d = d->next = apr_pmemdup(p, s, sizeof *s); 709362181Sdim } 710362181Sdim if (s->hostname) { 711362181Sdim if (s == src || s->hostname != src->hostname) { 712362181Sdim d->hostname = apr_pstrdup(p, s->hostname); 713362181Sdim } 714362181Sdim else { 715362181Sdim d->hostname = (*dst)->hostname; 716362181Sdim } 717362181Sdim } 718362181Sdim if (s->servname) { 719362181Sdim if (s == src || s->servname != src->servname) { 720362181Sdim d->servname = apr_pstrdup(p, s->servname); 721362181Sdim } 722362181Sdim else { 723362181Sdim d->servname = (*dst)->servname; 724362181Sdim } 725362181Sdim } 726362181Sdim d->pool = p; 727362181Sdim apr_sockaddr_vars_set(d, s->family, s->port); 728362181Sdim } 729362181Sdim return APR_SUCCESS; 730362181Sdim} 731362181Sdim 732251875SpeterAPR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, 733251875Speter apr_sockaddr_t *sockaddr, 734251875Speter apr_int32_t flags) 735251875Speter{ 736251875Speter#if defined(HAVE_GETNAMEINFO) 737251875Speter int rc; 738251875Speter#if defined(NI_MAXHOST) 739251875Speter char tmphostname[NI_MAXHOST]; 740251875Speter#else 741251875Speter char tmphostname[256]; 742251875Speter#endif 743251875Speter 744251875Speter /* don't know if it is portable for getnameinfo() to set h_errno; 745251875Speter * clear it then see if it was set */ 746251875Speter SET_H_ERRNO(0); 747251875Speter 748251875Speter /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return 749251875Speter * a numeric address string if it fails to resolve the host name; 750251875Speter * that is *not* what we want here 751251875Speter * 752251875Speter * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling 753251875Speter * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc). 754251875Speter */ 755251875Speter#if APR_HAVE_IPV6 756251875Speter if (sockaddr->family == AF_INET6 && 757251875Speter IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) { 758251875Speter struct sockaddr_in tmpsa; 759251875Speter tmpsa.sin_family = AF_INET; 760251875Speter tmpsa.sin_port = 0; 761251875Speter tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3]; 762251875Speter#ifdef SIN6_LEN 763251875Speter tmpsa.sin_len = sizeof(tmpsa); 764251875Speter#endif 765251875Speter 766251875Speter rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa), 767251875Speter tmphostname, sizeof(tmphostname), NULL, 0, 768251875Speter flags != 0 ? flags : NI_NAMEREQD); 769251875Speter } 770362181Sdim#if APR_HAVE_SOCKADDR_UN 771362181Sdim else if (sockaddr->family == APR_UNIX) { 772362181Sdim *hostname = sockaddr->hostname; 773362181Sdim return APR_SUCCESS; 774362181Sdim } 775362181Sdim#endif 776251875Speter else 777251875Speter#endif 778251875Speter rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen, 779251875Speter tmphostname, sizeof(tmphostname), NULL, 0, 780251875Speter flags != 0 ? flags : NI_NAMEREQD); 781251875Speter if (rc != 0) { 782251875Speter *hostname = NULL; 783251875Speter 784251875Speter#ifndef WIN32 785251875Speter /* something went wrong. Look at the EAI_ error code */ 786251875Speter if (rc == EAI_SYSTEM) { 787251875Speter /* EAI_SYSTEM System error returned in errno. */ 788251875Speter /* IMHO, Implementations that set h_errno a simply broken. */ 789251875Speter if (h_errno) { /* for broken implementations which set h_errno */ 790251875Speter return h_errno + APR_OS_START_SYSERR; 791251875Speter } 792251875Speter else { /* "normal" case */ 793251875Speter return errno + APR_OS_START_SYSERR; 794251875Speter } 795251875Speter } 796251875Speter else 797251875Speter#endif 798251875Speter { 799251875Speter#if defined(NEGATIVE_EAI) 800251875Speter if (rc < 0) rc = -rc; 801251875Speter#endif 802251875Speter return rc + APR_OS_START_EAIERR; /* return the EAI_ error */ 803251875Speter } 804251875Speter } 805251875Speter *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, 806251875Speter tmphostname); 807251875Speter return APR_SUCCESS; 808251875Speter#else 809251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \ 810251875Speter defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS) 811251875Speter#ifdef GETHOSTBYNAME_R_HOSTENT_DATA 812251875Speter struct hostent_data hd; 813251875Speter#else 814251875Speter char tmp[GETHOSTBYNAME_BUFLEN]; 815251875Speter#endif 816251875Speter int hosterror; 817251875Speter struct hostent hs, *hptr; 818251875Speter 819251875Speter#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) 820251875Speter /* AIX, HP/UX, D/UX et alia */ 821251875Speter gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 822251875Speter sizeof(struct in_addr), AF_INET, &hs, &hd); 823251875Speter hptr = &hs; 824251875Speter#else 825251875Speter#if defined(GETHOSTBYNAME_R_GLIBC2) 826251875Speter /* Linux glibc2+ */ 827251875Speter gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 828251875Speter sizeof(struct in_addr), AF_INET, 829251875Speter &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror); 830251875Speter#else 831251875Speter /* Solaris, Irix et alia */ 832251875Speter hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 833251875Speter sizeof(struct in_addr), AF_INET, 834251875Speter &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror); 835251875Speter#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ 836251875Speter if (!hptr) { 837251875Speter *hostname = NULL; 838251875Speter return hosterror + APR_OS_START_SYSERR; 839251875Speter } 840251875Speter#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ 841251875Speter#else 842251875Speter struct hostent *hptr; 843251875Speter hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, 844251875Speter sizeof(struct in_addr), AF_INET); 845251875Speter#endif 846251875Speter 847251875Speter if (hptr) { 848251875Speter *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name); 849251875Speter return APR_SUCCESS; 850251875Speter } 851251875Speter *hostname = NULL; 852251875Speter#if defined(WIN32) 853251875Speter return apr_get_netos_error(); 854251875Speter#elif defined(OS2) 855251875Speter return h_errno; 856251875Speter#else 857251875Speter return h_errno + APR_OS_START_SYSERR; 858251875Speter#endif 859251875Speter#endif 860251875Speter} 861251875Speter 862251875SpeterAPR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, 863251875Speter const char *servname) 864251875Speter{ 865251875Speter#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ 866251875Speter defined(HAVE_GETSERVBYNAME_R) && \ 867251875Speter (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ 868251875Speter defined(GETSERVBYNAME_R_OSF1)) 869251875Speter struct servent se; 870251875Speter#if defined(GETSERVBYNAME_R_OSF1) 871251875Speter struct servent_data sed; 872251875Speter 873251875Speter memset(&sed, 0, sizeof(sed)); /* must zero fill before use */ 874251875Speter#else 875251875Speter#if defined(GETSERVBYNAME_R_GLIBC2) 876251875Speter struct servent *res; 877251875Speter#endif 878251875Speter char buf[1024]; 879251875Speter#endif 880251875Speter#else 881251875Speter struct servent *se; 882251875Speter#endif 883251875Speter 884251875Speter if (servname == NULL) 885251875Speter return APR_EINVAL; 886251875Speter 887251875Speter#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ 888251875Speter defined(HAVE_GETSERVBYNAME_R) && \ 889251875Speter (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ 890251875Speter defined(GETSERVBYNAME_R_OSF1)) 891251875Speter#if defined(GETSERVBYNAME_R_GLIBC2) 892251875Speter if (getservbyname_r(servname, NULL, 893251875Speter &se, buf, sizeof(buf), &res) == 0 && res != NULL) { 894251875Speter sockaddr->port = ntohs(res->s_port); 895251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 896251875Speter sockaddr->sa.sin.sin_port = res->s_port; 897251875Speter return APR_SUCCESS; 898251875Speter } 899251875Speter#elif defined(GETSERVBYNAME_R_SOLARIS) 900251875Speter if (getservbyname_r(servname, NULL, &se, buf, sizeof(buf)) != NULL) { 901251875Speter sockaddr->port = ntohs(se.s_port); 902251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 903251875Speter sockaddr->sa.sin.sin_port = se.s_port; 904251875Speter return APR_SUCCESS; 905251875Speter } 906251875Speter#elif defined(GETSERVBYNAME_R_OSF1) 907251875Speter if (getservbyname_r(servname, NULL, &se, &sed) == 0) { 908251875Speter sockaddr->port = ntohs(se.s_port); 909251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 910251875Speter sockaddr->sa.sin.sin_port = se.s_port; 911251875Speter return APR_SUCCESS; 912251875Speter } 913251875Speter#endif 914251875Speter#else 915251875Speter if ((se = getservbyname(servname, NULL)) != NULL){ 916251875Speter sockaddr->port = ntohs(se->s_port); 917251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 918251875Speter sockaddr->sa.sin.sin_port = se->s_port; 919251875Speter return APR_SUCCESS; 920251875Speter } 921251875Speter#endif 922251875Speter return APR_ENOENT; 923251875Speter} 924251875Speter 925251875Speter#define V4MAPPED_EQUAL(a,b) \ 926251875Speter((a)->sa.sin.sin_family == AF_INET && \ 927251875Speter (b)->sa.sin.sin_family == AF_INET6 && \ 928251875Speter IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) && \ 929251875Speter !memcmp((a)->ipaddr_ptr, \ 930251875Speter &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12], \ 931251875Speter (a)->ipaddr_len)) 932251875Speter 933362181Sdim#if APR_HAVE_IPV6 934362181Sdim#define SCOPE_OR_ZERO(sa_) ((sa_)->family != AF_INET6 ? 0 : \ 935362181Sdim ((sa_)->sa.sin6.sin6_scope_id)) 936362181Sdim#else 937362181Sdim#define SCOPE_OR_ZERO(sa_) (0) 938362181Sdim#endif 939362181Sdim 940251875SpeterAPR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, 941251875Speter const apr_sockaddr_t *addr2) 942251875Speter{ 943362181Sdim if (addr1->ipaddr_len == addr2->ipaddr_len 944362181Sdim && !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len) 945362181Sdim && SCOPE_OR_ZERO(addr1) == SCOPE_OR_ZERO(addr2)) { 946251875Speter return 1; 947251875Speter } 948251875Speter#if APR_HAVE_IPV6 949251875Speter if (V4MAPPED_EQUAL(addr1, addr2)) { 950251875Speter return 1; 951251875Speter } 952251875Speter if (V4MAPPED_EQUAL(addr2, addr1)) { 953251875Speter return 1; 954251875Speter } 955251875Speter#endif 956251875Speter return 0; /* not equal */ 957251875Speter} 958251875Speter 959266735SpeterAPR_DECLARE(int) apr_sockaddr_is_wildcard(const apr_sockaddr_t *addr) 960266735Speter{ 961266735Speter static const char inaddr_any[ 962266735Speter#if APR_HAVE_IPV6 963266735Speter sizeof(struct in6_addr) 964266735Speter#else 965266735Speter sizeof(struct in_addr) 966266735Speter#endif 967266735Speter ] = {0}; 968266735Speter 969266735Speter if (addr->ipaddr_ptr /* IP address initialized */ 970266735Speter && addr->ipaddr_len <= sizeof inaddr_any) { /* else bug elsewhere? */ 971266735Speter if (!memcmp(inaddr_any, addr->ipaddr_ptr, addr->ipaddr_len)) { 972266735Speter return 1; 973266735Speter } 974266735Speter#if APR_HAVE_IPV6 975266735Speter if (addr->family == AF_INET6 976266735Speter && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr)) { 977266735Speter struct in_addr *v4 = (struct in_addr *)&((apr_uint32_t *)addr->ipaddr_ptr)[3]; 978266735Speter 979266735Speter if (!memcmp(inaddr_any, v4, sizeof *v4)) { 980266735Speter return 1; 981266735Speter } 982266735Speter } 983266735Speter#endif 984266735Speter } 985266735Speter return 0; 986266735Speter} 987266735Speter 988251875Speterstatic apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network) 989251875Speter{ 990251875Speter /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */ 991251875Speter int shift; 992251875Speter char *s, *t; 993251875Speter int octet; 994251875Speter char buf[sizeof "255.255.255.255"]; 995251875Speter 996251875Speter if (strlen(network) < sizeof buf) { 997251875Speter strcpy(buf, network); 998251875Speter } 999251875Speter else { 1000251875Speter return APR_EBADIP; 1001251875Speter } 1002251875Speter 1003251875Speter /* parse components */ 1004251875Speter s = buf; 1005251875Speter ipsub->sub[0] = 0; 1006251875Speter ipsub->mask[0] = 0; 1007251875Speter shift = 24; 1008251875Speter while (*s) { 1009251875Speter t = s; 1010251875Speter if (!apr_isdigit(*t)) { 1011251875Speter return APR_EBADIP; 1012251875Speter } 1013251875Speter while (apr_isdigit(*t)) { 1014251875Speter ++t; 1015251875Speter } 1016251875Speter if (*t == '.') { 1017251875Speter *t++ = 0; 1018251875Speter } 1019251875Speter else if (*t) { 1020251875Speter return APR_EBADIP; 1021251875Speter } 1022251875Speter if (shift < 0) { 1023251875Speter return APR_EBADIP; 1024251875Speter } 1025251875Speter octet = atoi(s); 1026251875Speter if (octet < 0 || octet > 255) { 1027251875Speter return APR_EBADIP; 1028251875Speter } 1029251875Speter ipsub->sub[0] |= octet << shift; 1030251875Speter ipsub->mask[0] |= 0xFFUL << shift; 1031251875Speter s = t; 1032251875Speter shift -= 8; 1033251875Speter } 1034251875Speter ipsub->sub[0] = ntohl(ipsub->sub[0]); 1035251875Speter ipsub->mask[0] = ntohl(ipsub->mask[0]); 1036251875Speter ipsub->family = AF_INET; 1037251875Speter return APR_SUCCESS; 1038251875Speter} 1039251875Speter 1040251875Speter/* return values: 1041251875Speter * APR_EINVAL not an IP address; caller should see if it is something else 1042251875Speter * APR_BADIP IP address portion is is not valid 1043251875Speter * APR_BADMASK mask portion is not valid 1044251875Speter */ 1045251875Speter 1046251875Speterstatic apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed) 1047251875Speter{ 1048251875Speter /* supported flavors of IP: 1049251875Speter * 1050251875Speter * . IPv6 numeric address string (e.g., "fe80::1") 1051251875Speter * 1052251875Speter * IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address. 1053251875Speter * 1054251875Speter * . IPv4 numeric address string (e.g., "127.0.0.1") 1055251875Speter * 1056251875Speter * . IPv4 network string (e.g., "9.67") 1057251875Speter * 1058251875Speter * IMPORTANT: This network form is only allowed if network_allowed is on. 1059251875Speter */ 1060251875Speter int rc; 1061251875Speter 1062251875Speter#if APR_HAVE_IPV6 1063251875Speter rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub); 1064251875Speter if (rc == 1) { 1065251875Speter if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) { 1066251875Speter /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6 1067251875Speter * addresses; this of course forces the user to specify IPv4 addresses 1068251875Speter * in a.b.c.d style instead of ::ffff:a.b.c.d style. 1069251875Speter */ 1070251875Speter return APR_EBADIP; 1071251875Speter } 1072251875Speter ipsub->family = AF_INET6; 1073251875Speter } 1074251875Speter else 1075251875Speter#endif 1076251875Speter { 1077251875Speter rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub); 1078251875Speter if (rc == 1) { 1079251875Speter ipsub->family = AF_INET; 1080251875Speter } 1081251875Speter } 1082251875Speter if (rc != 1) { 1083251875Speter if (network_allowed) { 1084251875Speter return parse_network(ipsub, ipstr); 1085251875Speter } 1086251875Speter else { 1087251875Speter return APR_EBADIP; 1088251875Speter } 1089251875Speter } 1090251875Speter return APR_SUCCESS; 1091251875Speter} 1092251875Speter 1093251875Speterstatic int looks_like_ip(const char *ipstr) 1094251875Speter{ 1095362181Sdim if (strlen(ipstr) == 0) { 1096362181Sdim return 0; 1097362181Sdim } 1098362181Sdim 1099251875Speter if (strchr(ipstr, ':')) { 1100251875Speter /* definitely not a hostname; assume it is intended to be an IPv6 address */ 1101251875Speter return 1; 1102251875Speter } 1103251875Speter 1104251875Speter /* simple IPv4 address string check */ 1105251875Speter while ((*ipstr == '.') || apr_isdigit(*ipstr)) 1106251875Speter ipstr++; 1107251875Speter return (*ipstr == '\0'); 1108251875Speter} 1109251875Speter 1110251875Speterstatic void fix_subnet(apr_ipsubnet_t *ipsub) 1111251875Speter{ 1112251875Speter /* in case caller specified more bits in network address than are 1113251875Speter * valid according to the mask, turn off the extra bits 1114251875Speter */ 1115251875Speter int i; 1116251875Speter 1117251875Speter for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) { 1118251875Speter ipsub->sub[i] &= ipsub->mask[i]; 1119251875Speter } 1120251875Speter} 1121251875Speter 1122251875Speter/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */ 1123251875SpeterAPR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, 1124251875Speter const char *mask_or_numbits, apr_pool_t *p) 1125251875Speter{ 1126251875Speter apr_status_t rv; 1127251875Speter char *endptr; 1128251875Speter long bits, maxbits = 32; 1129251875Speter 1130251875Speter /* filter out stuff which doesn't look remotely like an IP address; this helps 1131251875Speter * callers like mod_access which have a syntax allowing hostname or IP address; 1132251875Speter * APR_EINVAL tells the caller that it was probably not intended to be an IP 1133251875Speter * address 1134251875Speter */ 1135251875Speter if (!looks_like_ip(ipstr)) { 1136251875Speter return APR_EINVAL; 1137251875Speter } 1138251875Speter 1139251875Speter *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t)); 1140251875Speter 1141251875Speter /* assume ipstr is an individual IP address, not a subnet */ 1142251875Speter memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask); 1143251875Speter 1144251875Speter rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL); 1145251875Speter if (rv != APR_SUCCESS) { 1146251875Speter return rv; 1147251875Speter } 1148251875Speter 1149251875Speter if (mask_or_numbits) { 1150251875Speter#if APR_HAVE_IPV6 1151251875Speter if ((*ipsub)->family == AF_INET6) { 1152251875Speter maxbits = 128; 1153251875Speter } 1154251875Speter#endif 1155251875Speter bits = strtol(mask_or_numbits, &endptr, 10); 1156251875Speter if (*endptr == '\0' && bits > 0 && bits <= maxbits) { 1157251875Speter /* valid num-bits string; fill in mask appropriately */ 1158251875Speter int cur_entry = 0; 1159251875Speter apr_int32_t cur_bit_value; 1160251875Speter 1161251875Speter memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask); 1162251875Speter while (bits > 32) { 1163251875Speter (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */ 1164251875Speter bits -= 32; 1165251875Speter ++cur_entry; 1166251875Speter } 1167251875Speter cur_bit_value = 0x80000000; 1168251875Speter while (bits) { 1169251875Speter (*ipsub)->mask[cur_entry] |= cur_bit_value; 1170251875Speter --bits; 1171251875Speter cur_bit_value /= 2; 1172251875Speter } 1173251875Speter (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]); 1174251875Speter } 1175251875Speter else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 && 1176251875Speter (*ipsub)->family == AF_INET) { 1177251875Speter /* valid IPv4 netmask */ 1178251875Speter } 1179251875Speter else { 1180251875Speter return APR_EBADMASK; 1181251875Speter } 1182251875Speter } 1183251875Speter 1184251875Speter fix_subnet(*ipsub); 1185251875Speter 1186251875Speter return APR_SUCCESS; 1187251875Speter} 1188251875Speter 1189251875SpeterAPR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa) 1190251875Speter{ 1191251875Speter#if APR_HAVE_IPV6 1192251875Speter /* XXX This line will segv on Win32 build with APR_HAVE_IPV6, 1193251875Speter * but without the IPV6 drivers installed. 1194251875Speter */ 1195253734Speter if (sa->family == AF_INET) { 1196251875Speter if (ipsub->family == AF_INET && 1197251875Speter ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) { 1198251875Speter return 1; 1199251875Speter } 1200251875Speter } 1201251875Speter else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) { 1202251875Speter if (ipsub->family == AF_INET && 1203251875Speter (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) { 1204251875Speter return 1; 1205251875Speter } 1206251875Speter } 1207253734Speter else if (sa->family == AF_INET6 && ipsub->family == AF_INET6) { 1208251875Speter apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr; 1209251875Speter 1210251875Speter if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] && 1211251875Speter (addr[1] & ipsub->mask[1]) == ipsub->sub[1] && 1212251875Speter (addr[2] & ipsub->mask[2]) == ipsub->sub[2] && 1213251875Speter (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) { 1214251875Speter return 1; 1215251875Speter } 1216251875Speter } 1217251875Speter#else 1218251875Speter if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) { 1219251875Speter return 1; 1220251875Speter } 1221251875Speter#endif /* APR_HAVE_IPV6 */ 1222251875Speter return 0; /* no match */ 1223251875Speter} 1224362181Sdim 1225362181SdimAPR_DECLARE(apr_status_t) apr_sockaddr_zone_set(apr_sockaddr_t *sa, 1226362181Sdim const char *zone_id) 1227362181Sdim{ 1228362181Sdim#if !APR_HAVE_IPV6 || !defined(HAVE_IF_NAMETOINDEX) 1229362181Sdim return APR_ENOTIMPL; 1230362181Sdim#else 1231362181Sdim unsigned int idx; 1232362181Sdim 1233362181Sdim if (sa->family != APR_INET6 1234362181Sdim || !IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)sa->ipaddr_ptr)) { 1235362181Sdim return APR_EBADIP; 1236362181Sdim } 1237362181Sdim 1238362181Sdim idx = if_nametoindex(zone_id); 1239362181Sdim if (idx) { 1240362181Sdim sa->sa.sin6.sin6_scope_id = idx; 1241362181Sdim return APR_SUCCESS; 1242362181Sdim } 1243362181Sdim 1244362181Sdim if (errno != ENODEV) { 1245362181Sdim return errno; 1246362181Sdim } 1247362181Sdim else { 1248362181Sdim char *endptr; 1249362181Sdim apr_int64_t i = apr_strtoi64(zone_id, &endptr, 10); 1250362181Sdim 1251362181Sdim if (*endptr != '\0' || errno || i < 1 || i > APR_INT16_MAX) { 1252362181Sdim return APR_EGENERAL; 1253362181Sdim } 1254362181Sdim 1255362181Sdim sa->sa.sin6.sin6_scope_id = (unsigned int) i; 1256362181Sdim return APR_SUCCESS; 1257362181Sdim } 1258362181Sdim#endif 1259362181Sdim} 1260362181Sdim 1261362181SdimAPR_DECLARE(apr_status_t) apr_sockaddr_zone_get(const apr_sockaddr_t *sa, 1262362181Sdim const char **name, 1263362181Sdim apr_uint32_t *id, 1264362181Sdim apr_pool_t *p) 1265362181Sdim{ 1266362181Sdim#if !APR_HAVE_IPV6 || !defined(HAVE_IF_INDEXTONAME) 1267362181Sdim return APR_ENOTIMPL; 1268362181Sdim#else 1269362181Sdim if (sa->family != APR_INET6 || !sa->sa.sin6.sin6_scope_id) { 1270362181Sdim return APR_EBADIP; 1271362181Sdim } 1272362181Sdim 1273362181Sdim if (name) { 1274362181Sdim char *buf = apr_palloc(p, IF_NAMESIZE); 1275362181Sdim if (if_indextoname(sa->sa.sin6.sin6_scope_id, buf) == NULL) 1276362181Sdim return errno; 1277362181Sdim *name = buf; 1278362181Sdim } 1279362181Sdim 1280362181Sdim if (id) *id = sa->sa.sin6.sin6_scope_id; 1281362181Sdim 1282362181Sdim return APR_SUCCESS; 1283362181Sdim#endif 1284362181Sdim} 1285