diff options
Diffstat (limited to 'src/openvpn/mudp.c')
-rw-r--r-- | src/openvpn/mudp.c | 104 |
1 files changed, 85 insertions, 19 deletions
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 3468dab..fec5e8d 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -33,10 +33,15 @@ #if P2MP_SERVER #include "multi.h" +#include <inttypes.h> #include "forward-inline.h" #include "memdbg.h" +#ifdef HAVE_SYS_INOTIFY_H +#include <sys/inotify.h> +#endif + /* * Get a client instance based on real address. If * the instance doesn't exist, create it while @@ -44,26 +49,54 @@ */ 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; struct multi_instance *mi = NULL; struct hash *hash = m->hash; - if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) + if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) && + m->top.c2.buf.len > 0) { 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; + bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3)); + bool peer_id_disabled = false; - if (he) + /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ + if (v2) { - mi = (struct multi_instance *) he->value; + uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; + peer_id_disabled = (peer_id == MAX_PEER_ID); + + if (!peer_id_disabled && (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_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id, + mroute_addr_print (&real, &gc)); + } + } } - else + if (!v2 || peer_id_disabled) + { + 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)) @@ -73,8 +106,27 @@ multi_get_create_instance_udp (struct multi_context *m) mi = multi_create_instance (m, &real); if (mi) { + int i; + hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; + + /* max_clients must be less then max peer-id value */ + ASSERT(m->max_clients < MAX_PEER_ID); + + 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; + } + } + + /* should not really end up here, since multi_create_instance returns null + * if amount of clients exceeds max_clients */ + ASSERT(i < m->max_clients); } } else @@ -89,15 +141,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); @@ -143,6 +188,10 @@ multi_process_io_udp (struct multi_context *m) strcat (buf, "TR/"); else if (status & TUN_WRITE) strcat (buf, "TW/"); +#ifdef ENABLE_ASYNC_PUSH + else if (status & FILE_CLOSED) + strcat (buf, "FC/"); +#endif printf ("IO %s\n", buf); #endif @@ -168,7 +217,6 @@ multi_process_io_udp (struct multi_context *m) else if (status & SOCKET_READ) { read_incoming_link (&m->top); - multi_release_io_lock (m); if (!IS_SIG (&m->top)) multi_process_incoming_link (m, NULL, mpp_flags); } @@ -176,10 +224,16 @@ multi_process_io_udp (struct multi_context *m) else if (status & TUN_READ) { read_incoming_tun (&m->top); - multi_release_io_lock (m); if (!IS_SIG (&m->top)) multi_process_incoming_tun (m, mpp_flags); } +#ifdef ENABLE_ASYNC_PUSH + /* INOTIFY callback */ + else if (status & FILE_CLOSED) + { + multi_process_file_closed(m, mpp_flags); + } +#endif } /* @@ -234,7 +288,7 @@ tunnel_server_udp_single_threaded (struct context *top) multi_init (&multi, top, false, MC_SINGLE_THREADED); /* initialize our cloned top object */ - multi_top_init (&multi, top, true); + multi_top_init (&multi, top); /* initialize management interface */ init_management_callback_multi (&multi); @@ -242,6 +296,14 @@ tunnel_server_udp_single_threaded (struct context *top) /* finished with initialization */ initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto udp */ +#ifdef ENABLE_ASYNC_PUSH + multi.top.c2.inotify_fd = inotify_init(); + if (multi.top.c2.inotify_fd < 0) + { + msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + } +#endif + /* per-packet event loop */ while (true) { @@ -270,6 +332,10 @@ tunnel_server_udp_single_threaded (struct context *top) perf_pop (); } +#ifdef ENABLE_ASYNC_PUSH + close(top->c2.inotify_fd); +#endif + /* shut down management interface */ uninit_management_callback_multi (&multi); |