| 
    
     Matthew B-M: Mailfilter | 
   |||||||
     
     
  | 
    
 Since I have the entire domain for colondot.net, I got fed up with getting junk mail, so I decided to write the following filter (you can see the whole thing here). I employ several methods to do this: 
 This is all done through use of the Exim MTA, and it's capabilities of .forward files. If you don't understand why this works, the documentation for exim filter files is at http://www.exim.org/exim-html-3.20/doc/html/filter.html First of all, your .forward file must start with the following in order that exim recognises it should process it as a filter. # Exim filter In order to be useful, we decide that we're going to allow bounces back, these are usually useful, and then we can hope for reliable mail delivery. # Allow mail delivery failures through if error_message then finish endif RFCs 822 and 1123 mandate that we should accept postmaster for any domain: # Allow postmaster access if $original_local_part is postmaster then finish endif Automatic blacklist addresses
One method I employ is spambait addresses. If mail is sent to any of these, it is assumed to be spam, and the
sender is immediately blacklisted. Any given host might also be blacklisted, but is given two chances. 
if ( ${lc:$original_local_part} is "spamdump" or
	${lc:$original_local_part} matches ^\\d?[a-z]{3}\\d+(-[a-z0-9+=-]*)?\$)
	then
determine that the mail is for a spambait seen mail expand file $home/mailfilter/spam-bounce to $return_path return message subject "Returned mail: blacklisted" This will send back a mail saying that the person has been blacklisted. The expand keyword means that any $ variables can be expanded in the text, $sender_address is a possible one in this situation. This is a significant delivery because of seen. 
	logfile $home/mailfilter/black.list 0644
	logwrite "${lc:$sender_address}: black"
add them to the blacklist. 
	logfile $home/mailfilter/reject.log 0644
	logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: blacklisted"
Write a log of what we've done... In here, there would also be some code for the host blacklisting, but I'll get to that below. finish endif stop any other bits of the filter file processing the delivery. Having blacklisted the mail isn't much good if you can't do anything with the blacklist, so now we see why we wrote the blacklist out in that format. The following should appear near the top of the filter, to avoid entries being submitted twice. 
if ("${lookup{${lc:$sender_address}} lsearch
	{$home/mailfilter/black.list}{$value}}" is "black")
	then
if this condition is true, they are in our blacklist seen mail expand file $home/mailfilter/bl-bounce to $return_path return message subject "Returned mail: blacklisted" send them a bounce and tell them that they were already blacklisted 
	logfile $home/mailfilter/reject.log 0644
	logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: already blacklisted"
log what we've done. Again there is the same code for the host blacklisting as above finish endif end processing here. Open Relay BlacklistI also don't like any host that appears on a realtime blacklist, so: if ( $header_X-RBL-Warning contains "mail-abuse.org" ) then These are put in by an rbl_domains=relays.mail-abuse.org/warn:relays.orbs.org/warn directive in the exim configuration file. This will return true if the host is on either of the lists. seen mail expand file $home/mailfilter/rbl-bounce to $return_path return message subject "Returned mail: blacklisted" Send them a mail informing them that the service in question has realtime blacklisted them. 
	logfile $home/mailfilter/reject.log 0644
	if ( $header_X-RBL-Warning contains "mail-abuse.org" ) then
		logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: on rbl (MAPS ONLY)"
	endif
And log the error. This is enough to upgrade them from the host greylist to the blacklist, but not enough to put them on the greylist, see below. finish endif and stop any further deliveries Host BlacklistingAs with the blacklisted mail addresses, there is a part that does the blacklisting, and a part which rejects if the mail is from a host on the blacklist. The blacklisting happens in certain of the spam-trap rules - there are two lists, the black list and the grey list. If you are black then no mail is accepted from you. If you are grey, then one strike and you go onto the blacklist. This is done using the following code: 
	if("${lookup{$sender_host_address} lsearch {$home/mailfilter/grey.servers}{$value}}" is "grey")
		then
		logwrite "[$tod_log] *** [$sender_host_address]: blacklisted host"
		logfile $home/mailfilter/black.servers 0644
		logwrite "$sender_host_address: black"
	endif
