summaryrefslogtreecommitdiff
path: root/src/openvpn/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/socket.c')
-rw-r--r--src/openvpn/socket.c1938
1 files changed, 1063 insertions, 875 deletions
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index b7ac339..c233f2b 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -38,6 +38,9 @@
#include "ps.h"
#include "manage.h"
#include "misc.h"
+#include "manage.h"
+#include "openvpn.h"
+#include "forward.h"
#include "memdbg.h"
@@ -69,23 +72,6 @@ sf2gaf(const unsigned int getaddr_flags,
* Functions related to the translation of DNS names to IP addresses.
*/
-static const char*
-h_errno_msg(int h_errno_err)
-{
- switch (h_errno_err)
- {
- case HOST_NOT_FOUND:
- return "[HOST_NOT_FOUND] The specified host is unknown.";
- case NO_DATA:
- return "[NO_DATA] The requested name is valid but does not have an IP address.";
- case NO_RECOVERY:
- return "[NO_RECOVERY] A non-recoverable name server error occurred.";
- case TRY_AGAIN:
- return "[TRY_AGAIN] A temporary error occurred on an authoritative name server.";
- }
- return "[unknown h_errno value]";
-}
-
/*
* Translate IP addr or hostname to in_addr_t.
* If resolve error, try again for
@@ -100,8 +86,8 @@ getaddr (unsigned int flags,
{
struct addrinfo *ai;
int status;
- status = openvpn_getaddrinfo(flags, hostname, resolve_retry_seconds,
- signal_received, AF_INET, &ai);
+ status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL,
+ resolve_retry_seconds, signal_received, AF_INET, &ai);
if(status==0) {
struct in_addr ia;
if(succeeded)
@@ -116,6 +102,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
@@ -124,6 +282,7 @@ getaddr (unsigned int flags,
int
openvpn_getaddrinfo (unsigned int flags,
const char *hostname,
+ const char *servname,
int resolve_retry_seconds,
volatile int *signal_received,
int ai_family,
@@ -134,15 +293,27 @@ openvpn_getaddrinfo (unsigned int flags,
int sigrec = 0;
int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
struct gc_arena gc = gc_new ();
+ const char *print_hostname;
+ const char *print_servname;
ASSERT(res);
- if (!hostname)
- hostname = "::";
+ ASSERT (hostname || servname);
+ ASSERT (!(flags & GETADDR_HOST_ORDER));
- if (flags & GETADDR_RANDOMIZE)
+ if (hostname && (flags & GETADDR_RANDOMIZE))
hostname = hostname_randomize(hostname, &gc);
+ if(hostname)
+ print_hostname = hostname;
+ else
+ print_hostname = "undefined";
+
+ if(servname)
+ print_servname = servname;
+ else
+ print_servname = "";
+
if (flags & GETADDR_MSG_VIRT_OUT)
msglevel |= M_MSG_VIRT_OUT;
@@ -154,25 +325,35 @@ openvpn_getaddrinfo (unsigned int flags,
CLEAR(hints);
hints.ai_family = ai_family;
hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
- status = getaddrinfo(hostname, NULL, &hints, res);
+ if(flags & GETADDR_PASSIVE)
+ hints.ai_flags |= AI_PASSIVE;
+
+ if(flags & GETADDR_DATAGRAM)
+ hints.ai_socktype = SOCK_DGRAM;
+ else
+ hints.ai_socktype = SOCK_STREAM;
+
+ status = getaddrinfo(hostname, servname, &hints, res);
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);
+ /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */
+ int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 :
+ ((resolve_retry_seconds + 4)/ fail_wait_interval);
const char *fmt;
int level = 0;
- fmt = "RESOLVE: Cannot resolve host address: %s: %s";
+ fmt = "RESOLVE: Cannot resolve host address: %s:%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.)";
+ fmt = "RESOLVE: Cannot resolve host address: %s:%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 IP address: %s", hostname);
+ msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
+ print_hostname,print_servname, gai_strerror(status));
goto done;
}
@@ -183,8 +364,10 @@ openvpn_getaddrinfo (unsigned int flags,
management_set_state (management,
OPENVPN_STATE_RESOLVE,
NULL,
- (in_addr_t)0,
- (in_addr_t)0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
#endif
@@ -193,14 +376,14 @@ openvpn_getaddrinfo (unsigned int flags,
*/
while (true)
{
-#ifndef WIN32
+#ifndef _WIN32
res_init ();
#endif
/* try hostname lookup */
- hints.ai_flags = 0;
+ hints.ai_flags &= ~AI_NUMERICHOST;
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);
+ status = getaddrinfo(hostname, servname, &hints, res);
if (signal_received)
{
@@ -239,7 +422,8 @@ openvpn_getaddrinfo (unsigned int flags,
msg (level,
fmt,
- hostname,
+ print_hostname,
+ print_servname,
gai_strerror(status));
if (--resolve_retries <= 0)
@@ -252,7 +436,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 *
*/
}
@@ -422,59 +607,6 @@ mac_addr_safe (const char *mac_addr)
return true;
}
-static void
-update_remote (const char* host,
- struct openvpn_sockaddr *addr,
- bool *changed,
- const unsigned int sockflags)
-{
- switch(addr->addr.sa.sa_family)
- {
- case AF_INET:
- if (host && addr)
- {
- const in_addr_t new_addr = getaddr (
- sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
- host,
- 1,
- NULL,
- NULL);
- if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr)
- {
- addr->addr.in4.sin_addr.s_addr = new_addr;
- *changed = true;
- }
- }
- break;
- case AF_INET6:
- if (host && addr)
- {
- 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;
- /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */
- addr->addr.in6 = sin6;
- addr->addr.in6.sin6_port = port;
- }
- freeaddrinfo(ai);
- }
- }
- break;
- default:
- ASSERT(0);
- }
-}
-
static int
socket_get_sndbuf (int sd)
{
@@ -558,7 +690,7 @@ socket_set_buffers (int fd, const struct socket_buffer_size *sbs)
static bool
socket_set_tcp_nodelay (int sd, int state)
{
-#if defined(WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY))
+#if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY))
if (setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof (state)) != 0)
{
msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state);
@@ -579,7 +711,7 @@ static inline void
socket_set_mark (int sd, int mark)
{
#if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK
- if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, &mark, sizeof (mark)) != 0)
+ if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof (mark)) != 0)
msg (M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark);
#endif
}
@@ -619,14 +751,17 @@ 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! */
+#ifndef _WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
/* set SO_REUSEADDR on socket */
{
int on = 1;
@@ -640,106 +775,134 @@ create_socket_tcp (int af)
}
static socket_descriptor_t
-create_socket_udp (const unsigned int flags)
+create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags)
{
socket_descriptor_t sd;
- if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
- msg (M_ERR, "UDP: Cannot create UDP socket");
+ 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;
-#ifdef IP_PKTINFO
- if (setsockopt (sd, SOL_IP, IP_PKTINFO,
- (void*)&pad, sizeof(pad)) < 0)
- msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");
+ if(addrinfo->ai_family == AF_INET)
+ {
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+ if (setsockopt (sd, SOL_IP, IP_PKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
+ msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");
#elif defined(IP_RECVDSTADDR)
- if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
- (void*)&pad, sizeof(pad)) < 0)
- msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
+ if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
+ (void*)&pad, sizeof(pad)) < 0)
+ msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
#else
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
- }
-#endif
- return sd;
-}
-
-static socket_descriptor_t
-create_socket_udp6 (const unsigned int flags)
-{
- socket_descriptor_t sd;
-
- if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
- msg (M_ERR, "UDP: Cannot create UDP6 socket");
-#if ENABLE_IP_PKTINFO
- else if (flags & SF_USE_IP_PKTINFO)
- {
- int pad = 1;
+ }
+ else if (addrinfo->ai_family == AF_INET6 )
+ {
#ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */
- if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
- (void*)&pad, sizeof(pad)) < 0)
+ if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
#else
- if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
- (void*)&pad, sizeof(pad)) < 0)
+ if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
#endif
- msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
+ msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
+ }
}
#endif
return sd;
}
+static void bind_local (struct link_socket *sock, const sa_family_t 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);
+ }
+}
+
static void
-create_socket (struct link_socket *sock)
+create_socket (struct link_socket* sock, struct addrinfo* addr)
{
- /* create socket */
- if (sock->info.proto == PROTO_UDPv4)
+ if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
{
- sock->sd = create_socket_udp (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 (AF_INET);
-#endif
- }
- else if (sock->info.proto == PROTO_TCPv4_SERVER
- || sock->info.proto == PROTO_TCPv4_CLIENT)
- {
- 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_tcp (AF_INET6);
+ {
+ /* 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 (sock->info.proto == PROTO_UDPv6)
+ else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
{
- sock->sd = create_socket_udp6 (sock->sockflags);
- sock->sockflags |= SF_GETADDRINFO_DGRAM;
+ 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, const struct sockaddr* addr)
+{
+ /* 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(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd);
+ return;
+ }
+
+ msg(D_SOCKET_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 openvpn_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");
}
@@ -821,8 +984,7 @@ static int
socket_listen_accept (socket_descriptor_t sd,
struct link_socket_actual *act,
const char *remote_dynamic,
- bool *remote_changed,
- const struct openvpn_sockaddr *local,
+ const struct addrinfo *local,
bool do_listen,
bool nowait,
volatile int *signal_received)
@@ -868,18 +1030,26 @@ socket_listen_accept (socket_descriptor_t sd,
if (socket_defined (new_sd))
{
- update_remote (remote_dynamic, &remote_verify, remote_changed, 0);
- if (addr_defined (&remote_verify)
- && !addr_match (&remote_verify, &act->dest))
- {
- msg (M_WARN,
- "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
- print_link_socket_actual (act, &gc));
- if (openvpn_close_socket (new_sd))
- msg (M_ERR, "TCP: close socket failed (new_sd)");
- }
+ struct addrinfo* ai = NULL;
+ if(remote_dynamic)
+ openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
+ remote_verify.addr.sa.sa_family, &ai);
+
+ if(ai && !addrlist_match(&remote_verify, ai))
+ {
+ msg (M_WARN,
+ "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
+ print_link_socket_actual (act, &gc));
+ if (openvpn_close_socket (new_sd))
+ msg (M_ERR, "TCP: close socket failed (new_sd)");
+ freeaddrinfo(ai);
+ }
else
- break;
+ {
+ if(ai)
+ freeaddrinfo(ai);
+ break;
+ }
}
openvpn_sleep (1);
}
@@ -893,19 +1063,61 @@ socket_listen_accept (socket_descriptor_t sd,
return new_sd;
}
+/* older mingw versions and WinXP do not have this define,
+ * but Vista and up support the functionality - just define it here
+ */
+#ifdef _WIN32
+# ifndef IPV6_V6ONLY
+# define IPV6_V6ONLY 27
+# endif
+#endif
void
socket_bind (socket_descriptor_t sd,
- struct openvpn_sockaddr *local,
- const char *prefix)
+ struct addrinfo *local,
+ int ai_family,
+ const char *prefix,
+ bool ipv6only)
{
struct gc_arena gc = gc_new ();
- if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family)))
+ /* FIXME (schwabe)
+ * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6
+ * entries for the requested protocol.
+ * For example if an address has multiple A records
+ * What is the correct way to deal with it?
+ */
+
+ struct addrinfo* cur;
+
+ ASSERT(local);
+
+
+ /* find the first addrinfo with correct ai_family */
+ for (cur = local; cur; cur=cur->ai_next)
+ {
+ if(cur->ai_family == ai_family)
+ break;
+ }
+ 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, (void *) &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 ();
msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",
prefix,
- print_sockaddr (local, &gc),
+ print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc),
strerror_ts (errnum, &gc));
}
gc_free (&gc);
@@ -913,19 +1125,23 @@ socket_bind (socket_descriptor_t sd,
int
openvpn_connect (socket_descriptor_t sd,
- struct openvpn_sockaddr *remote,
+ const struct sockaddr *remote,
int connect_timeout,
volatile int *signal_received)
{
int status = 0;
+#ifdef TARGET_ANDROID
+ protect_fd_nonlocal(sd, remote);
+#endif
+
#ifdef CONNECT_NONBLOCK
set_nonblock (sd);
- status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
+ status = connect (sd, remote, af_addr_size(remote->sa_family));
if (status)
status = openvpn_errno ();
if (
-#ifdef WIN32
+#ifdef _WIN32
status == WSAEWOULDBLOCK
#else
status == EINPROGRESS
@@ -968,7 +1184,7 @@ openvpn_connect (socket_descriptor_t sd,
{
if (--connect_timeout < 0)
{
-#ifdef WIN32
+#ifdef _WIN32
status = WSAETIMEDOUT;
#else
status = ETIMEDOUT;
@@ -995,7 +1211,7 @@ openvpn_connect (socket_descriptor_t sd,
}
}
#else
- status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
+ status = connect (sd, remote, af_addr_size(remote->sa_family));
if (status)
status = openvpn_errno ();
#endif
@@ -1003,85 +1219,72 @@ openvpn_connect (socket_descriptor_t sd,
return status;
}
+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);
+ else if (ai->ai_family == AF_INET6)
+ actual->dest.addr.in6 =
+ *((struct sockaddr_in6*) ai->ai_addr);
+ else
+ ASSERT(0);
+
+}
+
void
-socket_connect (socket_descriptor_t *sd,
- struct openvpn_sockaddr *local,
- bool bind_local,
- struct openvpn_sockaddr *remote,
- const bool connection_profiles_defined,
- const char *remote_dynamic,
- bool *remote_changed,
- const int connect_retry_seconds,
- const int connect_timeout,
- const int connect_retry_max,
- const unsigned int sockflags,
- volatile int *signal_received)
+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 ();
- int retry = 0;
+ int status;
#ifdef CONNECT_NONBLOCK
- msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
- print_sockaddr (remote, &gc));
+ msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
+ print_sockaddr (dest, &gc));
#else
- msg (M_INFO, "Attempting to establish TCP connection with %s",
- print_sockaddr (remote, &gc));
+ msg (M_INFO, "Attempting to establish TCP connection with %s",
+ print_sockaddr (dest, &gc));
#endif
- while (true)
- {
- int status;
-
#ifdef ENABLE_MANAGEMENT
- if (management)
+ if (management)
management_set_state (management,
OPENVPN_STATE_TCP_CONNECT,
NULL,
- (in_addr_t)0,
- (in_addr_t)0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
#endif
- status = openvpn_connect (*sd, remote, connect_timeout, signal_received);
+ /* Set the actual address */
+ status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received);
- get_signal (signal_received);
- if (*signal_received)
+ get_signal (&sig_info->signal_received);
+ if (sig_info->signal_received)
goto done;
- if (!status)
- break;
+ if (status) {
- msg (D_LINK_ERRORS,
- "TCP: connect to %s failed, will try again in %d seconds: %s",
- print_sockaddr (remote, &gc),
- connect_retry_seconds,
- strerror_ts (status, &gc));
+ msg (D_LINK_ERRORS,
+ "TCP: connect to %s failed: %s",
+ print_sockaddr (dest, &gc),
+ strerror_ts (status, &gc));
- gc_reset (&gc);
-
- openvpn_close_socket (*sd);
- *sd = SOCKET_UNDEFINED;
-
- if ((connect_retry_max > 0 && ++retry >= connect_retry_max) || connection_profiles_defined)
- {
- *signal_received = SIGUSR1;
- goto done;
- }
-
- openvpn_sleep (connect_retry_seconds);
-
- get_signal (signal_received);
- if (*signal_received)
- goto done;
-
- *sd = create_socket_tcp (local->addr.sa.sa_family);
-
- if (bind_local)
- socket_bind (*sd, local, "TCP Client");
- update_remote (remote_dynamic, remote, remote_changed, sockflags);
- }
-
- msg (M_INFO, "TCP connection established with %s",
- print_sockaddr (remote, &gc));
+ openvpn_close_socket (*sd);
+ *sd = SOCKET_UNDEFINED;
+ sig_info->signal_received = SIGUSR1;
+ sig_info->source = SIG_SOURCE_CONNECTION_FAILED;
+ } else {
+ msg (M_INFO, "TCP connection established with %s",
+ print_sockaddr (dest, &gc));
+ }
done:
gc_free (&gc);
@@ -1093,7 +1296,7 @@ socket_connect (socket_descriptor_t *sd,
static void
socket_frame_init (const struct frame *frame, struct link_socket *sock)
{
-#ifdef WIN32
+#ifdef _WIN32
overlapped_io_init (&sock->reads, frame, FALSE, false);
overlapped_io_init (&sock->writes, frame, TRUE, false);
sock->rw_handle.read = sock->reads.overlapped.hEvent;
@@ -1102,7 +1305,7 @@ socket_frame_init (const struct frame *frame, struct link_socket *sock)
if (link_socket_connection_oriented (sock))
{
-#ifdef WIN32
+#ifdef _WIN32
stream_buf_init (&sock->stream_buf,
&sock->reads.buf_init,
sock->sockflags,
@@ -1132,70 +1335,39 @@ frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto)
}
static void
-resolve_bind_local (struct link_socket *sock)
+resolve_bind_local (struct link_socket *sock, const sa_family_t af)
{
struct gc_arena gc = gc_new ();
/* resolve local address if undefined */
- if (!addr_defined (&sock->info.lsa->local))
- {
- /* may return AF_{INET|INET6} guessed from local_host */
- switch(addr_guess_family(sock->info.proto, sock->local_host))
- {
- case AF_INET:
- sock->info.lsa->local.addr.in4.sin_family = AF_INET;
- sock->info.lsa->local.addr.in4.sin_addr.s_addr =
- (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
- sock->local_host,
- 0,
- NULL,
- NULL)
- : htonl (INADDR_ANY));
- sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port);
- break;
- case AF_INET6:
- {
- int status;
- CLEAR(sock->info.lsa->local.addr.in6);
- if (sock->local_host)
- {
- 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;
- status = 0;
- }
- if (!status == 0)
- {
- msg (M_FATAL, "getaddr6() failed for local \"%s\": %s",
- sock->local_host,
- gai_strerror(status));
- }
- sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port);
- }
- break;
- }
- }
-
- /* bind to local address/port */
- if (sock->bind_local)
+ if (!sock->info.lsa->bind_local)
{
-#ifdef ENABLE_SOCKS
- if (sock->socks_proxy && sock->info.proto == PROTO_UDPv4)
- socket_bind (sock->ctrl_sd, &sock->info.lsa->local, "SOCKS");
- else
-#endif
- socket_bind (sock->sd, &sock->info.lsa->local, "TCP/UDP");
+ int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL |
+ GETADDR_FATAL | GETADDR_PASSIVE;
+ int status;
+
+ if(proto_is_dgram(sock->info.proto))
+ flags |= GETADDR_DATAGRAM;
+
+ /* will return AF_{INET|INET6}from local_host */
+ 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));
+ }
}
+
gc_free (&gc);
}
@@ -1206,132 +1378,113 @@ resolve_remote (struct link_socket *sock,
volatile int *signal_received)
{
struct gc_arena gc = gc_new ();
- int af;
- if (!sock->did_resolve_remote)
+ /* resolve remote address if undefined */
+ if (!sock->info.lsa->remote_list)
{
- /* resolve remote address if undefined */
- if (!addr_defined (&sock->info.lsa->remote))
+ if (sock->remote_host)
{
- af = addr_guess_family(sock->info.proto, sock->remote_host);
- switch(af)
- {
- case AF_INET:
- sock->info.lsa->remote.addr.in4.sin_family = AF_INET;
- sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0;
- break;
- case AF_INET6:
- CLEAR(sock->info.lsa->remote.addr.in6);
- sock->info.lsa->remote.addr.in6.sin6_family = AF_INET6;
- sock->info.lsa->remote.addr.in6.sin6_addr = in6addr_any;
- break;
- }
-
- 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;
- struct addrinfo* ai;
-
- if (sock->connection_profiles_defined && 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);
+ }
- /* 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)
- {
- if ( ai->ai_family == AF_INET6 )
- sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr));
- else
- sock->info.lsa->remote.addr.in4 = *((struct sockaddr_in*)(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;
- }
+
+ 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;
}
- }
- switch(af)
- {
- case AF_INET:
- sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port);
- break;
- case AF_INET6:
- sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port);
- break;
- }
}
+ }
- /* 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
+ /* 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);
- sock->info.lsa->actual.dest = sock->info.lsa->remote;
+ set_actual_address (&sock->info.lsa->actual,
+ sock->info.lsa->current_remote);
}
-
- /* remember that we finished */
- sock->did_resolve_remote = true;
}
done:
gc_free (&gc);
}
+
+
struct link_socket *
link_socket_new (void)
{
@@ -1339,29 +1492,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;
}
-/* bind socket if necessary */
void
link_socket_init_phase1 (struct link_socket *sock,
- const bool connection_profiles_defined,
const char *local_host,
- int local_port,
+ const char *local_port,
const char *remote_host,
- int remote_port,
+ const char *remote_port,
+ struct cached_dns_entry *dns_cache,
int proto,
+ 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,38 +1520,25 @@ link_socket_init_phase1 (struct link_socket *sock,
const char *ipchange_command,
const struct plugin_list *plugins,
int resolve_retry_seconds,
- int connect_retry_seconds,
- int connect_timeout,
- int connect_retry_max,
int mtu_discover_type,
int rcvbuf,
int sndbuf,
int mark,
+ struct event_timeout* server_poll_timeout,
unsigned int sockflags)
{
ASSERT (sock);
- sock->connection_profiles_defined = connection_profiles_defined;
-
sock->local_host = local_host;
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;
- sock->connect_retry_seconds = connect_retry_seconds;
- sock->connect_timeout = connect_timeout;
- sock->connect_retry_max = connect_retry_max;
sock->mtu_discover_type = mtu_discover_type;
#ifdef ENABLE_DEBUG
@@ -1414,31 +1549,30 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->socket_buffer_sizes.sndbuf = sndbuf;
sock->sockflags = sockflags;
+ sock->mark = mark;
sock->info.proto = proto;
+ 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;
+ sock->server_poll_timeout = server_poll_timeout;
sock->mode = mode;
if (mode == LS_MODE_TCP_ACCEPT_FROM)
{
ASSERT (accept_from);
- ASSERT (sock->info.proto == PROTO_TCPv4_SERVER
- || sock->info.proto == PROTO_TCPv6_SERVER
- );
+ ASSERT (sock->info.proto == PROTO_TCP_SERVER);
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)
+ if (sock->http_proxy)
{
- ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT);
+ ASSERT (sock->info.proto == PROTO_TCP_CLIENT);
ASSERT (!sock->inetd);
/* the proxy server */
@@ -1449,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.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_UDPv4);
ASSERT (!sock->inetd);
/* the proxy server */
@@ -1465,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;
@@ -1473,7 +1603,7 @@ link_socket_init_phase1 (struct link_socket *sock,
}
/* bind behavior for TCP server vs. client */
- if (sock->info.proto == PROTO_TCPv4_SERVER)
+ if (sock->info.proto == PROTO_TCP_SERVER)
{
if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
sock->bind_local = false;
@@ -1484,43 +1614,255 @@ link_socket_init_phase1 (struct link_socket *sock,
/* were we started by inetd or xinetd? */
if (sock->inetd)
{
- ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT
- && sock->info.proto != PROTO_TCPv6_CLIENT);
+ ASSERT (sock->info.proto != PROTO_TCP_CLIENT);
ASSERT (socket_defined (inetd_socket_descriptor));
sock->sd = inetd_socket_descriptor;
}
else if (mode != LS_MODE_TCP_ACCEPT_FROM)
{
- create_socket (sock);
+ if (sock->bind_local) {
+ resolve_bind_local (sock, sock->info.af);
+ }
+ resolve_remote (sock, 1, NULL, NULL);
+ }
+}
- /* set socket buffers based on --sndbuf and --rcvbuf options */
- socket_set_buffers (sock->sd, &sock->socket_buffer_sizes);
+static
+void phase2_inetd (struct link_socket* sock, const struct frame *frame,
+ const char *remote_dynamic, volatile int *signal_received)
+{
+ bool remote_changed = false;
- /* set socket to --mark packets with given value */
- socket_set_mark (sock->sd, mark);
+ if (sock->info.proto == PROTO_TCP_SERVER) {
+ /* AF_INET as default (and fallback) for inetd */
+ sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
+#ifdef HAVE_GETSOCKNAME
+ {
+ /* inetd: hint family type for dest = local's */
+ 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);
+ } else
+ 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));
+#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);
- resolve_bind_local (sock);
- resolve_remote (sock, 1, NULL, NULL);
+ }
+ ASSERT (!remote_changed);
+}
+
+static void
+phase2_set_socket_flags (struct link_socket* sock)
+{
+ /* set misc socket parameters */
+ socket_set_flags (sock->sd, sock->sockflags);
+
+ /* set socket to non-blocking mode */
+ set_nonblock (sock->sd);
+
+ /* set socket file descriptor to not pass across execs, so that
+ scripts don't have access to it */
+ set_cloexec (sock->sd);
+
+ if (socket_defined (sock->ctrl_sd))
+ set_cloexec (sock->ctrl_sd);
+
+ /* set Path MTU discovery options on the socket */
+ set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af);
+
+#if EXTENDED_SOCKET_ERROR_CAPABILITY
+ /* if the OS supports it, enable extended error passing on the socket */
+ set_sock_extended_error_passing (sock->sd);
+#endif
+}
+
+
+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 */
+ 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)
+{
+ 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);
+ break;
+ case LS_MODE_TCP_LISTEN:
+ socket_do_listen (sock->sd,
+ 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);
+ if (!socket_defined (sock->sd))
+ {
+ *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)
+{
+ bool proxy_retry = false;
+ do {
+ socket_connect (&sock->sd,
+ sock->info.lsa->current_remote->ai_addr,
+ get_server_poll_remaining_time (sock->server_poll_timeout),
+ sig_info);
+
+ if (sig_info->signal_received)
+ return;
+
+ if (sock->http_proxy)
+ {
+ proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ sock->server_poll_timeout,
+ &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);
+
+}
+
+static void
+phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
+{
+ socket_connect (&sock->ctrl_sd,
+ sock->info.lsa->current_remote->ai_addr,
+ get_server_poll_remaining_time (sock->server_poll_timeout),
+ sig_info);
+
+ if (sig_info->signal_received)
+ return;
+
+ establish_socks_proxy_udpassoc (sock->socks_proxy,
+ sock->ctrl_sd,
+ sock->sd,
+ &sock->socks_relay.dest,
+ &sig_info->signal_received);
+
+ if (sig_info->signal_received)
+ return;
+
+ sock->remote_host = sock->proxy_dest_host;
+ sock->remote_port = sock->proxy_dest_port;
+
+ addr_zero_host(&sock->info.lsa->actual.dest);
+ if (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);
}
/* finalize socket initialization */
void
link_socket_init_phase2 (struct link_socket *sock,
const struct frame *frame,
- volatile int *signal_received)
+ struct signal_info *sig_info)
{
- struct gc_arena gc = gc_new ();
const char *remote_dynamic = NULL;
- bool remote_changed = false;
int sig_save = 0;
ASSERT (sock);
+ ASSERT (sig_info);
- if (signal_received && *signal_received)
+ if (sig_info->signal_received)
{
- sig_save = *signal_received;
- *signal_received = 0;
+ sig_save = sig_info->signal_received;
+ sig_info->signal_received = 0;
}
/* initialize buffers */
@@ -1537,246 +1879,83 @@ link_socket_init_phase2 (struct link_socket *sock,
/* were we started by inetd or xinetd? */
if (sock->inetd)
{
- if (sock->info.proto == PROTO_TCPv4_SERVER
- || sock->info.proto == PROTO_TCPv6_SERVER) {
- /* AF_INET as default (and fallback) for inetd */
- sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
-#ifdef HAVE_GETSOCKNAME
- {
- /* inetd: hint family type for dest = local's */
- struct openvpn_sockaddr local_addr;
- socklen_t addrlen = sizeof(local_addr);
- if (getsockname (sock->sd, (struct sockaddr *)&local_addr, &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, 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, 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));
-#endif
- sock->sd =
- socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- &remote_changed,
- &sock->info.lsa->local,
- false,
- sock->inetd == INETD_NOWAIT,
- signal_received);
- }
- ASSERT (!remote_changed);
- if (*signal_received)
+ phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received);
+ if (sig_info->signal_received)
goto done;
+
}
else
{
- resolve_remote (sock, 2, &remote_dynamic, signal_received);
+ /* Second chance to resolv/create socket */
+ resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received);
- if (*signal_received)
- goto done;
+ /* 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);
- /* TCP client/server */
- if (sock->info.proto == PROTO_TCPv4_SERVER
- ||sock->info.proto == PROTO_TCPv6_SERVER)
+ /* If socket has not already been created create it now */
+ if (sock->sd == SOCKET_UNDEFINED)
{
- switch (sock->mode)
+ /* 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)
{
- case LS_MODE_DEFAULT:
- sock->sd = socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- &remote_changed,
- &sock->info.lsa->local,
- true,
- false,
- signal_received);
- break;
- case LS_MODE_TCP_LISTEN:
- socket_do_listen (sock->sd,
- &sock->info.lsa->local,
- true,
- false);
- break;
- case LS_MODE_TCP_ACCEPT_FROM:
- sock->sd = socket_do_accept (sock->sd,
- &sock->info.lsa->actual,
- false);
- if (!socket_defined (sock->sd))
- {
- *signal_received = SIGTERM;
- goto done;
+ /* 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));
+ sock->info.af = sock->info.lsa->bind_local->ai_family;
}
- tcp_connection_established (&sock->info.lsa->actual);
- break;
- default:
- ASSERT (0);
+
+ create_socket (sock, sock->info.lsa->bind_local);
}
}
- else if (sock->info.proto == PROTO_TCPv4_CLIENT
- ||sock->info.proto == PROTO_TCPv6_CLIENT)
- {
-#ifdef GENERAL_PROXY_SUPPORT
- bool proxy_retry = false;
-#else
- const bool proxy_retry = false;
-#endif
- do {
- socket_connect (&sock->sd,
- &sock->info.lsa->local,
- sock->bind_local,
- &sock->info.lsa->actual.dest,
- sock->connection_profiles_defined,
- remote_dynamic,
- &remote_changed,
- sock->connect_retry_seconds,
- sock->connect_timeout,
- sock->connect_retry_max,
- sock->sockflags,
- signal_received);
-
- if (*signal_received)
- goto done;
-
- 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,
- 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,
- signal_received);
- }
-#endif
- if (proxy_retry)
- {
- openvpn_close_socket (sock->sd);
- sock->sd = create_socket_tcp (AF_INET);
- }
- } while (proxy_retry);
- }
-#ifdef ENABLE_SOCKS
- else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy)
+ /* Socket still undefined, give a warning and abort connection */
+ if (sock->sd == SOCKET_UNDEFINED)
{
- socket_connect (&sock->ctrl_sd,
- &sock->info.lsa->local,
- sock->bind_local,
- &sock->info.lsa->actual.dest,
- sock->connection_profiles_defined,
- remote_dynamic,
- &remote_changed,
- sock->connect_retry_seconds,
- sock->connect_timeout,
- sock->connect_retry_max,
- sock->sockflags,
- signal_received);
-
- if (*signal_received)
- goto done;
-
- establish_socks_proxy_udpassoc (sock->socks_proxy,
- sock->ctrl_sd,
- sock->sd,
- &sock->socks_relay.dest,
- signal_received);
-
- if (*signal_received)
- goto done;
-
- 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);
- addr_zero_host(&sock->info.lsa->remote);
-
- resolve_remote (sock, 1, NULL, signal_received);
-
- if (*signal_received)
- goto done;
+ msg (M_WARN, "Could not determine IPv4/IPv6 protocol");
+ sig_info->signal_received = SIGUSR1;
+ goto done;
}
-#endif
- if (*signal_received)
+ if (sig_info->signal_received)
goto done;
- if (remote_changed)
+ if (sock->info.proto == PROTO_TCP_SERVER)
{
- msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment");
- addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest);
+ phase2_tcp_server (sock, remote_dynamic,
+ &sig_info->signal_received);
}
- }
-
- /* set misc socket parameters */
- socket_set_flags (sock->sd, sock->sockflags);
-
- /* set socket to non-blocking mode */
- set_nonblock (sock->sd);
-
- /* set socket file descriptor to not pass across execs, so that
- 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);
+ else if (sock->info.proto == PROTO_TCP_CLIENT)
+ {
+ phase2_tcp_client (sock, sig_info);
-#if EXTENDED_SOCKET_ERROR_CAPABILITY
- /* if the OS supports it, enable extended error passing on the socket */
- set_sock_extended_error_passing (sock->sd);
+ }
+ 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->signal_received)
+ goto done;
+ }
- /* 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, true));
- else
- msg (msglevel, "%s link local%s: %s",
- proto2ascii (sock->info.proto, true),
- (sock->bind_local ? " (bound)" : ""),
- print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc));
-
- /* print active remote address */
- msg (msglevel, "%s link remote: %s",
- proto2ascii (sock->info.proto, true),
- print_link_socket_actual_ex (&sock->info.lsa->actual,
- ":",
- PS_SHOW_PORT_IF_DEFINED,
- &gc));
- }
+ phase2_set_socket_flags(sock);
+ linksock_print_addr(sock);
done:
- if (sig_save && signal_received)
+ if (sig_save)
{
- if (!*signal_received)
- *signal_received = sig_save;
+ if (!sig_info->signal_received)
+ sig_info->signal_received = sig_save;
}
- gc_free (&gc);
}
void
@@ -1792,7 +1971,7 @@ link_socket_close (struct link_socket *sock)
if (socket_defined (sock->sd))
{
-#ifdef WIN32
+#ifdef _WIN32
close_net_event_win32 (&sock->listen_handle, sock->sd, 0);
#endif
if (!gremlin)
@@ -1802,7 +1981,7 @@ link_socket_close (struct link_socket *sock)
msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed");
}
sock->sd = SOCKET_UNDEFINED;
-#ifdef WIN32
+#ifdef _WIN32
if (!gremlin)
{
overlapped_io_close (&sock->reads);
@@ -1811,14 +1990,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);
@@ -1844,17 +2021,15 @@ setenv_trusted (struct env_set *es, const struct link_socket_info *info)
static void
ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)
{
- const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc);
- const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc);
+ const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc);
if (include_cmd)
- argv_printf (argv, "%sc %s %s",
- info->ipchange_command,
- ip,
- port);
+ {
+ argv_parse_cmd (argv, info->ipchange_command);
+ argv_printf_cat (argv, "%s", host);
+ }
else
- argv_printf (argv, "%s %s",
- ip,
- port);
+ argv_printf (argv, "%s", host);
+
}
void
@@ -1911,6 +2086,7 @@ link_socket_bad_incoming_addr (struct buffer *buf,
const struct link_socket_actual *from_addr)
{
struct gc_arena gc = gc_new ();
+ struct addrinfo* ai;
switch(from_addr->dest.addr.sa.sa_family)
{
@@ -1920,7 +2096,12 @@ link_socket_bad_incoming_addr (struct buffer *buf,
"TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
print_link_socket_actual (from_addr, &gc),
(int)from_addr->dest.addr.sa.sa_family,
- print_sockaddr (&info->lsa->remote, &gc));
+ print_sockaddr_ex (info->lsa->remote_list->ai_addr,":" ,PS_SHOW_PORT, &gc));
+ /* print additional remote addresses */
+ for(ai=info->lsa->remote_list->ai_next;ai;ai=ai->ai_next) {
+ msg(D_LINK_ERRORS,"or from peer address: %s",
+ print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc));
+ }
break;
}
buf->len = 0;
@@ -1945,18 +2126,43 @@ link_socket_current_remote (const struct link_socket_info *info)
* Maybe in the future consider PF_INET6 endpoints also ...
* by now just ignore it
*
+ * For --remote entries with multiple addresses this
+ * only return the actual endpoint we have sucessfully connected to
*/
if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
return IPV4_INVALID_ADDR;
if (link_socket_actual_defined (&lsa->actual))
return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr);
- else if (addr_defined (&lsa->remote))
- return ntohl (lsa->remote.addr.in4.sin_addr.s_addr);
+ else if (lsa->current_remote)
+ return ntohl (((struct sockaddr_in*)lsa->current_remote->ai_addr)
+ ->sin_addr.s_addr);
else
return 0;
}
+const struct in6_addr *
+link_socket_current_remote_ipv6 (const struct link_socket_info *info)
+{
+ const struct link_socket_addr *lsa = info->lsa;
+
+/* This logic supports "redirect-gateway" semantic,
+ * for PF_INET6 routes over PF_INET6 endpoints
+ *
+ * For --remote entries with multiple addresses this
+ * only return the actual endpoint we have sucessfully connected to
+ */
+ if (lsa->actual.dest.addr.sa.sa_family != AF_INET6)
+ return NULL;
+
+ if (link_socket_actual_defined (&lsa->actual))
+ return &(lsa->actual.dest.addr.in6.sin6_addr);
+ else if (lsa->current_remote)
+ return &(((struct sockaddr_in6*)lsa->current_remote->ai_addr) ->sin6_addr);
+ else
+ return NULL;
+}
+
/*
* Return a status string describing socket state.
*/
@@ -1970,7 +2176,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena
{
buf_printf (&out, "S%s",
(s->rwflags_debug & EVENT_READ) ? "R" : "r");
-#ifdef WIN32
+#ifdef _WIN32
buf_printf (&out, "%s",
overlapped_io_state_ascii (&s->reads));
#endif
@@ -1979,7 +2185,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena
{
buf_printf (&out, "S%s",
(s->rwflags_debug & EVENT_WRITE) ? "W" : "w");
-#ifdef WIN32
+#ifdef _WIN32
buf_printf (&out, "%s",
overlapped_io_state_ascii (&s->writes));
#endif
@@ -2019,7 +2225,7 @@ stream_buf_init (struct stream_buf *sb,
sb->residual = alloc_buf (sb->maxlen);
sb->error = false;
#if PORT_SHARE
- sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCPv4_SERVER))
+ sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER))
? PS_ENABLED
: PS_DISABLED;
#endif
@@ -2154,7 +2360,7 @@ stream_buf_close (struct stream_buf* sb)
event_t
socket_listen_event_handle (struct link_socket *s)
{
-#ifdef WIN32
+#ifdef _WIN32
if (!defined_net_event_win32 (&s->listen_handle))
init_net_event_win32 (&s->listen_handle, FD_ACCEPT, s->sd, 0);
return &s->listen_handle;
@@ -2168,67 +2374,65 @@ socket_listen_event_handle (struct link_socket *s)
*/
const char *
-print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc)
-{
- return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc);
-}
-
-const char *
-print_sockaddr_ex (const struct openvpn_sockaddr *addr,
- const char* separator,
- const unsigned int flags,
- struct gc_arena *gc)
+print_sockaddr_ex (const struct sockaddr *sa,
+ const char* separator,
+ const unsigned int flags,
+ struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (128, gc);
- bool addr_is_defined;
- addr_is_defined = addr_defined (addr);
- if (!addr_is_defined) {
- return "[undef]";
- }
- switch(addr->addr.sa.sa_family)
+ bool addr_is_defined = false;
+ char hostaddr[NI_MAXHOST] = "";
+ char servname[NI_MAXSERV] = "";
+ int status;
+
+ socklen_t salen = 0;
+ switch(sa->sa_family)
{
case AF_INET:
- {
- const int port= ntohs (addr->addr.in4.sin_port);
- buf_puts (&out, "[AF_INET]");
-
- if (!(flags & PS_DONT_SHOW_ADDR))
- buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]"));
-
- if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
- && port)
- {
- if (separator)
- buf_printf (&out, "%s", separator);
-
- buf_printf (&out, "%d", port);
- }
- }
+ if (!(flags & PS_DONT_SHOW_FAMILY))
+ buf_puts (&out, "[AF_INET]");
+ salen = sizeof (struct sockaddr_in);
+ addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0;
break;
case AF_INET6:
- {
- const int port= ntohs (addr->addr.in6.sin6_port);
- char buf[INET6_ADDRSTRLEN] = "";
- buf_puts (&out, "[AF_INET6]");
- if (addr_is_defined)
- {
- getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
- buf, sizeof (buf), NULL, 0, NI_NUMERICHOST);
- buf_puts (&out, buf);
- }
- if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED)))
- && port)
- {
- if (separator)
- buf_puts (&out, separator);
-
- buf_printf (&out, "%d", port);
- }
- }
+ if (!(flags & PS_DONT_SHOW_FAMILY))
+ buf_puts (&out, "[AF_INET6]");
+ salen = sizeof (struct sockaddr_in6);
+ addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr);
break;
+ case AF_UNSPEC:
+ if (!(flags & PS_DONT_SHOW_FAMILY))
+ return "[AF_UNSPEC]";
+ else
+ return "";
default:
ASSERT(0);
}
+
+ status = getnameinfo(sa, salen, hostaddr, sizeof (hostaddr),
+ servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if(status!=0) {
+ buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status));
+ return BSTR(&out);
+ }
+
+ if (!(flags & PS_DONT_SHOW_ADDR))
+ {
+ if (addr_is_defined)
+ buf_puts (&out, hostaddr);
+ else
+ buf_puts (&out, "[undef]");
+ }
+
+ if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED))
+ {
+ if (separator)
+ buf_puts (&out, separator);
+
+ buf_puts (&out, servname);
+ }
+
return BSTR (&out);
}
@@ -2252,7 +2456,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
{
char ifname[IF_NAMESIZE] = "[undef]";
struct buffer out = alloc_buf_gc (128, gc);
- buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc));
+ buf_printf (&out, "%s", print_sockaddr_ex (&act->dest.addr.sa, separator, flags, gc));
#if ENABLE_IP_PKTINFO
if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
{
@@ -2263,7 +2467,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
struct openvpn_sockaddr sa;
CLEAR (sa);
sa.addr.in4.sin_family = AF_INET;
-#ifdef IP_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
if_indextoname(act->pi.in4.ipi_ifindex, ifname);
#elif defined(IP_RECVDSTADDR)
@@ -2273,7 +2477,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
buf_printf (&out, " (via %s%%%s)",
- print_sockaddr_ex (&sa, separator, 0, gc),
+ print_sockaddr_ex (&sa.addr.sa, separator, 0, gc),
ifname);
}
break;
@@ -2392,9 +2596,20 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv
}
break;
case AF_INET6:
- openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix);
- getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
- buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr ))
+ {
+ struct in_addr ia;
+ memcpy (&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12],
+ sizeof (ia.s_addr));
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
+ openvpn_snprintf (buf, sizeof(buf), "%s", inet_ntoa(ia) );
+ }
+ else
+ {
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix);
+ getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
+ buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ }
setenv_str (es, name_buf, buf);
if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port)
@@ -2451,22 +2666,28 @@ setenv_link_socket_actual (struct env_set *es,
struct proto_names {
const char *short_form;
const char *display_form;
- bool is_dgram;
- bool is_net;
- unsigned short proto_af;
+ sa_family_t proto_af;
+ int proto;
};
/* Indexed by PROTO_x */
-static const struct proto_names proto_names[PROTO_N] = {
- {"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC},
- {"udp", "UDPv4",1,1, AF_INET},
- {"tcp-server", "TCPv4_SERVER",0,1, AF_INET},
- {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET},
- {"tcp", "TCPv4",0,1, AF_INET},
- {"udp6" ,"UDPv6",1,1, AF_INET6},
- {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6},
- {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6},
- {"tcp6" ,"TCPv6",0,1, AF_INET6},
+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},
+ {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER},
+ {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT},
+ {"tcp", "TCP", AF_UNSPEC, 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},
+ {"tcp6" ,"TCPv6", AF_INET6, PROTO_TCP},
};
bool
@@ -2474,59 +2695,66 @@ proto_is_net(int proto)
{
if (proto < 0 || proto >= PROTO_N)
ASSERT(0);
- return proto_names[proto].is_net;
+ return proto != PROTO_NONE;
}
bool
proto_is_dgram(int proto)
{
- if (proto < 0 || proto >= PROTO_N)
- ASSERT(0);
- return proto_names[proto].is_dgram;
+ return proto_is_udp(proto);
}
+
bool
proto_is_udp(int proto)
{
if (proto < 0 || proto >= PROTO_N)
ASSERT(0);
- return proto_names[proto].is_dgram&&proto_names[proto].is_net;
+ return proto == PROTO_UDP;
}
+
bool
proto_is_tcp(int proto)
{
if (proto < 0 || proto >= PROTO_N)
ASSERT(0);
- return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net;
-}
-
-unsigned short
-proto_sa_family(int proto)
-{
- if (proto < 0 || proto >= PROTO_N)
- ASSERT(0);
- return proto_names[proto].proto_af;
+ return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER;
}
int
ascii2proto (const char* proto_name)
{
int i;
- ASSERT (PROTO_N == SIZE (proto_names));
- for (i = 0; i < PROTO_N; ++i)
+ for (i = 0; i < SIZE (proto_names); ++i)
if (!strcmp (proto_name, proto_names[i].short_form))
- return i;
+ return proto_names[i].proto;
return -1;
}
+sa_family_t
+ascii2af (const char* proto_name)
+{
+ int i;
+ for (i = 0; i < SIZE (proto_names); ++i)
+ if (!strcmp (proto_name, proto_names[i].short_form))
+ return proto_names[i].proto_af;
+ return 0;
+}
+
const char *
-proto2ascii (int proto, bool display_form)
+proto2ascii (int proto, sa_family_t af, bool display_form)
{
- ASSERT (PROTO_N == SIZE (proto_names));
- if (proto < 0 || proto >= PROTO_N)
- return "[unknown protocol]";
- else if (display_form)
- return proto_names[proto].display_form;
- else
- return proto_names[proto].short_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(display_form)
+ return proto_names[i].display_form;
+ else
+ return proto_names[i].short_form;
+ }
+ }
+
+ return "[unknown protocol]";
}
const char *
@@ -2535,40 +2763,15 @@ proto2ascii_all (struct gc_arena *gc)
struct buffer out = alloc_buf_gc (256, gc);
int i;
- ASSERT (PROTO_N == SIZE (proto_names));
- for (i = 0; i < PROTO_N; ++i)
+ for (i = 0; i < SIZE (proto_names); ++i)
{
if (i)
buf_printf(&out, " ");
- buf_printf(&out, "[%s]", proto2ascii(i, false));
+ buf_printf(&out, "[%s]", proto_names[i].short_form);
}
return BSTR (&out);
}
-int
-addr_guess_family(int proto, const char *name)
-{
- unsigned short ret;
- if (proto)
- {
- return proto_sa_family(proto); /* 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)
{
@@ -2592,31 +2795,22 @@ addr_family_name (int af)
* has always sent UDPv4, TCPv4 over the wire. Keep these
* strings for backward compatbility
*/
-int
+const char*
proto_remote (int proto, bool remote)
{
ASSERT (proto >= 0 && proto < PROTO_N);
- if (remote)
- {
- switch (proto)
- {
- case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT;
- case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER;
- case PROTO_TCPv6_SERVER: return PROTO_TCPv4_CLIENT;
- case PROTO_TCPv6_CLIENT: return PROTO_TCPv4_SERVER;
- case PROTO_UDPv6: return PROTO_UDPv4;
- }
- }
- else
- {
- switch (proto)
- {
- case PROTO_TCPv6_SERVER: return PROTO_TCPv4_SERVER;
- case PROTO_TCPv6_CLIENT: return PROTO_TCPv4_CLIENT;
- case PROTO_UDPv6: return PROTO_UDPv4;
- }
- }
- return proto;
+ if (proto == PROTO_UDP)
+ return "UDPv4";
+
+ if ( (remote && proto == PROTO_TCP_CLIENT) ||
+ (!remote && proto == PROTO_TCP_SERVER))
+ return "TCPv4_SERVER";
+ if ( (remote && proto == PROTO_TCP_SERVER) ||
+ (!remote && proto == PROTO_TCP_CLIENT))
+ return "TCPv4_CLIENT";
+
+ ASSERT (0);
+ return ""; /* Make the compiler happy */
}
/*
@@ -2643,7 +2837,7 @@ link_socket_read_tcp (struct link_socket *sock,
if (!sock->stream_buf.residual_fully_formed)
{
-#ifdef WIN32
+#ifdef _WIN32
len = socket_finalize (sock->sd, &sock->reads, buf, NULL);
#else
struct buffer frag;
@@ -2668,51 +2862,39 @@ link_socket_read_tcp (struct link_socket *sock,
return buf->len = 0; /* no error, but packet is still incomplete */
}
-#ifndef WIN32
+#ifndef _WIN32
#if ENABLE_IP_PKTINFO
-#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
-struct openvpn_in4_pktinfo
-{
- struct cmsghdr cmsghdr;
-#ifdef HAVE_IN_PKTINFO
- struct in_pktinfo pi4;
-#elif defined(IP_RECVDSTADDR)
- struct in_addr pi4;
+/* make the buffer large enough to handle ancilliary socket data for
+ * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292)
+ */
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \
+ CMSG_SPACE(sizeof (struct in_pktinfo)) )
+#else
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \
+ CMSG_SPACE(sizeof (struct in_addr)) )
#endif
-};
-struct openvpn_in6_pktinfo
-{
- struct cmsghdr cmsghdr;
- struct in6_pktinfo pi6;
-};
-
-union openvpn_pktinfo {
- struct openvpn_in4_pktinfo msgpi4;
- struct openvpn_in6_pktinfo msgpi6;
-};
-#pragma pack()
static socklen_t
link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
struct buffer *buf,
- int maxsize,
struct link_socket_actual *from)
{
struct iovec iov;
- union openvpn_pktinfo opi;
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
struct msghdr mesg;
socklen_t fromlen = sizeof (from->dest.addr);
iov.iov_base = BPTR (buf);
- iov.iov_len = maxsize;
+ iov.iov_len = buf_forward_capacity_total (buf);
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
mesg.msg_name = &from->dest.addr;
mesg.msg_namelen = fromlen;
- mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof opi;
+ mesg.msg_control = pktinfo_buf;
+ mesg.msg_controllen = sizeof pktinfo_buf;
buf->len = recvmsg (sock->sd, &mesg, 0);
if (buf->len >= 0)
{
@@ -2721,18 +2903,19 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
cmsg = CMSG_FIRSTHDR (&mesg);
if (cmsg != NULL
&& CMSG_NXTHDR (&mesg, cmsg) == NULL
-#ifdef IP_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
&& cmsg->cmsg_level == SOL_IP
&& cmsg->cmsg_type == IP_PKTINFO
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) )
#elif defined(IP_RECVDSTADDR)
&& cmsg->cmsg_level == IPPROTO_IP
&& cmsg->cmsg_type == IP_RECVDSTADDR
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) )
#else
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
- && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo))
{
-#ifdef IP_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
@@ -2746,13 +2929,18 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
&& CMSG_NXTHDR (&mesg, cmsg) == NULL
&& cmsg->cmsg_level == IPPROTO_IPV6
&& cmsg->cmsg_type == IPV6_PKTINFO
- && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo))
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) )
{
struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
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
@@ -2760,21 +2948,20 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
int
link_socket_read_udp_posix (struct link_socket *sock,
struct buffer *buf,
- int maxsize,
struct link_socket_actual *from)
{
socklen_t fromlen = sizeof (from->dest.addr);
- socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto));
+ socklen_t expectedlen = af_addr_size(sock->info.af);
addr_zero_host(&from->dest);
- 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)
- fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
+ if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
+ fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, from);
else
#endif
- buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
+ buf->len = recvfrom (sock->sd, BPTR (buf), buf_forward_capacity(buf), 0,
&from->dest.addr.sa, &fromlen);
+ /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
bad_address_length (fromlen, expectedlen);
return buf->len;
@@ -2796,7 +2983,7 @@ link_socket_write_tcp (struct link_socket *sock,
ASSERT (len <= sock->stream_buf.maxlen);
len = htonps (len);
ASSERT (buf_write_prepend (buf, &len, sizeof (len)));
-#ifdef WIN32
+#ifdef _WIN32
return link_socket_write_win32 (sock, buf, to);
#else
return link_socket_write_tcp_posix (sock, buf, to);
@@ -2805,7 +2992,7 @@ link_socket_write_tcp (struct link_socket *sock,
#if ENABLE_IP_PKTINFO
-int
+size_t
link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to)
@@ -2813,24 +3000,24 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct iovec iov;
struct msghdr mesg;
struct cmsghdr *cmsg;
- union openvpn_pktinfo opi;
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
iov.iov_base = BPTR (buf);
iov.iov_len = BLEN (buf);
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
- switch (sock->info.lsa->remote.addr.sa.sa_family)
+ switch (to->dest.addr.sa.sa_family)
{
case AF_INET:
{
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in);
- mesg.msg_control = &opi;
+ mesg.msg_control = pktinfo_buf;
mesg.msg_flags = 0;
-#ifdef HAVE_IN_PKTINFO
- mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo);
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_pktinfo));
cmsg = CMSG_FIRSTHDR (&mesg);
- cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
+ cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_pktinfo));
cmsg->cmsg_level = SOL_IP;
cmsg->cmsg_type = IP_PKTINFO;
{
@@ -2841,7 +3028,7 @@ 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) );
+ ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(pktinfo_buf) );
mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr));
cmsg = CMSG_FIRSTHDR (&mesg);
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
@@ -2858,13 +3045,16 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct in6_pktinfo *pkti6;
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in6);
- mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo);
+
+ ASSERT( CMSG_SPACE(sizeof (struct in6_pktinfo)) <= sizeof(pktinfo_buf) );
+ mesg.msg_control = pktinfo_buf;
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in6_pktinfo));
mesg.msg_flags = 0;
cmsg = CMSG_FIRSTHDR (&mesg);
- cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
+
pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex;
pkti6->ipi6_addr = to->pi.in6.ipi6_addr;
@@ -2881,7 +3071,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
* Win32 overlapped socket I/O functions.
*/
-#ifdef WIN32
+#ifdef _WIN32
int
socket_recv_queue (struct link_socket *sock, int maxsize)
@@ -2919,10 +3109,7 @@ 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
- sock->reads.addrlen = sizeof (sock->reads.addr);
+ sock->reads.addrlen = sizeof (sock->reads.addr6);
status = WSARecvFrom(
sock->sd,
wsabuf,
@@ -2954,9 +3141,10 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
if (!status) /* operation completed immediately? */
{
- int addrlen = af_addr_size(sock->info.lsa->local.addr.sa.sa_family);
- if (sock->reads.addr_defined && sock->reads.addrlen != addrlen)
- bad_address_length (sock->reads.addrlen, addrlen);
+ /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
+ int af_len = af_addr_size (sock->info.af);
+ if (sock->reads.addr_defined && af_len && sock->reads.addrlen != af_len)
+ bad_address_length (sock->reads.addrlen, af_len);
sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
/* since we got an immediate return, we must signal the event object ourselves */
@@ -3018,7 +3206,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 (to->dest.addr.sa.sa_family == AF_INET6)
{
sock->writes.addr6 = to->dest.addr.in6;
sock->writes.addrlen = sizeof (sock->writes.addr6);
@@ -3191,7 +3379,7 @@ socket_finalize (SOCKET s,
case sizeof(struct sockaddr_in):
case sizeof(struct sockaddr_in6):
/* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6
- * under WIN32*/
+ * under _WIN32*/
case sizeof(struct sockaddr_in6)-4:
break;
default:
@@ -3217,7 +3405,7 @@ socket_finalize (SOCKET s,
return ret;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Socket event notification
@@ -3238,7 +3426,7 @@ socket_set (struct link_socket *s,
rwflags &= ~EVENT_READ;
}
-#ifdef WIN32
+#ifdef _WIN32
if (rwflags & EVENT_READ)
socket_recv_queue (s, 0);
#endif