diff options
Diffstat (limited to 'openvpn/src/openvpn/socket.c')
-rw-r--r-- | openvpn/src/openvpn/socket.c | 548 |
1 files changed, 145 insertions, 403 deletions
diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 339470b..bb973bc 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -94,220 +94,53 @@ h_errno_msg(int h_errno_err) */ in_addr_t getaddr (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - bool *succeeded, - volatile int *signal_received) + const char *hostname, + int resolve_retry_seconds, + bool *succeeded, + volatile int *signal_received) { - return getaddr_multi (flags, hostname, resolve_retry_seconds, succeeded, signal_received, NULL); -} - -in_addr_t -getaddr_multi (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - bool *succeeded, - volatile int *signal_received, - struct resolve_list *reslist) -{ - struct in_addr ia; + struct addrinfo *ai; int status; - int sigrec = 0; - int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; - struct gc_arena gc = gc_new (); - - if (reslist) - reslist->len = 0; - - if (flags & GETADDR_RANDOMIZE) - hostname = hostname_randomize(hostname, &gc); - - if (flags & GETADDR_MSG_VIRT_OUT) - msglevel |= M_MSG_VIRT_OUT; - - CLEAR (ia); - if (succeeded) - *succeeded = false; - - if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL)) - && !signal_received) - signal_received = &sigrec; - - status = openvpn_inet_aton (hostname, &ia); /* parse ascii IP address */ - - if (status != OIA_IP) /* parse as IP address failed? */ - { - const int fail_wait_interval = 5; /* seconds */ - int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval); - struct hostent *h; - const char *fmt; - int level = 0; - - CLEAR (ia); - - fmt = "RESOLVE: Cannot resolve host address: %s: %s"; - if ((flags & GETADDR_MENTION_RESOLVE_RETRY) - && !resolve_retry_seconds) - fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)"; - - if (!(flags & GETADDR_RESOLVE) || status == OIA_ERROR) - { - msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname); - goto done; - } - -#ifdef ENABLE_MANAGEMENT - if (flags & GETADDR_UPDATE_MANAGEMENT_STATE) - { - if (management) - management_set_state (management, - OPENVPN_STATE_RESOLVE, - NULL, - (in_addr_t)0, - (in_addr_t)0); - } -#endif - - /* - * Resolve hostname - */ - while (true) - { - /* try hostname lookup */ -#if defined(HAVE_RES_INIT) - res_init (); -#endif - h = gethostbyname (hostname); - - if (signal_received) - { - get_signal (signal_received); - if (*signal_received) /* were we interrupted by a signal? */ - { - h = NULL; - if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ - { - msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); - *signal_received = 0; - } - else - goto done; - } - } - - /* success? */ - if (h) - break; - - /* resolve lookup failed, should we - continue or fail? */ - - level = msglevel; - if (resolve_retries > 0) - level = D_RESOLVE_ERRORS; - - msg (level, - fmt, - hostname, - h_errno_msg (h_errno)); - - if (--resolve_retries <= 0) - goto done; - - openvpn_sleep (fail_wait_interval); - } - - if (h->h_addrtype != AF_INET || h->h_length != 4) - { - msg (msglevel, "RESOLVE: Sorry, but we only accept IPv4 DNS names: %s", hostname); - goto done; - } - - ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]); - - if (ia.s_addr) - { - if (h->h_addr_list[1]) /* more than one address returned */ - { - int n = 0; - - /* count address list */ - while (h->h_addr_list[n]) - ++n; - ASSERT (n >= 2); - - msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d addresses", - hostname, - n); - - /* choose address randomly, for basic load-balancing capability */ - /*ia.s_addr = *(in_addr_t *) (h->h_addr_list[get_random () % n]);*/ - - /* choose first address */ - ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]); - - if (reslist) - { - int i; - for (i = 0; i < n && i < SIZE(reslist->data); ++i) - { - in_addr_t a = *(in_addr_t *) (h->h_addr_list[i]); - if (flags & GETADDR_HOST_ORDER) - a = ntohl(a); - reslist->data[i] = a; - } - reslist->len = i; - } - } - } - - /* hostname resolve succeeded */ - if (succeeded) - *succeeded = true; - } - else - { - /* IP address parse succeeded */ - if (succeeded) - *succeeded = true; - } - - done: - if (signal_received && *signal_received) - { - int level = 0; - if (flags & GETADDR_FATAL_ON_SIGNAL) - level = M_FATAL; - else if (flags & GETADDR_WARN_ON_SIGNAL) - level = M_WARN; - msg (level, "RESOLVE: signal received during DNS resolution attempt"); - } - - gc_free (&gc); - return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; + status = openvpn_getaddrinfo(flags, hostname, resolve_retry_seconds, + signal_received, AF_INET, &ai); + if(status==0) { + struct in_addr ia; + if(succeeded) + *succeeded=true; + ia = ((struct sockaddr_in*)ai->ai_addr)->sin_addr; + freeaddrinfo(ai); + return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; + } else { + if(succeeded) + *succeeded =false; + return 0; + } } + /* - * Translate IPv6 addr or hostname into struct addrinfo - * If resolve error, try again for - * resolve_retry_seconds seconds. + * Translate IPv4/IPv6 addr or hostname into struct addrinfo + * If resolve error, try again for resolve_retry_seconds seconds. */ -bool -getaddr6 (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - volatile int *signal_received, - int *gai_err, - struct sockaddr_in6 *in6) -{ - bool success; - struct addrinfo hints, *ai; +int +openvpn_getaddrinfo (unsigned int flags, + const char *hostname, + int resolve_retry_seconds, + volatile int *signal_received, + int ai_family, + struct addrinfo **res) +{ + struct addrinfo hints; int status; int sigrec = 0; int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; struct gc_arena gc = gc_new (); - ASSERT(in6); + ASSERT(res); + +#if defined(HAVE_RES_INIT) + res_init (); +#endif if (!hostname) hostname = "::"; @@ -318,151 +151,111 @@ getaddr6 (unsigned int flags, if (flags & GETADDR_MSG_VIRT_OUT) msglevel |= M_MSG_VIRT_OUT; - CLEAR (ai); - success = false; - if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL)) && !signal_received) signal_received = &sigrec; /* try numeric ipv6 addr first */ CLEAR(hints); - hints.ai_family = AF_INET6; + hints.ai_family = ai_family; hints.ai_flags = AI_NUMERICHOST; - if ((status = getaddrinfo(hostname, NULL, &hints, &ai))==0) - { - *in6 = *((struct sockaddr_in6 *)(ai->ai_addr)); - freeaddrinfo(ai); - ai = NULL; - } - if (gai_err) - *gai_err = status; + hints.ai_socktype = dnsflags_to_socktype(flags); + status = getaddrinfo(hostname, NULL, &hints, res); - if (status != 0) /* parse as IPv6 address failed? */ + if (status != 0) /* parse as numeric address failed? */ { const int fail_wait_interval = 5; /* seconds */ int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval); const char *fmt; int level = 0; - int err; - - ai = NULL; fmt = "RESOLVE: Cannot resolve host address: %s: %s"; if ((flags & GETADDR_MENTION_RESOLVE_RETRY) - && !resolve_retry_seconds) - fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)"; + && !resolve_retry_seconds) + fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)"; if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) - { - msg (msglevel, "RESOLVE: Cannot parse IPv6 address: %s", hostname); - goto done; - } + { + msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname); + goto done; + } #ifdef ENABLE_MANAGEMENT if (flags & GETADDR_UPDATE_MANAGEMENT_STATE) - { - if (management) - management_set_state (management, - OPENVPN_STATE_RESOLVE, - NULL, - (in_addr_t)0, - (in_addr_t)0); - } + { + if (management) + management_set_state (management, + OPENVPN_STATE_RESOLVE, + NULL, + (in_addr_t)0, + (in_addr_t)0); + } #endif /* * Resolve hostname */ while (true) - { - /* try hostname lookup */ + { + /* try hostname lookup */ hints.ai_flags = 0; - hints.ai_socktype = dnsflags_to_socktype(flags); - dmsg (D_SOCKET_DEBUG, "GETADDR6 flags=0x%04x ai_family=%d ai_socktype=%d", - flags, hints.ai_family, hints.ai_socktype); - err = getaddrinfo(hostname, NULL, &hints, &ai); + dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", + flags, hints.ai_family, hints.ai_socktype); + status = getaddrinfo(hostname, NULL, &hints, res); - if (gai_err) - *gai_err = err; - - if (signal_received) - { - get_signal (signal_received); - if (*signal_received) /* were we interrupted by a signal? */ - { - if (0 == err) { - ASSERT(ai); - freeaddrinfo(ai); - ai = NULL; + if (signal_received) + { + get_signal (signal_received); + if (*signal_received) /* were we interrupted by a signal? */ + { + if (0 == status) { + ASSERT(res); + freeaddrinfo(*res); + res = NULL; } - if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ - { - msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); - *signal_received = 0; - } - else - goto done; - } - } - - /* success? */ - if (0 == err) - break; - - /* resolve lookup failed, should we - continue or fail? */ - - level = msglevel; - if (resolve_retries > 0) - level = D_RESOLVE_ERRORS; - - msg (level, - fmt, - hostname, - gai_strerror(err)); - - if (--resolve_retries <= 0) - goto done; - - openvpn_sleep (fail_wait_interval); - } + if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ + { + msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); + *signal_received = 0; + } + else + goto done; + } + } - ASSERT(ai); + /* success? */ + if (0 == status) + break; - if (!ai->ai_next) - *in6 = *((struct sockaddr_in6*)(ai->ai_addr)); - else - /* more than one address returned */ - { - struct addrinfo *ai_cursor; - int n = 0; - /* count address list */ - for (ai_cursor = ai; ai_cursor; ai_cursor = ai_cursor->ai_next) n++; - ASSERT (n >= 2); + /* resolve lookup failed, should we + continue or fail? */ + level = msglevel; + if (resolve_retries > 0) + level = D_RESOLVE_ERRORS; - msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d ipv6 addresses, choosing one by random", + msg (level, + fmt, hostname, - n); + gai_strerror(status)); + + if (--resolve_retries <= 0) + goto done; - /* choose address randomly, for basic load-balancing capability */ - n--; - n %= get_random(); - for (ai_cursor = ai; n; ai_cursor = ai_cursor->ai_next) n--; - *in6 = *((struct sockaddr_in6*)(ai_cursor->ai_addr)); + openvpn_sleep (fail_wait_interval); } - freeaddrinfo(ai); - ai = NULL; + ASSERT(res); /* hostname resolve succeeded */ - success = true; + + /* Do not chose an IP Addresse by random or change the order * + * of IP addresses, doing so will break RFC 3484 address selection * + */ } else { /* IP address parse succeeded */ - success = true; } done: @@ -470,14 +263,14 @@ getaddr6 (unsigned int flags, { int level = 0; if (flags & GETADDR_FATAL_ON_SIGNAL) - level = M_FATAL; + level = M_FATAL; else if (flags & GETADDR_WARN_ON_SIGNAL) - level = M_WARN; + level = M_WARN; msg (level, "RESOLVE: signal received during DNS resolution attempt"); } gc_free (&gc); - return success; + return status; } /* @@ -653,18 +446,16 @@ update_remote (const char* host, case AF_INET6: if (host && addr) { - struct sockaddr_in6 sin6; - int success; - CLEAR(sin6); - success = getaddr6 ( - sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), - host, - 1, - NULL, - NULL, - &sin6); - if ( success ) + int status; + struct addrinfo* ai; + + status = openvpn_getaddrinfo(sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), host, 1, NULL, AF_INET6, &ai); + + if ( status ==0 ) { + struct sockaddr_in6 sin6; + CLEAR(sin6); + sin6 = *((struct sockaddr_in6*)ai->ai_addr); if (!IN6_ARE_ADDR_EQUAL(&sin6.sin6_addr, &addr->addr.in6.sin6_addr)) { int port = addr->addr.in6.sin6_port; @@ -672,6 +463,7 @@ update_remote (const char* host, addr->addr.in6 = sin6; addr->addr.in6.sin6_port = port; } + freeaddrinfo(ai); } } break; @@ -830,11 +622,11 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf) */ socket_descriptor_t -create_socket_tcp (void) +create_socket_tcp (int af) { socket_descriptor_t sd; - if ((sd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + if ((sd = socket (af, SOCK_STREAM, IPPROTO_TCP)) < 0) msg (M_ERR, "Cannot create TCP socket"); #ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ @@ -847,18 +639,6 @@ create_socket_tcp (void) } #endif -#if 0 - /* set socket linger options */ - { - struct linger linger; - linger.l_onoff = 1; - linger.l_linger = 2; - if (setsockopt (sd, SOL_SOCKET, SO_LINGER, - (void *) &linger, sizeof (linger)) < 0) - msg (M_ERR, "TCP: Cannot setsockopt SO_LINGER on TCP socket"); - } -#endif - return sd; } @@ -913,25 +693,6 @@ create_socket_udp6 (const unsigned int flags) return sd; } -static socket_descriptor_t -create_socket_tcp6 (void) -{ - socket_descriptor_t sd; - - if ((sd = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) - msg (M_ERR, "Cannot create TCP6 socket"); - - /* set SO_REUSEADDR on socket */ - { - int on = 1; - if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, - (void *) &on, sizeof (on)) < 0) - msg (M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket"); - } - - return sd; -} - static void create_socket (struct link_socket *sock) { @@ -943,18 +704,18 @@ create_socket (struct link_socket *sock) #ifdef ENABLE_SOCKS if (sock->socks_proxy) - sock->ctrl_sd = create_socket_tcp (); + sock->ctrl_sd = create_socket_tcp (AF_INET); #endif } else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT) { - sock->sd = create_socket_tcp (); + sock->sd = create_socket_tcp (AF_INET); } else if (sock->info.proto == PROTO_TCPv6_SERVER || sock->info.proto == PROTO_TCPv6_CLIENT) { - sock->sd = create_socket_tcp6 (); + sock->sd = create_socket_tcp (AF_INET6); } else if (sock->info.proto == PROTO_UDPv6) { @@ -1314,15 +1075,7 @@ socket_connect (socket_descriptor_t *sd, if (*signal_received) goto done; - switch(local->addr.sa.sa_family) - { - case PF_INET6: - *sd = create_socket_tcp6 (); - break; - case PF_INET: - *sd = create_socket_tcp (); - break; - } + *sd = create_socket_tcp (local->addr.sa.sa_family); if (bind_local) socket_bind (*sd, local, "TCP Client"); @@ -1404,25 +1157,27 @@ resolve_bind_local (struct link_socket *sock) break; case AF_INET6: { - int success; + int status; int err; CLEAR(sock->info.lsa->local.addr.in6); if (sock->local_host) { - success = getaddr6(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, - sock->local_host, - 0, - NULL, - &err, - &sock->info.lsa->local.addr.in6); + struct addrinfo *ai; + + status = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, + sock->local_host, 0, NULL, AF_INET6, &ai); + if(status ==0) { + sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); + freeaddrinfo(ai); + } } else { sock->info.lsa->local.addr.in6.sin6_family = AF_INET6; sock->info.lsa->local.addr.in6.sin6_addr = in6addr_any; - success = true; + status = 0; } - if (!success) + if (!status == 0) { msg (M_FATAL, "getaddr6() failed for local \"%s\": %s", sock->local_host, @@ -1479,7 +1234,7 @@ resolve_remote (struct link_socket *sock, { unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); int retry = 0; - bool status = false; + int status = -1; if (sock->connection_profiles_defined && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) { @@ -1516,40 +1271,27 @@ resolve_remote (struct link_socket *sock, ASSERT (0); } - switch(af) - { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr ( - flags, - sock->remote_host, - retry, - &status, - signal_received); - break; - case AF_INET6: - status = getaddr6 ( - flags, - sock->remote_host, - retry, - signal_received, - NULL, - &sock->info.lsa->remote.addr.in6); - break; - } - - dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", - flags, - phase, - retry, - signal_received ? *signal_received : -1, - status); - + struct addrinfo* ai; + /* Temporary fix, this need to be changed for dual stack */ + status = openvpn_getaddrinfo(flags, sock->remote_host, retry, + signal_received, af, &ai); + if(status == 0) { + sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); + freeaddrinfo(ai); + + dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", + flags, + phase, + retry, + signal_received ? *signal_received : -1, + status); + } if (signal_received) { if (*signal_received) goto done; } - if (!status) + if (status!=0) { if (signal_received) *signal_received = SIGUSR1; @@ -1927,7 +1669,7 @@ link_socket_init_phase2 (struct link_socket *sock, if (proxy_retry) { openvpn_close_socket (sock->sd); - sock->sd = create_socket_tcp (); + sock->sd = create_socket_tcp (AF_INET); } } while (proxy_retry); } |