From d79fdd8a405ddc495fa1245cc9c22ec119f7787d Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 5 Oct 2021 12:13:21 +0100 Subject: [PATCH] [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 #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({ - {"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({ + {"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(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::type; + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +constexpr received_flags operator |=(received_flags &lhs, const received_flags rhs) +{ + using ut = std::underlying_type::type; + lhs = static_cast(static_cast(lhs) | static_cast(rhs)); + return lhs; +} + +constexpr received_flags operator &(received_flags lhs, received_flags rhs) +{ + using ut = std::underlying_type::type; + return static_cast(static_cast(lhs) & static_cast(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& { + return headers; + } private: static auto received_header_chain_pool_dtor(void *ptr) -> void { delete static_cast(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 +#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 { -- 2.39.5