If you want to take something to grey or blacklist the host if it is already grey... 
	if("${lookup{$sender_host_address} lsearch {$home/mailfilter/grey.servers}{$value}}" is "grey")
		then
		logwrite "[$tod_log] *** [$sender_host_address]: blacklisted host"
		logfile $home/mailfilter/black.servers 0644
		logwrite "$sender_host_address: black"
	else
		if("${lookup{$sender_host_address} lsearch {$home/mailfilter/grey.servers}{$value}}" is "")
		then
			logfile $home/mailfilter/grey.servers 0644
			logwrite "$sender_host_address: grey"
		endif
	endif
This allows you to mark hosts you trust by manually entering them as "<ip>: <something>" where <something> is not "grey" into the greylist. They will never get blacklisted if this is the case. Once again you need the code to use the blacklist, which should go right at the top of the file to prevent you multi-blacklisting hosts. 
if ("${lookup{$sender_host_address} lsearch {$home/mailfilter/black.servers}{$value}}" is "black")
	then
	seen mail expand file $home/mailfilter/blh-bounce
		to $return_path return message
		subject "Returned mail: blacklisted"
	logfile $home/mailfilter/reject.log 0644
	logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: host already blacklisted"
	finish
endif
Domain BlacklistingThis was something I added late on. It allows a matching in the domain part of the sender envelope. You add manually, through appending "<domain>: black" to the black.domains file. 
if ("${lookup{${domain:${lc:$sender_address}}} lsearch {$home/mailfilter/black.domains}{$value}}" is "black")
	then
	seen mail expand file $home/mailfilter/bld-bounce
		to $return_path return message
		subject "Returned mail: blacklisted domain"
	logfile $home/mailfilter/reject.log 0644
	logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: already blacklisted domain"
	if("${lookup{$sender_host_address} lsearch {$home/mailfilter/grey.servers}{$value}}" is "grey")
		then
		logwrite "[$tod_log] *** [$sender_host_address]: blacklisted host"
		logfile $home/mailfilter/black.servers 0644
		logwrite "$sender_host_address: black"
	else
		if("${lookup{$sender_host_address} lsearch {$home/mailfilter/grey.servers}{$value}}" is "")
		then
			logfile $home/mailfilter/grey.servers 0644
			logwrite "$sender_host_address: grey"
		endif
	endif
	finish
endif
most of this is pretty similar to the blacklisting of email addresses, and as above, it includes the blacklist host code. One Use AddressesFor non-spammers, but people I don't trust, I also want to have mail addresses which are marked as single-use, so that if I decide I want to get back in touch with people, I mail them using my proper address, but otherwise the emails just work the once. The method for doing this is very similar to the blacklisting, but this time we have a list called use.once with the $original_local_part variable in it. 
if ( ${lc:$original_local_part} matches ^(^[a-z]{2}\\d{2}[a-z]{3}\\d{2})(-[a-z0-9+=-]*)?\$)
	then
	logfile $home/mailfilter/use.once 0644
	logwrite "${lc:$1}: used"
endif
As is evident, there is no significant delivery, so we've just effectively logged that we've seen that address used, and the email will still get delivered. This is only the half of it, and you need: 
if ( ${lc:$original_local_part} matches "^(.*?)(-[a-z0-9-+=]*)?\\\$" )
	then
	if ("${lookup{${lc:$1}} lsearch {$home/mailfilter/use.once}{$value}}" is "used")
		then
		seen mail expand file $home/mailfilter/used-bounce
			to $return_path return message
			subject "Returned mail: address no longer valid"
		logfile $home/mailfilter/reject.log 0644
		logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: reuse of a single-use address"
		finish
	endif
endif
To actually bounce the messages. Time-limited AddressesI also have some email addresses that have an expiry date encoded, obfuscated, within them. The first problem is to find out today's date. 
add 0 to n1
add 0 to n2
add 0 to n3
if ( $tod_log matches "^(\\\\d{4})-0*(\\\\d+)-0*(\\\\d)\\\\s" ) then
	add $1 to n1
	add $2 to n2
	add $3 to n3
endif
Now we'll extract the numbers as above. 
if ( ${lc:$original_local_part} matches
	"^\\\\$0*(\\\\d+)\\\\$0*(\\\\d+)[a-z]0*(\\\\d+)\\\\d\\$(-[a-z0-9-+=]*)?\\\$" )
	then
	add $1 to n6
	add $2 to n4
	add $3 to n5
