summaryrefslogtreecommitdiff
path: root/src/openvpn/mudp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/mudp.c')
-rw-r--r--src/openvpn/mudp.c448
1 files changed, 237 insertions, 211 deletions
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index fec5e8d..64ce4d7 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2002-2017 OpenVPN Technologies, 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
@@ -49,189 +49,205 @@
*/
struct multi_instance *
-multi_get_create_instance_udp (struct multi_context *m, bool *floated)
+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;
+ 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) &&
- m->top.c2.buf.len > 0)
+ 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);
- 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;
-
- /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */
- if (v2)
- {
- 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));
- }
- }
- }
- 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))
- {
- if (frequency_limit_event_allowed (m->new_connection_limiter))
- {
- 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
- {
- msg (D_MULTI_ERRORS,
- "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq",
- mroute_addr_print (&real, &gc));
- }
- }
- }
+ struct hash_element *he;
+ const uint32_t hv = hash_value(hash, &real);
+ struct hash_bucket *bucket = hash_bucket(hash, 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;
+
+ /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */
+ if (v2)
+ {
+ 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));
+ }
+ }
+ }
+ 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))
+ {
+ if (frequency_limit_event_allowed(m->new_connection_limiter))
+ {
+ 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
+ {
+ msg(D_MULTI_ERRORS,
+ "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq",
+ mroute_addr_print(&real, &gc));
+ }
+ }
+ }
#ifdef ENABLE_DEBUG
- if (check_debug_level (D_MULTI_DEBUG))
- {
- const char *status = mi ? "[ok]" : "[failed]";
-
- dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s",
- mroute_addr_print (&real, &gc),
- status);
- }
+ if (check_debug_level(D_MULTI_DEBUG))
+ {
+ const char *status = mi ? "[ok]" : "[failed]";
+
+ dmsg(D_MULTI_DEBUG, "GET INST BY REAL: %s %s",
+ mroute_addr_print(&real, &gc),
+ status);
+ }
#endif
}
- gc_free (&gc);
- ASSERT (!(mi && mi->halt));
- return mi;
+ gc_free(&gc);
+ ASSERT(!(mi && mi->halt));
+ return mi;
}
/*
* Send a packet to TCP/UDP socket.
*/
static inline void
-multi_process_outgoing_link (struct multi_context *m, const unsigned int mpp_flags)
+multi_process_outgoing_link(struct multi_context *m, const unsigned int mpp_flags)
{
- struct multi_instance *mi = multi_process_outgoing_link_pre (m);
- if (mi)
- multi_process_outgoing_link_dowork (m, mi, mpp_flags);
+ struct multi_instance *mi = multi_process_outgoing_link_pre(m);
+ if (mi)
+ {
+ multi_process_outgoing_link_dowork(m, mi, mpp_flags);
+ }
}
/*
* Process an I/O event.
*/
static void
-multi_process_io_udp (struct multi_context *m)
+multi_process_io_udp(struct multi_context *m)
{
- const unsigned int status = m->top.c2.event_set_status;
- const unsigned int mpp_flags = m->top.c2.fast_io
- ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL)
- : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL);
+ const unsigned int status = m->top.c2.event_set_status;
+ const unsigned int mpp_flags = m->top.c2.fast_io
+ ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL)
+ : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL);
#ifdef MULTI_DEBUG_EVENT_LOOP
- char buf[16];
- buf[0] = 0;
- if (status & SOCKET_READ)
- strcat (buf, "SR/");
- else if (status & SOCKET_WRITE)
- strcat (buf, "SW/");
- else if (status & TUN_READ)
- strcat (buf, "TR/");
- else if (status & TUN_WRITE)
- strcat (buf, "TW/");
+ char buf[16];
+ buf[0] = 0;
+ if (status & SOCKET_READ)
+ {
+ strcat(buf, "SR/");
+ }
+ else if (status & SOCKET_WRITE)
+ {
+ strcat(buf, "SW/");
+ }
+ else if (status & TUN_READ)
+ {
+ 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);
+ else if (status & FILE_CLOSED)
+ {
+ strcat(buf, "FC/");
+ }
#endif
+ printf("IO %s\n", buf);
+#endif /* ifdef MULTI_DEBUG_EVENT_LOOP */
#ifdef ENABLE_MANAGEMENT
- if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE))
+ if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE))
{
- ASSERT (management);
- management_io (management);
+ ASSERT(management);
+ management_io(management);
}
#endif
- /* UDP port ready to accept write */
- if (status & SOCKET_WRITE)
+ /* UDP port ready to accept write */
+ if (status & SOCKET_WRITE)
{
- multi_process_outgoing_link (m, mpp_flags);
+ multi_process_outgoing_link(m, mpp_flags);
}
- /* TUN device ready to accept write */
- else if (status & TUN_WRITE)
+ /* TUN device ready to accept write */
+ else if (status & TUN_WRITE)
{
- multi_process_outgoing_tun (m, mpp_flags);
+ multi_process_outgoing_tun(m, mpp_flags);
}
- /* Incoming data on UDP port */
- else if (status & SOCKET_READ)
+ /* Incoming data on UDP port */
+ else if (status & SOCKET_READ)
{
- read_incoming_link (&m->top);
- if (!IS_SIG (&m->top))
- multi_process_incoming_link (m, NULL, mpp_flags);
+ read_incoming_link(&m->top);
+ if (!IS_SIG(&m->top))
+ {
+ multi_process_incoming_link(m, NULL, mpp_flags);
+ }
}
- /* Incoming data on TUN device */
- else if (status & TUN_READ)
+ /* Incoming data on TUN device */
+ else if (status & TUN_READ)
{
- read_incoming_tun (&m->top);
- if (!IS_SIG (&m->top))
- multi_process_incoming_tun (m, mpp_flags);
+ read_incoming_tun(&m->top);
+ if (!IS_SIG(&m->top))
+ {
+ multi_process_incoming_tun(m, mpp_flags);
+ }
}
#ifdef ENABLE_ASYNC_PUSH
- /* INOTIFY callback */
- else if (status & FILE_CLOSED)
+ /* INOTIFY callback */
+ else if (status & FILE_CLOSED)
{
- multi_process_file_closed(m, mpp_flags);
+ multi_process_file_closed(m, mpp_flags);
}
#endif
}
@@ -241,22 +257,30 @@ multi_process_io_udp (struct multi_context *m)
* a point-to-multipoint tunnel.
*/
static inline unsigned int
-p2mp_iow_flags (const struct multi_context *m)
+p2mp_iow_flags(const struct multi_context *m)
{
- unsigned int flags = IOW_WAIT_SIGNAL;
- if (m->pending)
+ unsigned int flags = IOW_WAIT_SIGNAL;
+ if (m->pending)
+ {
+ if (TUN_OUT(&m->pending->context))
+ {
+ flags |= IOW_TO_TUN;
+ }
+ if (LINK_OUT(&m->pending->context))
+ {
+ flags |= IOW_TO_LINK;
+ }
+ }
+ else if (mbuf_defined(m->mbuf))
+ {
+ flags |= IOW_MBUF;
+ }
+ else
{
- if (TUN_OUT (&m->pending->context))
- flags |= IOW_TO_TUN;
- if (LINK_OUT (&m->pending->context))
- flags |= IOW_TO_LINK;
+ flags |= IOW_READ;
}
- else if (mbuf_defined (m->mbuf))
- flags |= IOW_MBUF;
- else
- flags |= IOW_READ;
- return flags;
+ return flags;
}
@@ -272,86 +296,88 @@ p2mp_iow_flags (const struct multi_context *m)
* @param top - Top-level context structure.
*/
static void
-tunnel_server_udp_single_threaded (struct context *top)
+tunnel_server_udp_single_threaded(struct context *top)
{
- struct multi_context multi;
+ struct multi_context multi;
- top->mode = CM_TOP;
- context_clear_2 (top);
+ top->mode = CM_TOP;
+ context_clear_2(top);
- /* initialize top-tunnel instance */
- init_instance_handle_signals (top, top->es, CC_HARD_USR1_TO_HUP);
- if (IS_SIG (top))
- return;
-
- /* initialize global multi_context object */
- multi_init (&multi, top, false, MC_SINGLE_THREADED);
+ /* initialize top-tunnel instance */
+ init_instance_handle_signals(top, top->es, CC_HARD_USR1_TO_HUP);
+ if (IS_SIG(top))
+ {
+ return;
+ }
- /* initialize our cloned top object */
- multi_top_init (&multi, top);
+ /* initialize global multi_context object */
+ multi_init(&multi, top, false, MC_SINGLE_THREADED);
- /* initialize management interface */
- init_management_callback_multi (&multi);
+ /* initialize our cloned top object */
+ multi_top_init(&multi, top);
- /* finished with initialization */
- initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto udp */
+ /* initialize management interface */
+ init_management_callback_multi(&multi);
+
+ /* 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)
+ 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));
+ msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno));
}
#endif
- /* per-packet event loop */
- while (true)
+ /* per-packet event loop */
+ while (true)
{
- perf_push (PERF_EVENT_LOOP);
-
- /* set up and do the io_wait() */
- multi_get_timeout (&multi, &multi.top.c2.timeval);
- io_wait (&multi.top, p2mp_iow_flags (&multi));
- MULTI_CHECK_SIG (&multi);
-
- /* check on status of coarse timers */
- multi_process_per_second_timers (&multi);
-
- /* timeout? */
- if (multi.top.c2.event_set_status == ES_TIMEOUT)
- {
- multi_process_timeout (&multi, MPP_PRE_SELECT|MPP_CLOSE_ON_SIGNAL);
- }
- else
- {
- /* process I/O */
- multi_process_io_udp (&multi);
- MULTI_CHECK_SIG (&multi);
- }
-
- perf_pop ();
+ perf_push(PERF_EVENT_LOOP);
+
+ /* set up and do the io_wait() */
+ multi_get_timeout(&multi, &multi.top.c2.timeval);
+ io_wait(&multi.top, p2mp_iow_flags(&multi));
+ MULTI_CHECK_SIG(&multi);
+
+ /* check on status of coarse timers */
+ multi_process_per_second_timers(&multi);
+
+ /* timeout? */
+ if (multi.top.c2.event_set_status == ES_TIMEOUT)
+ {
+ multi_process_timeout(&multi, MPP_PRE_SELECT|MPP_CLOSE_ON_SIGNAL);
+ }
+ else
+ {
+ /* process I/O */
+ multi_process_io_udp(&multi);
+ MULTI_CHECK_SIG(&multi);
+ }
+
+ perf_pop();
}
#ifdef ENABLE_ASYNC_PUSH
- close(top->c2.inotify_fd);
+ close(top->c2.inotify_fd);
#endif
- /* shut down management interface */
- uninit_management_callback_multi (&multi);
+ /* shut down management interface */
+ uninit_management_callback_multi(&multi);
- /* save ifconfig-pool */
- multi_ifconfig_pool_persist (&multi, true);
+ /* save ifconfig-pool */
+ multi_ifconfig_pool_persist(&multi, true);
- /* tear down tunnel instance (unless --persist-tun) */
- multi_uninit (&multi);
- multi_top_free (&multi);
- close_instance (top);
+ /* tear down tunnel instance (unless --persist-tun) */
+ multi_uninit(&multi);
+ multi_top_free(&multi);
+ close_instance(top);
}
void
-tunnel_server_udp (struct context *top)
+tunnel_server_udp(struct context *top)
{
- tunnel_server_udp_single_threaded (top);
+ tunnel_server_udp_single_threaded(top);
}
-#endif
+#endif /* if P2MP_SERVER */