diff options
Diffstat (limited to 'network_io/unix')
| -rw-r--r-- | network_io/unix/multicast.c | 21 | ||||
| -rw-r--r-- | network_io/unix/sendrecv.c | 14 | ||||
| -rw-r--r-- | network_io/unix/sockaddr.c | 44 | ||||
| -rw-r--r-- | network_io/unix/sockopt.c | 29 | 
4 files changed, 84 insertions, 24 deletions
diff --git a/network_io/unix/multicast.c b/network_io/unix/multicast.c index 67ab245740389..3767bfdd15c14 100644 --- a/network_io/unix/multicast.c +++ b/network_io/unix/multicast.c @@ -193,36 +193,39 @@ static apr_status_t do_mcast(int type, apr_socket_t *sock,      return rv;  } +/* Set the IP_MULTICAST_TTL or IP_MULTICAST_LOOP option, or IPv6 + * equivalents, for the socket, to the given value.  Note that this + * function *only works* for those particular option types. */  static apr_status_t do_mcast_opt(int type, apr_socket_t *sock,                                   apr_byte_t value)  {      apr_status_t rv = APR_SUCCESS;      if (sock_is_ipv4(sock)) { +        /* For the IP_MULTICAST_* options, this must be a (char *) +         * pointer. */          if (setsockopt(sock->socketdes, IPPROTO_IP, type,                         (const void *) &value, sizeof(value)) == -1) {              rv = errno;          }      }  #if APR_HAVE_IPV6 -    else if (sock_is_ipv6(sock) && type == IP_MULTICAST_LOOP) { -        unsigned int loopopt = value; -        type = IPV6_MULTICAST_LOOP; -        if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, -                       (const void *) &loopopt, sizeof(loopopt)) == -1) { -            rv = errno; -        } -    }      else if (sock_is_ipv6(sock)) { +        /* For the IPV6_* options, an (int *) pointer must be used. */ +        int ivalue = value; +          if (type == IP_MULTICAST_TTL) {              type = IPV6_MULTICAST_HOPS;          } +        else if (type == IP_MULTICAST_LOOP) { +            type = IPV6_MULTICAST_LOOP; +        }          else {              return APR_ENOTIMPL;          }          if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, -                       &value, sizeof(value)) == -1) { +                       (const void *) &ivalue, sizeof(ivalue)) == -1) {              rv = errno;          }      } diff --git a/network_io/unix/sendrecv.c b/network_io/unix/sendrecv.c index c133a26d9c7bf..6b14643cd58b9 100644 --- a/network_io/unix/sendrecv.c +++ b/network_io/unix/sendrecv.c @@ -174,7 +174,14 @@ apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock,          return errno;      } -    apr_sockaddr_vars_set(from, from->sa.sin.sin_family, ntohs(from->sa.sin.sin_port)); +    /* +     * Check if we have a valid address. recvfrom() with MSG_PEEK may return +     * success without filling in the address. +     */ +    if (from->salen > APR_OFFSETOF(struct sockaddr_in, sin_port)) { +        apr_sockaddr_vars_set(from, from->sa.sin.sin_family, +                              ntohs(from->sa.sin.sin_port)); +    }      (*len) = rv;      if (rv == 0 && sock->type == SOCK_STREAM) { @@ -245,7 +252,7 @@ do_select:  /* Define a structure to pass in when we have a NULL header value */  static apr_hdtr_t no_hdtr; -#if defined(__linux__) && defined(HAVE_WRITEV) +#if (defined(__linux__) || defined(__GNU__)) && defined(HAVE_WRITEV)  apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,                                   apr_hdtr_t *hdtr, apr_off_t *offset, @@ -285,9 +292,6 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,          hdtr = &no_hdtr;      } -    /* Ignore flags for now. */ -    flags = 0; -      if (hdtr->numheaders > 0) {          apr_size_t hdrbytes; diff --git a/network_io/unix/sockaddr.c b/network_io/unix/sockaddr.c index ed4c474dc63d6..9253a27461fb8 100644 --- a/network_io/unix/sockaddr.c +++ b/network_io/unix/sockaddr.c @@ -356,9 +356,27 @@ static apr_status_t call_resolver(apr_sockaddr_t **sa,      }      error = getaddrinfo(hostname, servname, &hints, &ai_list);  #ifdef HAVE_GAI_ADDRCONFIG -    if (error == EAI_BADFLAGS && family == APR_UNSPEC) { -        /* Retry with no flags if AI_ADDRCONFIG was rejected. */ -        hints.ai_flags = 0; +    /* +     * Using AI_ADDRCONFIG involves some unfortunate guesswork because it +     * does not consider loopback addresses when trying to determine if +     * IPv4 or IPv6 is configured on a system (see RFC 3493). +     * This is a problem if one actually wants to listen on or connect to +     * the loopback address of a protocol family that is not otherwise +     * configured on the system. See PR 52709. +     * To work around some of the problems, retry without AI_ADDRCONFIG +     * in case of EAI_ADDRFAMILY. +     * XXX: apr_sockaddr_info_get() should really accept a flag to determine +     * XXX: if AI_ADDRCONFIG's guesswork is wanted and if the address is +     * XXX: to be used for listen() or connect(). +     * +     * In case of EAI_BADFLAGS, AI_ADDRCONFIG is not supported. +     */ +    if ((family == APR_UNSPEC) && (error == EAI_BADFLAGS +#ifdef EAI_ADDRFAMILY +                                   || error == EAI_ADDRFAMILY +#endif +                                                             )) { +        hints.ai_flags &= ~AI_ADDRCONFIG;          error = getaddrinfo(hostname, servname, &hints, &ai_list);      }  #endif @@ -367,7 +385,7 @@ static apr_status_t call_resolver(apr_sockaddr_t **sa,          return apr_get_netos_error();  #else          if (error == EAI_SYSTEM) { -            return errno; +            return errno ? errno : APR_EGENERAL;          }          else           { @@ -422,6 +440,15 @@ static apr_status_t call_resolver(apr_sockaddr_t **sa,          ai = ai->ai_next;      }      freeaddrinfo(ai_list); + +    if (prev_sa == NULL) { +        /* +         * getaddrinfo returned only useless entries and *sa is still empty. +         * This should be treated as an error. +         */ +        return APR_EGENERAL; +    } +      return APR_SUCCESS;  } @@ -555,6 +582,11 @@ static apr_status_t find_addresses(apr_sockaddr_t **sa,          ++curaddr;      } +    if (prev_sa == NULL) { +        /* this should not happen but no result should be treated as error */ +        return APR_EGENERAL; +    } +      return APR_SUCCESS;  } @@ -1010,7 +1042,7 @@ APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa)      /* XXX This line will segv on Win32 build with APR_HAVE_IPV6,       * but without the IPV6 drivers installed.       */ -    if (sa->sa.sin.sin_family == AF_INET) { +    if (sa->family == AF_INET) {          if (ipsub->family == AF_INET &&              ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) {              return 1; @@ -1022,7 +1054,7 @@ APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa)              return 1;          }      } -    else { +    else if (sa->family == AF_INET6 && ipsub->family == AF_INET6) {          apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr;          if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] && diff --git a/network_io/unix/sockopt.c b/network_io/unix/sockopt.c index 3fc932f42f5e5..7b67c2ec13a12 100644 --- a/network_io/unix/sockopt.c +++ b/network_io/unix/sockopt.c @@ -381,12 +381,33 @@ apr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont)  }  #if APR_HAS_SO_ACCEPTFILTER -apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *name,  -                                      char *args) +apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *nonconst_name,  +                                      char *nonconst_args)  { +    /* these should have been const; act like they are */ +    const char *name = nonconst_name; +    const char *args = nonconst_args; +      struct accept_filter_arg af; -    strncpy(af.af_name, name, 16); -    strncpy(af.af_arg, args, 256 - 16); +    socklen_t optlen = sizeof(af); + +    /* FreeBSD returns an error if the filter is already set; ignore +     * this call if we previously set it to the same value. +     */ +    if ((getsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, +                    &af, &optlen)) == 0) { +        if (!strcmp(name, af.af_name) && !strcmp(args, af.af_arg)) { +            return APR_SUCCESS; +        } +    } + +    /* Uhh, at least in FreeBSD 9 the fields are declared as arrays of +     * these lengths; did sizeof not work in some ancient release? +     * +     * FreeBSD kernel sets the last byte to a '\0'. +     */ +    apr_cpystrn(af.af_name, name, 16); +    apr_cpystrn(af.af_arg, args, 256 - 16);      if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER,            &af, sizeof(af))) < 0) {  | 
