Tag: dspam


dspam experiement

So finally, SpamAssasin just could not hack it any more on my server. This year there has been a steady influx of spam, and some users of my mail services are literally getting 1 good message out of 100 messages. I feel like I have truly exhausted all SA resources out there. dspam in action From custom rule sets after more rule sets, after more configuration, SA just can't seem to learn fast enough. I also employ RBL/SBL checks and the works. So, what to do? Enter DSPAM.

Previously, I was a bit weary when I heard about the DSpam project and at the time, SpamAssassin was working for me, so why fix something that is not broken or so I thought. Well that mindset finally passed, and I dove into configuring DSpam for my setup. I run a Postfix/Cyrus type of a virtual email setup that is pretty complicated to say the least. I knew in advance that embarking down this road would mean learning some things and some elbow grease, but that is ok. I finally settled on a configuration that is similar to both Neale's Setup and Cepcep's Setup in different ways. In my setup, I have 2 independent chains, one for inbound email and one for outbound email. I decided to leave my outbound chain alone, and continue to send it thru amavisd. For the inbound chain, all mail is subject to getting sent to dspam, then dspam re-routes it back into postfix with a result attached.

Lastly, I wrote the following script, so that I may simply forward my mails to ham@ or spam@, and have postfix deliver it directly to my script, for retraining purposes.

It is piped to dspam, from postfix, like so:

dspam-retrain   unix    -       n       n       -       10      pipe
  flags=Ru user=dspam argv=ruby /usr/local/bin/dspam-retrain.rb $nexthop $sender $recipient

#!/usr/bin/ruby
# Ruby version of dspam-retrain perl script.
# Perl version: http://dspamwiki.expass.de/DspamRetrainScript
# Author: wsr@rushforthnetworks.com
# License: BSD
# Abstract: setup postfix to pipe mail into this script
#           so that we may then pass it off to dspam in
#           an appropriate way.
#
#           dspam-retrain.rb handles spam-user@domain.tld, and
#                                    spam@domain.tld formats
#
#           If dspam-retrain.rb does not find a signature,
#           it will train dspam using corpus or innoculation
#           mode.      
#
# Requirements: open4 gem is installed
# -----------------------------------------------------------

#### Configuration BEGIN ####################################

#enable logging?

@enable_logging = true
@log_file = '/tmp/dspam_retrain.log'

#what mode to train dspam in if we do not find signature?
#corpus or innoculation

@alternative_mode = 'corpus'

#### Configuration END #####################################


require 'rubygems'
require 'open4'

if @enable_logging
        require 'logger'
        @logfile = File.new(@log_file, 'a+')
        @log = Logger.new(@logfile)
end

def logthis(message)
        if @enable_logging
                @log.info(message)
        end
end

# Get arguments
spam_class  = ARGV[0]
sender = ARGV[1]
recip  = ARGV[2]

logthis("dspam-retrain Started. Arguments: #{spam_class}, #{sender}, #{recip}")

