From: Vsevolod Stakhov Date: Mon, 8 May 2017 12:17:33 +0000 (+0100) Subject: [Feature] Implement milter protocol scan reply X-Git-Tag: 1.6.0~251 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=5f2ef07094e6c0b4116f4cc1122c8fe95ee2a651;p=rspamd.git [Feature] Implement milter protocol scan reply --- diff --git a/src/libserver/milter.c b/src/libserver/milter.c index 6beadad7e..6f67a03ff 100644 --- a/src/libserver/milter.c +++ b/src/libserver/milter.c @@ -25,6 +25,7 @@ #include "libutil/http.h" #include "libutil/http_private.h" #include "libserver/protocol_internal.h" +#include "libmime/filter.h" #include "utlist.h" #define msg_err_milter(...) rspamd_default_log_function(G_LOG_LEVEL_CRITICAL, \ @@ -1226,4 +1227,192 @@ rspamd_milter_update_userdata (struct rspamd_milter_session *session, priv->ud = ud; return prev_ud; +} + +static void +rspamd_milter_process_rmilter_block (struct rspamd_milter_session *session, + const ucl_object_t *obj) +{ + const ucl_object_t *elt, *cur, *cur_elt; + ucl_object_iter_t it; + GString *hname, *hvalue; + gint nhdr; + + if (obj && ucl_object_type (obj) == UCL_OBJECT) { + elt = ucl_object_lookup (obj, "remove_headers"); + /* + * remove_headers: {"name": 1, ... } + * where number is the header's position starting from '1' + */ + if (elt && ucl_object_type (elt) == UCL_OBJECT) { + it = NULL; + + while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) { + if (ucl_object_type (cur) == UCL_INT) { + nhdr = ucl_object_toint (cur); + hname = g_string_new (ucl_object_key (cur)); + hvalue = g_string_new (""); + + if (nhdr >= 1) { + rspamd_milter_send_action (session, + RSPAMD_MILTER_CHGHEADER, + nhdr, hname, hvalue); + } + + g_string_free (hname, TRUE); + g_string_free (hvalue, TRUE); + } + } + } + + elt = ucl_object_lookup (obj, "add_headers"); + /* + * add_headers: {"name": "value", ... } + * name could have multiple values + */ + if (elt && ucl_object_type (elt) == UCL_OBJECT) { + it = NULL; + + while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) { + LL_FOREACH (cur, cur_elt) { + if (ucl_object_type (cur_elt) == UCL_STRING) { + hname = g_string_new (ucl_object_key (cur)); + hvalue = g_string_new (ucl_object_tostring (cur_elt)); + + rspamd_milter_send_action (session, + RSPAMD_MILTER_ADDHEADER, + hname, hvalue); + g_string_free (hname, TRUE); + g_string_free (hvalue, TRUE); + } + } + } + } + } +} + +void +rspamd_milter_send_task_results (struct rspamd_milter_session *session, + const ucl_object_t *results) +{ + const ucl_object_t *elt; + struct rspamd_milter_private *priv = session->priv; + gint action = METRIC_ACTION_REJECT; + rspamd_fstring_t *xcode, *rcode, *reply = NULL; + GString *hname, *hvalue; + + if (results == NULL) { + msg_err_milter ("cannot find scan results, tempfail"); + rspamd_milter_send_action (session, RSPAMD_MILTER_TEMPFAIL); + + return; + } + + elt = ucl_object_lookup (results, "action"); + + if (!elt) { + msg_err_milter ("cannot find action in results, tempfail"); + rspamd_milter_send_action (session, RSPAMD_MILTER_TEMPFAIL); + + return; + } + + rspamd_action_from_str (ucl_object_tostring (elt), &action); + + elt = ucl_object_lookup (results, "messages"); + if (elt) { + const ucl_object_t *smtp_res; + const gchar *msg; + gsize len = 0; + + smtp_res = ucl_object_lookup (elt, "smtp_message"); + + if (smtp_res) { + msg = ucl_object_tolstring (smtp_res, &len); + reply = rspamd_fstring_new_init (msg, len); + } + } + + /* Deal with milter headers */ + elt = ucl_object_lookup (results, "rmilter"); + if (elt) { + rspamd_milter_process_rmilter_block (session, elt); + } + + /* DKIM-Signature */ + elt = ucl_object_lookup (results, "dkim-signature"); + if (elt) { + hname = g_string_new (RSPAMD_MILTER_DKIM_HEADER); + hvalue = g_string_new (ucl_object_tostring (elt)); + + rspamd_milter_send_action (session, RSPAMD_MILTER_ADDHEADER, + hname, hvalue); + g_string_free (hname, TRUE); + g_string_free (hvalue, TRUE); + } + + switch (action) { + case METRIC_ACTION_REJECT: + rcode = rspamd_fstring_new_init (RSPAMD_MILTER_RCODE_REJECT, + sizeof (RSPAMD_MILTER_RCODE_REJECT) - 1); + xcode = rspamd_fstring_new_init (RSPAMD_MILTER_XCODE_REJECT, + sizeof (RSPAMD_MILTER_XCODE_REJECT) - 1); + + if (!reply) { + reply = rspamd_fstring_new_init (RSPAMD_MILTER_REJECT_MESSAGE, + sizeof (RSPAMD_MILTER_REJECT_MESSAGE) - 1); + } + + rspamd_milter_set_reply (session, rcode, xcode, reply); + rspamd_milter_send_action (session, RSPAMD_MILTER_REJECT); + + break; + case METRIC_ACTION_SOFT_REJECT: + case METRIC_ACTION_GREYLIST: + rcode = rspamd_fstring_new_init (RSPAMD_MILTER_RCODE_TEMPFAIL, + sizeof (RSPAMD_MILTER_RCODE_TEMPFAIL) - 1); + xcode = rspamd_fstring_new_init (RSPAMD_MILTER_XCODE_TEMPFAIL, + sizeof (RSPAMD_MILTER_XCODE_TEMPFAIL) - 1); + + if (!reply) { + reply = rspamd_fstring_new_init (RSPAMD_MILTER_TEMPFAIL_MESSAGE, + sizeof (RSPAMD_MILTER_TEMPFAIL_MESSAGE) - 1); + } + + rspamd_milter_set_reply (session, rcode, xcode, reply); + rspamd_milter_send_action (session, RSPAMD_MILTER_REJECT); + break; + + case METRIC_ACTION_REWRITE_SUBJECT: + elt = ucl_object_lookup (results, "subject"); + + if (elt) { + hname = g_string_new ("Subject"); + hvalue = g_string_new (ucl_object_tostring (elt)); + + rspamd_milter_send_action (session, RSPAMD_MILTER_CHGHEADER, + (guint32)1, hname, hvalue); + g_string_free (hname, TRUE); + g_string_free (hvalue, TRUE); + } + + rspamd_milter_send_action (session, RSPAMD_MILTER_ACCEPT); + break; + + case METRIC_ACTION_ADD_HEADER: + hname = g_string_new (RSPAMD_MILTER_SPAM_HEADER); + hvalue = g_string_new ("Yes"); + + rspamd_milter_send_action (session, RSPAMD_MILTER_CHGHEADER, + (guint32)1, hname, hvalue); + g_string_free (hname, TRUE); + g_string_free (hvalue, TRUE); + rspamd_milter_send_action (session, RSPAMD_MILTER_ACCEPT); + break; + + case METRIC_ACTION_NOACTION: + default: + rspamd_milter_send_action (session, RSPAMD_MILTER_ACCEPT); + break; + } } \ No newline at end of file diff --git a/src/libserver/milter.h b/src/libserver/milter.h index 3786f3b7b..869bc892d 100644 --- a/src/libserver/milter.h +++ b/src/libserver/milter.h @@ -19,6 +19,7 @@ #include "config.h" #include "fstring.h" #include "addr.h" +#include "contrib/libucl/ucl.h" #include "ref.h" enum rspamd_milter_reply { @@ -134,4 +135,12 @@ struct rspamd_milter_session * rspamd_milter_session_ref ( struct rspamd_http_message * rspamd_milter_to_http ( struct rspamd_milter_session *session); +/** + * Sends task results to the + * @param session + * @param results + */ +void rspamd_milter_send_task_results (struct rspamd_milter_session *session, + const ucl_object_t *results); + #endif diff --git a/src/libserver/milter_internal.h b/src/libserver/milter_internal.h index 4c01b8624..0008967ec 100644 --- a/src/libserver/milter_internal.h +++ b/src/libserver/milter_internal.h @@ -139,4 +139,13 @@ enum rspamd_milter_connect_proto { #define RSPAMD_MILTER_MESSAGE_CHUNK 65536 +#define RSPAMD_MILTER_RCODE_REJECT "554" +#define RSPAMD_MILTER_RCODE_TEMPFAIL "451" +#define RSPAMD_MILTER_RCODE_LATER "452" +#define RSPAMD_MILTER_XCODE_REJECT "5.7.1" +#define RSPAMD_MILTER_XCODE_TEMPFAIL "4.7.1" +#define RSPAMD_MILTER_REJECT_MESSAGE "Spam message rejected" +#define RSPAMD_MILTER_TEMPFAIL_MESSAGE "Try again later" +#define RSPAMD_MILTER_SPAM_HEADER "X-Spam" +#define RSPAMD_MILTER_DKIM_HEADER "DKIM-Signature" #endif diff --git a/src/rspamd_proxy.c b/src/rspamd_proxy.c index 7ba8759d7..bb20306c5 100644 --- a/src/rspamd_proxy.c +++ b/src/rspamd_proxy.c @@ -1266,12 +1266,9 @@ proxy_backend_master_finish_handler (struct rspamd_http_connection *conn, rspamd_upstream_ok (bk_conn->up); if (session->client_milter_conn) { - /* - * TODO: convert reply to milter reply - */ nsession = proxy_session_refresh (session); - rspamd_milter_send_action (nsession->client_milter_conn, - RSPAMD_MILTER_ACCEPT); + rspamd_milter_send_task_results (nsession->client_milter_conn, + session->master_conn->results); REF_RELEASE (session); rspamd_http_message_free (msg); } @@ -1323,12 +1320,9 @@ rspamd_proxy_scan_self_reply (struct rspamd_task *task) } if (session->client_milter_conn) { - /* - * TODO: convert reply to milter reply - */ nsession = proxy_session_refresh (session); - rspamd_milter_send_action (nsession->client_milter_conn, - RSPAMD_MILTER_ACCEPT); + rspamd_milter_send_task_results (nsession->client_milter_conn, + session->master_conn->results); rspamd_http_message_free (msg); REF_RELEASE (session); }