The following diff introduces the junk action which allows builtin
filters to junk a session or transaction.

The following would junk a session if it doesn't have rdns when it
reaches the helo filtering hook:

    match "check-rdns" phase helo match !rdns junk


Currently this is not doable so builtin filters may only accept or
throw away a session or transaction, whereas with this diff you'll
be able to automatically classify in Junk folder with the junk mda
option:

    action "local_users" maildir junk


This also allows simplifying proc filters that want to junk as the
current method requires registering for data-line and injecting an
X-Spam: Yes header, while this can now be handled by returning the
junk filter response at any phase and letting smtpd prefill header




Index: lka_filter.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/lka_filter.c,v
retrieving revision 1.44
diff -u -p -r1.44 lka_filter.c
--- lka_filter.c        29 Aug 2019 08:49:55 -0000      1.44
+++ lka_filter.c        2 Sep 2019 20:04:37 -0000
@@ -56,6 +56,7 @@ static int    filter_builtins_mail_from(str
 static int     filter_builtins_rcpt_to(struct filter_session *, struct filter 
*, uint64_t, const char *);
 
 static void    filter_result_proceed(uint64_t);
+static void    filter_result_junk(uint64_t);
 static void    filter_result_rewrite(uint64_t, const char *);
 static void    filter_result_reject(uint64_t, const char *);
 static void    filter_result_disconnect(uint64_t, const char *);
@@ -479,6 +480,11 @@ lka_filter_process_response(const char *
                        fatalx("Unexpected parameter after proceed: %s", line);
                filter_protocol_next(token, reqid, 0);
                return;
+       } else if (strcmp(response, "junk") == 0) {
+               if (parameter != NULL)
+                       fatalx("Unexpected parameter after junk: %s", line);
+               filter_result_junk(reqid);
+               return;
        } else {
                if (parameter == NULL)
                        fatalx("Missing parameter: %s", line);
@@ -574,6 +580,15 @@ filter_protocol_internal(struct filter_s
                        filter_result_disconnect(reqid, 
filter->config->disconnect);
                        return;
                }
+               else if (filter->config->junk) {
+                       log_trace(TRACE_FILTERS, "%016"PRIx64" filters protocol 
phase=%s, "
+                           "resume=%s, action=junk, filter=%s, query=%s",
+                           fs->id, phase_name, resume ? "y" : "n",
+                           filter->name,
+                           param);
+                       filter_result_junk(reqid);
+                       return;
+               }
                else {
                        log_trace(TRACE_FILTERS, "%016"PRIx64" filters protocol 
phase=%s, "
                            "resume=%s, action=reject, filter=%s, query=%s, 
response=%s",
@@ -759,6 +774,15 @@ filter_result_proceed(uint64_t reqid)
        m_create(p_pony, IMSG_FILTER_SMTP_PROTOCOL, 0, 0, -1);
        m_add_id(p_pony, reqid);
        m_add_int(p_pony, FILTER_PROCEED);
+       m_close(p_pony);
+}
+
+static void
+filter_result_junk(uint64_t reqid)
+{
+       m_create(p_pony, IMSG_FILTER_SMTP_PROTOCOL, 0, 0, -1);
+       m_add_id(p_pony, reqid);
+       m_add_int(p_pony, FILTER_JUNK);
        m_close(p_pony);
 }
 
Index: lka_report.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/lka_report.c,v
retrieving revision 1.27
diff -u -p -r1.27 lka_report.c
--- lka_report.c        29 Aug 2019 07:23:18 -0000      1.27
+++ lka_report.c        2 Sep 2019 20:04:38 -0000
@@ -428,6 +428,9 @@ lka_report_smtp_filter_response(const ch
        case FILTER_PROCEED:
                response_name = "proceed";
                break;
+       case FILTER_JUNK:
+               response_name = "junk";
+               break;
        case FILTER_REWRITE:
                response_name = "rewrite";
                break;
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.259
diff -u -p -r1.259 parse.y
--- parse.y     25 Aug 2019 03:40:45 -0000      1.259
+++ parse.y     2 Sep 2019 20:04:38 -0000
@@ -1297,6 +1297,9 @@ REJECT STRING {
 | REWRITE STRING {
        filter_config->rewrite = $2;
 }
+| JUNK {
+       filter_config->junk = 1;
+}
 ;
 
 filter_phase_check_fcrdns:
Index: smtp_session.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtp_session.c,v
retrieving revision 1.408
diff -u -p -r1.408 smtp_session.c
--- smtp_session.c      28 Aug 2019 15:50:36 -0000      1.408
+++ smtp_session.c      2 Sep 2019 20:04:39 -0000
@@ -126,6 +126,8 @@ struct smtp_tx {
        int                      rcvcount;
        int                      has_date;
        int                      has_message_id;
+
+       uint8_t                  junk;
 };
 
 struct smtp_session {
@@ -154,6 +156,8 @@ struct smtp_session {
        enum smtp_command        last_cmd;
        enum filter_phase        filter_phase;
        const char              *filter_param;
+
+       uint8_t                  junk;
 };
 
 #define ADVERTISE_TLS(s) \
@@ -970,7 +974,8 @@ smtp_session_imsg(struct mproc *p, struc
                m_msg(&m, imsg);
                m_get_id(&m, &reqid);
                m_get_int(&m, &filter_response);
-               if (filter_response != FILTER_PROCEED)
+               if (filter_response != FILTER_PROCEED &&
+                   filter_response != FILTER_JUNK)
                        m_get_string(&m, &filter_param);
                else
                        filter_param = NULL;
@@ -998,9 +1003,17 @@ smtp_session_imsg(struct mproc *p, struc
                                smtp_proceed_rollback(s, NULL);
                        break;
 
+
+               case FILTER_JUNK:
+                       if (s->tx)
+                               s->tx->junk = 1;
+                       else
+                               s->junk = 1;
+                       /* fallthrough */
+
                case FILTER_PROCEED:
                        filter_param = s->filter_param;
-                       /* fallthrough*/
+                       /* fallthrough */
 
                case FILTER_REWRITE:
                        report_smtp_filter_response("smtp-in", s->id, 
s->filter_phase,
@@ -2815,6 +2828,9 @@ smtp_message_begin(struct smtp_tx *tx)
        smtp_reply(s, "354 Enter mail, end with \".\""
            " on a line by itself");    
        
+       if (s->junk || (s->tx && s->tx->junk))
+               m_printf(tx, "X-Spam: Yes\n");
+
        m_printf(tx, "Received: ");
        if (!(s->listener->flags & F_MASK_SOURCE)) {
                m_printf(tx, "from %s (%s [%s])",
Index: smtpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.conf.5,v
retrieving revision 1.221
diff -u -p -r1.221 smtpd.conf.5
--- smtpd.conf.5        17 Aug 2019 14:43:21 -0000      1.221
+++ smtpd.conf.5        2 Sep 2019 20:04:39 -0000
@@ -348,6 +348,15 @@ to disconnect session with
 Phase and matching conditions are documented in a specific section,
 see
 .Sx BUILTIN FILTERING .
+.It Ic filter Ar filter-name Ic phase Ar phase-name Ic match Ar conditions Ic 
junk
+Register builtin filter
+.Ar filter-name
+matching
+.Ar conditions
+to mark a session or a transaction as junk.
+Phase and matching conditions are documented in a specific section,
+see
+.Sx BUILTIN FILTERING .
 .It Ic filter Ar filter-name Ic phase Ar phase-name Ic match Ar conditions Ic 
reject Ar message
 Register builtin filter
 .Ar filter-name
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.633
diff -u -p -r1.633 smtpd.h
--- smtpd.h     28 Aug 2019 15:50:36 -0000      1.633
+++ smtpd.h     2 Sep 2019 20:04:40 -0000
@@ -1046,6 +1046,7 @@ struct filter_config {
        char                           *reject;
        char                           *disconnect;
        char                           *rewrite;
+       uint8_t                         junk;
        char                           *proc;
 
        const char                    **chain;
@@ -1095,6 +1096,7 @@ enum filter_status {
        FILTER_REWRITE,
        FILTER_REJECT,
        FILTER_DISCONNECT,
+       FILTER_JUNK,
 };
 
 enum ca_resp_status {

Reply via email to