summaryrefslogtreecommitdiff
path: root/src/libpttls/pt_tls_dispatcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpttls/pt_tls_dispatcher.c')
-rw-r--r--src/libpttls/pt_tls_dispatcher.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/libpttls/pt_tls_dispatcher.c b/src/libpttls/pt_tls_dispatcher.c
new file mode 100644
index 000000000..469951616
--- /dev/null
+++ b/src/libpttls/pt_tls_dispatcher.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "pt_tls_dispatcher.h"
+#include "pt_tls_server.h"
+
+#include <threading/thread.h>
+#include <utils/debug.h>
+#include <processing/jobs/callback_job.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef struct private_pt_tls_dispatcher_t private_pt_tls_dispatcher_t;
+
+/**
+ * Private data of an pt_tls_dispatcher_t object.
+ */
+struct private_pt_tls_dispatcher_t {
+
+ /**
+ * Public pt_tls_dispatcher_t interface.
+ */
+ pt_tls_dispatcher_t public;
+
+ /**
+ * Listening socket
+ */
+ int fd;
+
+ /**
+ * Client authentication requirements
+ */
+ pt_tls_auth_t auth;
+
+ /**
+ * Server identity
+ */
+ identification_t *server;
+
+ /**
+ * Peer identity
+ */
+ identification_t *peer;
+
+ /**
+ * TNCCS protocol handler constructor
+ */
+ pt_tls_tnccs_constructor_t *create;
+};
+
+/**
+ * Open listening server socket
+ */
+static bool open_socket(private_pt_tls_dispatcher_t *this, host_t *host)
+{
+ this->fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (this->fd == -1)
+ {
+ DBG1(DBG_TNC, "opening PT-TLS socket failed: %s", strerror(errno));
+ return FALSE;
+ }
+ if (bind(this->fd, host->get_sockaddr(host),
+ *host->get_sockaddr_len(host)) == -1)
+ {
+ DBG1(DBG_TNC, "binding to PT-TLS socket failed: %s", strerror(errno));
+ return FALSE;
+ }
+ if (listen(this->fd, 5) == -1)
+ {
+ DBG1(DBG_TNC, "listen on PT-TLS socket failed: %s", strerror(errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Handle a single PT-TLS client connection
+ */
+static job_requeue_t handle(pt_tls_server_t *connection)
+{
+ while (TRUE)
+ {
+ switch (connection->handle(connection))
+ {
+ case NEED_MORE:
+ continue;
+ case FAILED:
+ case SUCCESS:
+ default:
+ break;
+ }
+ break;
+ }
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Clean up connection state
+ */
+static void cleanup(pt_tls_server_t *connection)
+{
+ int fd;
+
+ fd = connection->get_fd(connection);
+ connection->destroy(connection);
+ close(fd);
+}
+
+METHOD(pt_tls_dispatcher_t, dispatch, void,
+ private_pt_tls_dispatcher_t *this,
+ pt_tls_tnccs_constructor_t *create)
+{
+ while (TRUE)
+ {
+ pt_tls_server_t *connection;
+ tnccs_t *tnccs;
+ bool old;
+ int fd;
+
+ old = thread_cancelability(TRUE);
+ fd = accept(this->fd, NULL, NULL);
+ thread_cancelability(old);
+ if (fd == -1)
+ {
+ DBG1(DBG_TNC, "accepting PT-TLS failed: %s", strerror(errno));
+ continue;
+ }
+
+ tnccs = create(this->server, this->peer);
+ if (!tnccs)
+ {
+ close(fd);
+ continue;
+ }
+ connection = pt_tls_server_create(this->server, fd, this->auth, tnccs);
+ if (!connection)
+ {
+ close(fd);
+ continue;
+ }
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create_with_prio((callback_job_cb_t)handle,
+ connection, (void*)cleanup,
+ (callback_job_cancel_t)return_false,
+ JOB_PRIO_CRITICAL));
+ }
+}
+
+METHOD(pt_tls_dispatcher_t, destroy, void,
+ private_pt_tls_dispatcher_t *this)
+{
+ if (this->fd != -1)
+ {
+ close(this->fd);
+ }
+ this->server->destroy(this->server);
+ this->peer->destroy(this->peer);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pt_tls_dispatcher_t *pt_tls_dispatcher_create(host_t *address,
+ identification_t *id, pt_tls_auth_t auth)
+{
+ private_pt_tls_dispatcher_t *this;
+
+ INIT(this,
+ .public = {
+ .dispatch = _dispatch,
+ .destroy = _destroy,
+ },
+ .server = id,
+ /* we currently don't authenticate the peer, use %any identity */
+ .peer = identification_create_from_encoding(ID_ANY, chunk_empty),
+ .fd = -1,
+ .auth = auth,
+ );
+
+ if (!open_socket(this, address))
+ {
+ address->destroy(address);
+ destroy(this);
+ return NULL;
+ }
+ address->destroy(address);
+
+ return &this->public;
+}