commit d79fdd8: [Project] Finish received headers rework part

Vsevolod Stakhov vsevolod at highsecure.ru
Tue Oct 5 11:14:09 UTC 2021


Author: Vsevolod Stakhov
Date: 2021-10-05 12:13:21 +0100
URL: https://github.com/rspamd/rspamd/commit/d79fdd8a405ddc495fa1245cc9c22ec119f7787d (HEAD -> master)

[Project] Finish received headers rework part

---
 src/libmime/received.cxx | 140 +++++++++++++++++++++++++++++++++++++++++------
 src/libmime/received.h   |  38 +++----------
 src/libmime/received.hxx |  75 ++++++++++++++++++++++++-
 src/lua/lua_task.c       | 118 +++------------------------------------
 4 files changed, 215 insertions(+), 156 deletions(-)

diff --git a/src/libmime/received.cxx b/src/libmime/received.cxx
index 3d273081f..6c79ced00 100644
--- a/src/libmime/received.cxx
+++ b/src/libmime/received.cxx
@@ -17,6 +17,7 @@
 #include <mempool_vars_internal.h>
 #include "config.h"
 #include "libserver/url.h"
+#include "lua/lua_common.h"
 #include "libserver/cfg_file.h"
 #include "mime_string.hxx"
 #include "smtp_parsers.h"
