summaryrefslogtreecommitdiff
path: root/app/openvpn/src/openvpn/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/openvpn/src/openvpn/socket.c')
-rw-r--r--app/openvpn/src/openvpn/socket.c1029
1 files changed, 584 insertions, 445 deletions
diff --git a/app/openvpn/src/openvpn/socket.c b/app/openvpn/src/openvpn/socket.c
index 31ff6d21..9e6bd10c 100644
--- a/app/openvpn/src/openvpn/socket.c
+++ b/app/openvpn/src/openvpn/socket.c
@@ -39,6 +39,7 @@
#include "manage.h"
#include "misc.h"
#include "manage.h"
+#include "openvpn.h"
#include "memdbg.h"
@@ -117,6 +118,178 @@ getaddr (unsigned int flags,
}
}
+static inline bool
+streqnull (const char* a, const char* b)
+{
+ if (a == NULL && b == NULL)
+ return true;
+ else if (a == NULL || b == NULL)
+ return false;
+ else
+ return streq (a, b);
+}
+
+/*
+ get_cached_dns_entry return 0 on success and -1
+ otherwise. (like getaddrinfo)
+ */
+static int
+get_cached_dns_entry (struct cached_dns_entry* dns_cache,
+ const char* hostname,
+ const char* servname,
+ int ai_family,
+ int resolve_flags,
+ struct addrinfo **ai)
+{
+ struct cached_dns_entry *ph;
+ int flags;
+
+ /* Only use flags that are relevant for the structure */
+ flags = resolve_flags & GETADDR_CACHE_MASK;
+
+ for (ph = dns_cache; ph ; ph = ph->next)
+ {
+ if (streqnull (ph->hostname, hostname) &&
+ streqnull (ph->servname, servname) &&
+ ph->ai_family == ai_family &&
+ ph->flags == flags)
+ {
+ *ai = ph->ai;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+static int
+do_preresolve_host (struct context *c,
+ const char *hostname,
+ const char *servname,
+ const int af,
+ const int flags)
+{
+ struct addrinfo *ai;
+ int status;
+
+ if (get_cached_dns_entry(c->c1.dns_cache,
+ hostname,
+ servname,
+ af,
+ flags,
+ &ai) == 0 )
+ {
+ /* entry already cached, return success */
+ return 0;
+ }
+
+ status = openvpn_getaddrinfo (flags, hostname, servname,
+ c->options.resolve_retry_seconds, NULL,
+ af, &ai);
+ if (status == 0)
+ {
+ struct cached_dns_entry *ph;
+
+ ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc);
+ ph->ai = ai;
+ ph->hostname = hostname;
+ ph->servname = servname;
+ ph->flags = flags & GETADDR_CACHE_MASK;
+
+ if (!c->c1.dns_cache)
+ c->c1.dns_cache = ph;
+ else
+ {
+ struct cached_dns_entry *prev = c->c1.dns_cache;
+ while (prev->next)
+ prev = prev->next;
+ prev->next = ph;
+ }
+
+ gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc);
+
+ }
+ return status;
+}
+
+void
+do_preresolve (struct context *c)
+{
+ int i;
+ struct connection_list *l = c->options.connection_list;
+ const unsigned int preresolve_flags = GETADDR_RESOLVE|
+ GETADDR_UPDATE_MANAGEMENT_STATE|
+ GETADDR_MENTION_RESOLVE_RETRY|
+ GETADDR_FATAL;
+
+
+ for (i = 0; i < l->len; ++i)
+ {
+ int status;
+ const char *remote;
+ int flags = preresolve_flags;
+
+ struct connection_entry* ce = c->options.connection_list->array[i];
+
+ if (proto_is_dgram(ce->proto))
+ flags |= GETADDR_DATAGRAM;
+
+ if (c->options.sockflags & SF_HOST_RANDOMIZE)
+ flags |= GETADDR_RANDOMIZE;
+
+ if (c->options.ip_remote_hint)
+ remote = c->options.ip_remote_hint;
+ else
+ remote = ce->remote;
+
+ /* HTTP remote hostname does not need to be resolved */
+ if (! ce->http_proxy_options)
+ {
+ status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags);
+ if (status != 0)
+ goto err;
+ }
+
+ /* Preresolve proxy */
+ if (ce->http_proxy_options)
+ {
+ status = do_preresolve_host (c,
+ ce->http_proxy_options->server,
+ ce->http_proxy_options->port,
+ ce->af,
+ preresolve_flags);
+
+ if (status != 0)
+ goto err;
+ }
+
+ if (ce->socks_proxy_server)
+ {
+ status = do_preresolve_host (c,
+ ce->socks_proxy_server,
+ ce->socks_proxy_port,
+ ce->af,
+ flags);
+ if (status != 0)
+ goto err;
+ }
+
+ if (ce->bind_local)
+ {
+ flags |= GETADDR_PASSIVE;
+ flags &= ~GETADDR_RANDOMIZE;
+ status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags);
+ if (status != 0)
+ goto err;
+
+ }
+
+ }
+ return;
+
+ err:
+ throw_signal_soft (SIGHUP, "Preresolving failed");
+}
/*
* Translate IPv4/IPv6 addr or hostname into struct addrinfo
@@ -155,7 +328,7 @@ openvpn_getaddrinfo (unsigned int flags,
print_hostname = hostname;
else
print_hostname = "undefined";
-
+
if(servname)
print_servname = servname;
else
@@ -172,11 +345,10 @@ openvpn_getaddrinfo (unsigned int flags,
CLEAR(hints);
hints.ai_family = ai_family;
hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
-
+
if(flags & GETADDR_PASSIVE)
hints.ai_flags |= AI_PASSIVE;
-
+
if(flags & GETADDR_DATAGRAM)
hints.ai_socktype = SOCK_DGRAM;
else
@@ -192,7 +364,7 @@ openvpn_getaddrinfo (unsigned int flags,
((resolve_retry_seconds + 4)/ fail_wait_interval);
const char *fmt;
int level = 0;
-
+
fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";
if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
&& !resolve_retry_seconds)
@@ -276,8 +448,8 @@ openvpn_getaddrinfo (unsigned int flags,
/* hostname resolve succeeded */
- /*
- * Do not chose an IP Addresse by random or change the order *
+ /*
+ * Do not choose an IP Addresse by random or change the order *
* of IP addresses, doing so will break RFC 3484 address selection *
*/
}
@@ -597,11 +769,14 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf)
*/
socket_descriptor_t
-create_socket_tcp (int af)
+create_socket_tcp (struct addrinfo* addrinfo)
{
socket_descriptor_t sd;
- if ((sd = socket (af, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ ASSERT (addrinfo);
+ ASSERT (addrinfo->ai_socktype == SOCK_STREAM);
+
+ if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
msg (M_ERR, "Cannot create TCP socket");
#ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
@@ -618,17 +793,20 @@ create_socket_tcp (int af)
}
static socket_descriptor_t
-create_socket_udp (const int af, const unsigned int flags)
+create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags)
{
socket_descriptor_t sd;
- if ((sd = socket (af, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ ASSERT (addrinfo);
+ ASSERT (addrinfo->ai_socktype == SOCK_DGRAM);
+
+ if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket");
#if ENABLE_IP_PKTINFO
else if (flags & SF_USE_IP_PKTINFO)
{
int pad = 1;
- if(af == AF_INET)
+ if(addrinfo->ai_family == AF_INET)
{
#ifdef IP_PKTINFO
if (setsockopt (sd, SOL_IP, IP_PKTINFO,
@@ -641,8 +819,8 @@ create_socket_udp (const int af, const unsigned int flags)
#else
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
- }
- else if (af == AF_INET6 )
+ }
+ else if (addrinfo->ai_family == AF_INET6 )
{
#ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */
if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
@@ -658,75 +836,91 @@ create_socket_udp (const int af, const unsigned int flags)
return sd;
}
-static void
-create_socket (struct link_socket *sock)
+static void bind_local (struct link_socket *sock, const sa_family_t ai_family)
{
- /* create socket, use information carried over from getaddrinfo */
- const int ai_proto = sock->info.lsa->actual.ai_protocol;
- const int ai_family = sock->info.lsa->actual.ai_family;
-
- ASSERT (sock->info.af == AF_UNSPEC || sock->info.af == ai_family);
+ /* bind to local address/port */
+ if (sock->bind_local)
+ {
+ if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
+ socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local,
+ ai_family, "SOCKS", false);
+ else
+ socket_bind (sock->sd, sock->info.lsa->bind_local,
+ ai_family,
+ "TCP/UDP", sock->info.bind_ipv6_only);
+ }
+}
-
- if (ai_proto == IPPROTO_UDP)
+static void
+create_socket (struct link_socket* sock, struct addrinfo* addr)
+{
+ if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
{
- sock->sd = create_socket_udp (ai_family, sock->sockflags);
+ sock->sd = create_socket_udp (addr, sock->sockflags);
sock->sockflags |= SF_GETADDRINFO_DGRAM;
-#ifdef ENABLE_SOCKS
+ /* Assume that control socket and data socket to the socks proxy
+ * are using the same IP family */
if (sock->socks_proxy)
- sock->ctrl_sd = create_socket_tcp (ai_family);
-#endif
+ {
+ /* Construct a temporary addrinfo to create the socket,
+ * currently resolve two remote addresses is not supported,
+ * TODO: Rewrite the whole resolve_remote */
+ struct addrinfo addrinfo_tmp = *addr;
+ addrinfo_tmp.ai_socktype = SOCK_STREAM;
+ addrinfo_tmp.ai_protocol = IPPROTO_TCP;
+ sock->ctrl_sd = create_socket_tcp (&addrinfo_tmp);
+ }
}
- else if (ai_proto == IPPROTO_TCP)
+ else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
{
- sock->sd = create_socket_tcp (ai_family);
+ sock->sd = create_socket_tcp (addr);
}
else
{
ASSERT (0);
}
-
/* set socket buffers based on --sndbuf and --rcvbuf options */
socket_set_buffers (sock->sd, &sock->socket_buffer_sizes);
-
+
/* set socket to --mark packets with given value */
socket_set_mark (sock->sd, sock->mark);
-
+
+ bind_local (sock, addr->ai_family);
}
#ifdef TARGET_ANDROID
-static void protect_fd_nonlocal (int fd, struct sockaddr* addr)
+static void protect_fd_nonlocal (int fd, const struct sockaddr* addr)
{
- if (addr_local (addr)) {
- msg(M_DEBUG, "Address is local, not protecting socket fd %d", fd);
- return;
- }
-
- struct user_pass up;
- strcpy(up.username ,__func__);
- management->connection.fdtosend = fd;
- msg(M_DEBUG, "Protecting socket fd %d", fd);
- management_query_user_pass(management, &up , "PROTECTFD", GET_USER_PASS_NEED_OK,(void*) 0);
+ /* pass socket FD to management interface to pass on to VPNService API
+ * as "protected socket" (exempt from being routed into tunnel)
+ */
+ if (addr_local (addr)) {
+ msg(M_DEBUG, "Address is local, not protecting socket fd %d", fd);
+ return;
+ }
+ msg(M_DEBUG, "Protecting socket fd %d", fd);
+ management->connection.fdtosend = fd;
+ management_android_control (management, "PROTECTFD", __func__);
}
#endif
-
/*
* Functions used for establishing a TCP stream connection.
*/
static void
socket_do_listen (socket_descriptor_t sd,
- const struct sockaddr *local,
+ const struct addrinfo *local,
bool do_listen,
bool do_set_nonblock)
{
struct gc_arena gc = gc_new ();
if (do_listen)
{
+ ASSERT(local);
msg (M_INFO, "Listening for incoming TCP connection on %s",
- print_sockaddr (local, &gc));
+ print_sockaddr (local->ai_addr, &gc));
if (listen (sd, 1))
msg (M_ERR, "TCP: listen() failed");
}
@@ -819,7 +1013,7 @@ socket_listen_accept (socket_descriptor_t sd,
int new_sd = SOCKET_UNDEFINED;
CLEAR (*act);
- socket_do_listen (sd, local->ai_addr, do_listen, true);
+ socket_do_listen (sd, local, do_listen, true);
while (true)
{
@@ -854,7 +1048,7 @@ socket_listen_accept (socket_descriptor_t sd,
if (socket_defined (new_sd))
{
- struct addrinfo* ai;
+ struct addrinfo* ai = NULL;
if(remote_dynamic)
openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
remote_verify.addr.sa.sa_family, &ai);
@@ -891,7 +1085,8 @@ void
socket_bind (socket_descriptor_t sd,
struct addrinfo *local,
int ai_family,
- const char *prefix)
+ const char *prefix,
+ bool ipv6only)
{
struct gc_arena gc = gc_new ();
@@ -901,10 +1096,12 @@ socket_bind (socket_descriptor_t sd,
* For example if an address has multiple A records
* What is the correct way to deal with it?
*/
-
- ASSERT(local);
+
struct addrinfo* cur;
-
+
+ ASSERT(local);
+
+
/* find the first addrinfo with correct ai_family */
for (cur = local; cur; cur=cur->ai_next)
{
@@ -914,7 +1111,17 @@ socket_bind (socket_descriptor_t sd,
if (!cur)
msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
prefix, addr_family_name(ai_family));
-
+
+ if (ai_family == AF_INET6)
+ {
+ int v6only = ipv6only ? 1: 0; /* setsockopt must have an "int" */
+
+ msg (M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only);
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)))
+ {
+ msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only);
+ }
+ }
if (bind (sd, cur->ai_addr, cur->ai_addrlen))
{
const int errnum = openvpn_errno ();
@@ -934,12 +1141,13 @@ openvpn_connect (socket_descriptor_t sd,
{
int status = 0;
+#ifdef TARGET_ANDROID
+ protect_fd_nonlocal(sd, remote);
+#endif
+
#ifdef CONNECT_NONBLOCK
set_nonblock (sd);
-
- protect_fd_nonlocal(sd, remote);
status = connect (sd, remote, af_addr_size(remote->sa_family));
-
if (status)
status = openvpn_errno ();
if (
@@ -1015,7 +1223,7 @@ void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai)
{
CLEAR (*actual);
ASSERT (ai);
-
+
if (ai->ai_family == AF_INET)
actual->dest.addr.in4 =
*((struct sockaddr_in*) ai->ai_addr);
@@ -1024,24 +1232,18 @@ void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai)
*((struct sockaddr_in6*) ai->ai_addr);
else
ASSERT(0);
-
- /* Copy addrinfo sock parameters for socket creating */
- actual->ai_family = ai->ai_family;
- actual->ai_protocol = ai->ai_protocol;
- actual->ai_socktype = ai->ai_socktype;
+
}
void
-socket_connect (socket_descriptor_t *sd,
- struct link_socket_addr *lsa,
+socket_connect (socket_descriptor_t* sd,
+ const struct sockaddr* dest,
const int connect_timeout,
struct signal_info* sig_info)
{
struct gc_arena gc = gc_new ();
- const struct sockaddr *dest = &lsa->actual.dest.addr.sa;
-
int status;
-
+
#ifdef CONNECT_NONBLOCK
msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
print_sockaddr (dest, &gc));
@@ -1049,14 +1251,14 @@ socket_connect (socket_descriptor_t *sd,
msg (M_INFO, "Attempting to establish TCP connection with %s",
print_sockaddr (dest, &gc));
#endif
-
+
#ifdef ENABLE_MANAGEMENT
if (management)
management_set_state (management,
- OPENVPN_STATE_TCP_CONNECT,
- NULL,
- (in_addr_t)0,
- (in_addr_t)0);
+ OPENVPN_STATE_TCP_CONNECT,
+ NULL,
+ (in_addr_t)0,
+ (in_addr_t)0);
#endif
/* Set the actual address */
@@ -1139,41 +1341,34 @@ resolve_bind_local (struct link_socket *sock, const sa_family_t af)
if (!sock->info.lsa->bind_local)
{
int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL |
- GETADDR_FATAL | GETADDR_PASSIVE;
+ GETADDR_FATAL | GETADDR_PASSIVE;
int status;
-
+
if(proto_is_dgram(sock->info.proto))
- flags |= GETADDR_DATAGRAM;
-
+ flags |= GETADDR_DATAGRAM;
+
/* will return AF_{INET|INET6}from local_host */
- status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
- NULL, af, &sock->info.lsa->bind_local);
+ status = get_cached_dns_entry (sock->dns_cache,
+ sock->local_host,
+ sock->local_port,
+ af,
+ flags,
+ &sock->info.lsa->bind_local);
+
+ if (status)
+ status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
+ NULL, af, &sock->info.lsa->bind_local);
+
if(status !=0) {
- msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
- sock->local_host, sock->local_port,
- gai_strerror(status));
+ msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
+ sock->local_host, sock->local_port,
+ gai_strerror(status));
}
}
gc_free (&gc);
}
-static void bind_local (struct link_socket *sock)
-{
- /* bind to local address/port */
- if (sock->bind_local)
- {
-#ifdef ENABLE_SOCKS
- if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
- socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local,
- sock->info.lsa->actual.ai_family, "SOCKS");
- else
-#endif
- socket_bind (sock->sd, sock->info.lsa->bind_local,
- sock->info.lsa->actual.ai_family, "TCP/UDP");
- }
-}
-
static void
resolve_remote (struct link_socket *sock,
int phase,
@@ -1182,103 +1377,104 @@ resolve_remote (struct link_socket *sock,
{
struct gc_arena gc = gc_new ();
- if (!sock->did_resolve_remote)
+ /* resolve remote address if undefined */
+ if (!sock->info.lsa->remote_list)
{
- /* resolve remote address if undefined */
- if (!sock->info.lsa->remote_list)
+ if (sock->remote_host)
{
- if (sock->remote_host)
+ unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
+ int retry = 0;
+ int status = -1;
+ struct addrinfo* ai;
+ if (proto_is_dgram(sock->info.proto))
+ flags |= GETADDR_DATAGRAM;
+
+ if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
{
- unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
- int retry = 0;
- int status = -1;
-
- if (proto_is_dgram(sock->info.proto))
- flags |= GETADDR_DATAGRAM;
-
- if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
+ if (phase == 2)
+ flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
+ retry = 0;
+ }
+ else if (phase == 1)
+ {
+ if (sock->resolve_retry_seconds)
{
- if (phase == 2)
- flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
retry = 0;
}
- else if (phase == 1)
+ else
{
- if (sock->resolve_retry_seconds)
- {
- retry = 0;
- }
- else
- {
- flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
- retry = 0;
- }
+ flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
+ retry = 0;
}
- else if (phase == 2)
+ }
+ else if (phase == 2)
+ {
+ if (sock->resolve_retry_seconds)
{
- if (sock->resolve_retry_seconds)
- {
- flags |= GETADDR_FATAL;
- retry = sock->resolve_retry_seconds;
- }
- else
- {
- ASSERT (0);
- }
+ flags |= GETADDR_FATAL;
+ retry = sock->resolve_retry_seconds;
}
else
{
ASSERT (0);
}
+ }
+ else
+ {
+ ASSERT (0);
+ }
- struct addrinfo* ai;
- status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
- retry, signal_received, sock->info.af, &ai);
- if(status == 0) {
- sock->info.lsa->remote_list = ai;
- sock->info.lsa->current_remote = 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;
- }
+
+ status = get_cached_dns_entry (sock->dns_cache,
+ sock->remote_host,
+ sock->remote_port,
+ sock->info.af,
+ flags, &ai);
+ if (status)
+ status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
+ retry, signal_received, sock->info.af, &ai);
+
+ if(status == 0) {
+ sock->info.lsa->remote_list = ai;
+ sock->info.lsa->current_remote = 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!=0)
{
if (signal_received)
*signal_received = SIGUSR1;
goto done;
}
- }
}
+ }
- /* should we re-use previous active remote address? */
- if (link_socket_actual_defined (&sock->info.lsa->actual))
- {
- msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
- print_link_socket_actual (&sock->info.lsa->actual, &gc));
- if (remote_dynamic)
- *remote_dynamic = NULL;
- }
- /* else, quick hack to fix persistent-remote ....*/
+ /* should we re-use previous active remote address? */
+ if (link_socket_actual_defined (&sock->info.lsa->actual))
+ {
+ msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
+ print_link_socket_actual (&sock->info.lsa->actual, &gc));
+ if (remote_dynamic)
+ *remote_dynamic = NULL;
+ }
+ else
+ {
+ CLEAR (sock->info.lsa->actual);
+ if(sock->info.lsa->current_remote)
{
- CLEAR (sock->info.lsa->actual);
- if(sock->info.lsa->current_remote)
- {
- set_actual_address (&sock->info.lsa->actual,
- sock->info.lsa->current_remote);
- }
+ set_actual_address (&sock->info.lsa->actual,
+ sock->info.lsa->current_remote);
}
-
- /* remember that we finished */
- sock->did_resolve_remote = true;
}
done:
@@ -1294,61 +1490,24 @@ link_socket_new (void)
ALLOC_OBJ_CLEAR (sock, struct link_socket);
sock->sd = SOCKET_UNDEFINED;
-#ifdef ENABLE_SOCKS
sock->ctrl_sd = SOCKET_UNDEFINED;
-#endif
return sock;
}
void
-create_new_socket (struct link_socket* sock)
-{
- if (sock->bind_local) {
- resolve_bind_local (sock, sock->info.af);
- }
- resolve_remote (sock, 1, NULL, NULL);
- /*
- * In P2P or server mode we must create the socket even when resolving
- * the remote site fails/is not specified. */
-
- if (sock->info.af && sock->info.lsa->actual.ai_family==0 && sock->bind_local)
- {
- /* Copy sock parameters from bind addr */
- set_actual_address (&sock->info.lsa->actual, sock->info.lsa->bind_local);
- /* clear destination set by set_actual_address */
- CLEAR(sock->info.lsa->actual.dest);
- }
-
- /*
- * Create the socket early if socket should be bound
- */
- if (sock->bind_local && sock->info.lsa->actual.ai_family)
- {
- create_socket (sock);
-
- if (sock->bind_local)
- bind_local(sock);
- }
-}
-
-
-/* bind socket if necessary */
-void
link_socket_init_phase1 (struct link_socket *sock,
const char *local_host,
const char *local_port,
const char *remote_host,
const char *remote_port,
+ struct cached_dns_entry *dns_cache,
int proto,
- sa_family_t af,
+ sa_family_t af,
+ bool bind_ipv6_only,
int mode,
const struct link_socket *accept_from,
-#ifdef ENABLE_HTTP_PROXY
struct http_proxy_info *http_proxy,
-#endif
-#ifdef ENABLE_SOCKS
struct socks_proxy_info *socks_proxy,
-#endif
#ifdef ENABLE_DEBUG
int gremlin,
#endif
@@ -1372,15 +1531,9 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->local_port = local_port;
sock->remote_host = remote_host;
sock->remote_port = remote_port;
-
-#ifdef ENABLE_HTTP_PROXY
+ sock->dns_cache = dns_cache;
sock->http_proxy = http_proxy;
-#endif
-
-#ifdef ENABLE_SOCKS
sock->socks_proxy = socks_proxy;
-#endif
-
sock->bind_local = bind_local;
sock->inetd = inetd;
sock->resolve_retry_seconds = resolve_retry_seconds;
@@ -1401,6 +1554,7 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->info.af = af;
sock->info.remote_float = remote_float;
sock->info.lsa = lsa;
+ sock->info.bind_ipv6_only = bind_ipv6_only;
sock->info.ipchange_command = ipchange_command;
sock->info.plugins = plugins;
@@ -1412,10 +1566,9 @@ link_socket_init_phase1 (struct link_socket *sock,
ASSERT (!sock->inetd);
sock->sd = accept_from->sd;
}
-
+
if (false)
;
-#ifdef ENABLE_HTTP_PROXY
/* are we running in HTTP proxy mode? */
else if (sock->http_proxy)
{
@@ -1430,12 +1583,9 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->proxy_dest_host = remote_host;
sock->proxy_dest_port = remote_port;
}
-#endif
-#ifdef ENABLE_SOCKS
/* or in Socks proxy mode? */
else if (sock->socks_proxy)
{
- ASSERT (sock->info.af == AF_INET);
ASSERT (!sock->inetd);
/* the proxy server */
@@ -1446,7 +1596,6 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->proxy_dest_host = remote_host;
sock->proxy_dest_port = remote_port;
}
-#endif
else
{
sock->remote_host = remote_host;
@@ -1454,7 +1603,7 @@ link_socket_init_phase1 (struct link_socket *sock,
}
/* bind behavior for TCP server vs. client */
- if (sock->info.proto == PROTO_TCP_SERVER && sock->info.af==AF_INET)
+ if (sock->info.proto == PROTO_TCP_SERVER)
{
if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
sock->bind_local = false;
@@ -1471,13 +1620,16 @@ link_socket_init_phase1 (struct link_socket *sock,
}
else if (mode != LS_MODE_TCP_ACCEPT_FROM)
{
- create_new_socket (sock);
+ if (sock->bind_local) {
+ resolve_bind_local (sock, sock->info.af);
+ }
+ resolve_remote (sock, 1, NULL, NULL);
}
}
static
void phase2_inetd (struct link_socket* sock, const struct frame *frame,
- const char *remote_dynamic, volatile int *signal_received)
+ const char *remote_dynamic, volatile int *signal_received)
{
bool remote_changed = false;
@@ -1490,27 +1642,28 @@ void phase2_inetd (struct link_socket* sock, const struct frame *frame,
struct openvpn_sockaddr local_addr;
socklen_t addrlen = sizeof(local_addr);
if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) {
- sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
- dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
- proto2ascii(sock->info.proto, sock->info.af, false), local_addr.addr.sa.sa_family,
- sock->sd);
+ sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
+ dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
+ proto2ascii(sock->info.proto, sock->info.af, false),
+ local_addr.addr.sa.sa_family, sock->sd);
} else
- msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
- proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);
+ msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
+ proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);
}
#else
msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
- "function, using AF_INET",
- proto2ascii(sock->info.proto, false));
+ "function, using AF_INET",
+ proto2ascii(sock->info.proto, false));
#endif
sock->sd =
socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- sock->info.lsa->bind_local,
- false,
- sock->inetd == INETD_NOWAIT,
- signal_received);
+ &sock->info.lsa->actual,
+ remote_dynamic,
+ sock->info.lsa->bind_local,
+ false,
+ sock->inetd == INETD_NOWAIT,
+ signal_received);
+
}
ASSERT (!remote_changed);
}
@@ -1528,10 +1681,8 @@ phase2_set_socket_flags (struct link_socket* sock)
scripts don't have access to it */
set_cloexec (sock->sd);
-#ifdef ENABLE_SOCKS
if (socket_defined (sock->ctrl_sd))
set_cloexec (sock->ctrl_sd);
-#endif
/* set Path MTU discovery options on the socket */
set_mtu_discover_type (sock->sd, sock->mtu_discover_type);
@@ -1547,171 +1698,161 @@ static void
linksock_print_addr (struct link_socket *sock)
{
struct gc_arena gc = gc_new ();
+ const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
/* print local address */
- {
- const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
-
- if (sock->inetd)
- msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
- else if (sock->bind_local)
- {
- /* Socket is always bound on the first matching address */
- struct addrinfo *cur;
- for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
- {
- if(cur->ai_family == sock->info.lsa->actual.ai_family)
- break;
- }
- ASSERT (cur);
- msg (msglevel, "%s link local (bound): %s",
- proto2ascii (sock->info.proto, sock->info.af, true),
- print_sockaddr(cur->ai_addr,&gc));
- }
- else
- msg (msglevel, "%s link local: (not bound)",
- proto2ascii (sock->info.proto, sock->info.af, true));
-
- /* print active remote address */
- msg (msglevel, "%s link remote: %s",
- proto2ascii (sock->info.proto, sock->info.af, true),
- print_link_socket_actual_ex (&sock->info.lsa->actual,
- ":",
- PS_SHOW_PORT_IF_DEFINED,
- &gc));
- }
+ if (sock->inetd)
+ msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
+ else if (sock->bind_local)
+ {
+ sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family;
+ /* Socket is always bound on the first matching address,
+ * For bound sockets with no remote addr this is the element of
+ * the list */
+ struct addrinfo *cur;
+ for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
+ {
+ if(!ai_family || ai_family == cur->ai_family)
+ break;
+ }
+ ASSERT (cur);
+ msg (msglevel, "%s link local (bound): %s",
+ proto2ascii (sock->info.proto, sock->info.af, true),
+ print_sockaddr(cur->ai_addr,&gc));
+ }
+ else
+ msg (msglevel, "%s link local: (not bound)",
+ proto2ascii (sock->info.proto, sock->info.af, true));
+
+ /* print active remote address */
+ msg (msglevel, "%s link remote: %s",
+ proto2ascii (sock->info.proto, sock->info.af, true),
+ print_link_socket_actual_ex (&sock->info.lsa->actual,
+ ":",
+ PS_SHOW_PORT_IF_DEFINED,
+ &gc));
gc_free(&gc);
}
static void
phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic,
- volatile int *signal_received)
+ volatile int *signal_received)
{
switch (sock->mode)
{
case LS_MODE_DEFAULT:
sock->sd = socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- sock->info.lsa->bind_local,
- true,
- false,
- signal_received);
+ &sock->info.lsa->actual,
+ remote_dynamic,
+ sock->info.lsa->bind_local,
+ true,
+ false,
+ signal_received);
break;
case LS_MODE_TCP_LISTEN:
socket_do_listen (sock->sd,
- sock->info.lsa->bind_local->ai_addr,
- true,
- false);
+ sock->info.lsa->bind_local,
+ true,
+ false);
break;
case LS_MODE_TCP_ACCEPT_FROM:
sock->sd = socket_do_accept (sock->sd,
- &sock->info.lsa->actual,
- false);
+ &sock->info.lsa->actual,
+ false);
if (!socket_defined (sock->sd))
- {
- *signal_received = SIGTERM;
- return;
- }
+ {
+ *signal_received = SIGTERM;
+ return;
+ }
tcp_connection_established (&sock->info.lsa->actual);
break;
default:
ASSERT (0);
}
-
}
static void
phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info)
{
-#ifdef GENERAL_PROXY_SUPPORT
- bool proxy_retry = false;
-#else
- const bool proxy_retry = false;
-#endif
- do {
- socket_connect (&sock->sd,
- sock->info.lsa,
- sock->connect_timeout,
- sig_info);
-
- if (sig_info->signal_received)
- return;
-
- if (false)
- ;
-#ifdef ENABLE_HTTP_PROXY
- else if (sock->http_proxy)
- {
- proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- &sock->stream_buf.residual,
- &sig_info->signal_received);
- }
-#endif
-#ifdef ENABLE_SOCKS
- else if (sock->socks_proxy)
- {
- establish_socks_proxy_passthru (sock->socks_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- &sig_info->signal_received);
- }
-#endif
- if (proxy_retry)
- {
- /* TODO (schwabe): This code assumes AF_INET for the proxy socket
- * when retrying a connection */
- openvpn_close_socket (sock->sd);
- sock->sd = create_socket_tcp (AF_INET);
- }
- } while (proxy_retry);
+ bool proxy_retry = false;
+ do {
+ socket_connect (&sock->sd,
+ sock->info.lsa->current_remote->ai_addr,
+ sock->connect_timeout,
+ sig_info);
+
+ if (sig_info->signal_received)
+ return;
+
+ if (false)
+ ;
+ else if (sock->http_proxy)
+ {
+ proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ &sock->stream_buf.residual,
+ &sig_info->signal_received);
+ }
+ else if (sock->socks_proxy)
+ {
+ establish_socks_proxy_passthru (sock->socks_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ &sig_info->signal_received);
+ }
+ if (proxy_retry)
+ {
+ openvpn_close_socket (sock->sd);
+ sock->sd = create_socket_tcp (sock->info.lsa->current_remote);
+ }
+
+ } while (proxy_retry);
}
-#ifdef ENABLE_SOCKS
static void
phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
{
socket_connect (&sock->ctrl_sd,
- sock->info.lsa,
- sock->connect_timeout,
- sig_info);
-
+ sock->info.lsa->current_remote->ai_addr,
+ sock->connect_timeout,
+ sig_info);
+
if (sig_info->signal_received)
- return;
-
+ return;
+
establish_socks_proxy_udpassoc (sock->socks_proxy,
- sock->ctrl_sd,
- sock->sd,
- &sock->socks_relay.dest,
- &sig_info->signal_received);
-
+ sock->ctrl_sd,
+ sock->sd,
+ &sock->socks_relay.dest,
+ &sig_info->signal_received);
+
if (sig_info->signal_received)
- return;
-
+ return;
+
sock->remote_host = sock->proxy_dest_host;
sock->remote_port = sock->proxy_dest_port;
- sock->did_resolve_remote = false;
-
+
addr_zero_host(&sock->info.lsa->actual.dest);
if (sock->info.lsa->remote_list)
- freeaddrinfo(sock->info.lsa->remote_list);
-
+ {
+ freeaddrinfo(sock->info.lsa->remote_list);
+ sock->info.lsa->current_remote = NULL;
+ sock->info.lsa->remote_list = NULL;
+ }
+
resolve_remote (sock, 1, NULL, &sig_info->signal_received);
-
}
-#endif
/* finalize socket initialization */
void
link_socket_init_phase2 (struct link_socket *sock,
- const struct frame *frame,
- struct signal_info *sig_info)
+ const struct frame *frame,
+ struct signal_info *sig_info)
{
const char *remote_dynamic = NULL;
int sig_save = 0;
@@ -1740,69 +1881,77 @@ link_socket_init_phase2 (struct link_socket *sock,
{
phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received);
if (sig_info && sig_info->signal_received)
- goto done;
+ goto done;
}
else
{
/* Second chance to resolv/create socket */
resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received);
-
+
+ /* If a valid remote has been found, create the socket with its addrinfo */
+ if (sock->info.lsa->current_remote)
+ create_socket (sock, sock->info.lsa->current_remote);
+
/* If socket has not already been created create it now */
if (sock->sd == SOCKET_UNDEFINED)
- {
- if (sock->info.lsa->actual.ai_family)
- {
- create_socket (sock);
- }
- else
- {
- msg (M_WARN, "Could not determine IPv4/IPv6 protocol");
- sig_info->signal_received = SIGUSR1;
- goto done;
- }
-
- if (sock->bind_local)
- bind_local(sock);
- }
+ {
+ /* If we have no --remote and have still not figured out the
+ * protocol family to use we will use the first of the bind */
+
+ if (sock->bind_local && !sock->remote_host && sock->info.lsa->bind_local)
+ {
+ /* Warn if this is because neither v4 or v6 was specified
+ * and we should not connect a remote */
+ if (sock->info.af == AF_UNSPEC)
+ msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s",
+ addr_family_name(sock->info.lsa->bind_local->ai_family));
+
+ create_socket (sock, sock->info.lsa->bind_local);
+ }
+ }
+
+ /* Socket still undefined, give a warning and abort connection */
+ if (sock->sd == SOCKET_UNDEFINED)
+ {
+ msg (M_WARN, "Could not determine IPv4/IPv6 protocol");
+ sig_info->signal_received = SIGUSR1;
+ goto done;
+ }
-
if (sig_info && sig_info->signal_received)
- goto done;
+ goto done;
if (sock->info.proto == PROTO_TCP_SERVER)
- {
- phase2_tcp_server (sock, remote_dynamic,
- &sig_info->signal_received);
- }
+ {
+ phase2_tcp_server (sock, remote_dynamic,
+ &sig_info->signal_received);
+ }
else if (sock->info.proto == PROTO_TCP_CLIENT)
- {
- phase2_tcp_client (sock, sig_info);
-
- }
- else if (sock->info.proto == PROTO_UDP)
- {
-#ifdef ENABLE_SOCKS
- if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
- {
- phase2_socks_client (sock, sig_info);
-#endif
- }
- protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
- }
+ {
+ phase2_tcp_client (sock, sig_info);
+ }
+ else if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
+ {
+ phase2_socks_client (sock, sig_info);
+ }
+#ifdef TARGET_ANDROID
+ if (sock->sd != -1)
+ protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
+#endif
if (sig_info && sig_info->signal_received)
- goto done;
+ goto done;
}
phase2_set_socket_flags(sock);
linksock_print_addr(sock);
-
+
done:
if (sig_save && sig_info)
{
if (!sig_info->signal_received)
- sig_info->signal_received = sig_save;
+ sig_info->signal_received = sig_save;
}
}
@@ -1838,14 +1987,12 @@ link_socket_close (struct link_socket *sock)
#endif
}
-#ifdef ENABLE_SOCKS
if (socket_defined (sock->ctrl_sd))
{
if (openvpn_close_socket (sock->ctrl_sd))
msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed");
sock->ctrl_sd = SOCKET_UNDEFINED;
}
-#endif
stream_buf_close (&sock->stream_buf);
free_buf (&sock->stream_buf_data);
@@ -2251,10 +2398,10 @@ print_sockaddr_ex (const struct sockaddr *sa,
{
if (separator)
buf_puts (&out, separator);
-
+
buf_puts (&out, servname);
}
-
+
return BSTR (&out);
}
@@ -2468,12 +2615,17 @@ struct proto_names {
/* Indexed by PROTO_x */
static const struct proto_names proto_names[] = {
{"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE},
+ /* try IPv4 and IPv6 (client), bind dual-stack (server) */
{"udp", "UDP", AF_UNSPEC, PROTO_UDP},
- {"udp4", "UDPv4", AF_INET, PROTO_UDP},
- {"tcp-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER},
- {"tcp-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT},
+ {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER},
+ {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT},
{"tcp", "TCP", AF_UNSPEC, PROTO_TCP},
- {"tcp4", "TCPv4", AF_INET, PROTO_TCP},
+ /* force IPv4 */
+ {"udp4", "UDPv4", AF_INET, PROTO_UDP},
+ {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER},
+ {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT},
+ {"tcp4", "TCPv4", AF_INET, PROTO_TCP},
+ /* force IPv6 */
{"udp6" ,"UDPv6", AF_INET6, PROTO_UDP},
{"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER},
{"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT},
@@ -2535,7 +2687,7 @@ proto2ascii (int proto, sa_family_t af, bool display_form)
unsigned int i;
for (i = 0; i < SIZE (proto_names); ++i)
{
- if(proto_names[i].proto_af == af && proto_names[i].proto == proto)
+ if(proto_names[i].proto_af == af && proto_names[i].proto == proto)
{
if(display_form)
return proto_names[i].display_form;
@@ -2562,30 +2714,6 @@ proto2ascii_all (struct gc_arena *gc)
return BSTR (&out);
}
-int
-addr_guess_family(sa_family_t af, const char *name)
-{
- unsigned short ret;
- if (af)
- {
- return af; /* already stamped */
- }
- else
- {
- struct addrinfo hints , *ai;
- int err;
- CLEAR(hints);
- hints.ai_flags = AI_NUMERICHOST;
- err = getaddrinfo(name, NULL, &hints, &ai);
- if ( 0 == err )
- {
- ret=ai->ai_family;
- freeaddrinfo(ai);
- return ret;
- }
- }
- return AF_INET; /* default */
-}
const char *
addr_family_name (int af)
{
@@ -2615,13 +2743,16 @@ proto_remote (int proto, bool remote)
ASSERT (proto >= 0 && proto < PROTO_N);
if (proto == PROTO_UDP)
return "UDPv4";
-
- if ( (remote && proto == PROTO_TCP_CLIENT) || proto == PROTO_TCP_SERVER)
+
+ if ( (remote && proto == PROTO_TCP_CLIENT) ||
+ (!remote && proto == PROTO_TCP_SERVER))
return "TCPv4_SERVER";
- if ( (remote && proto == PROTO_TCP_SERVER) || proto == PROTO_TCP_CLIENT)
+ if ( (remote && proto == PROTO_TCP_SERVER) ||
+ (!remote && proto == PROTO_TCP_CLIENT))
return "TCPv4_CLIENT";
ASSERT (0);
+ return ""; /* Make the compiler happy */
}
/*
@@ -2757,7 +2888,12 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
from->pi.in6.ipi6_addr = pkti6->ipi6_addr;
}
+ else if (cmsg != NULL)
+ {
+ msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len );
+ }
}
+
return fromlen;
}
#endif
@@ -2774,7 +2910,7 @@ link_socket_read_udp_posix (struct link_socket *sock,
ASSERT (buf_safe (buf, maxsize));
#if ENABLE_IP_PKTINFO
/* Both PROTO_UDPv4 and PROTO_UDPv6 */
- if (proto_is_udp(sock->info.proto) && sock->sockflags & SF_USE_IP_PKTINFO)
+ if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
else
#endif
@@ -2818,24 +2954,24 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct iovec iov;
struct msghdr mesg;
struct cmsghdr *cmsg;
+ union openvpn_pktinfo opi;
iov.iov_base = BPTR (buf);
iov.iov_len = BLEN (buf);
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
- switch (to->ai_family)
+ switch (to->dest.addr.sa.sa_family)
{
case AF_INET:
{
- struct openvpn_in4_pktinfo msgpi4;
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in);
- mesg.msg_control = &msgpi4;
- mesg.msg_controllen = sizeof msgpi4;
+ mesg.msg_control = &opi;
mesg.msg_flags = 0;
+#ifdef HAVE_IN_PKTINFO
+ mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo);
cmsg = CMSG_FIRSTHDR (&mesg);
cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
-#ifdef HAVE_IN_PKTINFO
cmsg->cmsg_level = SOL_IP;
cmsg->cmsg_type = IP_PKTINFO;
{
@@ -2846,6 +2982,10 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
pkti->ipi_addr.s_addr = 0;
}
#elif defined(IP_RECVDSTADDR)
+ ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) );
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr));
+ cmsg = CMSG_FIRSTHDR (&mesg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_RECVDSTADDR;
*(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4;
@@ -2856,12 +2996,11 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
}
case AF_INET6:
{
- struct openvpn_in6_pktinfo msgpi6;
struct in6_pktinfo *pkti6;
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in6);
- mesg.msg_control = &msgpi6;
- mesg.msg_controllen = sizeof msgpi6;
+ mesg.msg_control = &opi;
+ mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo);
mesg.msg_flags = 0;
cmsg = CMSG_FIRSTHDR (&mesg);
cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
@@ -2921,10 +3060,10 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
if (proto_is_udp(sock->info.proto))
{
sock->reads.addr_defined = true;
- if (sock->info.proto == PROTO_UDPv6)
- sock->reads.addrlen = sizeof (sock->reads.addr6);
- else
+ if (sock->info.af == AF_INET)
sock->reads.addrlen = sizeof (sock->reads.addr);
+ else
+ sock->reads.addrlen = sizeof (sock->reads.addr6);
status = WSARecvFrom(
sock->sd,
wsabuf,
@@ -3020,7 +3159,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li
{
/* set destination address for UDP writes */
sock->writes.addr_defined = true;
- if (sock->info.proto == PROTO_UDPv6)
+ if (sock->info.af == AF_INET6)
{
sock->writes.addr6 = to->dest.addr.in6;
sock->writes.addrlen = sizeof (sock->writes.addr6);