[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Recipient filtering...
From: |
Joe Maimon |
Subject: |
Recipient filtering... |
Date: |
Mon, 20 Sep 2004 12:13:04 -0400 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040616 Mnenhy/0.6.0.101 |
Hello all,
I havent been a list member long and have not spent much time searching
archives, so forgive me if this is somebody elses old news already.
I recently decided that I did not want to waste spamassassin resources
on recipients sendmail had skipped all RBL and other spam check on due
to "Spam: FRIEND" checks.(being as most of the spams would have been
caught and rejected by the skipped checks)
Since I could not find anyway to have sendmail selectively not launch a
milter connection (I did start looking into patching sendmail to use
rulesets for milter connections...if anybody is interested) I decided to
hack in a filter to spamass-milt.
Attached is my (amatuer) attempts as a patch against 0.2.0 and a patch
that will fit into the debian package. Also attached is a bash script
that I use as a filter.
I probably should have tried this agains cvs....I guess I will check
that out next.
Seems to work stable here for a few hours, but is by no means a polished
and finished piece of work.
This patch adds command line argument -R which accepts as an argument a
program that will be called with a parameter of recpient email adrress,
once per recipient.
(Yes i know, not the most resource cheap way)
When the program exits, the exit code of 0 is taken to mean "filtered
successfully".
If there are no un-filtered recipients, spamass-milter will return to
sendmail a SMFIS_ACCEPT at the start of mlfi_header.
Any and all feedback is most welcome.
Joe
Only in spamass-milter-0.2.0-orig/contrib: spamass-milter.spec
diff -ur spamass-milter-0.2.0-orig/spamass-milter.cpp
spamass-milter-0.2.0/spamass-milter.cpp
--- spamass-milter-0.2.0-orig/spamass-milter.cpp 2003-06-26
11:10:44.000000000 -0400
+++ spamass-milter-0.2.0/spamass-milter.cpp 2004-09-20 10:42:24.000000000
-0400
@@ -150,13 +150,15 @@
};
const char *const debugstrings[] = {
- "ALL", "FUNC", "POLL", "UORI", "STR", "MISC", "NET", "SPAMC",
+ "ALL", "FUNC", "POLL", "UORI", "STR", "MISC", "NET", "SPAMC", "RCPT",
NULL
};
int flag_debug = (1<<D_ALWAYS);
bool flag_reject = false;
int reject_score = -1;
+bool flag_rcpt_filter = false;
+char *rcpt_filter = NULL;
bool dontmodify = false;
bool flag_sniffuser = false;
char *defaultuser;
@@ -174,7 +176,7 @@
main(int argc, char* argv[])
{
int c, err = 0;
- const char *args = "p:fd:mr:u:D:i:b:B:";
+ const char *args = "p:fd:mr:R:u:D:i:b:B:";
char *sock = NULL;
bool dofork = false;
@@ -207,6 +209,10 @@
flag_reject = true;
reject_score = atoi(optarg);
break;
+ case 'R':
+ flag_rcpt_filter = true;
+ rcpt_filter = optarg;
+ break;
case 'u':
flag_sniffuser = true;
defaultuser = strdup(optarg);
@@ -259,6 +265,7 @@
cout << " -m: don't modify body, Content-type: or Subject:" << endl;
cout << " -r nn: reject messages with a score >= nn with an SMTP
error.\n"
" use -1 to reject any messages tagged by SA." << endl;
+ cout << " -R cmd: filter out recipients with zero exit status."<< endl;
cout << " -u defaultuser: pass the recipient's username to spamc.\n"
" Uses 'defaultuser' if there are multiple recipients."
<< endl;
cout << " -- spamc args: pass the remaining flags to spamc." << endl;
@@ -576,6 +583,7 @@
}
sctx->assassin = NULL;
sctx->helo = NULL;
+ sctx->rcpts = 0;
/* store a pointer to it with setpriv */
smfi_setpriv(ctx, sctx);
@@ -718,6 +726,54 @@
{
assassin->recipients.push_back( *rcpt ); // XXX verify that
this worked
}
+
+ sctx->rcpts++;
+ if(flag_rcpt_filter && rcpt_filter)
+ {
+ int rcpt_filter_result = 0;
+ int size = 0;
+ char *cmd_buffer = NULL;
+ char *tmp_rcpt = NULL;
+ char * queue_id = smfi_getsymval(ctx,"i");
+
+ debug(D_RCPT,"%s: rcpt_filter",queue_id);
+
+
+ if((tmp_rcpt = strdup(envrcpt[0])) != NULL)
+ {
+ tmp_rcpt[strlen(tmp_rcpt)-1] = '\0';
+ size = strlen(rcpt_filter);
+ tmp_rcpt++;
+ size += strlen(tmp_rcpt);
+ cmd_buffer = (char *) malloc(size+10);
+ }
+ if(cmd_buffer)
+ {
+ debug(D_RCPT,"%s: rcpt_filter, malloc succeeded",
queue_id);
+ sprintf(cmd_buffer,"%s %s",rcpt_filter, tmp_rcpt );
+ cmd_buffer[size+2] = '\0';
+ debug(D_RCPT, "%s: rcpt_filter, filter string <%s>",
queue_id, cmd_buffer);
+
+ rcpt_filter_result = system(cmd_buffer);
+ if(!rcpt_filter_result)
+ {
+ debug(D_RCPT,"%s: rcpt_filter, removing rcpt",
queue_id);
+ sctx->rcpts--;
+ } else
+ debug(D_RCPT,"%s: rcpt_filter, leaving rcpt",
queue_id);
+
+ } else
+ debug(D_RCPT,"%s: rcp_filter, malloc failed", queue_id);
+
+ if(cmd_buffer)
+ free(cmd_buffer);
+ if(tmp_rcpt)
+ {
+ tmp_rcpt--;
+ free(tmp_rcpt);
+ }
+
+ }
return SMFIS_CONTINUE;
}
@@ -740,6 +796,21 @@
SpamAssassin* assassin = ((struct context *)smfi_getpriv(ctx))->assassin;
debug(D_FUNC, "mlfi_header: enter");
+ {
+ struct context * sctx = (struct context *) smfi_getpriv(ctx);
+ char * queue_id = smfi_getsymval(ctx,"i");
+ if(flag_rcpt_filter && !sctx->rcpts)
+ {
+ debug(D_RCPT,"%s: rcpt_filter, accepting message without
processing");
+ mlfi_abort(ctx); // For lack of specific cleanup
+ debug(D_FUNC, "%s: mlfi_header: rcpt_filter leave", queue_id);
+ return SMFIS_ACCEPT;
+ } else
+ debug(D_RCPT, "%s: rcpt_filter, processing message", queue_id);
+
+ debug(D_FUNC, "%s: mlfi_header: rcpt_filter leave", queue_id);
+ }
+
// Check if the SPAMC program has already been run, if not we run it.
if ( !(assassin->connected) )
{
diff -ur spamass-milter-0.2.0-orig/spamass-milter.h
spamass-milter-0.2.0/spamass-milter.h
--- spamass-milter-0.2.0-orig/spamass-milter.h 2003-06-14 15:17:41.000000000
-0400
+++ spamass-milter-0.2.0/spamass-milter.h 2004-09-20 10:42:33.000000000
-0400
@@ -63,7 +63,7 @@
// Debug tokens.
enum debuglevel
{
- D_ALWAYS, D_FUNC, D_POLL, D_UORI, D_STR, D_MISC, D_NET, D_SPAMC,
+ D_ALWAYS, D_FUNC, D_POLL, D_UORI, D_STR, D_MISC, D_NET, D_SPAMC, D_RCPT,
D_MAX // must be last
};
@@ -153,6 +153,7 @@
struct in_addr connect_ip; // remote IP address
char *helo;
SpamAssassin *assassin; // pointer to the SA object if we're processing
a message
+ int rcpts; // must be positive if we are to do ANY spamassassin
processing
};
/* This hack is the only way to call pointers to member functions! */
--- Rcpt-Filter.jm.patch 2004-09-20 10:44:10.000000000 -0400
+++ Rcpt-Filter.jm-Debian.patch 2004-09-20 10:55:20.000000000 -0400
@@ -23,8 +23,8 @@
main(int argc, char* argv[])
{
int c, err = 0;
-- const char *args = "p:fd:mr:u:D:i:b:B:";
-+ const char *args = "p:fd:mr:R:u:D:i:b:B:";
+- const char *args = "fd:mp:P:r:u:D:i:b:B:";
++ const char *args = "fd:mp:P:r:R:u:D:i:b:B:";
char *sock = NULL;
bool dofork = false;
Only in spamass-milter-0.2.0-orig/contrib: spamass-milter.spec
diff -ur spamass-milter-0.2.0-orig/spamass-milter.cpp
spamass-milter-0.2.0/spamass-milter.cpp
--- spamass-milter-0.2.0-orig/spamass-milter.cpp 2003-06-26
11:10:44.000000000 -0400
+++ spamass-milter-0.2.0/spamass-milter.cpp 2004-09-20 10:42:24.000000000
-0400
@@ -150,13 +150,15 @@
};
const char *const debugstrings[] = {
- "ALL", "FUNC", "POLL", "UORI", "STR", "MISC", "NET", "SPAMC",
+ "ALL", "FUNC", "POLL", "UORI", "STR", "MISC", "NET", "SPAMC", "RCPT",
NULL
};
int flag_debug = (1<<D_ALWAYS);
bool flag_reject = false;
int reject_score = -1;
+bool flag_rcpt_filter = false;
+char *rcpt_filter = NULL;
bool dontmodify = false;
bool flag_sniffuser = false;
char *defaultuser;
@@ -174,7 +176,7 @@
main(int argc, char* argv[])
{
int c, err = 0;
- const char *args = "fd:mp:P:r:u:D:i:b:B:";
+ const char *args = "fd:mp:P:r:R:u:D:i:b:B:";
char *sock = NULL;
bool dofork = false;
@@ -207,6 +209,10 @@
flag_reject = true;
reject_score = atoi(optarg);
break;
+ case 'R':
+ flag_rcpt_filter = true;
+ rcpt_filter = optarg;
+ break;
case 'u':
flag_sniffuser = true;
defaultuser = strdup(optarg);
@@ -259,6 +265,7 @@
cout << " -m: don't modify body, Content-type: or Subject:" << endl;
cout << " -r nn: reject messages with a score >= nn with an SMTP
error.\n"
" use -1 to reject any messages tagged by SA." << endl;
+ cout << " -R cmd: filter out recipients with zero exit status."<< endl;
cout << " -u defaultuser: pass the recipient's username to spamc.\n"
" Uses 'defaultuser' if there are multiple recipients."
<< endl;
cout << " -- spamc args: pass the remaining flags to spamc." << endl;
@@ -576,6 +583,7 @@
}
sctx->assassin = NULL;
sctx->helo = NULL;
+ sctx->rcpts = 0;
/* store a pointer to it with setpriv */
smfi_setpriv(ctx, sctx);
@@ -718,6 +726,54 @@
{
assassin->recipients.push_back( *rcpt ); // XXX verify that
this worked
}
+
+ sctx->rcpts++;
+ if(flag_rcpt_filter && rcpt_filter)
+ {
+ int rcpt_filter_result = 0;
+ int size = 0;
+ char *cmd_buffer = NULL;
+ char *tmp_rcpt = NULL;
+ char * queue_id = smfi_getsymval(ctx,"i");
+
+ debug(D_RCPT,"%s: rcpt_filter",queue_id);
+
+
+ if((tmp_rcpt = strdup(envrcpt[0])) != NULL)
+ {
+ tmp_rcpt[strlen(tmp_rcpt)-1] = '\0';
+ size = strlen(rcpt_filter);
+ tmp_rcpt++;
+ size += strlen(tmp_rcpt);
+ cmd_buffer = (char *) malloc(size+10);
+ }
+ if(cmd_buffer)
+ {
+ debug(D_RCPT,"%s: rcpt_filter, malloc succeeded",
queue_id);
+ sprintf(cmd_buffer,"%s %s",rcpt_filter, tmp_rcpt );
+ cmd_buffer[size+2] = '\0';
+ debug(D_RCPT, "%s: rcpt_filter, filter string <%s>",
queue_id, cmd_buffer);
+
+ rcpt_filter_result = system(cmd_buffer);
+ if(!rcpt_filter_result)
+ {
+ debug(D_RCPT,"%s: rcpt_filter, removing rcpt",
queue_id);
+ sctx->rcpts--;
+ } else
+ debug(D_RCPT,"%s: rcpt_filter, leaving rcpt",
queue_id);
+
+ } else
+ debug(D_RCPT,"%s: rcp_filter, malloc failed", queue_id);
+
+ if(cmd_buffer)
+ free(cmd_buffer);
+ if(tmp_rcpt)
+ {
+ tmp_rcpt--;
+ free(tmp_rcpt);
+ }
+
+ }
return SMFIS_CONTINUE;
}
@@ -740,6 +796,21 @@
SpamAssassin* assassin = ((struct context *)smfi_getpriv(ctx))->assassin;
debug(D_FUNC, "mlfi_header: enter");
+ {
+ struct context * sctx = (struct context *) smfi_getpriv(ctx);
+ char * queue_id = smfi_getsymval(ctx,"i");
+ if(flag_rcpt_filter && !sctx->rcpts)
+ {
+ debug(D_RCPT,"%s: rcpt_filter, accepting message without
processing");
+ mlfi_abort(ctx); // For lack of specific cleanup
+ debug(D_FUNC, "%s: mlfi_header: rcpt_filter leave", queue_id);
+ return SMFIS_ACCEPT;
+ } else
+ debug(D_RCPT, "%s: rcpt_filter, processing message", queue_id);
+
+ debug(D_FUNC, "%s: mlfi_header: rcpt_filter leave", queue_id);
+ }
+
// Check if the SPAMC program has already been run, if not we run it.
if ( !(assassin->connected) )
{
diff -ur spamass-milter-0.2.0-orig/spamass-milter.h
spamass-milter-0.2.0/spamass-milter.h
--- spamass-milter-0.2.0-orig/spamass-milter.h 2003-06-14 15:17:41.000000000
-0400
+++ spamass-milter-0.2.0/spamass-milter.h 2004-09-20 10:42:33.000000000
-0400
@@ -63,7 +63,7 @@
// Debug tokens.
enum debuglevel
{
- D_ALWAYS, D_FUNC, D_POLL, D_UORI, D_STR, D_MISC, D_NET, D_SPAMC,
+ D_ALWAYS, D_FUNC, D_POLL, D_UORI, D_STR, D_MISC, D_NET, D_SPAMC, D_RCPT,
D_MAX // must be last
};
@@ -153,6 +153,7 @@
struct in_addr connect_ip; // remote IP address
char *helo;
SpamAssassin *assassin; // pointer to the SA object if we're processing
a message
+ int rcpts; // must be positive if we are to do ANY spamassassin
processing
};
/* This hack is the only way to call pointers to member functions! */
#!/bin/bash
EDITMAP="/usr/sbin/editmap"
MAPNAME="/etc/mail/access"
MAPTYPE="hash"
LOCALPART=`echo $1 | cut -d'@' -f1`
RECURPART=`echo $1 | cut -d'@' -f2`
function editmapquery() {
OUTPUT=`$EDITMAP -q $MAPTYPE $MAPNAME Spam:$1 2> /dev/null | tr
[[:upper:]] [[:lower:]]`
if [[ "$?" == "0" && "$OUTPUT" == "friend" ]]; then
exit 0;
fi
}
editmapquery $1
while [[ "$RECURPART" != "" && "$RECURPART" != "$OLDPART" ]]; do
OLDPART=$RECURPART
editmapquery $RECURPART
RECURPART=${RECURPART#*.}
done
editmapquery $LOCALPART@
editmapquery
exit 1;
- Recipient filtering...,
Joe Maimon <=