#see if we were passed spam-user@ or just user@
if match = recip.to_s.match(/^(spam|ham)-(\w+)@/)
        user = recip.gsub(/#{match[1]}\-/, '')
elsif match = recip.to_s.match(/^(\w+)@/)
        user = sender
else
        logthis("\tCant't determine user")
        exit 75                
end

signature = String.new
message   = String.new

#loop through email (passed via stdinput)
#search for signature

$stdin.each do |line|
        if line.match(/X-DSPAM-Signature/)
                signature = line.gsub(/X-DSPAM-Signature:/, '')
                #remove any potential whitespace
                signature.strip!
                #since we found signature, break loop
                break
        end
        message << line
end


if signature.length.to_i == 0 
        #we did not find a signature, do normal training

        mode = 'train'

        logthis("\tEmail did not have signature passed in. Attempting #{@alternative_mode} train.")

        #open up dspam with appropriate options
        pid, dspam_in, dspam_out, dspam_err = Open4::popen4 "/usr/bin/dspam --source=#{@alternative_mode} --class=#{spam_class} --user #{user}"

        #attempt to feed message in
        begin
                dspam_in << message
        rescue
                #means dspam closed stdinput because our
                #options failed
                dspam_err.each_line do |o|
                        logthis("\t" + o.gsub(/\n/, ''))
                end
        end
        #close dspams stdinput
        dspam_in.close_write

        #see if dspam left any messages for us
        dspam_out.each_line do |o|
                if o.strip.length == 0 then next end
                logthis("\t" + o.gsub(/\n/, ''))
        end

else
        #we found signature, so we will only pass that.

        mode = 'retrain'

        logthis("\tRetraining Signature: #{signature} for User: #{user} as: #{spam_class}")

        #open up dspam with appropriate options
        pid, dspam_in, dspam_out, dspam_err = Open4::popen4 "/usr/bin/dspam --source=error --signature=#{signature} --class=#{spam_class} --user #{user}"

        #see if dspam left any messages for us
        dspam_out.each_line do |o|
                if o.strip.length == 0 then next end
                logthis("\t" + o.gsub(/\n/,''))
        end
        dspam_err.each_line do |o|
                if o.strip.length == 0 then next end
                logthis("\t" + o.gsub(/\n/,''))
        end
end

ignored, status = Process::waitpid2 pid

#see if we exited cleanly and log it
if status.exitstatus == 0
        logthis("\tMessage successfully #{mode}ed as #{spam_class}")  
else
        logthis("\tMessage NOT #{mode}ed")
end

Tag cloud

  1. 1 entries are tagged with 2007
  2. 1 entries are tagged with 2008
  3. 1 entries are tagged with 2009
  4. 2 entries are tagged with 2010
  5. 1 entries are tagged with altly
  6. 2 entries are tagged with applevalley
  7. 1 entries are tagged with archlinux
  8. 1 entries are tagged with artichoke
  9. 1 entries are tagged with automation
  10. 1 entries are tagged with batcountry
  11. 1 entries are tagged with beats
  12. 1 entries are tagged with bigsur
  13. 3 entries are tagged with bm2009
  14. 1 entries are tagged with bm2010
  15. 8 entries are tagged with burningman
  16. 2 entries are tagged with c
  17. 1 entries are tagged with christmas
  18. 8 entries are tagged with code
  19. 1 entries are tagged with consistent
  20. 1 entries are tagged with cplusplus
  21. 1 entries are tagged with desert
  22. 1 entries are tagged with drinks
  23. 1 entries are tagged with dspam
  24. 2 entries are tagged with dunes
  25. 1 entries are tagged with energy
  26. 1 entries are tagged with esplanade
  27. 5 entries are tagged with europe
  28. 1 entries are tagged with evdo
  29. 2 entries are tagged with flv
  30. 1 entries are tagged with gadgets
  31. 1 entries are tagged with government
  32. 1 entries are tagged with haiku
  33. 1 entries are tagged with hashring
  34. 1 entries are tagged with icecast
  35. 1 entries are tagged with internetradio
  36. 1 entries are tagged with iphone
  37. 1 entries are tagged with linkfinder
  38. 2 entries are tagged with losangeles
  39. 1 entries are tagged with math
  40. 1 entries are tagged with minespotter
  41. 1 entries are tagged with minesweeper
  42. 3 entries are tagged with mix
  43. 1 entries are tagged with motivation
  44. 1 entries are tagged with moving
  45. 3 entries are tagged with music
  46. 1 entries are tagged with newserver
  47. 4 entries are tagged with node.js
  48. 1 entries are tagged with obama
  49. 1 entries are tagged with oil
  50. 1 entries are tagged with productivity
  51. 1 entries are tagged with radio
  52. 1 entries are tagged with rails
  53. 3 entries are tagged with recipe
  54. 1 entries are tagged with redmine
  55. 2 entries are tagged with reflections
  56. 1 entries are tagged with rmine
  57. 8 entries are tagged with ruby
  58. 1 entries are tagged with salmon
  59. 1 entries are tagged with salsa
  60. 1 entries are tagged with shoutcast
  61. 3 entries are tagged with site
  62. 2 entries are tagged with snow
  63. 1 entries are tagged with spill
  64. 1 entries are tagged with spotmanradio
  65. 1 entries are tagged with streamtranscoder
  66. 1 entries are tagged with summer
  67. 1 entries are tagged with tecate
  68. 1 entries are tagged with technology
  69. 1 entries are tagged with thanksgiving
  70. 1 entries are tagged with thoughts
  71. 6 entries are tagged with travel
  72. 1 entries are tagged with trip
  73. 1 entries are tagged with turkey
  74. 3 entries are tagged with twitter
  75. 1 entries are tagged with website
  76. 1 entries are tagged with wordsquared
  77. 4 entries are tagged with work
  78. 1 entries are tagged with x4200
  79. 3 entries are tagged with yz250
  80. 1 entries are tagged with zeromq

Twitter Updates

Links to check out

Subscribe RSS