@@ -587,18 +588,24 @@ received_header_parse(struct rspamd_task *task, const std::string_view &in,
 {
 	std::ptrdiff_t date_pos = -1;
 
-	static constexpr const auto protos_map = frozen::make_unordered_map<frozen::string, int>({
-			{"smtp",    RSPAMD_RECEIVED_SMTP},
-			{"esmtp",   RSPAMD_RECEIVED_ESMTP},
-			{"esmtpa",  RSPAMD_RECEIVED_ESMTPA | RSPAMD_RECEIVED_FLAG_AUTHENTICATED},
-			{"esmtpsa", RSPAMD_RECEIVED_ESMTPSA | RSPAMD_RECEIVED_FLAG_SSL | RSPAMD_RECEIVED_FLAG_AUTHENTICATED},
-			{"esmtps",  RSPAMD_RECEIVED_ESMTPS | RSPAMD_RECEIVED_FLAG_SSL},
-			{"lmtp",    RSPAMD_RECEIVED_LMTP},
-			{"imap",    RSPAMD_RECEIVED_IMAP},
-			{"imaps",   RSPAMD_RECEIVED_IMAP | RSPAMD_RECEIVED_FLAG_SSL},
-			{"http",    RSPAMD_RECEIVED_HTTP},
-			{"https",   RSPAMD_RECEIVED_HTTP | RSPAMD_RECEIVED_FLAG_SSL},
-			{"local",   RSPAMD_RECEIVED_LOCAL}
+	static constexpr const auto protos_map = frozen::make_unordered_map<frozen::string, received_flags>({
+			{"smtp",    received_flags::SMTP},
+			{"esmtp",   received_flags::ESMTP},
+			{"esmtpa",  received_flags::ESMTPA |
+						received_flags::AUTHENTICATED},
+			{"esmtpsa", received_flags::ESMTPSA |
+						received_flags::SSL |
+						received_flags::AUTHENTICATED},
+			{"esmtps",  received_flags::ESMTPS |
+						received_flags::SSL},
+			{"lmtp",    received_flags::LMTP},
+			{"imap",    received_flags::IMAP},
+			{"imaps",   received_flags::IMAP |
+						received_flags::SSL},
+			{"http",    received_flags::HTTP},
+			{"https",   received_flags::HTTP |
+						received_flags::SSL},
+			{"local",   received_flags::LOCAL}
 	});
 
 	auto parts = received_spill(task, in, date_pos);
@@ -617,7 +624,7 @@ received_header_parse(struct rspamd_task *task, const std::string_view &in,
 
 	auto &rh = recv_chain_ptr->new_received();
 
-	rh.flags = RSPAMD_RECEIVED_UNKNOWN;
+	rh.flags = received_flags::UNKNOWN;
 	rh.hdr = hdr;
 
 	for (const auto &part : parts) {
@@ -707,14 +714,14 @@ received_maybe_fix_task(struct rspamd_task *task) -> bool
 								" not ours, prepend it with fake one");
 
 				auto trecv = recv_chain_ptr->new_received(received_header_chain::append_type::append_head);
-				trecv.flags |= RSPAMD_RECEIVED_FLAG_ARTIFICIAL;
+				trecv.flags |= received_flags::ARTIFICIAL;
 
 				if (task->flags & RSPAMD_TASK_FLAG_SSL) {
-					trecv.flags |= RSPAMD_RECEIVED_FLAG_SSL;
+					trecv.flags |= received_flags::SSL;
 				}
 
 				if (task->user) {
-					trecv.flags |= RSPAMD_RECEIVED_FLAG_AUTHENTICATED;
+					trecv.flags |= received_flags::AUTHENTICATED;
 				}
 
 				trecv.real_ip.assign_copy(std::string_view(rspamd_inet_address_to_string(task->from_addr)));
@@ -761,6 +768,99 @@ received_maybe_fix_task(struct rspamd_task *task) -> bool
 	return false;
 }
 
+static auto
+received_export_to_lua(received_header_chain *chain, lua_State *L) -> bool
+{
+	if (chain == nullptr) {
+		return false;
+	}
+
+	lua_createtable(L, chain->size(), 0);
+
+	auto push_flag = [L](const received_header &rh, received_flags fl, const char *name) {
+		lua_pushboolean(L, !!(rh.flags & fl));
+		lua_setfield(L, -2, name);
+	};
+
+	auto i = 1;
+
+	for (const auto &rh : chain->as_vector()) {
+		lua_createtable (L, 0, 10);
+
+		if (rh.hdr && rh.hdr->decoded) {
+			rspamd_lua_table_set(L, "raw", rh.hdr->decoded);
+		}
+
+		lua_createtable(L, 0, 3);
+		push_flag(rh, received_flags::ARTIFICIAL, "artificial");
+		push_flag(rh, received_flags::AUTHENTICATED, "authenticated");
+		push_flag(rh, received_flags::SSL, "ssl");
+		lua_setfield(L, -2, "flags");
+
+		lua_pushlstring(L, rh.from_hostname.data(), rh.from_hostname.size());
+		lua_setfield(L, -2, "from_hostname");
+		lua_pushlstring(L, rh.real_hostname.data(), rh.real_hostname.size());
+		lua_setfield(L, -2, "real_hostname");
+		lua_pushlstring(L, rh.from_ip.data(), rh.from_ip.size());
+		lua_setfield(L, -2, "from_ip");
+		lua_pushlstring(L, rh.by_hostname.data(), rh.by_hostname.size());
+		lua_setfield(L, -2, "by_hostname");
+		lua_pushlstring(L, rh.for_mbox.data(), rh.for_mbox.size());
+		lua_setfield(L, -2, "for");
+
+		rspamd_lua_ip_push (L, rh.addr);
+		lua_setfield(L, -2, "real_ip");
+
+		const auto *proto = "unknown";
+
+		switch (received_type_apply_maks(rh.flags)) {
+		case received_flags::SMTP:
+			proto = "smtp";
+			break;
+		case received_flags::ESMTP:
+			proto = "esmtp";
+			break;
+		case received_flags::ESMTPS:
+			proto = "esmtps";
+			break;
+		case received_flags::ESMTPA:
+			proto = "esmtpa";
+			break;
+		case received_flags::ESMTPSA:
+			proto = "esmtpsa";
+			break;
+		case received_flags::LMTP:
+			proto = "lmtp";
+			break;
+		case received_flags::IMAP:
+			proto = "imap";
+			break;
+		case received_flags::HTTP:
+			proto = "http";
+			break;
+		case received_flags::LOCAL:
+			proto = "local";
+			break;
+		case received_flags::MAPI:
+			proto = "mapi";
+			break;
+		default:
+			proto = "unknown";
+			break;
+		}
+
+		lua_pushstring(L, proto);
+		lua_setfield(L, -2, "proto");
+
+		lua_pushinteger(L, rh.timestamp);
+		lua_setfield(L, -2, "timestamp");
+
+		lua_rawseti(L, -2, i++);
+	}
+
+	return true;
+}
+
 } // namespace rspamd::mime
 
 bool
@@ -776,3 +876,11 @@ rspamd_received_maybe_fix_task(struct rspamd_task *task)
 {
 	return rspamd::mime::received_maybe_fix_task(task);
 }
+
+bool
+rspamd_received_export_to_lua(struct rspamd_task *task, lua_State *L)
+{
+	return rspamd::mime::received_export_to_lua(
+			static_cast<rspamd::mime::received_header_chain *>(MESSAGE_FIELD(task, received_headers)),
+			L);
+}
\ No newline at end of file
diff --git a/src/libmime/received.h b/src/libmime/received.h
index 845bf4357..14f9f848b 100644
--- a/src/libmime/received.h
+++ b/src/libmime/received.h
@@ -28,35 +28,6 @@ extern "C" {
  * C bindings for C++ received code
  */
 
-enum rspamd_received_type {
-	RSPAMD_RECEIVED_SMTP = 1u << 0u,
-	RSPAMD_RECEIVED_ESMTP = 1u << 1u,
-	RSPAMD_RECEIVED_ESMTPA = 1u << 2u,
-	RSPAMD_RECEIVED_ESMTPS = 1u << 3u,
-	RSPAMD_RECEIVED_ESMTPSA = 1u << 4u,
-	RSPAMD_RECEIVED_LMTP = 1u << 5u,
-	RSPAMD_RECEIVED_IMAP = 1u << 6u,
-	RSPAMD_RECEIVED_LOCAL = 1u << 7u,
-	RSPAMD_RECEIVED_HTTP = 1u << 8u,
-	RSPAMD_RECEIVED_MAPI = 1u << 9u,
-	RSPAMD_RECEIVED_UNKNOWN = 1u << 10u,
-	RSPAMD_RECEIVED_FLAG_ARTIFICIAL = (1u << 11u),
-	RSPAMD_RECEIVED_FLAG_SSL = (1u << 12u),
-	RSPAMD_RECEIVED_FLAG_AUTHENTICATED = (1u << 13u),
-};
-
-#define RSPAMD_RECEIVED_FLAG_TYPE_MASK (RSPAMD_RECEIVED_SMTP| \
-            RSPAMD_RECEIVED_ESMTP| \
-            RSPAMD_RECEIVED_ESMTPA| \
-            RSPAMD_RECEIVED_ESMTPS| \
-            RSPAMD_RECEIVED_ESMTPSA| \
-            RSPAMD_RECEIVED_LMTP| \
-            RSPAMD_RECEIVED_IMAP| \
-            RSPAMD_RECEIVED_LOCAL| \
-            RSPAMD_RECEIVED_HTTP| \
-            RSPAMD_RECEIVED_MAPI| \
-            RSPAMD_RECEIVED_UNKNOWN)
-
 struct rspamd_email_address;
 struct rspamd_received_header_chain;
 struct rspamd_mime_header;
@@ -80,6 +51,15 @@ bool rspamd_received_header_parse(struct rspamd_task *task,
  */
 bool rspamd_received_maybe_fix_task(struct rspamd_task *task);
 
+struct lua_State;
+/**
+ * Push received headers chain to lua
+ * @param task
+ * @param L
+ * @return
+ */
+bool rspamd_received_export_to_lua(struct rspamd_task *task, struct lua_State *L);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/src/libmime/received.hxx b/src/libmime/received.hxx
index fd03fd1fa..7c8d5f397 100644
--- a/src/libmime/received.hxx
+++ b/src/libmime/received.hxx
@@ -41,6 +41,73 @@ received_char_filter(UChar32 uc) -> UChar32
 	return 0;
 }
 
+enum class received_flags {
+	DEFAULT = 0,
+	SMTP = 1u << 0u,
+	ESMTP = 1u << 1u,
+	ESMTPA = 1u << 2u,
+	ESMTPS = 1u << 3u,
+	ESMTPSA = 1u << 4u,
+	LMTP = 1u << 5u,
+	IMAP = 1u << 6u,
+	LOCAL = 1u << 7u,
+	HTTP = 1u << 8u,
+	MAPI = 1u << 9u,
+	UNKNOWN = 1u << 10u,
+	ARTIFICIAL = (1u << 11u),
+	SSL = (1u << 12u),
+	AUTHENTICATED = (1u << 13u),
+};
+
+#define RSPAMD_RECEIVED_FLAG_TYPE_MASK (received_flags::SMTP| \
+            RSPAMD_RECEIVED_ESMTP| \
+            RSPAMD_RECEIVED_ESMTPA| \
+            RSPAMD_RECEIVED_ESMTPS| \
+            RSPAMD_RECEIVED_ESMTPSA| \
+            RSPAMD_RECEIVED_LMTP| \
+            RSPAMD_RECEIVED_IMAP| \
+            RSPAMD_RECEIVED_LOCAL| \
+            RSPAMD_RECEIVED_HTTP| \
+            RSPAMD_RECEIVED_MAPI| \
+            RSPAMD_RECEIVED_UNKNOWN)
+
+constexpr received_flags operator |(received_flags lhs, received_flags rhs)
+{
+	using ut = std::underlying_type<received_flags>::type;
+	return static_cast<received_flags>(static_cast<ut>(lhs) | static_cast<ut>(rhs));
+}
+
+constexpr received_flags operator |=(received_flags &lhs, const received_flags rhs)
+{
+	using ut = std::underlying_type<received_flags>::type;
+	lhs = static_cast<received_flags>(static_cast<ut>(lhs) | static_cast<ut>(rhs));
+	return lhs;
+}
+
+constexpr received_flags operator &(received_flags lhs, received_flags rhs)
+{
+	using ut = std::underlying_type<received_flags>::type;
+	return static_cast<received_flags>(static_cast<ut>(lhs) & static_cast<ut>(rhs));
+}
+
+constexpr bool operator !(received_flags fl)
+{
+	return fl == received_flags::DEFAULT;
+}
+
+constexpr received_flags received_type_apply_maks(received_flags fl) {
+	return fl & (received_flags::SMTP|
+			received_flags::ESMTP|
+			received_flags::ESMTPA|
+			received_flags::ESMTPS|
+			received_flags::ESMTPSA|
+			received_flags::IMAP|
+			received_flags::HTTP|
+			received_flags::LOCAL|
+			received_flags::MAPI|
+			received_flags::LMTP);
+}
+
 struct received_header {
 	mime_string from_hostname;
 	std::string_view from_ip;
@@ -52,7 +119,7 @@ struct received_header {
 	rspamd_inet_addr_t *addr = nullptr;
 	struct rspamd_mime_header *hdr = nullptr;
 	time_t timestamp = 0;
-	int flags = 0; /* See enum rspamd_received_type */
+	received_flags flags = received_flags::DEFAULT; /* See enum rspamd_received_type */
 
 	received_header() noexcept
 			: from_hostname(received_char_filter),
@@ -99,6 +166,12 @@ public:
 
 		return std::nullopt;
 	}
+	constexpr auto size() const -> std::size_t {
+		return headers.size();
+	}
+	constexpr auto as_vector() const -> const std::vector<received_header>& {
+		return headers;
+	}
 private:
 	static auto received_header_chain_pool_dtor(void *ptr) -> void {
 		delete static_cast<received_header_chain *>(ptr);
diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c
index de2b130d6..1eb67a430 100644
--- a/src/lua/lua_task.c
+++ b/src/lua/lua_task.c
@@ -31,6 +31,7 @@
 #include "libserver/maps/map_helpers.h"
 
 #include <math.h>
+#include "libmime/received.h"
 
 /***
  * @module rspamd_task
@@ -3139,9 +3140,6 @@ lua_task_get_received_headers (lua_State * L)
 {
 	LUA_TRACE_POINT;
 	struct rspamd_task *task = lua_check_task (L, 1);
-	struct rspamd_received_header *rh;
-	const gchar *proto;
-	guint k = 1;
 
 	if (task) {
 		if (!task->message) {
@@ -3151,115 +3149,15 @@ lua_task_get_received_headers (lua_State * L)
 		}
 
 		if (!lua_task_get_cached (L, task, "received")) {
-			lua_createtable (L, 0, 0);
-
-			DL_FOREACH (MESSAGE_FIELD (task, received), rh) {
-				lua_createtable (L, 0, 10);
-
-				if (rh->hdr && rh->hdr->decoded) {
-					rspamd_lua_table_set (L, "raw", rh->hdr->decoded);
-				}
-
-				lua_pushstring (L, "flags");
-				lua_createtable (L, 0, 3);
-
-				lua_pushstring (L, "artificial");
-				if (rh->flags & RSPAMD_RECEIVED_FLAG_ARTIFICIAL) {
-					lua_pushboolean (L, true);
-				}
-				else {
-					lua_pushboolean (L, false);
-				}
-				lua_settable (L, -3);
-
-				lua_pushstring (L, "authenticated");
-				if (rh->flags & RSPAMD_RECEIVED_FLAG_AUTHENTICATED) {
-					lua_pushboolean (L, true);
-				}
-				else {
-					lua_pushboolean (L, false);
-				}
-				lua_settable (L, -3);
-
-				lua_pushstring (L, "ssl");
-				if (rh->flags & RSPAMD_RECEIVED_FLAG_SSL) {
-					lua_pushboolean (L, true);
-				}
-				else {
-					lua_pushboolean (L, false);
-				}
-				lua_settable (L, -3);
-
-				lua_settable (L, -3);
-
-				if (G_UNLIKELY (rh->from_ip == NULL &&
-						rh->real_ip == NULL &&
-						rh->real_hostname == NULL &&
-						rh->by_hostname == NULL && rh->timestamp == 0 &&
-						rh->for_mbox == NULL)) {
-					lua_rawseti (L, -2, k ++);
 
-					continue;
-				}
-
-				rspamd_lua_table_set (L, "from_hostname", rh->from_hostname);
-				rspamd_lua_table_set (L, "from_ip", rh->from_ip);
-				rspamd_lua_table_set (L, "real_hostname", rh->real_hostname);
-				lua_pushstring (L, "real_ip");
-				rspamd_lua_ip_push (L, rh->addr);
-				lua_settable (L, -3);
-				lua_pushstring (L, "proto");
-
-				switch (rh->flags & RSPAMD_RECEIVED_FLAG_TYPE_MASK) {
-				case RSPAMD_RECEIVED_SMTP:
-					proto = "smtp";
-					break;
-				case RSPAMD_RECEIVED_ESMTP:
-					proto = "esmtp";
-					break;
-				case RSPAMD_RECEIVED_ESMTPS:
-					proto = "esmtps";
-					break;
-				case RSPAMD_RECEIVED_ESMTPA:
-					proto = "esmtpa";
-					break;
-				case RSPAMD_RECEIVED_ESMTPSA:
-					proto = "esmtpsa";
-					break;
-				case RSPAMD_RECEIVED_LMTP:
-					proto = "lmtp";
-					break;
-				case RSPAMD_RECEIVED_IMAP:
-					proto = "imap";
-					break;
-				case RSPAMD_RECEIVED_HTTP:
-					proto = "http";
-					break;
-				case RSPAMD_RECEIVED_LOCAL:
-					proto = "local";
-					break;
-				case RSPAMD_RECEIVED_MAPI:
-					proto = "mapi";
-					break;
-				case RSPAMD_RECEIVED_UNKNOWN:
-				default:
-					proto = "unknown";
-					break;
-				}
-
-				lua_pushstring (L, proto);
-				lua_settable (L, -3);
-
-				lua_pushstring (L, "timestamp");
-				lua_pushinteger (L, rh->timestamp);
-				lua_settable (L, -3);
-
-				rspamd_lua_table_set (L, "by_hostname", rh->by_hostname);
-				rspamd_lua_table_set (L, "for", rh->for_mbox);
-				lua_rawseti (L, -2, k ++);
+			if (rspamd_received_export_to_lua(task, L)) {
+				lua_task_set_cached (L, task, "received", -1);
+			}
+			else {
+				/* no received, preserve compatibility */
+				lua_newtable (L);
+				return 1;
 			}
-
-			lua_task_set_cached (L, task, "received", -1);
 		}
 	}
 	else {


More information about the Commits mailing list