sockaddr.c revision 251875
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 328251875Speter if(hostname == NULL) { 329251875Speter#ifdef AI_PASSIVE 330251875Speter /* If hostname is NULL, assume we are trying to bind to all 331251875Speter * interfaces. */ 332251875Speter hints.ai_flags |= AI_PASSIVE; 333251875Speter#endif 334251875Speter /* getaddrinfo according to RFC 2553 must have either hostname 335251875Speter * or servname non-NULL. 336251875Speter */ 337251875Speter#ifdef OSF1 338251875Speter /* The Tru64 5.0 getaddrinfo() can only resolve services given 339251875Speter * by the name listed in /etc/services; a numeric or unknown 340251875Speter * servname gets an EAI_SERVICE error. So just resolve the 341251875Speter * appropriate anyaddr and fill in the port later. */ 342251875Speter hostname = family == AF_INET6 ? "::" : "0.0.0.0"; 343251875Speter servname = NULL; 344251875Speter#ifdef AI_NUMERICHOST 345251875Speter hints.ai_flags |= AI_NUMERICHOST; 346251875Speter#endif 347251875Speter#else 348251875Speter#if AIX_SERVNAME_HACK 349251875Speter if (!port) { 350251875Speter servname = "1"; 351251875Speter } 352251875Speter else 353251875Speter#endif /* AIX_SERVNAME_HACK */ 354251875Speter servname = apr_itoa(p, port); 355251875Speter#endif /* OSF1 */ 356251875Speter } 357251875Speter error = getaddrinfo(hostname, servname, &hints, &ai_list); 358251875Speter#ifdef HAVE_GAI_ADDRCONFIG 359251875Speter if (error == EAI_BADFLAGS && family == APR_UNSPEC) { 360251875Speter /* Retry with no flags if AI_ADDRCONFIG was rejected. */ 361251875Speter hints.ai_flags = 0; 362251875Speter error = getaddrinfo(hostname, servname, &hints, &ai_list); 363251875Speter } 364251875Speter#endif 365251875Speter if (error) { 366251875Speter#if defined(WIN32) 367251875Speter return apr_get_netos_error(); 368251875Speter#else 369251875Speter if (error == EAI_SYSTEM) { 370251875Speter return errno; 371251875Speter } 372251875Speter else 373251875Speter { 374251875Speter /* issues with representing this with APR's error scheme: 375251875Speter * glibc uses negative values for these numbers, perhaps so 376251875Speter * they don't conflict with h_errno values... Tru64 uses 377251875Speter * positive values which conflict with h_errno values 378251875Speter */ 379251875Speter#if defined(NEGATIVE_EAI) 380251875Speter error = -error; 381251875Speter#endif 382251875Speter return error + APR_OS_START_EAIERR; 383251875Speter } 384251875Speter#endif /* WIN32 */ 385251875Speter } 386251875Speter 387251875Speter prev_sa = NULL; 388251875Speter ai = ai_list; 389251875Speter while (ai) { /* while more addresses to report */ 390251875Speter apr_sockaddr_t *new_sa; 391251875Speter 392251875Speter /* Ignore anything bogus: getaddrinfo in some old versions of 393251875Speter * glibc will return AF_UNIX entries for APR_UNSPEC+AI_PASSIVE 394251875Speter * lookups. */ 395251875Speter#if APR_HAVE_IPV6 396251875Speter if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { 397251875Speter#else 398251875Speter if (ai->ai_family != AF_INET) { 399251875Speter#endif 400251875Speter ai = ai->ai_next; 401251875Speter continue; 402251875Speter } 403251875Speter 404251875Speter new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 405251875Speter 406251875Speter new_sa->pool = p; 407251875Speter memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen); 408251875Speter apr_sockaddr_vars_set(new_sa, ai->ai_family, port); 409251875Speter 410251875Speter if (!prev_sa) { /* first element in new list */ 411251875Speter if (hostname) { 412251875Speter new_sa->hostname = apr_pstrdup(p, hostname); 413251875Speter } 414251875Speter *sa = new_sa; 415251875Speter } 416251875Speter else { 417251875Speter new_sa->hostname = prev_sa->hostname; 418251875Speter prev_sa->next = new_sa; 419251875Speter } 420251875Speter 421251875Speter prev_sa = new_sa; 422251875Speter ai = ai->ai_next; 423251875Speter } 424251875Speter freeaddrinfo(ai_list); 425251875Speter return APR_SUCCESS; 426251875Speter} 427251875Speter 428251875Speterstatic apr_status_t find_addresses(apr_sockaddr_t **sa, 429251875Speter const char *hostname, apr_int32_t family, 430251875Speter apr_port_t port, apr_int32_t flags, 431251875Speter apr_pool_t *p) 432251875Speter{ 433251875Speter if (flags & APR_IPV4_ADDR_OK) { 434251875Speter apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p); 435251875Speter 436251875Speter#if APR_HAVE_IPV6 437251875Speter if (error) { 438251875Speter family = AF_INET6; /* try again */ 439251875Speter } 440251875Speter else 441251875Speter#endif 442251875Speter return error; 443251875Speter } 444251875Speter#if APR_HAVE_IPV6 445251875Speter else if (flags & APR_IPV6_ADDR_OK) { 446251875Speter apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p); 447251875Speter 448251875Speter if (error) { 449251875Speter family = AF_INET; /* try again */ 450251875Speter } 451251875Speter else { 452251875Speter return APR_SUCCESS; 453251875Speter } 454251875Speter } 455251875Speter#endif 456251875Speter 457251875Speter return call_resolver(sa, hostname, family, port, flags, p); 458251875Speter} 459251875Speter 460251875Speter#else /* end of HAVE_GETADDRINFO code */ 461251875Speter 462251875Speterstatic apr_status_t find_addresses(apr_sockaddr_t **sa, 463251875Speter const char *hostname, apr_int32_t family, 464251875Speter apr_port_t port, apr_int32_t flags, 465251875Speter apr_pool_t *p) 466251875Speter{ 467251875Speter struct hostent *hp; 468251875Speter apr_sockaddr_t *prev_sa; 469251875Speter int curaddr; 470251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 471251875Speter defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) 472251875Speter#ifdef GETHOSTBYNAME_R_HOSTENT_DATA 473251875Speter struct hostent_data hd; 474251875Speter#else 475251875Speter /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be 476251875Speter * bumped. */ 477251875Speter char tmp[GETHOSTBYNAME_BUFLEN]; 478251875Speter#endif 479251875Speter int hosterror; 480251875Speter#endif 481251875Speter struct hostent hs; 482251875Speter struct in_addr ipaddr; 483251875Speter char *addr_list[2]; 484251875Speter const char *orig_hostname = hostname; 485251875Speter 486251875Speter if (hostname == NULL) { 487251875Speter /* if we are given a NULL hostname, assume '0.0.0.0' */ 488251875Speter hostname = "0.0.0.0"; 489251875Speter } 490251875Speter 491251875Speter if (*hostname >= '0' && *hostname <= '9' && 492251875Speter strspn(hostname, "0123456789.") == strlen(hostname)) { 493251875Speter 494251875Speter ipaddr.s_addr = inet_addr(hostname); 495251875Speter addr_list[0] = (char *)&ipaddr; 496251875Speter addr_list[1] = NULL; /* just one IP in list */ 497251875Speter hs.h_addr_list = (char **)addr_list; 498251875Speter hp = &hs; 499251875Speter } 500251875Speter else { 501251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ 502251875Speter defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) 503251875Speter#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) 504251875Speter /* AIX, HP/UX, D/UX et alia */ 505251875Speter gethostbyname_r(hostname, &hs, &hd); 506251875Speter hp = &hs; 507251875Speter#else 508251875Speter#if defined(GETHOSTBYNAME_R_GLIBC2) 509251875Speter /* Linux glibc2+ */ 510251875Speter gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 511251875Speter &hp, &hosterror); 512251875Speter#else 513251875Speter /* Solaris, Irix et alia */ 514251875Speter hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 515251875Speter &hosterror); 516251875Speter#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ 517251875Speter if (!hp) { 518251875Speter return (hosterror + APR_OS_START_SYSERR); 519251875Speter } 520251875Speter#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ 521251875Speter#else 522251875Speter hp = gethostbyname(hostname); 523251875Speter#endif 524251875Speter 525251875Speter if (!hp) { 526251875Speter#ifdef WIN32 527251875Speter return apr_get_netos_error(); 528251875Speter#else 529251875Speter return (h_errno + APR_OS_START_SYSERR); 530251875Speter#endif 531251875Speter } 532251875Speter } 533251875Speter 534251875Speter prev_sa = NULL; 535251875Speter curaddr = 0; 536251875Speter while (hp->h_addr_list[curaddr]) { 537251875Speter apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 538251875Speter 539251875Speter new_sa->pool = p; 540251875Speter new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr]; 541251875Speter apr_sockaddr_vars_set(new_sa, AF_INET, port); 542251875Speter 543251875Speter if (!prev_sa) { /* first element in new list */ 544251875Speter if (orig_hostname) { 545251875Speter new_sa->hostname = apr_pstrdup(p, orig_hostname); 546251875Speter } 547251875Speter *sa = new_sa; 548251875Speter } 549251875Speter else { 550251875Speter new_sa->hostname = prev_sa->hostname; 551251875Speter prev_sa->next = new_sa; 552251875Speter } 553251875Speter 554251875Speter prev_sa = new_sa; 555251875Speter ++curaddr; 556251875Speter } 557251875Speter 558251875Speter return APR_SUCCESS; 559251875Speter} 560251875Speter 561251875Speter#endif /* end of !HAVE_GETADDRINFO code */ 562251875Speter 563251875SpeterAPR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, 564251875Speter const char *hostname, 565251875Speter apr_int32_t family, apr_port_t port, 566251875Speter apr_int32_t flags, apr_pool_t *p) 567251875Speter{ 568251875Speter apr_int32_t masked; 569251875Speter *sa = NULL; 570251875Speter 571251875Speter if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { 572251875Speter if (!hostname || 573251875Speter family != APR_UNSPEC || 574251875Speter masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) { 575251875Speter return APR_EINVAL; 576251875Speter } 577251875Speter#if !APR_HAVE_IPV6 578251875Speter if (flags & APR_IPV6_ADDR_OK) { 579251875Speter return APR_ENOTIMPL; 580251875Speter } 581251875Speter#endif 582251875Speter } 583251875Speter#if !APR_HAVE_IPV6 584251875Speter /* What may happen is that APR is not IPv6-enabled, but we're still 585251875Speter * going to call getaddrinfo(), so we have to tell the OS we only 586251875Speter * want IPv4 addresses back since we won't know what to do with 587251875Speter * IPv6 addresses. 588251875Speter */ 589251875Speter if (family == APR_UNSPEC) { 590251875Speter family = APR_INET; 591251875Speter } 592251875Speter#endif 593251875Speter 594251875Speter return find_addresses(sa, hostname, family, port, flags, p); 595251875Speter} 596251875Speter 597251875SpeterAPR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, 598251875Speter apr_sockaddr_t *sockaddr, 599251875Speter apr_int32_t flags) 600251875Speter{ 601251875Speter#if defined(HAVE_GETNAMEINFO) 602251875Speter int rc; 603251875Speter#if defined(NI_MAXHOST) 604251875Speter char tmphostname[NI_MAXHOST]; 605251875Speter#else 606251875Speter char tmphostname[256]; 607251875Speter#endif 608251875Speter 609251875Speter /* don't know if it is portable for getnameinfo() to set h_errno; 610251875Speter * clear it then see if it was set */ 611251875Speter SET_H_ERRNO(0); 612251875Speter 613251875Speter /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return 614251875Speter * a numeric address string if it fails to resolve the host name; 615251875Speter * that is *not* what we want here 616251875Speter * 617251875Speter * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling 618251875Speter * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc). 619251875Speter */ 620251875Speter#if APR_HAVE_IPV6 621251875Speter if (sockaddr->family == AF_INET6 && 622251875Speter IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) { 623251875Speter struct sockaddr_in tmpsa; 624251875Speter tmpsa.sin_family = AF_INET; 625251875Speter tmpsa.sin_port = 0; 626251875Speter tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3]; 627251875Speter#ifdef SIN6_LEN 628251875Speter tmpsa.sin_len = sizeof(tmpsa); 629251875Speter#endif 630251875Speter 631251875Speter rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa), 632251875Speter tmphostname, sizeof(tmphostname), NULL, 0, 633251875Speter flags != 0 ? flags : NI_NAMEREQD); 634251875Speter } 635251875Speter else 636251875Speter#endif 637251875Speter rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen, 638251875Speter tmphostname, sizeof(tmphostname), NULL, 0, 639251875Speter flags != 0 ? flags : NI_NAMEREQD); 640251875Speter if (rc != 0) { 641251875Speter *hostname = NULL; 642251875Speter 643251875Speter#ifndef WIN32 644251875Speter /* something went wrong. Look at the EAI_ error code */ 645251875Speter if (rc == EAI_SYSTEM) { 646251875Speter /* EAI_SYSTEM System error returned in errno. */ 647251875Speter /* IMHO, Implementations that set h_errno a simply broken. */ 648251875Speter if (h_errno) { /* for broken implementations which set h_errno */ 649251875Speter return h_errno + APR_OS_START_SYSERR; 650251875Speter } 651251875Speter else { /* "normal" case */ 652251875Speter return errno + APR_OS_START_SYSERR; 653251875Speter } 654251875Speter } 655251875Speter else 656251875Speter#endif 657251875Speter { 658251875Speter#if defined(NEGATIVE_EAI) 659251875Speter if (rc < 0) rc = -rc; 660251875Speter#endif 661251875Speter return rc + APR_OS_START_EAIERR; /* return the EAI_ error */ 662251875Speter } 663251875Speter } 664251875Speter *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, 665251875Speter tmphostname); 666251875Speter return APR_SUCCESS; 667251875Speter#else 668251875Speter#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \ 669251875Speter defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS) 670251875Speter#ifdef GETHOSTBYNAME_R_HOSTENT_DATA 671251875Speter struct hostent_data hd; 672251875Speter#else 673251875Speter char tmp[GETHOSTBYNAME_BUFLEN]; 674251875Speter#endif 675251875Speter int hosterror; 676251875Speter struct hostent hs, *hptr; 677251875Speter 678251875Speter#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) 679251875Speter /* AIX, HP/UX, D/UX et alia */ 680251875Speter gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 681251875Speter sizeof(struct in_addr), AF_INET, &hs, &hd); 682251875Speter hptr = &hs; 683251875Speter#else 684251875Speter#if defined(GETHOSTBYNAME_R_GLIBC2) 685251875Speter /* Linux glibc2+ */ 686251875Speter gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 687251875Speter sizeof(struct in_addr), AF_INET, 688251875Speter &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror); 689251875Speter#else 690251875Speter /* Solaris, Irix et alia */ 691251875Speter hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 692251875Speter sizeof(struct in_addr), AF_INET, 693251875Speter &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror); 694251875Speter#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ 695251875Speter if (!hptr) { 696251875Speter *hostname = NULL; 697251875Speter return hosterror + APR_OS_START_SYSERR; 698251875Speter } 699251875Speter#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ 700251875Speter#else 701251875Speter struct hostent *hptr; 702251875Speter hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, 703251875Speter sizeof(struct in_addr), AF_INET); 704251875Speter#endif 705251875Speter 706251875Speter if (hptr) { 707251875Speter *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name); 708251875Speter return APR_SUCCESS; 709251875Speter } 710251875Speter *hostname = NULL; 711251875Speter#if defined(WIN32) 712251875Speter return apr_get_netos_error(); 713251875Speter#elif defined(OS2) 714251875Speter return h_errno; 715251875Speter#else 716251875Speter return h_errno + APR_OS_START_SYSERR; 717251875Speter#endif 718251875Speter#endif 719251875Speter} 720251875Speter 721251875SpeterAPR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, 722251875Speter const char *servname) 723251875Speter{ 724251875Speter#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ 725251875Speter defined(HAVE_GETSERVBYNAME_R) && \ 726251875Speter (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ 727251875Speter defined(GETSERVBYNAME_R_OSF1)) 728251875Speter struct servent se; 729251875Speter#if defined(GETSERVBYNAME_R_OSF1) 730251875Speter struct servent_data sed; 731251875Speter 732251875Speter memset(&sed, 0, sizeof(sed)); /* must zero fill before use */ 733251875Speter#else 734251875Speter#if defined(GETSERVBYNAME_R_GLIBC2) 735251875Speter struct servent *res; 736251875Speter#endif 737251875Speter char buf[1024]; 738251875Speter#endif 739251875Speter#else 740251875Speter struct servent *se; 741251875Speter#endif 742251875Speter 743251875Speter if (servname == NULL) 744251875Speter return APR_EINVAL; 745251875Speter 746251875Speter#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ 747251875Speter defined(HAVE_GETSERVBYNAME_R) && \ 748251875Speter (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ 749251875Speter defined(GETSERVBYNAME_R_OSF1)) 750251875Speter#if defined(GETSERVBYNAME_R_GLIBC2) 751251875Speter if (getservbyname_r(servname, NULL, 752251875Speter &se, buf, sizeof(buf), &res) == 0 && res != NULL) { 753251875Speter sockaddr->port = ntohs(res->s_port); 754251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 755251875Speter sockaddr->sa.sin.sin_port = res->s_port; 756251875Speter return APR_SUCCESS; 757251875Speter } 758251875Speter#elif defined(GETSERVBYNAME_R_SOLARIS) 759251875Speter if (getservbyname_r(servname, NULL, &se, buf, sizeof(buf)) != NULL) { 760251875Speter sockaddr->port = ntohs(se.s_port); 761251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 762251875Speter sockaddr->sa.sin.sin_port = se.s_port; 763251875Speter return APR_SUCCESS; 764251875Speter } 765251875Speter#elif defined(GETSERVBYNAME_R_OSF1) 766251875Speter if (getservbyname_r(servname, NULL, &se, &sed) == 0) { 767251875Speter sockaddr->port = ntohs(se.s_port); 768251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 769251875Speter sockaddr->sa.sin.sin_port = se.s_port; 770251875Speter return APR_SUCCESS; 771251875Speter } 772251875Speter#endif 773251875Speter#else 774251875Speter if ((se = getservbyname(servname, NULL)) != NULL){ 775251875Speter sockaddr->port = ntohs(se->s_port); 776251875Speter sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); 777251875Speter sockaddr->sa.sin.sin_port = se->s_port; 778251875Speter return APR_SUCCESS; 779251875Speter } 780251875Speter#endif 781251875Speter return APR_ENOENT; 782251875Speter} 783251875Speter 784251875Speter#define V4MAPPED_EQUAL(a,b) \ 785251875Speter((a)->sa.sin.sin_family == AF_INET && \ 786251875Speter (b)->sa.sin.sin_family == AF_INET6 && \ 787251875Speter IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) && \ 788251875Speter !memcmp((a)->ipaddr_ptr, \ 789251875Speter &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12], \ 790251875Speter (a)->ipaddr_len)) 791251875Speter 792251875SpeterAPR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, 793251875Speter const apr_sockaddr_t *addr2) 794251875Speter{ 795251875Speter if (addr1->ipaddr_len == addr2->ipaddr_len && 796251875Speter !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len)) { 797251875Speter return 1; 798251875Speter } 799251875Speter#if APR_HAVE_IPV6 800251875Speter if (V4MAPPED_EQUAL(addr1, addr2)) { 801251875Speter return 1; 802251875Speter } 803251875Speter if (V4MAPPED_EQUAL(addr2, addr1)) { 804251875Speter return 1; 805251875Speter } 806251875Speter#endif 807251875Speter return 0; /* not equal */ 808251875Speter} 809251875Speter 810251875Speterstatic apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network) 811251875Speter{ 812251875Speter /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */ 813251875Speter int shift; 814251875Speter char *s, *t; 815251875Speter int octet; 816251875Speter char buf[sizeof "255.255.255.255"]; 817251875Speter 818251875Speter if (strlen(network) < sizeof buf) { 819251875Speter strcpy(buf, network); 820251875Speter } 821251875Speter else { 822251875Speter return APR_EBADIP; 823251875Speter } 824251875Speter 825251875Speter /* parse components */ 826251875Speter s = buf; 827251875Speter ipsub->sub[0] = 0; 828251875Speter ipsub->mask[0] = 0; 829251875Speter shift = 24; 830251875Speter while (*s) { 831251875Speter t = s; 832251875Speter if (!apr_isdigit(*t)) { 833251875Speter return APR_EBADIP; 834251875Speter } 835251875Speter while (apr_isdigit(*t)) { 836251875Speter ++t; 837251875Speter } 838251875Speter if (*t == '.') { 839251875Speter *t++ = 0; 840251875Speter } 841251875Speter else if (*t) { 842251875Speter return APR_EBADIP; 843251875Speter } 844251875Speter if (shift < 0) { 845251875Speter return APR_EBADIP; 846251875Speter } 847251875Speter octet = atoi(s); 848251875Speter if (octet < 0 || octet > 255) { 849251875Speter return APR_EBADIP; 850251875Speter } 851251875Speter ipsub->sub[0] |= octet << shift; 852251875Speter ipsub->mask[0] |= 0xFFUL << shift; 853251875Speter s = t; 854251875Speter shift -= 8; 855251875Speter } 856251875Speter ipsub->sub[0] = ntohl(ipsub->sub[0]); 857251875Speter ipsub->mask[0] = ntohl(ipsub->mask[0]); 858251875Speter ipsub->family = AF_INET; 859251875Speter return APR_SUCCESS; 860251875Speter} 861251875Speter 862251875Speter/* return values: 863251875Speter * APR_EINVAL not an IP address; caller should see if it is something else 864251875Speter * APR_BADIP IP address portion is is not valid 865251875Speter * APR_BADMASK mask portion is not valid 866251875Speter */ 867251875Speter 868251875Speterstatic apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed) 869251875Speter{ 870251875Speter /* supported flavors of IP: 871251875Speter * 872251875Speter * . IPv6 numeric address string (e.g., "fe80::1") 873251875Speter * 874251875Speter * IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address. 875251875Speter * 876251875Speter * . IPv4 numeric address string (e.g., "127.0.0.1") 877251875Speter * 878251875Speter * . IPv4 network string (e.g., "9.67") 879251875Speter * 880251875Speter * IMPORTANT: This network form is only allowed if network_allowed is on. 881251875Speter */ 882251875Speter int rc; 883251875Speter 884251875Speter#if APR_HAVE_IPV6 885251875Speter rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub); 886251875Speter if (rc == 1) { 887251875Speter if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) { 888251875Speter /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6 889251875Speter * addresses; this of course forces the user to specify IPv4 addresses 890251875Speter * in a.b.c.d style instead of ::ffff:a.b.c.d style. 891251875Speter */ 892251875Speter return APR_EBADIP; 893251875Speter } 894251875Speter ipsub->family = AF_INET6; 895251875Speter } 896251875Speter else 897251875Speter#endif 898251875Speter { 899251875Speter rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub); 900251875Speter if (rc == 1) { 901251875Speter ipsub->family = AF_INET; 902251875Speter } 903251875Speter } 904251875Speter if (rc != 1) { 905251875Speter if (network_allowed) { 906251875Speter return parse_network(ipsub, ipstr); 907251875Speter } 908251875Speter else { 909251875Speter return APR_EBADIP; 910251875Speter } 911251875Speter } 912251875Speter return APR_SUCCESS; 913251875Speter} 914251875Speter 915251875Speterstatic int looks_like_ip(const char *ipstr) 916251875Speter{ 917251875Speter if (strchr(ipstr, ':')) { 918251875Speter /* definitely not a hostname; assume it is intended to be an IPv6 address */ 919251875Speter return 1; 920251875Speter } 921251875Speter 922251875Speter /* simple IPv4 address string check */ 923251875Speter while ((*ipstr == '.') || apr_isdigit(*ipstr)) 924251875Speter ipstr++; 925251875Speter return (*ipstr == '\0'); 926251875Speter} 927251875Speter 928251875Speterstatic void fix_subnet(apr_ipsubnet_t *ipsub) 929251875Speter{ 930251875Speter /* in case caller specified more bits in network address than are 931251875Speter * valid according to the mask, turn off the extra bits 932251875Speter */ 933251875Speter int i; 934251875Speter 935251875Speter for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) { 936251875Speter ipsub->sub[i] &= ipsub->mask[i]; 937251875Speter } 938251875Speter} 939251875Speter 940251875Speter/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */ 941251875SpeterAPR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, 942251875Speter const char *mask_or_numbits, apr_pool_t *p) 943251875Speter{ 944251875Speter apr_status_t rv; 945251875Speter char *endptr; 946251875Speter long bits, maxbits = 32; 947251875Speter 948251875Speter /* filter out stuff which doesn't look remotely like an IP address; this helps 949251875Speter * callers like mod_access which have a syntax allowing hostname or IP address; 950251875Speter * APR_EINVAL tells the caller that it was probably not intended to be an IP 951251875Speter * address 952251875Speter */ 953251875Speter if (!looks_like_ip(ipstr)) { 954251875Speter return APR_EINVAL; 955251875Speter } 956251875Speter 957251875Speter *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t)); 958251875Speter 959251875Speter /* assume ipstr is an individual IP address, not a subnet */ 960251875Speter memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask); 961251875Speter 962251875Speter rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL); 963251875Speter if (rv != APR_SUCCESS) { 964251875Speter return rv; 965251875Speter } 966251875Speter 967251875Speter if (mask_or_numbits) { 968251875Speter#if APR_HAVE_IPV6 969251875Speter if ((*ipsub)->family == AF_INET6) { 970251875Speter maxbits = 128; 971251875Speter } 972251875Speter#endif 973251875Speter bits = strtol(mask_or_numbits, &endptr, 10); 974251875Speter if (*endptr == '\0' && bits > 0 && bits <= maxbits) { 975251875Speter /* valid num-bits string; fill in mask appropriately */ 976251875Speter int cur_entry = 0; 977251875Speter apr_int32_t cur_bit_value; 978251875Speter 979251875Speter memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask); 980251875Speter while (bits > 32) { 981251875Speter (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */ 982251875Speter bits -= 32; 983251875Speter ++cur_entry; 984251875Speter } 985251875Speter cur_bit_value = 0x80000000; 986251875Speter while (bits) { 987251875Speter (*ipsub)->mask[cur_entry] |= cur_bit_value; 988251875Speter --bits; 989251875Speter cur_bit_value /= 2; 990251875Speter } 991251875Speter (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]); 992251875Speter } 993251875Speter else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 && 994251875Speter (*ipsub)->family == AF_INET) { 995251875Speter /* valid IPv4 netmask */ 996251875Speter } 997251875Speter else { 998251875Speter return APR_EBADMASK; 999251875Speter } 1000251875Speter } 1001251875Speter 1002251875Speter fix_subnet(*ipsub); 1003251875Speter 1004251875Speter return APR_SUCCESS; 1005251875Speter} 1006251875Speter 1007251875SpeterAPR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa) 1008251875Speter{ 1009251875Speter#if APR_HAVE_IPV6 1010251875Speter /* XXX This line will segv on Win32 build with APR_HAVE_IPV6, 1011251875Speter * but without the IPV6 drivers installed. 1012251875Speter */ 1013251875Speter if (sa->sa.sin.sin_family == AF_INET) { 1014251875Speter if (ipsub->family == AF_INET && 1015251875Speter ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) { 1016251875Speter return 1; 1017251875Speter } 1018251875Speter } 1019251875Speter else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) { 1020251875Speter if (ipsub->family == AF_INET && 1021251875Speter (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) { 1022251875Speter return 1; 1023251875Speter } 1024251875Speter } 1025251875Speter else { 1026251875Speter apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr; 1027251875Speter 1028251875Speter if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] && 1029251875Speter (addr[1] & ipsub->mask[1]) == ipsub->sub[1] && 1030251875Speter (addr[2] & ipsub->mask[2]) == ipsub->sub[2] && 1031251875Speter (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) { 1032251875Speter return 1; 1033251875Speter } 1034251875Speter } 1035251875Speter#else 1036251875Speter if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) { 1037251875Speter return 1; 1038251875Speter } 1039251875Speter#endif /* APR_HAVE_IPV6 */ 1040251875Speter return 0; /* no match */ 1041251875Speter} 1042