summaryrefslogtreecommitdiffstats
path: root/src/openvpn/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/multi.c')
-rw-r--r--src/openvpn/multi.c155
1 files changed, 152 insertions, 3 deletions
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 902c4dc..05c36db 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -28,6 +28,11 @@
#include "config-msvc.h"
#endif
+#ifdef HAVE_SYS_INOTIFY_H
+#include <sys/inotify.h>
+#define INOTIFY_EVENT_BUFFER_SIZE 16384
+#endif
+
#include "syshead.h"
#if P2MP_SERVER
@@ -243,6 +248,23 @@ cid_compare_function (const void *key1, const void *key2)
#endif
+#ifdef ENABLE_ASYNC_PUSH
+static uint32_t
+/*
+ * inotify watcher descriptors are used as hash value
+ */
+int_hash_function (const void *key, uint32_t iv)
+{
+ return (unsigned long)key;
+}
+
+static bool
+int_compare_function (const void *key1, const void *key2)
+{
+ return (unsigned long)key1 == (unsigned long)key2;
+}
+#endif
+
/*
* Main initialization function, init multi_context object.
*/
@@ -304,6 +326,17 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
cid_compare_function);
#endif
+#ifdef ENABLE_ASYNC_PUSH
+ /*
+ * Mapping between inotify watch descriptors and
+ * multi_instances.
+ */
+ m->inotify_watchers = hash_init (t->options.real_hash_size,
+ get_random(),
+ int_hash_function,
+ int_compare_function);
+#endif
+
/*
* This is our scheduler, for time-based wakeup
* events.
@@ -562,6 +595,14 @@ multi_close_instance (struct multi_context *m,
}
#endif
+#ifdef ENABLE_ASYNC_PUSH
+ if (mi->inotify_watch != -1)
+ {
+ hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch);
+ mi->inotify_watch = -1;
+ }
+#endif
+
m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
@@ -642,6 +683,11 @@ multi_uninit (struct multi_context *m)
free(m->instances);
+#ifdef ENABLE_ASYNC_PUSH
+ hash_free (m->inotify_watchers);
+ m->inotify_watchers = NULL;
+#endif
+
schedule_free (m->schedule);
mbuf_free (m->mbuf);
ifconfig_pool_free (m->ifconfig_pool);
@@ -718,6 +764,11 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real)
mi->context.c2.push_reply_deferred = true;
+#ifdef ENABLE_ASYNC_PUSH
+ mi->context.c2.push_request_received = false;
+ mi->inotify_watch = -1;
+#endif
+
if (!multi_process_post (m, mi, MPP_PRE_SELECT))
{
msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization");
@@ -923,6 +974,13 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
status_flush (so);
gc_free (&gc_top);
}
+
+#ifdef ENABLE_ASYNC_PUSH
+ if (m->inotify_watchers)
+ {
+ msg (D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers));
+ }
+#endif
}
/*
@@ -1877,6 +1935,14 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
/* set context-level authentication flag */
mi->context.c2.context_auth = CAS_SUCCEEDED;
+
+#ifdef ENABLE_ASYNC_PUSH
+ /* authentication complete, send push reply */
+ if (mi->context.c2.push_request_received)
+ {
+ process_incoming_push_request(&mi->context);
+ }
+#endif
}
else
{
@@ -1906,6 +1972,58 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
mi->context.c2.push_reply_deferred = false;
}
+#ifdef ENABLE_ASYNC_PUSH
+/*
+ * Called when inotify event is fired, which happens when acf file is closed or deleted.
+ * Continues authentication and sends push_reply.
+ */
+void
+multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags)
+{
+ char buffer[INOTIFY_EVENT_BUFFER_SIZE];
+ size_t buffer_i = 0;
+ int r = read (m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE);
+
+ while (buffer_i < r)
+ {
+ /* parse inotify events */
+ struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i];
+ size_t event_size = sizeof (struct inotify_event) + pevent->len;
+ buffer_i += event_size;
+
+ msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask);
+
+ struct multi_instance* mi = hash_lookup(m->inotify_watchers, (void*) (unsigned long) pevent->wd);
+
+ if (pevent->mask & IN_CLOSE_WRITE)
+ {
+ if (mi)
+ {
+ /* continue authentication and send push_reply */
+ multi_process_post (m, mi, mpp_flags);
+ }
+ else
+ {
+ msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!");
+ }
+ }
+ else if (pevent->mask & IN_IGNORED)
+ {
+ /* this event is _always_ fired when watch is removed or file is deleted */
+ if (mi)
+ {
+ hash_remove(m->inotify_watchers, (void*) (unsigned long) pevent->wd);
+ mi->inotify_watch = -1;
+ }
+ }
+ else
+ {
+ msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask);
+ }
+ }
+}
+#endif
+
/*
* Add a mbuf buffer to a particular
* instance.
@@ -2066,19 +2184,50 @@ multi_process_post (struct multi_context *m, struct multi_instance *mi, const un
if (!IS_SIG (&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT (&mi->context))))
{
+#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
+ bool was_authenticated = false;
+ struct key_state *ks = NULL;
+ if (mi->context.c2.tls_multi)
+ {
+ ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY];
+ was_authenticated = ks->authenticated;
+ }
+#endif
+
/* figure timeouts and fetch possible outgoing
to_link packets (such as ping or TLS control) */
pre_select (&mi->context);
- if (!IS_SIG (&mi->context))
+#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
+ if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated)
{
- /* tell scheduler to wake us up at some point in the future */
- multi_schedule_context_wakeup(m, mi);
+ /* watch acf file */
+ long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT);
+ if (watch_descriptor >= 0)
+ {
+ if (mi->inotify_watch != -1)
+ {
+ hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch);
+ }
+ hash_add (m->inotify_watchers, (const uintptr_t*)watch_descriptor, mi, true);
+ mi->inotify_watch = watch_descriptor;
+ }
+ else
+ {
+ msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno));
+ }
+ }
+#endif
+ if (!IS_SIG (&mi->context))
+ {
/* connection is "established" when SSL/TLS key negotiation succeeds
and (if specified) auth user/pass succeeds */
if (!mi->connection_established_flag && CONNECTION_ESTABLISHED (&mi->context))
multi_connection_established (m, mi);
+
+ /* tell scheduler to wake us up at some point in the future */
+ multi_schedule_context_wakeup(m, mi);
}
}