We will now add some random numbers to hide the fact that these are times. add 1977 to n4 add -52 to n5 add -9 to n6 And then check the mail for validity if ( ( $n1 is above $n4 ) or ( $n1 is $n4 and $n2 is above $n5 ) or ( $n1 is $n4 and $n2 is $n5 and $n3 is above $n6 ) or ( $n4 is below 1 or $n5 is below 1 or $n6 is below 1 ) ) then If any of these tests succeeds, then the mail is not valid and should bounce. 
		seen mail expand file $home/mailfilter/time-bounce
			to $return_path return message
			subject "Returned mail: address no longer valid"
		logfile $home/mailfilter/reject.log 0644
		logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: address timed out (expired $n4-$n5-$n6)"
		finish
	endif
endif
and finish, as before. Scoring MessagesFinally, I have some pointers for messages that look like spam. Each time a rule succeeds, a counter is incremented, and if it ever reaches a certain value, the message fails and is bounced. I use n9 as the variable for my scorefile, if it gets greater than 99, then the message is bounced. In some cases this takes two rules, in some cases 3. 
if( ${lc:$message_body} matches "a\\\\shref=(['\"])mailto:([^@]@[^@])\$1" and
	$2 is not {$lc:$return_path} and $2 is not {$lc:$sender_address})
	then
	add 60 to n9
endif
If we find a "mailto:" link for which the address is not the same as the sender address or return path. 
if (${lc:$message_body} matches "<html>")
	then
	add 60 to n9
endif
I don't often get real people sending me html mail. 
if (${lc:$message_body} matches "<script")
	then
	add 90 to n9
endif
There has been an alarming tendency recently to send messages which are javascript encoded to get through these kind of scoring rules. 
if (${lc:$message_body} matches "checks?\\\\spayable\\\\sto.*for \\\\\\$\\\\d+")
	then
	add 90 to n9
endif
No english person I know spells cheque as "check", so trap all the americans. if($message_body matches "Dear Friend,") then add 80 to n9 endif A very standard spam pointer 
if(${lc:$header_subject} matches "\\\\s\\\\s\\\\s\\\\s+(\\\\(\\\\d+\\\\)|\\\\d+)\\\$")
	then
	add 40 to n9
endif
A lot of spams seem to have a subject which has a number (possibly in brackets) at the right-hand side, this is designed to catch this. 
if(${lc:$header_to} matches "friend@" or ${lc:$header_from} matches "friend@")
	then
	add 90 to n9
endif
Classic spam pointer, but still occasionally seen. 
if(${lc:$header_to} matches "@public.com")
	then
	add 90 to n9
endif
And this. 
if(${lc:$message_body} matches "not spam" or ${lc:$message_body} matches "spam free")
	then
	add 80 to n9
endif
if(${lc:$message_body} matches "not junk mail")
	then
	add 80 to n9
endif
This has been appearing recently, especially in the disclaimers at the bottom. Genuine mail shouldn't say this kind of thing - it doesn't need to. 
if(${lc:$message_body} matches "university diploma")
	then
	add 80 to n9
endif
Lots of these being advertised. Good thing I already have a degree. ;) 
if(${domain:${lc:$header_to}} is "")
	then
	add 30 to n9
endif
Well, I certainly shouldn't see this in legitimate mails. 
if(${lc:$sender_address} matches "([a-z\\\\d]+)@(lycos|hotmail|aol|yahoo|msn)\\\\.co(\\\\..*|m)" and
	$1 matches \\d)
	then
	add 40 to n9
endif
Don't trust anything with a number in the localpart at lycos, hotmail, aol, yahoo or msn. if($header_subject matches \\\$\\\$+) then add 50 to n9 endif Classic negative scorer in spam. 
if(${lc:$sender_host_name} matches "ppp" or ${lc:$sender_host_name} matches "dial-?up")
	then
	add 50 to n9
endif
Catch things that should have been on the MAPS DUL, but apparently aren't. 
if($n9 is above 99)
	then
	seen mail expand file $home/mailfilter/score-bounce
		to $return_path return message
		subject "Returned mail: failed score checking"
		logfile $home/mailfilter/reject.log 0644
		logwrite "[$tod_log] ${lc:$sender_address} [$sender_host_address] -> ${lc:$original_local_part}@${lc:$original_domain}: score failure"
	finish
endif
And check the score to see if it's too high. Bounce the message if it is.  | 
   
  This page last modified on
   Monday, 05-Feb-2018 19:43:34 UTC
  Contact <webmaster@colondot.net> for more information about this
   site, or <plunder@colondot.net> if you want not to be able to send
   any more mail to this machine.