commit 4a56dc5: [Feature] Lua_tcp: Add preliminary support of SSL connections

Vsevolod Stakhov vsevolod at highsecure.ru
Thu May 30 14:07:03 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-05-29 22:15:45 +0100
URL: https://github.com/rspamd/rspamd/commit/4a56dc5e0e39e1b7d756c86ed73468c607f3e090

[Feature] Lua_tcp: Add preliminary support of SSL connections

---
 src/lua/lua_tcp.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 125 insertions(+), 14 deletions(-)

diff --git a/src/lua/lua_tcp.c b/src/lua/lua_tcp.c
index 1c789a9d3..1e19efd97 100644
--- a/src/lua/lua_tcp.c
+++ b/src/lua/lua_tcp.c
@@ -15,6 +15,7 @@
  */
 #include "lua_common.h"
 #include "lua_thread_pool.h"
+#include "libutil/ssl_util.h"
 #include "utlist.h"
 #include "unix-std.h"
 #include <math.h>
@@ -117,6 +118,8 @@ local function http_simple_tcp_symbol(task)
       host = '127.0.0.1',
       timeout = 20,
       port = 18080,
+      ssl = false, -- If SSL connection is needed
+      ssl_verify = true, -- set to false if verify is not needed
     }
 
     is_ok, err = connection:write('GET /request_sync HTTP/1.1\r\nConnection: keep-alive\r\n\r\n')
@@ -189,6 +192,14 @@ LUA_FUNCTION_DEF (tcp, add_write);
  */
 LUA_FUNCTION_DEF (tcp, shift_callback);
 
+/***
+ * @method tcp:starttls([no_verify])
+ *
+ * Starts tls connection
+ * @param {boolean} no_verify used to skip ssl verification
+ */
+LUA_FUNCTION_DEF (tcp, starttls);
+
 static const struct luaL_reg tcp_libf[] = {
 	LUA_INTERFACE_DEF (tcp, request),
 	{"new", lua_tcp_request},
@@ -203,6 +214,7 @@ static const struct luaL_reg tcp_libm[] = {
 	LUA_INTERFACE_DEF (tcp, add_read),
 	LUA_INTERFACE_DEF (tcp, add_write),
 	LUA_INTERFACE_DEF (tcp, shift_callback),
+	LUA_INTERFACE_DEF (tcp, starttls),
 	{"__tostring", rspamd_lua_class_tostring},
 	{NULL, NULL}
 };
@@ -302,12 +314,14 @@ struct lua_tcp_dtor {
 	struct lua_tcp_dtor *next;
 };
 
-#define LUA_TCP_FLAG_PARTIAL (1 << 0)
-#define LUA_TCP_FLAG_SHUTDOWN (1 << 2)
-#define LUA_TCP_FLAG_CONNECTED (1 << 3)
-#define LUA_TCP_FLAG_FINISHED (1 << 4)
-#define LUA_TCP_FLAG_SYNC (1 << 5)
-#define LUA_TCP_FLAG_RESOLVED (1 << 6)
+#define LUA_TCP_FLAG_PARTIAL (1u << 0u)
+#define LUA_TCP_FLAG_SHUTDOWN (1u << 2u)
+#define LUA_TCP_FLAG_CONNECTED (1u << 3u)
+#define LUA_TCP_FLAG_FINISHED (1u << 4u)
+#define LUA_TCP_FLAG_SYNC (1u << 5u)
+#define LUA_TCP_FLAG_RESOLVED (1u << 6u)
+#define LUA_TCP_FLAG_SSL (1u << 7u)
+#define LUA_TCP_FLAG_SSL_NOVERIFY (1u << 8u)
 
 #undef TCP_DEBUG_REFS
 #ifdef TCP_DEBUG_REFS
@@ -345,6 +359,8 @@ struct lua_tcp_cbdata {
 	struct rspamd_symcache_item *item;
 	struct thread_entry *thread;
 	struct rspamd_config *cfg;
+	struct rspamd_ssl_connection *ssl_conn;
+	gchar *hostname;
 	gboolean eof;
 };
 
@@ -445,6 +461,11 @@ lua_tcp_fin (gpointer arg)
 		luaL_unref (cbd->cfg->lua_state, LUA_REGISTRYINDEX, cbd->connect_cb);
 	}
 
