Commit 23d61c56 authored by Arne Schwabe's avatar Arne Schwabe Committed by Gert Doering

Implement dual stack client support for OpenVPN

This patch contains a number of changes. I did not further spit this since some changes make only sense being changed together.

Always use connection_list, simplifies the reconnection logic.

Change meaning of --connect-retry-max and --connect-retry to be used
all connections. This now allows OpenVPN to quit after n unsuccessful
udp connection attempts

Remove the tcp reconnection logic. Failing a TCP connection will now
cause a USR1 like a UDP connection. Also extend sig->source from bool to
int to specify signal source. This allows a finer grained reconnection
logic if necessary in the future.

Dual-Stack support: if an address resolves to multiple records each
address is tried in sequential order. Then proceed to next connection
entry. Introduce the field current_remote to represent the current
connecting remote. Also change some fields to struct addrinfo* form
openvn_addr to store multiple addresses needed for the dual stack support.

Change meaning from udp and tcp to allow both IPv4 and IPv6. Introducue
new udp4 and tcp4 to force IPv4.
Signed-off-by: Arne Schwabe's avatarArne Schwabe <[email protected]>
Acked-by: default avatarGert Doering <[email protected]>
Message-Id: <[email protected]>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8058Signed-off-by: default avatarGert Doering <[email protected]>
Message-ID: <[email protected]>
Acked-by: Arne Schwabe's avatarArne Schwabe <[email protected]>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8071Signed-off-by: default avatarGert Doering <[email protected]>
parent aa162d44
......@@ -221,6 +221,9 @@ options.
indicates the protocol to use when connecting with the
remote, and may be "tcp" or "udp".
For forcing IPv4 or IPv6 connection suffix tcp or udp
with 4/6 like udp4/udp6/tcp4/tcp6.
The client will move on to the next host in the list,
in the event of connection failure.
Note that at any given time, the OpenVPN client
......@@ -463,13 +466,9 @@ possess a built-in reliability layer.
.\"*********************************************************
.TP
.B \-\-connect-retry n
For
.B \-\-proto tcp-client,
take
Wait
.B n
as the
number of seconds to wait
between connection retries (default=5).
seconds between connection attempts (default=5).
.\"*********************************************************
.TP
.B \-\-connect-timeout n
......@@ -481,12 +480,15 @@ seconds (default=10).
.\"*********************************************************
.TP
.B \-\-connect-retry-max n
For
.B \-\-proto tcp-client,
take
.B n
as the
number of retries of connection attempt (default=infinite).
specifies the number of times all
.B \-\-remote
respectively
.B <connection>
statements are tried. Specifiying
.B n
as one would try each entry exactly once. A sucessful connection
resets the counter. (default=umlimited).
.\"*********************************************************
.TP
.B \-\-show-proxy-settings
......
......@@ -259,7 +259,7 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist)
if (flags & M_SSL)
{
int nerrs = 0;
int err;
size_t err;
while ((err = ERR_get_error ()))
{
openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s",
......
This diff is collapsed.
......@@ -1461,7 +1461,7 @@ man_new_connection_post (struct management *man, const char *description)
#endif
msg (D_MANAGEMENT, "MANAGEMENT: %s %s",
description,
print_sockaddr (&man->settings.local, &gc));
print_sockaddr (man->settings.local->ai_addr, &gc));
buffer_list_reset (man->connection.out);
......@@ -1569,7 +1569,8 @@ man_listen (struct management *man)
#endif
{
man->connection.sd_top = create_socket_tcp (AF_INET);
socket_bind (man->connection.sd_top, &man->settings.local, "MANAGEMENT");
socket_bind (man->connection.sd_top, man->settings.local,
AF_INET, "MANAGEMENT");
}
/*
......@@ -1593,7 +1594,7 @@ man_listen (struct management *man)
else
#endif
msg (D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s",
print_sockaddr (&man->settings.local, &gc));
print_sockaddr (man->settings.local->ai_addr, &gc));
}
#ifdef WIN32
......@@ -1636,7 +1637,7 @@ man_connect (struct management *man)
{
man->connection.sd_cli = create_socket_tcp (AF_INET);
status = openvpn_connect (man->connection.sd_cli,
&man->settings.local,
man->settings.local->ai_addr,
5,
&signal_received);
}
......@@ -1661,7 +1662,7 @@ man_connect (struct management *man)
#endif
msg (D_LINK_ERRORS,
"MANAGEMENT: connect to %s failed: %s",
print_sockaddr (&man->settings.local, &gc),
print_sockaddr (man->settings.local->ai_addr, &gc),
strerror_ts (status, &gc));
throw_signal_soft (SIGTERM, "management-connect-failed");
goto done;
......@@ -2122,13 +2123,9 @@ man_settings_init (struct man_settings *ms,
}
else
{
struct addrinfo* ai;
int status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL,
addr, port, 0, NULL, AF_INET, &ai);
addr, port, 0, NULL, AF_INET, &ms->local);
ASSERT(status==0);
ms->local.addr.in4 = *((struct sockaddr_in*)ai->ai_addr);
freeaddrinfo(ai);
}
}
......@@ -2587,7 +2584,13 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i
&& man->connection.state == MS_INITIAL)
{
/* listen on our local TUN/TAP IP address */
man->settings.local.addr.in4.sin_addr.s_addr = htonl (tun_local_ip);
struct in_addr ia;
int ret;
ia.s_addr = htonl(tun_local_ip);
ret = openvpn_getaddrinfo(0, inet_ntoa(ia), NULL, 0, NULL,
AF_INET, &man->settings.local);
ASSERT (ret==0);
man_connection_init (man);
}
......
......@@ -212,7 +212,7 @@ struct man_persist {
struct man_settings {
bool defined;
unsigned int flags; /* MF_x flags */
struct openvpn_sockaddr local;
struct addrinfo* local;
#if UNIX_SOCK_SUPPORT
struct sockaddr_un local_unix;
#endif
......
......@@ -778,10 +778,10 @@ init_options (struct options *o, const bool init_gc)
o->mode = MODE_POINT_TO_POINT;
o->topology = TOP_NET30;
o->ce.proto = PROTO_UDP;
o->ce.af = AF_INET;
o->ce.af = AF_UNSPEC;
o->ce.connect_retry_seconds = 5;
o->ce.connect_timeout = 10;
o->ce.connect_retry_max = 0;
o->connect_retry_max = 0;
o->ce.local_port = o->ce.remote_port = OPENVPN_PORT;
o->verbosity = 1;
o->status_file_update_freq = 60;
......@@ -1369,7 +1369,6 @@ show_connection_entry (const struct connection_entry *o)
SHOW_BOOL (bind_local);
SHOW_INT (connect_retry_seconds);
SHOW_INT (connect_timeout);
SHOW_INT (connect_retry_max);
#ifdef ENABLE_HTTP_PROXY
if (o->http_proxy_options)
......@@ -1446,6 +1445,7 @@ show_settings (const struct options *o)
#endif
#endif
SHOW_INT (connect_retry_max);
show_connection_entries (o);
SHOW_BOOL (remote_random);
......@@ -1727,32 +1727,31 @@ void
options_postprocess_http_proxy_override (struct options *o)
{
const struct connection_list *l = o->connection_list;
if (l)
int i;
bool succeed = false;
for (i = 0; i < l->len; ++i)
{
struct connection_entry *ce = l->array[i];
if (ce->proto == PROTO_TCP_CLIENT || ce->proto == PROTO_TCP)
{
ce->http_proxy_options = o->http_proxy_override;
succeed = true;
}
}
if (succeed)
{
int i;
bool succeed = false;
for (i = 0; i < l->len; ++i)
{
struct connection_entry *ce = l->array[i];
if (ce->proto == PROTO_TCP_CLIENT || ce->proto == PROTO_TCP)
{
ce->http_proxy_options = o->http_proxy_override;
succeed = true;
}
}
if (succeed)
{
for (i = 0; i < l->len; ++i)
{
struct connection_entry *ce = l->array[i];
if (ce->proto == PROTO_UDP)
{
ce->flags |= CE_DISABLED;
}
}
}
else
msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined");
{
struct connection_entry *ce = l->array[i];
if (ce->proto == PROTO_UDP)
{
ce->flags |= CE_DISABLED;
}
}
}
else
{
msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined");
}
}
......@@ -1882,11 +1881,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
/*
* Sanity check on TCP mode options
*/
if (ce->connect_retry_defined && ce->proto != PROTO_TCP_CLIENT)
msg (M_USAGE, "--connect-retry doesn't make sense unless also used with "
"--proto tcp-client or tcp6-client");
if (ce->connect_timeout_defined && ce->proto != PROTO_TCP_CLIENT)
msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with "
"--proto tcp-client or tcp6-client");
......@@ -2004,7 +1998,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");
#endif
if (ce->proto == PROTO_TCP_SERVER && connection_list_defined (options))
if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1))
msg (M_USAGE, "TCP server mode allows at most one --remote address");
#if P2MP_SERVER
......@@ -2041,8 +2035,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if (ce->socks_proxy_server)
msg (M_USAGE, "--socks-proxy cannot be used with --mode server");
#endif
if (options->connection_list)
msg (M_USAGE, "<connection> cannot be used with --mode server");
/* <connection> blocks force to have a remote embedded, so we check for the
* --remote and bail out if it is present */
if (options->connection_list->len >1 ||
options->connection_list->array[0]->remote)
msg (M_USAGE, "<connection> cannot be used with --mode server");
#if 0
if (options->tun_ipv6)
msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
......@@ -2485,6 +2483,7 @@ options_postprocess_verify (const struct options *o)
static void
options_postprocess_mutate (struct options *o)
{
int i;
/*
* Process helper-type options which map to other, more complex
* sequences of options.
......@@ -2498,48 +2497,38 @@ options_postprocess_mutate (struct options *o)
if (o->remote_list && !o->connection_list)
{
/*
* For compatibility with 2.0.x, map multiple --remote options
* into connection list (connection lists added in 2.1).
* Convert remotes into connection list
*/
if (o->remote_list->len > 1 || o->force_connection_list)
{
const struct remote_list *rl = o->remote_list;
int i;
for (i = 0; i < rl->len; ++i)
{
const struct remote_entry *re = rl->array[i];
struct connection_entry ce = o->ce;
struct connection_entry *ace;
ASSERT (re->remote);
connection_entry_load_re (&ce, re);
ace = alloc_connection_entry (o, M_USAGE);
ASSERT (ace);
*ace = ce;
}
}
else if (o->remote_list->len == 1) /* one --remote option specified */
{
connection_entry_load_re (&o->ce, o->remote_list->array[0]);
}
else
{
ASSERT (0);
}
const struct remote_list *rl = o->remote_list;
for (i = 0; i < rl->len; ++i)
{
const struct remote_entry *re = rl->array[i];
struct connection_entry ce = o->ce;
struct connection_entry *ace;
ASSERT (re->remote);
connection_entry_load_re (&ce, re);
ace = alloc_connection_entry (o, M_USAGE);
ASSERT (ace);
*ace = ce;
}
}
if (o->connection_list)
else if(!o->remote_list && !o->connection_list)
{
int i;
for (i = 0; i < o->connection_list->len; ++i)
struct connection_entry *ace;
ace = alloc_connection_entry (o, M_USAGE);
ASSERT (ace);
*ace = o->ce;
}
ASSERT (o->connection_list);
for (i = 0; i < o->connection_list->len; ++i)
options_postprocess_mutate_ce (o, o->connection_list->array[i]);
#if HTTP_PROXY_OVERRIDE
if (o->http_proxy_override)
if (o->http_proxy_override)
options_postprocess_http_proxy_override(o);
#endif
}
else
options_postprocess_mutate_ce (o, &o->ce);
#if P2MP
/*
......@@ -4169,7 +4158,6 @@ add_option (struct options *options,
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_QUERY_PROXY;
options->force_connection_list = true;
}
else if (streq (p[0], "management-hold"))
{
......@@ -4442,7 +4430,6 @@ add_option (struct options *options,
options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc);
if (!options->http_proxy_override)
goto err;
options->force_connection_list = true;
}
#endif
else if (streq (p[0], "remote") && p[1])
......@@ -4494,7 +4481,6 @@ add_option (struct options *options,
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.connect_retry_seconds = positive_atoi (p[1]);
options->ce.connect_retry_defined = true;
}
else if (streq (p[0], "connect-timeout") && p[1])
{
......@@ -4505,7 +4491,7 @@ add_option (struct options *options,
else if (streq (p[0], "connect-retry-max") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.connect_retry_max = positive_atoi (p[1]);
options->connect_retry_max = positive_atoi (p[1]);
}
else if (streq (p[0], "ipchange") && p[1])
{
......@@ -4930,7 +4916,6 @@ add_option (struct options *options,
goto err;
}
options->proto_force = proto_force;
options->force_connection_list = true;
}
#ifdef ENABLE_HTTP_PROXY
else if (streq (p[0], "http-proxy") && p[1])
......
......@@ -97,8 +97,6 @@ struct connection_entry
bool bind_defined;
bool bind_local;
int connect_retry_seconds;
bool connect_retry_defined;
int connect_retry_max;
int connect_timeout;
bool connect_timeout_defined;
#ifdef ENABLE_HTTP_PROXY
......@@ -155,8 +153,6 @@ struct connection_list
{
int len;
int current;
int n_cycles;
bool no_advance;
struct connection_entry *array[CONNECTION_LIST_SIZE];
};
......@@ -209,10 +205,15 @@ struct options
#endif
/* Networking parms */
int connect_retry_max;
struct connection_entry ce;
struct connection_list *connection_list;
struct remote_list *remote_list;
bool force_connection_list;
/* Do not advanced the connection or remote addr list*/
bool no_advance;
/* Counts the number of unsuccessful connection attempts */
unsigned int unsuccessful_attempts;
#if HTTP_PROXY_OVERRIDE
struct http_proxy_options *http_proxy_override;
......@@ -775,20 +776,5 @@ bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
unsigned int * netbits, char ** printable_ipv6,
int msglevel );
/*
* inline functions
*/
static inline bool
connection_list_defined (const struct options *o)
{
return o->connection_list != NULL;
}
static inline void
connection_list_set_no_advance (struct options *o)
{
if (o->connection_list)
o->connection_list->no_advance = true;
}
#endif
......@@ -330,8 +330,8 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_
if (!getpeername (pc->sd, (struct sockaddr *) &from.addr.sa, &slen)
&& !getsockname (cp->sd, (struct sockaddr *) &to.addr.sa, &dlen))
{
const char *f = print_sockaddr (&from, &gc);
const char *t = print_sockaddr (&to, &gc);
const char *f = print_openvpn_sockaddr (&from, &gc);
const char *t = print_openvpn_sockaddr (&to, &gc);
fnlen = strlen(journal_dir) + strlen(t) + 2;
jfn = (char *) malloc(fnlen);
check_malloc_return (jfn);
......@@ -408,20 +408,18 @@ proxy_entry_new (struct proxy_connection **list,
struct buffer *initial_data,
const char *journal_dir)
{
struct openvpn_sockaddr osaddr;
socket_descriptor_t sd_server;
int status;
struct proxy_connection *pc;
struct proxy_connection *cp;
/* connect to port share server */
osaddr.addr.in4 = server_addr;
if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
msg (M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket");
return false;
}
status = openvpn_connect (sd_server, &osaddr, 5, NULL);
status = openvpn_connect (sd_server,(const struct sockaddr*) &server_addr, 5, NULL);
if (status)
{
msg (M_WARN, "PORT SHARE PROXY: connect to port-share server failed");
......
......@@ -49,7 +49,8 @@ void
receive_auth_failed (struct context *c, const struct buffer *buffer)
{
msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer));
connection_list_set_no_advance(&c->options);
c->options.no_advance=true;
if (c->options.pull)
{
switch (auth_retry_get ())
......
......@@ -97,14 +97,14 @@ void
throw_signal (const int signum)
{
siginfo_static.signal_received = signum;
siginfo_static.hard = true;
siginfo_static.source = SIG_SOURCE_HARD;
}
void
throw_signal_soft (const int signum, const char *signal_text)
{
siginfo_static.signal_received = signum;
siginfo_static.hard = false;
siginfo_static.source = SIG_SOURCE_SOFT;
siginfo_static.signal_text = signal_text;
}
......@@ -115,7 +115,7 @@ signal_reset (struct signal_info *si)
{
si->signal_received = 0;
si->signal_text = NULL;
si->hard = false;
si->source = SIG_SOURCE_SOFT;
}
}
......@@ -124,9 +124,23 @@ print_signal (const struct signal_info *si, const char *title, int msglevel)
{
if (si)
{
const char *hs = (si->hard ? "hard" : "soft");
const char *type = (si->signal_text ? si->signal_text : "");
const char *t = (title ? title : "process");
const char *hs;
switch (si->source)
{
case SIG_SOURCE_SOFT:
hs= "soft";
break;
case SIG_SOURCE_HARD:
hs = "hard";
break;
case SIG_SOURCE_CONNECTION_FAILED:
hs = "connection failed(soft)";
break;
default:
ASSERT(0);
}
switch (si->signal_received)
{
......
......@@ -28,6 +28,15 @@
#include "status.h"
#include "win32.h"
#define SIG_SOURCE_SOFT 0
#define SIG_SOURCE_HARD 1
/* CONNECTION_FAILED is also a "soft" status,
* It is thrown if a connection attempt fails
*/
#define SIG_SOURCE_CONNECTION_FAILED 2
/*
* Signal information, including signal code
* and descriptive text.
......@@ -35,7 +44,7 @@
struct signal_info
{
volatile int signal_received;
volatile bool hard;
volatile int source;
const char *signal_text;
};
......
This diff is collapsed.
......@@ -81,6 +81,11 @@ struct openvpn_sockaddr
struct link_socket_actual
{
/*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
struct openvpn_sockaddr dest;
#if ENABLE_IP_PKTINFO
union {
......@@ -97,8 +102,10 @@ struct link_socket_actual
/* IP addresses which are persistant across SIGUSR1s */
struct link_socket_addr
{
struct openvpn_sockaddr local;
struct addrinfo* remote_list; /* initial remote */
struct addrinfo* bind_local;
struct addrinfo* remote_list; /* complete remote list */
struct addrinfo* current_remote; /* remote used in the
current connection attempt */
struct link_socket_actual actual; /* reply to this address */
};
......@@ -176,9 +183,6 @@ struct link_socket
/* used for long-term queueing of pre-accepted socket listen */
bool listen_persistent_queued;
/* Does config file contain any <connection> ... </connection> blocks? */
bool connection_profiles_defined;
const char *remote_host;
const char *remote_port;
const char *local_host;
......@@ -196,9 +200,7 @@ struct link_socket
int mode;
int resolve_retry_seconds;
int connect_retry_seconds;
int connect_timeout;
int connect_retry_max;
int mtu_discover_type;
struct socket_buffer_size socket_buffer_sizes;
......@@ -213,6 +215,7 @@ struct link_socket
# define SF_HOST_RANDOMIZE (1<<3)
# define SF_GETADDRINFO_DGRAM (1<<4)
unsigned int sockflags;
int mark;
/* for stream sockets */
struct stream_buf stream_buf;
......@@ -284,11 +287,12 @@ int socket_finalize (
struct link_socket *link_socket_new (void);
void socket_bind (socket_descriptor_t sd,
struct openvpn_sockaddr *local,
struct addrinfo *local,
int af_family,
const char *prefix);
int openvpn_connect (socket_descriptor_t sd,
struct openvpn_sockaddr *remote,
const struct sockaddr *remote,
int connect_timeout,
volatile int *signal_received);
......@@ -298,7 +302,6 @@ int openvpn_connect (socket_descriptor_t sd,
void
link_socket_init_phase1 (struct link_socket *sock,
const bool connection_profiles_defined,
const char *local_host,
const char *local_port,
const char *remote_host,
......@@ -323,9 +326,7 @@ 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,
......@@ -334,7 +335,7 @@ link_socket_init_phase1 (struct link_socket *sock,
void link_socket_init_phase2 (struct link_socket *sock,
const struct frame *frame,
volatile int *signal_received);
struct signal_info *sig_info);
void socket_adjust_frame_parameters (struct frame *frame, int proto);
......@@ -364,12 +365,21 @@ const char *print_openvpn_sockaddr_ex (const struct openvpn_sockaddr *addr,
}
static inline
const char *print_sockaddr (const struct openvpn_sockaddr *addr,
const char *print_openvpn_sockaddr (const struct openvpn_sockaddr *addr,
struct gc_arena *gc)
{
return print_sockaddr_ex (&addr->addr.sa, ":", PS_SHOW_PORT, gc);
}
static inline
const char *print_sockaddr (const struct sockaddr *addr,
struct gc_arena *gc)
{
return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc);
}
const char *print_link_socket_actual_ex (const struct link_socket_actual *act,
const char* separator,
const unsigned int flags,
......@@ -420,6 +430,9 @@ void link_socket_bad_incoming_addr (struct buffer *buf,
const struct link_socket_info *info,
const struct link_socket_actual *from_addr);
<