]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Implement milter protocol scan reply
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 8 May 2017 12:17:33 +0000 (13:17 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 8 May 2017 12:17:33 +0000 (13:17 +0100)
src/libserver/milter.c
src/libserver/milter.h
src/libserver/milter_internal.h
src/rspamd_proxy.c

index 6beadad7ee481fb4990fe8d37588333cf8b351f1..6f67a03fff692f69c1e17cf69a41ac70f94772b6 100644 (file)
@@ -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
index 3786f3b7bd1397f037d90a4fa2526f1686fe06e1..869bc892dda3bfa11430f5cf57fbc7943ea0e809 100644 (file)
@@ -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
index 4c01b8624e485567c02eb2e7af22b806c0004a53..0008967ecba4669f6599a044fdacb78e89c3e40a 100644 (file)
@@ -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
index 7ba8759d720d95d4f2e70489a665bddb0bb056a7..bb20306c59c22f23a9fa084992fa0c25bf614737 100644 (file)
@@ -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);
        }