+	if (cbd->ssl_conn) {
+		/* TODO: postpone close in case ssl is used ! */
+		rspamd_ssl_connection_free (cbd->ssl_conn);
+	}
+
 	if (cbd->fd != -1) {
 		event_del (&cbd->ev);
 		close (cbd->fd);
@@ -464,6 +485,7 @@ lua_tcp_fin (gpointer arg)
 	}
 
 	g_byte_array_unref (cbd->in);
+	g_free (cbd->hostname);
 	g_free (cbd);
 }
 
@@ -817,7 +839,13 @@ lua_tcp_write_helper (struct lua_tcp_cbdata *cbd)
 #ifdef MSG_NOSIGNAL
 	flags = MSG_NOSIGNAL;
 #endif
-	r = sendmsg (cbd->fd, &msg, flags);
+
+	if (cbd->ssl_conn) {
+		r = rspamd_ssl_writev (cbd->ssl_conn, msg.msg_iov, msg.msg_iovlen);
+	}
+	else {
+		r = sendmsg (cbd->fd, &msg, flags);
+	}
 
 	if (r == -1) {
 		lua_tcp_push_error (cbd, FALSE, "IO write error while trying to write %d "
@@ -1006,7 +1034,13 @@ lua_tcp_handler (int fd, short what, gpointer ud)
 	event_type = rh->type;
 
 	if (what == EV_READ) {
-		r = read (cbd->fd, inbuf, sizeof (inbuf));
+		if (cbd->ssl_conn) {
+			r = rspamd_ssl_read (cbd->ssl_conn, inbuf, sizeof (inbuf));
+		}
+		else {
+			r = read (cbd->fd, inbuf, sizeof (inbuf));
+		}
+
 		lua_tcp_process_read (cbd, inbuf, r);
 	}
 	else if (what == EV_WRITE) {
@@ -1189,6 +1223,21 @@ lua_tcp_register_watcher (struct lua_tcp_cbdata *cbd)
 	}
 }
 
+static void
+lua_tcp_ssl_on_error (gpointer ud, GError *err)
+{
+	struct lua_tcp_cbdata *cbd = (struct lua_tcp_cbdata *)ud;
+
+	if (err) {
+		lua_tcp_push_error (cbd, TRUE, "ssl error: %s", err->message);
+	}
+	else {
+		lua_tcp_push_error (cbd, TRUE, "ssl error: unknown error");
+	}
+
+	TCP_RELEASE (cbd);
+}
+
 static gboolean
 lua_tcp_make_connection (struct lua_tcp_cbdata *cbd)
 {
@@ -1200,19 +1249,23 @@ lua_tcp_make_connection (struct lua_tcp_cbdata *cbd)
 	if (fd == -1) {
 		if (cbd->session) {
 			rspamd_mempool_t *pool = rspamd_session_mempool (cbd->session);
-			msg_info_pool ("cannot connect to %s: %s",
+			msg_info_pool ("cannot connect to %s (%s): %s",
 					rspamd_inet_address_to_string (cbd->addr),
+					cbd->hostname,
 					strerror (errno));
 		}
 		else {
-			msg_info ("cannot connect to %s: %s",
+			msg_info ("cannot connect to %s (%s): %s",
 					rspamd_inet_address_to_string (cbd->addr),
+					cbd->hostname,
 					strerror (errno));
 		}
 
 		return FALSE;
 	}
 
+	cbd->fd = fd;
+
 #if 0
 	if (!(cbd->flags & LUA_TCP_FLAG_RESOLVED)) {
 		/* We come here without resolving, so we need to add a watcher */
@@ -1223,10 +1276,39 @@ lua_tcp_make_connection (struct lua_tcp_cbdata *cbd)
 	}
 #endif
 
-	lua_tcp_register_event (cbd);
+	if (cbd->flags & LUA_TCP_FLAG_SSL) {
+		gpointer ssl_ctx;
+		gboolean verify_peer;
+
+		if (cbd->flags & LUA_TCP_FLAG_SSL_NOVERIFY) {
+			ssl_ctx = cbd->cfg->libs_ctx->ssl_ctx_noverify;
+			verify_peer = FALSE;
+		}
+		else {
+			ssl_ctx = cbd->cfg->libs_ctx->ssl_ctx;
+			verify_peer = TRUE;
+		}
+
+		event_base_set (cbd->ev_base, &cbd->ev);
+		cbd->ssl_conn =
+				rspamd_ssl_connection_new (ssl_ctx, cbd->ev_base, verify_peer);
+
+		if (!rspamd_ssl_connect_fd (cbd->ssl_conn, fd, cbd->hostname, &cbd->ev,
+				&cbd->tv, lua_tcp_handler, lua_tcp_ssl_on_error, cbd)) {
+			lua_tcp_push_error (cbd, TRUE, "ssl connection failed: %s",
+					strerror (errno));
+
+			return FALSE;
+		}
+		else {
+			lua_tcp_register_event (cbd);
+		}
+	}
+	else {
+		lua_tcp_register_event (cbd);
+		lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
+	}
 
-	cbd->fd = fd;
-	lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
 
 	return TRUE;
 }
@@ -1359,7 +1441,8 @@ lua_tcp_request (lua_State *L)
 	guint niov = 0, total_out;
 	guint64 h;
 	gdouble timeout = default_tcp_timeout;
-	gboolean partial = FALSE, do_shutdown = FALSE, do_read = TRUE;
+	gboolean partial = FALSE, do_shutdown = FALSE, do_read = TRUE,
+		ssl = FALSE, ssl_noverify = FALSE;
 
 	if (lua_type (L, 1) == LUA_TTABLE) {
 		lua_pushstring (L, "host");
@@ -1486,6 +1569,20 @@ lua_tcp_request (lua_State *L)
 		}
 		lua_pop (L, 1);
 
+		lua_pushstring (L, "ssl");
+		lua_gettable (L, -2);
+		if (lua_type (L, -1) == LUA_TBOOLEAN) {
+			ssl = lua_toboolean (L, -1);
+		}
+		lua_pop (L, 1);
+
+		lua_pushstring (L, "ssl_noverify");
+		lua_gettable (L, -2);
+		if (lua_type (L, -1) == LUA_TBOOLEAN) {
+			ssl_noverify = lua_toboolean (L, -1);
+		}
+		lua_pop (L, 1);
+
 		lua_pushstring (L, "on_connect");
 		lua_gettable (L, -2);
 
@@ -1568,6 +1665,7 @@ lua_tcp_request (lua_State *L)
 	h = rspamd_random_uint64_fast ();
 	rspamd_snprintf (cbd->tag, sizeof (cbd->tag), "%uxL", h);
 	cbd->handlers = g_queue_new ();
+	cbd->hostname = g_strdup (host);
 
 	if (total_out > 0) {
 		struct lua_tcp_handler *wh;
@@ -1598,6 +1696,14 @@ lua_tcp_request (lua_State *L)
 	cbd->fd = -1;
 	cbd->port = port;
 
+	if (ssl) {
+		cbd->flags |= LUA_TCP_FLAG_SSL;
+
+		if (ssl_noverify) {
+			cbd->flags |= LUA_TCP_FLAG_SSL_NOVERIFY;
+		}
+	}
+
 	if (do_read) {
 		cbd->in = g_byte_array_sized_new (8192);
 	}
@@ -2236,6 +2342,11 @@ lua_tcp_sync_shutdown (lua_State *L)
 	return 0;
 }
 
+static gint
+lua_tcp_starttls (lua_State * L)
+{
+	return 0;
+}
 
 static gint
 lua_tcp_sync_gc (lua_State * L)


More information about the Commits mailing list