- Code: Select all
{ Script: DNSBL.poc v1.19 by Mat Bowen (Hogyt)
{ Purpose: Check where email has been sent from in DNSBLs
{ Requires http://www.woken.com/runmin.exe (set the path to it in "Setup Script")
{ Updates: http://www.pocosystems.com/forum/viewtopic.php?t=482
{ Changelog: v1.00 - Initial release
{ v1.01 - DOS window no longer appears (an icon flashes in the system tray, requires runmin.exe)
{ - Basic error checking added
{ v1.02 - Supports multiple DNSBLs (say goodbye to spam!)
{ v1.03 - If X-Poco-Spam-DNSBL already exists, do not repeat tests
{ - X-Poco-Spam-DNSBL header is indented (looks tidier)
{ - Check the script is running on incoming messages only
{ v1.04 - Checks DNSBLs in parallel
{ - Timeout message added to X-Poco-Spam-DNSBL header if applicable
{ - Debugging info added to X-Poco-Spam-DNSBL header
{ - Displays error if runmin.exe cannot be found
{ v1.05 - Minor bug fixed when running the script twice on a message
{ v1.06 - Rewritten runmin.exe - no icons appear, faster and only 3k!
{ v1.07 - Extra filters are no longer needed (just one to run this script)
{ - Ham/spam scores are defined in $dnsbllist for each DNSBL
{ - The ham/spam score is added in brackets to the X-Poco-Spam-DNSBL header
{ - "Not found in..." is added to the X-Poco-Spam-DNSBL header if the IP address is not found
{ - Added two more DNSBLs
{ v1.08 - Minor bug fix with repeated entries in X-Poco-Spam-DNSBL header
{ v1.09 - Improved the IP address scanner
{ - Path to runmin and timeout are now set in "Setup Script"
{ v1.10 - Header layout has changed to "dnsbl-true" or "dnsbl-false" in "New style headers" is True
{ - For original header layout "Found in dnsbl" or "Not in dnsbl" enter False for "New style headers"
{ - Changed name to DNSBL
{ v1.11 - Changed default DNSBLs
{ - Fix for IP reading routine
{ v1.12 - Another fix for the IP reading routine ;-)
{ - 'Old' DNSBLs are commented out, use them if you wish
{ v1.13 - Updates X-Poco-Scored header as well as X-Poco-Score
{ v1.14 - Fix non-integer error
{ v1.15 - cmd.exe changed to command.com
{ - Short filename used for temp files instead of long filename
{ - New option on setup script, points to nslookup for Win 95, 98, ME (leave blank on Win 2K, XP, NT)
{ v1.16 - Check script is running on incoming messages or manually only
{ v1.17 - Added check for timeout value (must be integer >= 1)
{ v1.18 - Added a check for temporary files at start (which are removed if they exist)
{ - Timeout code modified
{ v1.19 - Temporary files have a random suffix (to prevent DNSBL results clashing between emails)
{ - Version number of script included in X-Poco-Spam-DNSBL header
Set $OnErrorGoTo generalerror
{ Choose DNSBLs in the list below (the more you have the slower checking email can be)
Embed $dnsbllist "end"
dnsbl.sorbs.net,15,0
dnsbl.njabl.org,15,0
list.dsbl.org,15,0
bl.spamcop.net,15,0
sbl-xbl.spamhaus.org,15,0
end
{ Other DNSBLs are listed below
{ ipwhois.rfc-ignorant.org,2,0
{ dsn.rfc-ignorant.org,2,0
{ spamsources.fabel.dk,4,0
{ opm.blitzed.org,8,-1 - sbl-xbl.spamhaus.org already checks this!
{ cbl.abuseat.org,6,0 - sbl-xbl.spamhaus.org already checks this!
{ sbl.spamhaus.org,10,0 - sbl-xbl.spamhaus.org already checks this!
{ relays.nthelp.com,6,0
{ block.blars.org,3,0
{ Define options in "Setup Script"
External $userdata1 "The full path to runmin.exe" "c:\\runmin.exe"
External $userdata2 "The full path to nslookup tool on Win 95, 98, ME (leave blank for Win 2K, XP, NT)" ""
External $userdata3 "Timeout (max attempts to wait for DNSBL response)" "8"
External $userdata4 "Use new style headers?" "False"
Set #mode 1 { 1 for nslookup on Win 2K, XP, NT. 2 for nslook (external tool for Win 95, 98, ME)
Set $nslookup "nslookup" { For Win 2K, XP, NT. Should be in current path
{ Check mode script is running in
If #PocoScriptMode = 1 Then modeokay { Incoming mail okay
If #PocoScriptMode = 5 Then modeokay { Manually okay
Goto wrongmode
:modeokay
Set $runmin $userdata1
Lowercase $userdata4
Set &newstyle $userdata4="true"
{ Check timeout value
If $userdata3 = "" Then wrongtimeout
Set #timeout $userdata3
If #timeout < 1 Then wrongtimeout
{ Check external nslookup tool can be found on Win 95, 98, ME
If $userdata2 = "" Then nslookupfound
Set #mode 2
Set $nslookup $userdata2
FileExists &checkns $nslookup
If &checkns Then nslookupfound
Set $message "The script "
AddStrings $message $PocoScriptName " cannot find file the nslookup file " $nslookup " for Win 95, 98, ME"
MessageBox $message
Exit
:nslookupfound
TrimLines $dnsbllist
Set &leavemessage True
{ Check runmin.exe can be found
FileExists &check $runmin
If &check Then filefound
Set $message "The script "
AddStrings $message $PocoScriptName " cannot find file runmin.exe at " $runmin
MessageBox $message
Exit
{ Read X-Poco-Spam-DNSBL header
:filefound
ReadHeader $check "X-Poco-Spam-DNSBL:" %message
{ Default header
:SetDefault
Set $header "Received from IP address (unknown)"
{ Create a temporary filename with random suffix
Set $tempfile $temppath
Random #rand 9999
AddStrings $tempfile "DNS" #rand
{ Remove old temporary files
DirList $dir $temppath "DNS*.txt" 0
LineCount #deltotal $dir
If #deltotal < 1 Then skipremove
:removeloop
Dec #deltotal
Set $tempfile2 $temppath
GetLine $thisline #deltotal $dir
AddStrings $tempfile2 $thisline
FileExists &delcheck $tempfile2
Not &delcheck
If &delcheck Then skipremove
Set $OnErrorGoTo skipremove
DeleteFile $tempfile2
Set $OnErrorGoTo generalerror
:skipremove
If #deltotal > 0 Then removeloop
{ Start with a spam score of 0
Set #spamscore 0
{ Extract current X-Poco-Score
ReadHeader $pocoscore "X-Poco-Score:" %message
Set #val 0
If $pocoscore = "" Then skipscore
LineCount #n $pocoscore
Dec #n
GetLine $pocoscorelastline #n $pocoscore
Set #val $pocoscorelastline
{ Extract current X-Poco-Score
:skipscore
ReadHeader $pocoscored "X-Poco-Scored:" %message
Set #val2 0
If $pocoscored = "" Then skipscore2
LineCount #n $pocoscored
Dec #n
GetLine $pocoscoredlastline #n $pocoscored
Set #val2 $pocoscoredlastline
{ Extract Received from IP address
:skipscore2
ReadHeader $received "Received:" %message
Set #waitattempt 1
If $received = "" Then updateheader
Set #line 0
LineCount #totallines $received
:loop
GetLine $current #line $received
Trim $current
StringPos #pos "from" $current
If #pos ! 1 Then jump
CharCount #scanline $current
StringPos #bypos " by " $current
If #bypos = 0 Then skip
Set #scanline #bypos
Dec #scanline
:skip
Char $thischar #scanline $current
Set $openchar $thischar
Set $closechar "("
If $openchar = ")" Then restart
If $openchar = "]" Then square
Dec #scanline
If #scanline > 0 Then skip
Goto jump
:square
Set $closechar "["
:restart
Set #dotcount 0
Set $ipaddress ""
Set #numbers 0
Set $revpart0 ""
Set $revpart1 ""
Set $revpart2 ""
Set $revpart3 ""
:innerloop
Dec #scanline
If #scanline < 1 Then jump
Char $thischar #scanline $current
If $thischar = ")" Then skip
If $thischar = "]" Then skip
If $thischar ! "." Then innerjump
If #numbers ! 0 Then jumpchange
{ Find closing char
:findcloseloop
Dec #scanline
If #scanline < 1 Then jump
Char $thischar #scanline $current
If $thischar = $closechar Then foundopen
Goto findcloseloop
{ Trim remainder and retry
:foundopen
CharCount #linelen $current
ChopString $current #scanline #linelen
Trim $current
CharCount #scanline $current
Goto skip
:jumpchange
InsertString $ipaddress 1 $thischar
Inc #dotcount
If #dotcount > 3 Then jump
:innerjump
If $thischar = $closechar Then jumpout
If $thischar < "0" Then innerjump2
If $thischar > "9" Then innerjump2
Inc #numbers
InsertString $ipaddress 1 $thischar
If #dotcount = 1 Then grab1
If #dotcount = 2 Then grab2
If #dotcount = 3 Then grab3
InsertString $revpart0 1 $thischar
Goto innerjump2
:grab1
InsertString $revpart1 1 $thischar
Goto innerjump2
:grab2
InsertString $revpart2 1 $thischar
Goto innerjump2
:grab3
InsertString $revpart3 1 $thischar
:innerjump2
If #scanline > 1 Then innerloop
:jump
Inc #line
If #line < #totallines Then loop
Goto updateheader
{ Reverse order of IP address
:jumpout
Dec #scanline
If #dotcount ! 3 Then skip
Set $revipaddress $revpart0
AddStrings $revipaddress "." $revpart1 "." $revpart2 "." $revpart3
Set $header "Received from IP address ("
AddStrings $header $ipaddress ")"
LineCount #dnsbltotal $dnsbllist
If #dnsbltotal < 1 Then updateheader
{ Loop through DNSBL list
:dnsblloop
Dec #dnsbltotal
GetLine $thisline #dnsbltotal $dnsbllist
ReadCSV $thislineCSV $thisline
GetLine $thisdnsbl 0 $thislineCSV
Set $extendrevip $revipaddress
AddStrings $extendrevip "." $thisdnsbl
If #mode = 2 Then skiptomode2
Set $params "command.com /c "
AddStrings $params $nslookup " -type=A -timeout=" #timeout " " $extendrevip " > " $tempfile #dnsbltotal ".txt"
Goto modefinished
:skiptomode2
Set $params "command.com /c "
AddStrings $params $nslookup " " $extendrevip " > " $tempfile #dnsbltotal ".txt"
:modefinished
Execute $runmin $params
If #dnsbltotal > 0 Then dnsblloop
LineCount #dnsbltotal $dnsbllist
:dnsblloop2
Dec #dnsbltotal
GetLine $thisline #dnsbltotal $dnsbllist
ReadCSV $thislineCSV $thisline
GetLine $thisdnsbl 0 $thislineCSV
Set $extendrevip $revipaddress
AddStrings $extendrevip "." $thisdnsbl
Set $tempfile2 $tempfile
AddStrings $tempfile2 #dnsbltotal ".TXT"
Set &timedout False
{ Messy error handling routine to ensure a timeout
Set $output ""
Set $OnErrorGoTo retryopenbody
Goto tryopenbody2
:retryopenbody
If #waitattempt < #timeout Then tryopenbody
Set &timedout True
AddStrings $header "\n Timed out checking " $thisdnsbl
Goto pastopenbody
:tryopenbody
Inc #waitattempt
Wait 1
:tryopenbody2
OpenBody $output $tempfile2
:pastopenbody
Set $OnErrorGoTo canceldelete
DeleteFile $tempfile2
:canceldelete
Set $OnErrorGoTo generalerror
LineCount #totallines $output
If &timedout Then skipaddtoheader
If #totallines < 1 Then skipexamine
{ See if IP address is listed with DNSBL
:examine
If #mode = 2 Then examinemode2
{ For nslookup (Win 2K, XP, NT)
:examinemode1
Dec #totallines
GetLine $current #totallines $output
StringPos #pos $extendrevip $current
If #pos ! 0 Then found
If #totallines > 0 Then examinemode1
Goto skipexamine
{ For nslook (Win 95, 98, ME)
:examinemode2
Dec #totallines
GetLine $current #totallines $output
StringPos #pos "127.0.0." $current
If #pos ! 0 Then found
If #totallines > 0 Then examinemode2
{ IP address isn't in DNSBL so update header and change spam score
:skipexamine
If &newstyle Then newstyleheaderno
AddStrings $header "\n Not in " $thisdnsbl " ("
Goto doneheaderno
:newstyleheaderno
AddStrings $header "\n " $thisdnsbl "-false ("
:doneheaderno
GetLine $score 2 $thislineCSV
Goto addspamscore
{ IP address found in DNSBL so add to header and change spam score
:found
If &newstyle Then newstyleheaderyes
AddStrings $header "\n Found in " $thisdnsbl " ("
Goto doneheaderyes
:newstyleheaderyes
AddStrings $header "\n " $thisdnsbl "-true ("
:doneheaderyes
GetLine $score 1 $thislineCSV
:addspamscore
If $score < 0 Then skipplussign
AddStrings $header "+"
:skipplussign
AddStrings $header $score ")"
AddIntegers #spamscore $score
:skipaddtoheader
If #dnsbltotal > 0 Then dnsblloop2
{ Add status of checking to X-Poco-Spam-DNSBL header
:updateheader
AddStrings $header "\n Debug - v1.19 #spamscore " #spamscore " #waitattempt " #waitattempt
AddStrings $header " #timeout " #timeout " #mode " #mode
Set $headercopy $header
TrimLines $headercopy
LineCount #n $check
Dec #n
DeleteLine $check #n
LineCount #n $headercopy
Dec #n
DeleteLine $headercopy #n
If $check = $headercopy Then resetspamscore
DeleteHeader "X-Poco-Spam-DNSBL:" %message
AddHeader %message "X-Poco-Spam-DNSBL:" $header
Set &leavemessage False
Goto addnewspamscore
{ X-Poco-Spam-DNSBL hasn't changed (apart from possibly the final line) so they have the spam score
:resetspamscore
Set #spamscore 0
{ Add spam score to X-Poco-Score
:addnewspamscore
If #spamscore = 0 Then finishup
AddIntegers #val #spamscore
Set $val ""
If #val < 0 Then skipplus
Set $val "+"
{ Save updated X-Poco-Score header
:skipplus
AddStrings $val #val
DeleteHeader "X-Poco-Score:" %message
AddHeader %message "X-Poco-Score:" $val
Set &leavemessage False
{ Add spam score to X-Poco-Scored
AddIntegers #val2 #spamscore
{ If #val2 = 0 Then quit
Set $val2 ""
If #val2 < 0 Then skipplus2
Set $val2 "+"
{ Save updated X-Poco-Scored header
:skipplus2
AddStrings $val2 #val2
DeleteHeader "X-Poco-Scored:" %message
AddHeader %message "X-Poco-Scored:" $val2
Set &leavemessage False
{ If headers have changed then delete the message (to ensure they update) and save message
:finishup
If #PocoScriptMode = 1 Then quit
If &leavemessage Then quit
DeleteMessage %message
SaveMessage %message $CurrentMailbox
:quit
Exit
{ Inform user we're running in the wrong mode
:wrongmode
Set $message "The "
AddStrings $message $PocoScriptName " script must be run on incoming messages or manually only."
AddStrings $message " #PocoScriptMode = " #PocoScriptMode
MessageBox $message
Exit
{ Inform user timeout value is not an integer >= 1
:wrongtimeout
Set $message "The "
AddStrings $message $PocoScriptName " script has a timeout value that is not an integer >= 1"
MessageBox $message
Exit
{ Error handler
:generalerror
Set $message "An error has occurred in "
AddStrings $message $PocoScriptName "\n$ErrorResult: " $ErrorResult "\n$ErrorLine: " $ErrorLine
MessageBox $message
Exit
Disclaimer:
This script is still being tested so if you want to be safe then please test it on a backup installation. The standard Frazmi disclaimer of 'it works for me, it may not work for you' and the Hogyt disclaimer of 'even if it works today, it may not work tomorrow' apply
To set it up (new and easy method from v1.07 onwards):
- Create a new script with the code above, call it something like DNSBL.
- Create a new filter in Tools->Filters to run the above script (before your junk mail filter in the filter window).
- Download runmin.exe and update the path to it in "Setup Script" in Tools->Scripts (it's the first field).
- For Win 95, 98, ME: Download nslook.exe from ->this page<- and update the path to it in "Setup Script" in Tools->Scripts (it's the second field). For Win 2K, XP, NT, leave the second field blank (they come with nslookup.exe and don't require this separate download).
- Code: Select all
X-Poco-Spam-DNSBL: Received from IP address (81.51.146.32)
spamsources.fabel.dk-false (+0)
cbl.abuseat.org-false (+0)
relays.nthelp.com-false (+0)
dsn.rfc-ignorant.org-false (+0)
ipwhois.rfc-ignorant.org-false (+0)
dnsbl.sorbs.net-true (+8)
Debug - #spamscore 4 #waitattempt 1 #timeout 8
This assumes the setting "Use new style headers?" is set to the default value "True" in "Setup Script". If set to "False" it will look more like:
- Code: Select all
X-Poco-Spam-DNSBL: Received from IP address (81.51.146.32)
Not in spamsources.fabel.dk (+0)
Not in cbl.abuseat.org (+0)
Not in relays.nthelp.com (+0)
Not in dsn.rfc-ignorant.org (+0)
Not in ipwhois.rfc-ignorant.org (+0)
Found in dnsbl.sorbs.net (+8)
Debug - #spamscore 4 #waitattempt 1 #timeout 8
This X-Poco-Spam-DNSBL header lists all the DNSBLs checked along with whether the IP address was found in that DNSBL or not and the score associated with it. You can edit which DNSBLs to check and their spam/ham scores in the section:
- Code: Select all
Embed $dnsbllist "end"
dnsbl.sorbs.net,8,0
dnsbl.njabl.org,8,-1
opm.blitzed.org,8,-1
sbl.spamhaus.org,10,0
list.dsbl.org,8,-1
bl.spamcop.net,8,-1
block.blars.org,3,0
ipwhois.rfc-ignorant.org,2,0
dsn.rfc-ignorant.org,2,0
relays.nthelp.com,6,0
cbl.abuseat.org,6,0
spamsources.fabel.dk,4,0
end
The format is:
"DNSBL address" comma "spam score (IP is found)" comma "ham score (IP is not found)"
If you find the checking too slow then try getting rid of some of the DNSBLs and decreasing the timeout value in "Script Setup". For what it's worth it is scanning all DNSBLs in a few seconds here. I'm not sure what scores are best so they may take some fiddling with.