Hi,
To allow seamless roaming of our robots at willowgarage
(http://willowgarage.com), I have put together a patch that allows TLS
connections to float. I would like to put this patch up for critique
and possible inclusion into mainline openvpn. The general approach has
been to prefix a few bytes at the start of each packet which contain
an opcode and a unique identifier (random number) for the session.
That identifier is used instead of the IP address for determining
which connection the packet belongs to.
Regards,
Blaise
--- a/configure.ac
+++ b/configure.ac
@@ -129,6 +129,12 @@
[FRAGMENT="yes"]
)
+AC_ARG_ENABLE(floating-tls,
+ [ --disable-floating-tls Disable floating tls support (--floating-tls)],
+ [FLOATING_TLS="$enableval"],
+ [FLOATING_TLS="yes"]
+)
+
AC_ARG_ENABLE(multihome,
[ --disable-multihome Disable multi-homed UDP server support
(--multihome)],
[MULTIHOME="$enableval"],
@@ -791,6 +797,11 @@
AC_DEFINE(ENABLE_HTTP_PROXY, 1, [Enable HTTP proxy support])
fi
+dnl compile --floating-tls option
+if test "$FLOATING_TLS" = "yes"; then
+ AC_DEFINE(FLOATING_TLS, 1, [Enable floating-tls UDP server capability])
+fi
+
dnl compile --multihome option
if test "$MULTIHOME" = "yes"; then
AC_DEFINE(ENABLE_MULTIHOME, 1, [Enable multi-homed UDP server capability])
--- a/forward.c
+++ b/forward.c
@@ -39,6 +39,10 @@
#include "occ-inline.h"
#include "ping-inline.h"
+#ifdef FLOATING_TLS
+#include "ssl.h"
+#endif
+
/* show event wait debugging info */
#ifdef ENABLE_DEBUG
@@ -834,7 +838,11 @@
*
* Also, update the persisted version of our packet-id.
*/
- if (!TLS_MODE (c))
+ if (!TLS_MODE (c)
+#ifdef FLOATING_TLS
+ || c->options.floating_tls
+#endif
+ )
link_socket_set_outgoing_addr (&c->c2.buf, lsi, &c->c2.from,
NULL, c->c2.es);
/* reset packet received timer */
@@ -1088,6 +1096,21 @@
/* If Socks5 over UDP, prepend header */
socks_preprocess_outgoing_link (c, &to_addr, &size_delta);
#endif
+
+#ifdef FLOATING_TLS
+ if (c->c2.link_socket->info.proto == PROTO_UDPv4 &&
+ c->options.floating_tls &&
+ c->options.tls_client)
+ {
+ if (c->floating_tls_prefix == 0)
+ RAND_bytes((uint8_t *) &c->floating_tls_prefix,
sizeof(c->floating_tls_prefix));
+
+ struct buffer *buf = &c->c2.to_link;
+ uint8_t opcode = FLOATING_TLS_OPCODE |
sizeof(c->floating_tls_prefix);
+ ASSERT (buf_write_prepend (buf,
&c->floating_tls_prefix, sizeof (c->floating_tls_prefix)));
+ ASSERT (buf_write_prepend (buf, &opcode, sizeof (opcode)));
+ }
+#endif
/* Send packet */
size = link_socket_write (c->c2.link_socket,
&c->c2.to_link,
--- a/init.c
+++ b/init.c
@@ -1826,6 +1826,10 @@
to.disable_occ = !options->occ;
#endif
+#ifdef FLOATING_TLS
+ to.floating_tls = options->floating_tls;
+#endif
+
to.verify_command = options->tls_verify;
to.verify_x509name = options->tls_remote;
to.crl_file = options->crl_file;
--- a/mudp.c
+++ b/mudp.c
@@ -31,6 +31,10 @@
#include "memdbg.h"
+#ifdef FLOATING_TLS
+#include "ssl.h"
+#endif
+
/*
* Get a client instance based on real address. If
* the instance doesn't exist, create it while
@@ -44,8 +48,36 @@
struct mroute_addr real;
struct multi_instance *mi = NULL;
struct hash *hash = m->hash;
+ bool ret = false;
+
+#ifdef FLOATING_TLS
+ // Check if this is a floating-tls packet
+ if (m->top.c2.buf.len > 0)
+ {
+ uint8_t c = *BPTR (&m->top.c2.buf);
+ if ((c & FLOATING_TLS_OPCODE_MASK) == FLOATING_TLS_OPCODE)
+ {
+ int len = c & FLOATING_TLS_LENGTH_MASK;
+ uint8_t *id = BPTR (&m->top.c2.buf) + 1;
+
+ if (buf_advance(&m->top.c2.buf, len + 1))
+ {
+ int i;
+ real.type = MR_ADDR_IPV4 | MR_WITH_PORT;
+ real.netbits = 0;
+ real.len = len;
+ memcpy (real.addr, id, real.len);
+ ret = true;
+ }
+ }
+ }
+#endif
+
+ // Not a floating-tls packet
+ if (!ret)
+ ret = mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true);
- if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true))
+ if (ret)
{
struct hash_element *he;
const uint32_t hv = hash_value (hash, &real);
--- a/openvpn.h
+++ b/openvpn.h
@@ -484,6 +484,10 @@
/* persistent across SIGHUP */
struct context_persist persist;
+#ifdef FLOATING_TLS
+ uint64_t floating_tls_prefix;
+#endif
+
/* level 0 context contains data related to
once-per OpenVPN instantiation events
such as daemonization */
--- a/options.c
+++ b/options.c
@@ -126,6 +126,7 @@
" Set n=\"infinite\" to retry indefinitely.\n"
"--float : Allow remote to change its IP address/port, such
as through\n"
" DHCP (this is the default if --remote is not used).\n"
+ "--floating-tls : Allows floating in multi-tls sessions.\n"
"--ipchange cmd : Execute shell command cmd on remote ip address initial\n"
" setting or change -- execute as: cmd ip-address port#\n"
"--port port : TCP/UDP port # for both local and remote.\n"
@@ -1334,6 +1335,10 @@
SHOW_BOOL (tls_exit);
SHOW_STR (tls_auth_file);
+
+#ifdef FLOATING_TLS
+ SHOW_BOOL (floating_tls);
+#endif
#endif
#endif
@@ -1909,6 +1914,9 @@
MUST_BE_UNDEF (transition_window);
MUST_BE_UNDEF (tls_auth_file);
MUST_BE_UNDEF (single_session);
+#ifdef FLOATING_TLS
+ MUST_BE_UNDEF (floating_tls);
+#endif
MUST_BE_UNDEF (tls_exit);
MUST_BE_UNDEF (crl_file);
MUST_BE_UNDEF (key_method);
@@ -2339,6 +2347,11 @@
buf_printf (&out, ",no-iv");
}
+#ifdef FLOATING_TLS
+ if (o->floating_tls)
+ buf_printf (&out, ",floating-tls");
+#endif
+
#ifdef USE_SSL
/*
* SSL Options
@@ -5413,6 +5426,13 @@
VERIFY_PERMISSION (OPT_P_GENERAL);
options->single_session = true;
}
+#ifdef FLOATING_TLS
+ else if (streq (p[0], "floating-tls"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->floating_tls = true;
+ }
+#endif
else if (streq (p[0], "tls-exit"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
--- a/options.h
+++ b/options.h
@@ -168,6 +168,10 @@
bool genkey;
#endif
+#ifdef FLOATING_TLS
+ bool floating_tls;
+#endif
+
/* Networking parms */
struct connection_entry ce;
--- a/ssl.c
+++ b/ssl.c
@@ -4160,7 +4160,12 @@
#ifdef ENABLE_DEF_AUTH
&& !ks->auth_deferred
#endif
- && link_socket_actual_match (from, &ks->remote_addr))
+ && (
+#ifdef FLOATING_TLS
+ multi->opt.floating_tls ||
+#endif
+ link_socket_actual_match (from, &ks->remote_addr)
+ ))
{
/* return appropriate data channel decrypt key in opt */
opt->key_ctx_bi = &ks->key;
@@ -4403,7 +4408,11 @@
/*
* Verify remote IP address
*/
- if (!new_link && !link_socket_actual_match
(&ks->remote_addr, from))
+ if (!new_link
+#ifdef FLOATING_TLS
+ && !multi->opt.floating_tls
+#endif
+ && !link_socket_actual_match (&ks->remote_addr, from))
{
msg (D_TLS_ERRORS, "TLS Error: Received control packet from
unexpected IP addr: %s",
print_link_socket_actual (from, &gc));
@@ -4468,7 +4477,11 @@
ks->remote_addr = *from;
++multi->n_sessions;
}
- else if (!link_socket_actual_match (&ks->remote_addr, from))
+ else if (
+#ifdef FLOATING_TLS
+ !multi->opt.floating_tls &&
+#endif
+ !link_socket_actual_match (&ks->remote_addr, from))
{
msg (D_TLS_ERRORS,
"TLS Error: Existing session control channel packet from
unknown IP address: %s",
--- a/ssl.h
+++ b/ssl.h
@@ -221,6 +221,13 @@
#define P_FIRST_OPCODE 1
#define P_LAST_OPCODE 8
+/* Extra opcodes for floating TLS */
+#ifdef FLOATING_TLS
+#define FLOATING_TLS_OPCODE_MASK 0xF0
+#define FLOATING_TLS_OPCODE 0xF0
+#define FLOATING_TLS_LENGTH_MASK 0x0F
+#endif
+
/* key negotiation states */
#define S_ERROR -1
#define S_UNDEF 0
@@ -416,6 +423,10 @@
int key_method;
bool replay;
bool single_session;
+#ifdef FLOATING_TLS
+ bool floating_tls;
+#endif
+
#ifdef ENABLE_OCC
bool disable_occ;
#endif
--- a/openvpn.8
+++ b/openvpn.8
@@ -573,6 +573,10 @@
option.
.\"*********************************************************
.TP
+.B \-\-floating-tls
+Allows tls connections to float.
+.\"*********************************************************
+.TP
.B \-\-ipchange cmd
Execute shell command
.B cmd