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.c131
1 files changed, 91 insertions, 40 deletions
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index 9131ec2..cd41893 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
+ * Copyright (C) 2002-2021 OpenVPN Inc <sales@openvpn.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -35,6 +35,7 @@
#include "gremlin.h"
#include "plugin.h"
#include "ps.h"
+#include "run_command.h"
#include "manage.h"
#include "misc.h"
#include "manage.h"
@@ -99,10 +100,12 @@ get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname,
bits = 0;
max_bits = sizeof(in_addr_t) * 8;
break;
+
case AF_INET6:
bits = 64;
max_bits = sizeof(struct in6_addr) * 8;
break;
+
default:
msg(M_WARN,
"Unsupported AF family passed to getaddrinfo for %s (%d)",
@@ -124,7 +127,7 @@ get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname,
}
/* check if this hostname has a /bits suffix */
- sep = strchr(var_host , '/');
+ sep = strchr(var_host, '/');
if (sep)
{
bits = strtoul(sep + 1, &endp, 10);
@@ -155,10 +158,12 @@ get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname,
*ip4 = ntohl(*ip4);
}
break;
+
case AF_INET6:
ip6 = network;
*ip6 = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
break;
+
default:
/* can't get here because 'af' was previously checked */
msg(M_WARN,
@@ -373,7 +378,8 @@ do_preresolve(struct context *c)
/* 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);
+ status = do_preresolve_host(c, remote, ce->remote_port,
+ ce->af, flags);
if (status != 0)
{
goto err;
@@ -412,7 +418,8 @@ do_preresolve(struct context *c)
{
flags |= GETADDR_PASSIVE;
flags &= ~GETADDR_RANDOMIZE;
- status = do_preresolve_host(c, ce->local, ce->local_port, ce->af, flags);
+ status = do_preresolve_host(c, ce->local, ce->local_port,
+ ce->af, flags);
if (status != 0)
{
goto err;
@@ -521,7 +528,9 @@ openvpn_getaddrinfo(unsigned int flags,
if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
&& !resolve_retry_seconds)
{
- fmt = "RESOLVE: Cannot resolve host address: %s:%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)
@@ -553,11 +562,13 @@ openvpn_getaddrinfo(unsigned int flags,
while (true)
{
#ifndef _WIN32
+ /* force resolv.conf reload */
res_init();
#endif
/* try hostname lookup */
hints.ai_flags &= ~AI_NUMERICHOST;
- dmsg(D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",
+ dmsg(D_SOCKET_DEBUG,
+ "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",
flags, hints.ai_family, hints.ai_socktype);
status = getaddrinfo(hostname, servname, &hints, res);
@@ -568,7 +579,9 @@ openvpn_getaddrinfo(unsigned int flags,
{
if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */
{
- msg(level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt");
+ msg(level,
+ "RESOLVE: Ignored SIGUSR1 signal received during "
+ "DNS resolution attempt");
*signal_received = 0;
}
else
@@ -629,7 +642,9 @@ openvpn_getaddrinfo(unsigned int flags,
/* IP address parse succeeded */
if (flags & GETADDR_RANDOMIZE)
{
- msg(M_WARN, "WARNING: ignoring --remote-random-hostname because the hostname is an IP address");
+ msg(M_WARN,
+ "WARNING: ignoring --remote-random-hostname because the "
+ "hostname is an IP address");
}
}
@@ -987,7 +1002,7 @@ link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf)
}
/*
- * SOCKET INITALIZATION CODE.
+ * SOCKET INITIALIZATION CODE.
* Create a TCP/UDP socket
*/
@@ -1133,6 +1148,18 @@ create_socket(struct link_socket *sock, struct addrinfo *addr)
/* set socket to --mark packets with given value */
socket_set_mark(sock->sd, sock->mark);
+#if defined(TARGET_LINUX)
+ if (sock->bind_dev)
+ {
+ msg(M_INFO, "Using bind-dev %s", sock->bind_dev);
+ if (setsockopt(sock->sd, SOL_SOCKET, SO_BINDTODEVICE, sock->bind_dev, strlen(sock->bind_dev) + 1) != 0)
+ {
+ msg(M_WARN|M_ERRNO, "WARN: setsockopt SO_BINDTODEVICE=%s failed", sock->bind_dev);
+ }
+
+ }
+#endif
+
bind_local(sock, addr->ai_family);
}
@@ -1453,14 +1480,14 @@ openvpn_connect(socket_descriptor_t sd,
struct pollfd fds[1];
fds[0].fd = sd;
fds[0].events = POLLOUT;
- status = poll(fds, 1, 0);
+ status = poll(fds, 1, (connect_timeout > 0) ? 1000 : 0);
#else
fd_set writes;
struct timeval tv;
FD_ZERO(&writes);
openvpn_fd_set(sd, &writes);
- tv.tv_sec = 0;
+ tv.tv_sec = (connect_timeout > 0) ? 1 : 0;
tv.tv_usec = 0;
status = select(sd + 1, NULL, &writes, NULL, &tv);
@@ -1490,7 +1517,7 @@ openvpn_connect(socket_descriptor_t sd,
#endif
break;
}
- management_sleep(1);
+ management_sleep(0);
continue;
}
@@ -1607,6 +1634,22 @@ done:
gc_free(&gc);
}
+/*
+ * Stream buffer handling prototypes -- stream_buf is a helper class
+ * to assist in the packetization of stream transport protocols
+ * such as TCP.
+ */
+
+static void
+stream_buf_init(struct stream_buf *sb, struct buffer *buf,
+ const unsigned int sockflags, const int proto);
+
+static void
+stream_buf_close(struct stream_buf *sb);
+
+static bool
+stream_buf_added(struct stream_buf *sb, int length_added);
+
/* For stream protocols, allocate a buffer to build up packet.
* Called after frame has been finalized. */
@@ -1769,7 +1812,8 @@ resolve_remote(struct link_socket *sock,
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",
+ dmsg(D_SOCKET_DEBUG,
+ "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
flags,
phase,
retry,
@@ -1859,6 +1903,7 @@ link_socket_init_phase1(struct link_socket *sock,
int rcvbuf,
int sndbuf,
int mark,
+ const char *bind_dev,
struct event_timeout *server_poll_timeout,
unsigned int sockflags)
{
@@ -1885,6 +1930,7 @@ link_socket_init_phase1(struct link_socket *sock,
sock->sockflags = sockflags;
sock->mark = mark;
+ sock->bind_dev = bind_dev;
sock->info.proto = proto;
sock->info.af = af;
@@ -1995,8 +2041,14 @@ phase2_inetd(struct link_socket *sock, const struct frame *frame,
}
else
{
- msg(M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
+ int saved_errno = errno;
+ msg(M_WARN|M_ERRNO, "inetd(%s): getsockname(%d) failed, using AF_INET",
proto2ascii(sock->info.proto, sock->info.af, false), (int)sock->sd);
+ /* if not called with a socket on stdin, --inetd cannot work */
+ if (saved_errno == ENOTSOCK)
+ {
+ msg(M_FATAL, "ERROR: socket required for --inetd operation");
+ }
}
}
#else /* ifdef HAVE_GETSOCKNAME */
@@ -2012,7 +2064,6 @@ phase2_inetd(struct link_socket *sock, const struct frame *frame,
false,
sock->inetd == INETD_NOWAIT,
signal_received);
-
}
ASSERT(!remote_changed);
}
@@ -2415,8 +2466,7 @@ ipchange_fmt(const bool include_cmd, struct argv *argv, const struct link_socket
}
void
-link_socket_connection_initiated(const struct buffer *buf,
- struct link_socket_info *info,
+link_socket_connection_initiated(struct link_socket_info *info,
const struct link_socket_actual *act,
const char *common_name,
struct env_set *es)
@@ -2450,7 +2500,7 @@ link_socket_connection_initiated(const struct buffer *buf,
{
msg(M_WARN, "WARNING: ipchange plugin call failed");
}
- argv_reset(&argv);
+ argv_free(&argv);
}
/* Process --ipchange option */
@@ -2460,7 +2510,7 @@ link_socket_connection_initiated(const struct buffer *buf,
setenv_str(es, "script_type", "ipchange");
ipchange_fmt(true, &argv, info, &gc);
openvpn_run_script(&argv, es, 0, "--ipchange");
- argv_reset(&argv);
+ argv_free(&argv);
}
gc_free(&gc);
@@ -2514,7 +2564,7 @@ link_socket_current_remote(const struct link_socket_info *info)
* by now just ignore it
*
* For --remote entries with multiple addresses this
- * only return the actual endpoint we have sucessfully connected to
+ * only return the actual endpoint we have successfully connected to
*/
if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
{
@@ -2545,7 +2595,7 @@ link_socket_current_remote_ipv6(const struct link_socket_info *info)
* 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
+ * only return the actual endpoint we have successfully connected to
*/
if (lsa->actual.dest.addr.sa.sa_family != AF_INET6)
{
@@ -2616,7 +2666,7 @@ stream_buf_reset(struct stream_buf *sb)
sb->len = -1;
}
-void
+static void
stream_buf_init(struct stream_buf *sb,
struct buffer *buf,
const unsigned int sockflags,
@@ -2690,7 +2740,7 @@ stream_buf_read_setup_dowork(struct link_socket *sock)
return !sock->stream_buf.residual_fully_formed;
}
-bool
+static bool
stream_buf_added(struct stream_buf *sb,
int length_added)
{
@@ -2757,7 +2807,7 @@ stream_buf_added(struct stream_buf *sb,
}
}
-void
+static void
stream_buf_close(struct stream_buf *sb)
{
free_buf(&sb->residual);
@@ -3116,22 +3166,22 @@ struct proto_names {
/* Indexed by PROTO_x */
static const struct proto_names proto_names[] = {
- {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE},
+ {"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},
+ {"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},
+ {"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},
+ {"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
@@ -3143,6 +3193,7 @@ proto_is_net(int proto)
}
return proto != PROTO_NONE;
}
+
bool
proto_is_dgram(int proto)
{
@@ -3258,7 +3309,7 @@ addr_family_name(int af)
*
* IPv6 and IPv4 protocols are comptabile but OpenVPN
* has always sent UDPv4, TCPv4 over the wire. Keep these
- * strings for backward compatbility
+ * strings for backward compatibility
*/
const char *
proto_remote(int proto, bool remote)
@@ -3343,7 +3394,7 @@ link_socket_read_tcp(struct link_socket *sock,
#if ENABLE_IP_PKTINFO
-/* make the buffer large enough to handle ancilliary socket data for
+/* make the buffer large enough to handle ancillary socket data for
* both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292)
*/
#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
@@ -3858,7 +3909,7 @@ socket_finalize(SOCKET s,
if (ret >= 0 && io->addr_defined)
{
/* TODO(jjo): streamline this mess */
- /* in this func we dont have relevant info about the PF_ of this
+ /* in this func we don't have relevant info about the PF_ of this
* endpoint, as link_socket_actual will be zero for the 1st received packet
*
* Test for inets PF_ possible sizes