@@ -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); | |||
} |
@@ -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 |
@@ -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); |
@@ -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 { |