summaryrefslogtreecommitdiffstats
path: root/src/openvpn/mudp.c
diff options
context:
space:
mode:
authorLev Stipakov <lstipakov@gmail.com>2014-11-23 17:17:11 +0200
committerGert Doering <gert@greenie.muc.de>2014-11-27 15:10:05 +0100
commit65eedc353349d2967fc03c54da807727e416e1b0 (patch)
treeccbea0a0472f3172c1ceae593449c8707f700a5b /src/openvpn/mudp.c
parent3341a98c2852d1d0c1eafdc70a3bdb218ec29049 (diff)
downloadopenvpn-65eedc353349d2967fc03c54da807727e416e1b0.tar.gz
openvpn-65eedc353349d2967fc03c54da807727e416e1b0.tar.xz
openvpn-65eedc353349d2967fc03c54da807727e416e1b0.zip
Peer-id patch v7
Added new packet format P_DATA_V2, which includes peer-id. If server supports, client sends all data packets in the new format. When data packet arrives, server identifies peer by peer-id. If peer's ip/port has changed, server assumes that client has floated, verifies HMAC and updates ip/port in internal structs. Changes in v7: A few nitpicks. Changes in v6: Fixed: Make sure float won't happen if hmac check failed (regression). Fixed: Access outside of bounds of array, which has caused memory corruption and crash. Various review fixes. Changes in v5: Protection agains replay attack by commiting float changes only after existing packet processing flow has completed. If peer floats to an address which is already taken by another active session, drop float packet, otherwise disconnect existing session. Changes in v4: Handles correctly float to an address which is used by another peer. This also has fixed crash on assert in multi_client_disconnect. Changes in v3: Bugfix: If float happens after TLS renegotiation and there are no data packets between reneg and float, server will not recognize floated client. Acked-by: Steffan Karger <steffan.karger@fox-it.com> Acked-by: Gert Doering <gert@greenie.muc.de> Message-Id: <1416755831-21250-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9270 Signed-off-by: Gert Doering <gert@greenie.muc.de>
Diffstat (limited to 'src/openvpn/mudp.c')
-rw-r--r--src/openvpn/mudp.c57
1 files changed, 43 insertions, 14 deletions
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 3468dab..853c08c 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -33,6 +33,7 @@
#if P2MP_SERVER
#include "multi.h"
+#include <inttypes.h>
#include "forward-inline.h"
#include "memdbg.h"
@@ -44,7 +45,7 @@
*/
struct multi_instance *
-multi_get_create_instance_udp (struct multi_context *m)
+multi_get_create_instance_udp (struct multi_context *m, bool *floated)
{
struct gc_arena gc = gc_new ();
struct mroute_addr real;
@@ -56,15 +57,40 @@ multi_get_create_instance_udp (struct multi_context *m)
struct hash_element *he;
const uint32_t hv = hash_value (hash, &real);
struct hash_bucket *bucket = hash_bucket (hash, hv);
-
- he = hash_lookup_fast (hash, bucket, &real, hv);
+ uint8_t* ptr = BPTR(&m->top.c2.buf);
+ uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
+ uint32_t peer_id;
+ int i;
- if (he)
+ /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */
+ if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
{
- mi = (struct multi_instance *) he->value;
+ peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF;
+ if ((peer_id < m->max_clients) && (m->instances[peer_id]))
+ {
+ mi = m->instances[peer_id];
+
+ *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from);
+
+ if (*floated)
+ {
+ /* reset prefix, since here we are not sure peer is the one it claims to be */
+ ungenerate_prefix(mi);
+ msg (D_MULTI_ERRORS, "Untrusted peer %" PRIu32 " wants to float to %s", peer_id,
+ mroute_addr_print (&real, &gc));
+ }
+ }
}
else
{
+ he = hash_lookup_fast (hash, bucket, &real, hv);
+ if (he)
+ {
+ mi = (struct multi_instance *) he->value;
+ }
+ }
+ if (!mi)
+ {
if (!m->top.c2.tls_auth_standalone
|| tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf))
{
@@ -75,6 +101,16 @@ multi_get_create_instance_udp (struct multi_context *m)
{
hash_add_fast (hash, bucket, &mi->real, hv, mi);
mi->did_real_hash = true;
+
+ for (i = 0; i < m->max_clients; ++i)
+ {
+ if (!m->instances[i])
+ {
+ mi->context.c2.tls_multi->peer_id = i;
+ m->instances[i] = mi;
+ break;
+ }
+ }
}
}
else
@@ -89,15 +125,8 @@ multi_get_create_instance_udp (struct multi_context *m)
#ifdef ENABLE_DEBUG
if (check_debug_level (D_MULTI_DEBUG))
{
- const char *status;
-
- if (he && mi)
- status = "[succeeded]";
- else if (!he && mi)
- status = "[created]";
- else
- status = "[failed]";
-
+ const char *status = mi ? "[ok]" : "[failed]";
+
dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s",
mroute_addr_print (&real, &gc),
status);