I'd like bypassing SMRAZOR milter if messages contain a specific
header, delivering to recipient:
for example if I receive email tagged with "checked out : OK" I don't
want to check this message with SMRAZOR (to know if it's a spam )but
delivering it immediately to recipient.
Can I create a check_rule in sendmail.mc to do it ?
Headers can be inserted by parties not under your control, this is an
unsecured backdoor.
You can do this one of two ways.
1) Using a header ruleset, set a macro if the header is this and passed
the rulese and in the milter add code in xxfi_eoh() callback to return
SMFIS_ACCEPT if that macro is set
2) Use the milter_rrres patch and write rulesets that examine each
header sent to the milter. The rulesets can abort the milter and many
other things.
http://www.jmaimon.com/sendmail/#milter-rrres.v15
See cf/README on how to add a header ruleset into your mc file.
Thanks for your time that you spend to answer to my questions.
You will need to learn a bit about sendmail maps and rulesets.
You can read up on from the sendmail source
doc/op
You will also need to configure sendmail to send the macro to the
milter.
I have similar problem, but i want to skip spam checking by regular
expressions of networks and domains. I extended sendmail and libmilter
for extra command - "skip filter". The idea: milter checks controlled
by some external filter which could command to skip any specific milter
going after himself. Patch quite rough, but works fine for a month (avg
load: about 0.5 msg/min on 2xPPro with 320M RAM). SPAM checker is
amavisd-new+spamassassin.
Here 2 patchsets:
1. sendmail/libmilter itself
2. milter-regex (i'am using it as "dispatcher" doing "skip" commands)
--- include/libmilter/mfapi.h.orig Sat Aug 26 18:42:06 2006
+++ include/libmilter/mfapi.h Wed Nov 15 14:19:51 2006
@@ -464,7 +464,7 @@
** Quarantine an envelope
**
** SMFICTX *ctx; Opaque context structure
-** char *reason: explanation
+** char *reason; explanation
*/
LIBMILTER_API int smfi_quarantine __P((SMFICTX *ctx, char *reason));
@@ -485,6 +485,15 @@
*/
LIBMILTER_API void *smfi_getpriv __P((SMFICTX *));
+
+/*
+** Set milter to skip next time
+**
+** SMFICTX *ctx; Opaque context structure
+** mfi_skipname; name of filter to skip
+*/
+
+LIBMILTER_API int smfi_skip __P((SMFICTX *, char *));
#ifdef __cplusplus
}
--- include/libmilter/mfdef.h.orig Fri Mar 31 04:06:02 2006
+++ include/libmilter/mfdef.h Tue Nov 14 16:12:38 2006
@@ -71,6 +71,7 @@
# define SMFIR_INSHEADER 'i' /* insert header */
# define SMFIR_REPLYCODE 'y' /* reply code etc */
# define SMFIR_QUARANTINE 'q' /* quarantine */
+# define SMFIR_MFISKIP 's' /* skip other filter */
/* What the MTA can send/filter wants in protocol */
# define SMFIP_NOCONNECT 0x00000001L /* MTA should not send connect
info */
--- libmilter/smfi.c.orig Fri Mar 31 04:06:02 2006
+++ libmilter/smfi.c Wed Nov 15 13:08:21 2006
@@ -646,3 +646,45 @@
return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
}
+
+/*
+** SMFI_SKIP -- send "skip filter" message to the MTA to prevent
message
+** from processing by particular filter next time
+**
+** Parameters:
+** ctx -- Opaque context structure
+** mfi_skipname -- name of filter to skip
+**
+** Return value:
+** MI_SUCCESS/MI_FAILURE
+*/
+
+int
+smfi_skip(ctx, mfi_skipname)
+ SMFICTX *ctx;
+ char *mfi_skipname;
+{
+ size_t len;
+ int r;
+ char *buf;
+ struct timeval timeout;
+
+ if (mfi_skipname == NULL)
+ return MI_FAILURE;
+
+ timeout.tv_sec = ctx->ctx_timeout;
+ timeout.tv_usec = 0;
+
+ len = strlen(mfi_skipname) + 1;
+ buf = malloc(len);
+ if (buf == NULL)
+ return MI_FAILURE;
+
+ (void) memcpy(buf, mfi_skipname, len);
+
+ r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_MFISKIP, buf, len);
+
+ free(buf);
+
+ return r;
+}
--- src/milter.c.orig Wed Mar 29 13:34:35 2006
+++ src/milter.c Tue Dec 5 09:25:27 2006
@@ -1900,6 +1900,7 @@
{
char rcmd;
ssize_t rlen;
+ ssize_t sm_i; /* mfi_skipmap counter */
unsigned long skipflag;
#if _FFR_MILTER_NOHDR_RESP
unsigned long norespflag = 0;
@@ -2067,6 +2068,19 @@
m->mf_name, action);
break;
+ case SMFIR_MFISKIP:
+ for (sm_i = 0; InputFilters[sm_i] != NULL; ++sm_i)
+ {
+ if (sm_strcasecmp(InputFilters[sm_i]->mf_name, response) == 0)
+ e->mfi_skipmap[sm_i] = 1;
+ }
+ if (MilterLogLevel > 12)
+ {
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, mfiskip=%s",
+ m->mf_name, action, response);
+ }
+ /* FALLTHROUGH */
+
case SMFIR_CONTINUE:
/* if MAIL command is ok, filter is in message state */
if (command == SMFIC_MAIL)
@@ -2158,7 +2172,20 @@
if (MilterLogLevel > 21)
tn = curtime();
- response = milter_send_command(m, command, data, sz, e, state);
+ if (e->mfi_skipmap[i])
+ {
+ if (MilterLogLevel > 12)
+ {
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter (%s): skipped", m->mf_name);
+ }
+ continue;
+ }
+ else
+ {
+ response = milter_send_command(m, command, data,
+ sz, e, state);
+ }
if (MilterLogLevel > 21)
{
@@ -3725,7 +3752,7 @@
bool dfopen = false; /* data file open for writing? */
bool newfilter; /* reset on each new filter */
char rcmd;
- int i;
+ int i, sm_i;
int save_errno;
char *response = NULL;
time_t eomsent;
@@ -3762,6 +3789,17 @@
*state = SMFIR_CONTINUE;
newfilter = true;
+ /* check if filter set to be skipped */
+ if (e->mfi_skipmap[i])
+ {
+ if (MilterLogLevel > 12)
+ {
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter (%s): skipped", m->mf_name);
+ }
+ continue;
+ }
+
/* previous problem? */
if (m->mf_state == SMFS_ERROR)
{
@@ -3879,6 +3917,19 @@
m->mf_name);
*state = rcmd;
m->mf_state = SMFS_DONE;
+ break;
+
+ case SMFIR_MFISKIP:
+ for (sm_i = 0; InputFilters[sm_i] != NULL; ++sm_i)
+ {
+ if (sm_strcasecmp(InputFilters[sm_i]->mf_name, response) == 0)
+ e->mfi_skipmap[sm_i] = 1;
+ }
+ if (MilterLogLevel > 12)
+ {
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, mfiskip=%s",
+ m->mf_name, response);
+ }
break;
case SMFIR_CONTINUE:
--- src/sendmail.h.orig Sat Aug 26 18:42:08 2006
+++ src/sendmail.h Sun Nov 19 22:28:16 2006
@@ -911,6 +911,7 @@
long e_deliver_by; /* deliver by */
int e_dlvr_flag; /* deliver by flag */
SM_RPOOL_T *e_rpool; /* resource pool for this envelope */
+ ssize_t mfi_skipmap[MAXFILTERS]; /* filter map to skip */
};
/* values for e_flags */
--- eval.h.orig Fri Oct 29 21:48:41 2004
+++ eval.h Tue Nov 14 17:03:19 2006
@@ -40,7 +40,7 @@
COND_HEADER, COND_BODY, COND_MAX };
enum { EXPR_AND, EXPR_OR, EXPR_NOT, EXPR_COND };
enum { ACTION_REJECT, ACTION_TEMPFAIL, ACTION_QUARANTINE,
- ACTION_DISCARD, ACTION_ACCEPT };
+ ACTION_DISCARD, ACTION_ACCEPT, ACTION_MFISKIP };
struct expr;
--- parse.y.orig Fri Oct 29 21:48:42 2004
+++ parse.y Wed Nov 15 12:12:02 2006
@@ -75,7 +75,7 @@
%}
%token ERROR STRING
-%token ACCEPT REJECT TEMPFAIL DISCARD QUARANTINE
+%token ACCEPT REJECT TEMPFAIL DISCARD QUARANTINE MFISKIP
%token CONNECT HELO ENVFROM ENVRCPT HEADER BODY
%token AND OR NOT
%type <v.string> STRING
@@ -146,6 +146,14 @@
YYERROR;
}
}
+ | MFISKIP STRING {
+ $$ = create_action(rs, ACTION_MFISKIP, $2);
+ if ($$ == NULL) {
+ yyerror("yyparse: create_action");
+ YYERROR;
+ }
+ free($2);
+ }
;
expr_l : expr {
@@ -287,6 +295,7 @@
{ "envrcpt", ENVRCPT },
{ "header", HEADER },
{ "helo", HELO },
+ { "mfiskip", MFISKIP },
{ "not", NOT },
{ "or", OR },
{ "quarantine", QUARANTINE },
--- milter-regex.c.orig Wed Nov 15 12:23:41 2006
+++ milter-regex.c Wed Nov 15 12:24:49 2006
@@ -180,6 +180,9 @@
smfi_setreply(ctx, RCODE_TEMPFAIL, XCODE_TEMPFAIL,
(char *)action->msg) != MI_SUCCESS)
msg(LOG_ERR, context, "smfi_setreply");
+ if (action->type == ACTION_MFISKIP &&
+ smfi_skip(ctx, (char *)action->msg) != MI_SUCCESS)
+ msg(LOG_ERR, context, "smfi_skip");
return (result);
}
--- milter-regex.8.orig Wed Nov 29 17:12:46 2006
+++ milter-regex.8 Wed Nov 29 17:13:34 2006
@@ -140,6 +140,10 @@
Subsequent matching rules cause the mail to be accepted without
further rule evaluation.
Can be used for whitelist criteria.
+.It mfiskip <milter>
+Matching rules cause specified mail filter to be skipped next time
+for envelope being in process. Milter names set with INPUT_MAIL_FILTER
+1st parameter.
.El
.Pp
A command is followed by one or more expressions, each causing
> I have similar problem, but i want to skip spam checking by regular
> expressions of networks and domains. I extended sendmail and libmilter
> for extra command - "skip filter". The idea: milter checks controlled
> by some external filter which could command to skip any specific milter
> going after himself.
This is an interesting approach, but not very generic.
I would attempt to accomplish the same thing with a sendmail/libmilter
patched by milter-rrres by either
A)
1 - Have the milter call into sendmail with smfi_sm_class() to control
the contents of a sendmail class
2 - Have sendmail control subsequent milters with rulesets that can
compare milter names against the class and abort the milter or skip the
particular command,
B)
1 - Use a regex map in sendmail.mc
2 - Write a ruleset in sendmail.mc that accomplishes your objective
3 - Use milter-rrres patch so that you can control milters with that
ruleset
C)
1 - If for some reason the regex map isnt enough for you, use the
compare map
2 - Write a ruleset in sendmail.mc that accomplishes your objectives
3 - Use milter-rrres patch so that you can control milters with that
ruleset
D)
1 - Use a tag in sendmail access map such as
SkipMilters:127.0.0.1 milter1,milter2,milter3
2 - Write a rulset in sendmail.mc that lookups the access map tags and
sees if {milter_name} macro matches the returned value
3 - Use milter-rrres so you can control the milter with that ruleset.
Here are links to the relevant patches:
http://www.jmaimon.com/sendmail/patches/milter-rrres.v15.tar.gz
http://www.jmaimon.com/sendmail/patches/milter-rrres.Changes.v15.txt
http://www.jmaimon.com/sendmail/#milter-rrres.v15
http://www.jmaimon.com/sendmail/patches/compare-map.v2.81304.patch
http://www.jmaimon.com/sendmail/
If you have an outline for specific ruleset objectives, I may be able
to help you write it.
> 1 - Have the milter call into sendmail with smfi_sm_class() to control
> the contents of a sendmail class
Oops. Make that a macro. milter-rrres doesnt delete class members
(yet), just adds.
I see your point now. You prefer more MTA-centric and ruleset driven
way.
Well, yes, mine was more... straight. Simple and fast to implement.
> If you have an outline for specific ruleset objectives, I may be able
> to help you write it.
This means patching base sendmail anyway. Plus ruleset magic... and
i'am not too good at this. :)
Thanks for help.
This is not only possible, it has happened. The Habeas haiku header
nonsense comes to mind. Unless this tag is changed often, has a
time-to-live, and never repeats, it sounds like just another bad idea.
dp