This document is outdated! Please refer to the CHANGELOG for up-to-date information on new features.
This file is slowly turning into the Anomy sanitizer's user manual. The document is organized so that it makes sense to start at the beginning, and read continuously until you reach the mailer-specific configuration chapters. From that point on, everything is optional, read what interests you. Well... the feedback chapter isn't really optional. Read it. :-)
The sanitizer is designed not to waste important system resources (CPU, memory, disk space) unnecessarily, and does so by treating it's input as a stream which is scanned and rewritten a little bit at a time.
One of the core ideas behind the design of the sanitizer, is that just because a message contains an infected attachment doesn't mean that the rest of it shouldn't be delivered. Email often contains important information, and it is vital that a tool like this interrupt the normal flow of communication as little as possible. It's common courtesy to inform the user of any changes that are made. The Anomy sanitizer tries to follow these rules.
The sanitizer is based on solid foundations - most of the ideas implemented in the first versions of the sanitizer were ported from John D. Hardin's "email security through procmail" package. The sanitizer, like the code it is based on, is Free Software in the GNU sense of the term - the sanitizer may be modified and redistributed according to the terms of the GNU General Public License.
The following is a random sample of the attacks that are blocked by the Anomy sanitizer in it's most common configurations (as of release 1.28):
In all cases the above exploits are blocked by some sort of generic mechanism which will prevent a number of related attacks against similar software with similar problems. This list doesn't include the more common low-tech trojan-horse/social engineering attack methods which are best handled with user education and an automatically enforced attachment policy.
[ contents ]
The sanitizer makes no assumptions about what mailer you are using - it has been configured to work well with sendmail and qmail, and it should be relatively easy to get it to work with others, such as postfix or exim.
For testing purposes, it may be a good idea to invoke the sanitizer from within procmail, since procmail does a very good job of recovering mail if the sanitizer panics (e.g. because of an invalid configuration file) and can easily be configured to keep backup copies of all processed messages.
If you want to scan attachments for viruses, you will need a third party virus scanner which can be invoked from the command line to scan a single file. The virus scanner must return an exit code describing whether the file is infected or not, and may optionally also use exit codes to indicate that the file was successfully disinfected.
[ contents ]
Download the most recent sanitizer from the web and install all the prerequisites. The sanitizer can be downloaded from it's home page, mailtools.anomy.net.
Unpack the tarball somewhere on your system, e.g. in /usr/local/ or your home directory. It will create a directory named anomy/ which will contain this file and a directory named bin/ containing the sanitizer itself and the MIME parsing module it depends on.
Next, you should run the included test cases to make sure that the sanitizer functions properly on your system. Enter the anomy/testcases directory, and give the command ./testall.sh. This will perform all included tests, and compare their results to files named test-name.ok in the subdirectory named results.def. You can examine these files to see how the sanitizer alters email. If a test fails, a test-name.diff file is created which shows the difference between the expected value and the test result. Empty lines are usually harmless, but any other failures should be reported back to the author.
If you cannot figure out why a test failed and wish to submit a bug report, please include information about your operating system and a copy of the relevant test-name.failed file. If all tests succeed, then the sanitizer is ready to be used.
To test the sanitizer on one of your own messages, you can invoke the it from the command line, like this (bourne shell syntax):
$ cd /path/to/anomy
$ export ANOMY=/path/to/anomy
$ ./bin/sanitizer.pl < /path/to/message |more
This is an excellent way to test your first configuration file, simply add the path to your configuration file to the command line invoking the sanitizer, as the first argument:
$ ./bin/sanitizer.pl /etc/sanitizer.cfg < /path/to/message |more
For a more extended test, you may want to sanitize only a single user's mail until you are comfortable with the tool. How this is done depends on your mailer, but one common case (sendmail and procmail) is very simple. Just add the following lines to the user's .procmailrc file:
:0 c backup-mailbox ANOMY=/path/to/anomy/ :0 fw |/path/to/anomy/bin/sanitizer.pl
The first rule creates a backup of all messages, in a mailbox named backup-mailbox. Since you will probably make mistakes as you define your first policy, this is probably a good idea in case the sanitizer mistakenly destroys your mail. The second rule passes the messages through the sanitizer, using procmail's filter feature, possibly rewriting the message to deactivate virii, trojans, etc.
If you had created a configuration file named /path/to/sanitizer.cfg, then the sanitization rule would be modified to read as follows:
:0 fw |/path/to/anomy/bin/sanitizer.pl /path/to/sanitizer.cfg
Note that this is a completely valid way to invoke the sanitizer - if your system administrator won't install it globally, but you have access to your .procmailrc file, you can simply sanitizer your own mail in this fashion. Also, instead of putting those rules in a .procmailrc file, you can put them in /etc/procmailrc instead and thus sanitize all mail delivered to local users.
Procmail is an excellent tool, and it can be configured to work with most popular MTAs, including sendmail, postfix, qmail and exim. Using procmail is probably the easiest way to take advantage of the sanitizer.
Note: The above recipies may not be sufficient to get the sanitizer to work on your platform - if you have problems, please be sure to check the newest version of this manual for platform specific instructions, as well as the procmail(1), procmailrc(1) and procmailex(1) man pages. Of particular interest when debugging procmail related problems are the LOGFILE and VERBOSE directives. Also be sure to check the contrib/ directory of the distribution for user-contributed tips and tricks.
[ contents ]
# this is a comment, bla bla # feat_log_stderr = 1 # enable logging to stderr feat_log_inline = 0 # disable logging in the message itself feat_trust_pgp = 1 # trust signed or encrypted messages # Disable most of the advertisements the sanitizer would otherwise # put in the header, replace them with our own bogus ones. # header_info = X-Virus-Scanned: Secured by FooCorp RealSecure MailWall header_info += \nX-Garbage: \# this is not a comment # but this is header_url = 0 header_rev = 0 # Include more configuration... # /path/to/policy/configuration/file /path/to/another/configuration/file
And could be activated like this:
$ sanitizer.pl /path/to/configuration/file
The first setting (logging to standard error) could also have been activated with this command line:
$ sanitizer.pl "feat_log_stderr = 1"
#
# These are the default values for all feature switches.
#
feat_verbose = 1 # Warn user about unscanned parts, etc.
feat_log_inline = 1 # Inline logs: 0 = Off, 1 = Maybe, 2 = Force
feat_log_stderr = 1 # Print log to standard error
feat_log_xml = 0 # Don't use XML format for logs.
feat_log_trace = 0 # Omit trace info from logs.
feat_log_after = 0 # Don't add any scratch space to part headers.
feat_files = 1 # Enable filename-based policy decisions.
feat_force_name = 0 # Force all parts (except text/plain and
# text/html parts) to have file names.
feat_boundaries = 0 # Replace all boundary strings with our own
# NOTE: Always breaks PGP/MIME messages!
feat_lengths = 1 # Protect against buffer overflows and null
# values.
feat_scripts = 1 # Defang incoming shell scripts.
feat_html = 1 # Defang active HTML content.
feat_webbugs = 0 # Web-bugs are allowed.
feat_trust_pgp = 0 # Don't scan PGP signed message parts.
feat_uuencoded = 1 # Sanitize inline uuencoded files.
feat_forwards = 1 # Sanitize forwarded messages
feat_testing = 0 # This isn't a test-case configuration.
feat_fixmime = 1 # Fix invalid MIME, if possible.
feat_paranoid = 0 # Don't be excessively paranoid about MIME headers etc.
#
# Scoring
#
score_bad = 100 # Any message requring this many modifications
# will cause the sanitizer to return a non-zero
# exit code after processing the entire message.
#
# You may need to increase the following if you have a very
# complex configuration split between multiple files.
#
max_conf_recursions = 5 # The default is 5.
#
# Create temporary or saved files using this template.
# An attachment named "dude.txt" might be saved as
#
# /var/quarantine/att-dude-txt.A9Y
#
# Note: The directory must exist and be writable by
# the user running the sanitizer.
#
file_name_tpl = /var/quarantine/att-$F.$$$
# We have three policies, in addition to the default which is
# to defang file names.
#
file_list_rules = 3
file_default_policy = defang
file_default_filename = unnamed.file
# Delete obviously executable attachments. This list is VERY
# incomplete! This is a perl regular expression, see "man
# perlre" for info. The (?i) prefix makes the regexp case
# insensitive.
#
# There is only one policy, since we aren't using an external
# scanner. The file list is split accross two lines, for fun.
#
file_list_1 = (?i)\.(exe|com
file_list_1 += |cmd|bat)$
file_list_1_policy = drop
file_list_1_scanner = 0
# Scan mp3 files for Evil Viruses, using the imaginary mp3virscan
# utility. Always define FOUR potential policies, which depend on the
# exit code returned by the scanner. Which code means what is
# defined in the scanner line, which must contain THREE entries.
# The fourth policy is used for "anything else".
#
# "accept" if the file is clean (exit status 0 or 1)
# "mangle" if the file was dirty, but is now clean (2 or 4)
# "drop" if the file is still dirty (66)
# "save" if the mp3virscan utility returns some other exit code
# or an error occurs.
#
file_list_2 = (?i)\.(mp3|mp2|mpg)$
file_list_2_policy = accept:mangle:drop:save
file_list_2_scanner = 0,1:2,4:66:/path/to/mp3virscan -opt -f %FILENAME
# Scan WinWord and Excel attachments with built-in macro scanner.
# We consider anything exceeding the score of 25 to be dangerous,
# and save it in the quarantine.
#
file_list_3 = (?i)\.(doc|dot|xls|xlw)$
file_list_3_policy = accept:accept:save:save
file_list_3_scanner = 0:1:2:builtin/macro 25
# # Add two lines of informational headers to each message. # header_info = X-Sanitizer: Gotcha! header_info += \nX-Gotcha: Sanitizer! # # Disable these builtin headers. # header_url = 0 header_rev = 0 # # Replace the "DEFANGED" string with "FIXED". This # string is used to mangle file names, HTML and other # stuff within the message, so the user might see it. # msg_defanged = FIXED # # Also replace a couple of other similar strings. # These are only used by the filename mangling code. # msg_blacklisted = EVIL # # Replace the defaults with truly obnoxious messages. # These two replace attachments which are dropped or # saved. # msg_file_drop = *****\n msg_file_drop += HA HA, I DROPPED YOUR ATTACHMENT!\n msg_file_drop += Now you'll never see %FILENAME again! msg_file_drop += *****\n # msg_file_save = *****\n msg_file_save += Added %FILENAME as %SAVEDNAME to my\n msg_file_save += stolen email collection.\n msg_file_save += *****\n # # This is prepended to PGP signed/encrypted message # parts, to warn the user. # msg_pgp_warning = WARNING: Unsanitized content follows.\n # # Tell the user what's going on. This prefixes the # sanitizer log, which is always in english. # msg_log_prefix = This message has been sanitized. Stuff\n msg_log_prefix += may have been altered - the following\n msg_log_prefix += log explains what was done and why.\n #
If you are paranoid, don't use the default configuration!
If you intend to use the program regularly, I recommend subscribing to the anomy-list mailing list (see the Anomy home page for more information). The traffic is currently very low, and is primarily used to announce new versions or warn users of email-related hazards.
[ contents ]
The configuration itself is stored in /etc/sanitizer.cfg, and looks about like this:
# Active features. # feat_boundaries = 0 feat_files = 1 feat_forwards = 1 feat_html = 1 feat_lengths = 1 feat_log_inline = 1 feat_log_stderr = 0 feat_scripts = 1 feat_trust_pgp = 0 feat_uuencoded = 1 feat_verbose = 1 file_list_rules = 4 # # Note: This directory must exist and be writable by # the user running the sanitizer. # file_name_tpl = /var/quarantine/att-$F-$T.$$ # Files we absolutely don't want (mostly executables). # file_list_1_scanner = 0 file_list_1_policy = save file_list_1 = (?i)(winmail\.dat file_list_1 += |\.(exe|vb[es]|c(om|hm)|bat|pif|s(ys|cr)) file_list_1 += (\.g?z|\.bz\d?)*)$ # Pure data, don't mangle this stuff (much). # file_list_2_scanner = 0 file_list_2_policy = accept file_list_2 = (?i)\.(gif|jpe?g|pn[mg]|x[pb]m|dvi|e?ps|p(df|cx)|bmp file_list_2 += |mp[32]|wav|au|ram? file_list_2 += |avi|mov|mpe?g file_list_2 += |t(xt|ex)|csv|l(og|yx)|sql|jtmpl file_list_2 += |[ch](pp|\+\+)?|s|inc|asm|pa(tch|s)|java|php\d? file_list_2 += |[ja]sp file_list_2 += |can|pos|ux|reg|kbf|xal|\d+)(\.g?z|\.bz\d?)*$ file_list_3_scanner = 0 file_list_3_policy = accept file_list_3 = ^[^\.]+$ # Archives and scriptable stuff - virus scan these. # NOTE: There must be THREE groups of exit codes and FOUR policies, # - the first three match the code groups, the fourth is default. # file_list_4_scanner = 0:5:3,4:/usr/local/bin/avp.sh %FILENAME file_list_4_policy = accept:accept:save:save file_list_4 = (?i)\.(xls|d(at|oc)|p(pt|l)|rtf|[sp]?html? file_list_4 += |class|upd|wp\d?|m?db file_list_4 += |z(ip|oo)|ar[cj]|lha|[tr]ar|rpm|deb|slp|tgz file_list_4 += )(\.g?z|\.bz\d?)*$ # Default policy: accept, but mangle file name. # file_default_policy = defang
This policy invokes the AVP virus scanner for common Microsoft document formats and compressed archives. The scanner (AvpLinux) is installed in /usr/local/avp, and it's virus database is in the subdirectory avc. The scanner is invoked by calling the /usr/local/bin/avp.sh script, which looks like this:
#!/bin/bash cd /usr/local/avp/avc [ "$1" = "" ] && exit 21 [ -f "$1" ] || exit 20 exec ../AvpLinux -M -P -B -- $1 2>/dev/null >/dev/null
Keeping the virus database in it's own special directory simplifies updating it automatically. Such updates can be accomplished by invoking a script once a week from cron. My script looks like this:
#!/bin/bash # cd /usr/local/avp/ rm -rf avc-old mkdir avc-update || exit 1 cd avc-update || exit 1 ncftpget -V -R ftp.avp.ru . '/updates/*' || (echo 'Failed!'; exit 2) ../AvpLinux ../infected.doc >/dev/null 2>/dev/null [ "$?" != "4" ] && (echo 'Failed!'; exit 3) echo "OK, update complete, activating new files." cd .. mv avc avc-old && mv avc-update avc
[ contents ]
The following instructions describe two different methods to sanitize in-transit email with sendmail. This works fine on a mail gateway, but if you are just sanitizing mail being delivered to local recipients (on the same machine as the sanitizer) then it is far simpler and safer to use procmail as your local delivery agent and invoke the sanitizer as described in the installation chapter.
One method involves using procmail as an intermediate layer between sendmail and the sanitizer, the other method invokes the sanitizer directly. The procmail method is recommended, since procmail provides simple and robust error handling and logging functions. On the other hand, the procmail method may be signifigantly slower, since it involves at least twice as many I/O operations and perhaps some disk accesses as well. On an already loaded system, this may not be acceptible overhead.
The choice is yours - but whatever you do be careful, and be sure to test this carefully on a non-production machine before implementing it anywhere important! Keep in mind that sendmail is a tricky beast and this may not work on your system without lots of modifications. This works for me, but your mileage may vary.
If you are using procmail, skip steps 2. and 3.
If you are not using procmail, skip steps 4. and 5.
If you are using procmail, skip this step.
Create the following shell script, e.g. in
/usr/local/bin/sanitize.
#!/bin/sh
#
export ANOMY=/path/to/anomy
export CFG=/path/to/sanitizer/configuration
exec $ANOMY/bin/sanitizer.pl $CFG | /path/to/sendmail -oi -f ${@+"$@"}
Be sure to set all the paths to whatever makes sense on your system. Don't forget to make the script executable (chmod +x /usr/local/bin/sanitize).
If you are using procmail, skip this step.
Add the following mailer specification to sendmail.cf. It's a
good idea to add this to the part of the file containing the other
mailer definitions.
Msanitize,
P=/usr/local/bin/sanitize, F=DFMmhu,
S=11/31, R=21/31, T=DNS/RFC822/X-Unix, A=sanitize $f $u
If you are not using procmail, skip this step.
Create a procmail configuration file named /etc/sanitizer.rc
like this:
# Procmail filter rules for sanitizing email and then resending it. # Uncomment the following lines to enable logging or verbose logging. # VERBOSE=yes # LOGFILE=/var/log/procmail-sanitizer.log ANOMY=/path/to/anomy/ :0 f | $ANOMY/bin/sanitizer.pl /path/to/sanitizer/configuration :0 ! -oi -f "$@"
Be sure to set all the paths to whatever makes sense on your system.
If you are not using procmail, skip this step.
Add the following mailer specification to sendmail.cf, if
it doesn't exist already. It's a good idea to add this to the part of
the file containing the other mailer definitions. Be sure to
adjust the path to the procmail binary to match your system.
Mprocmail,
P=/usr/bin/procmail, F=DFMmShu,
S=11/31, R=21/31, T=DNS/RFC822/X-Unix, A=procmail -m $h $f $u
Add the following rules to sendmail.cf, either in ruleset 98 (local hacks, on RedHat systems) or right before the virtual user stuff in ruleset 0:
# Sanitize with procmail:
#R$* < @test.com. > $* $#procmail $@/etc/sanitizer.rc $:$1<@test.com.CLEAN.>$2
# Sanitize without procmail:
#R$* < @test.com. > $* $#sanitize $@anomy $:$1<@test.com.CLEAN.>$2
R$* < @ $+ .CLEAN. > $* $1<@$2.>$3
R$* < @ $+ .CLEAN > $* $1<@$2.>$3
^
use TABS here!
Notes: Only one of the two .CLEAN rules are necessary - which one seems slightly system-dependant. Having both won't hurt. Be sure to replace "test.com" with the domain for which you want to sanitize mail - the example will sanitize all messages destined for someone@test.com. Multiple domains can be specified by repeating the first line, once for each domain or by specifying a class of domains, as described below.
Add the user sendmail runs as, on the mail port, to the list of trusted users (the "t" class - search sendmail.cf for the phrase "Trusted users"). This instructs sendmail not to generate a warning header when the shell script sets the From-address when it resends the sanitized mail. On RedHat 6.x systems this user is named "mail". This step may not be necessary on some systems, but again, it won't hurt.
Finally, activate the sanitizing method you prefer (with or without procmail) by uncommenting (removing the leading #-sign) the relevant line added in step 6 and then restart sendmail.
Please be careful to use TABs where necessary in the sendmail.cf file. In the Msanitize and Mprocmail definitions above, the lines have been split to improve readability - either copy the entire text into a single line in your sendmail.cf or be sure that the continuations begin with TAB characters, not spaces.
Although the above instructions all assume you are editing your sendmail.cf file directly, they can easily be adapted for people using the (recommended) m4 method to configure sendmail. Simply append the mailer definitions to your m4 file in a section named MAILER_DEFINITIONS, and the local hacks stuff to a section named LOCAL_RULE_0. People interested in m4 configuration might also find the anomy.m4 and sendmail-m4.txt files in the contrib/ directory of the distribution helpful.
To match a class of domains (instead of just test.com), you could replace the first R$* line(s) with something like this:
# Sanitize with procmail: #R$* < @ $=w . > $* $#procmail $@/etc/sanitizer.rc $:$1<@$2.CLEAN.>$3 # Sanitize without procmail: #R$* < @ $=w . > $* $#sanitize $@anomy $:$1<@$2.CLEAN.>$3
This matches any host names in the "w" class (traditionally /etc/sendmail.cw). An "X" class can be defined with "CX host" or "FX/path/to/file" lines near the beginning of the sendmail configuration file. People using m4 configuration can add such definitions after the LOCAL_CONFIG directive in their m4 files.
If you are somewhat reckless (or are sure you know what you are doing), you can just sanitize everything, like this:
# Sanitize with procmail: #R$* < @ $+ . > $* $#procmail $@/etc/sanitizer.rc $:$1<@$2.CLEAN.>$3 # Sanitize without procmail: #R$* < @ $+ . > $* $#sanitize $@anomy $:$1<@$2.CLEAN.>$3
Please note that sanitizing everything like this is not recommended, since it will sanitize both incoming and outgoing email.
It is the author's humble opinion, that incoming and outgoing email should be handled in fundamentally different ways; incoming email should always be delivered to the recipient, if at all possible (but it's a good idea to defang the dangerous bits first), but outgoing email should be bounced back to the sender if it contains a virus or security hazard. You don't want to send partial messages out of your organization - you want to notify the sender so they can fix the problem and re-send the content as quickly as possible. Future revisions of this document will describe how to use the Sanitizer to simply block risky outgoing mail.
[ contents ]
Install qmail with the qmail-queue-patch and qmail-qfilter.
From qmail.org: "Bruce Guenter has written a patch which causes any program that would run qmail-queue to look for an environment variable QMAILQUEUE. If it is present, it is used in place of the string "bin/qmail-queue" when running qmail-queue. This could be used, for example, to add a program into the qmail-smtpd->qmail-queue pipeline that could do filtering, rewrite broken headers, etc."
This is just what we are going to use. You will find the qmail-queue-patch here: http://www.math.ntnu.no/mirror/www.qmail.org/qmailqueue-patch (and on every other qmail-mirrior site).
qmail-qfilter is found here: http://em.ca/~bruceg/qmail-qfilter/.
Install tcpserver (ucspi).
You can find this here: http://em.ca/~bruceg/rpms/ucspi-tcp/.
Make tcpserver set the qmail-queue-parameter/variable
This is done by editing the /etc/tcpcontrol/smtp.rules file. The file should look something like:
# Myself going through the filter 127.0.0.1:allow,RELAYCLIENT="",QMAILQUEUE="/var/qmail/filters/smtpd-queue" # Server(s) allowed to relay, but not going through the filter xxx.xxx.xxx.xxx:allow,RELAYCLIENT="" # Default (everyone else must go through) :allow,RELAYCLIENT="",QMAILQUEUE="/var/qmail/filters/smtpd-queue"
Compile the file (tcpserver uses a compiled version of this file with a .cdb-extension). If you also use qmail-qmqpd or any other qmail daemon that receives incoming mail, be sure to edit and recompile the corrosponding rule file (e.g. /etc/tcpcontrol/qmqp.rules) and use the same value for QMAILQUEUE in both (or all) places.
Now you have tcpserver accepting connections, sending the incoming email with the QMAILQUEUE-variable set to the script "smtpd-queue".
The script smtpd-queue (or whatever you choose to call it) should look something like:
#!/bin/sh
exec /usr/bin/qmail-qfilter
/var/qmail/filters/sanitizer /var/qmail/filters/sanitizer.cfg
Note: the exec command has been split between lines for readability. It should all be in one line.
What happens here is that qmail-qfilter passes the email to sanitizer (which starts with a config-file in this example). When sanitizer is finished with it, it is passed back qmail so it can be sent the usual way.
Configure qmail to act as a relay server.
Read the FAQ if you don't know how to do this.
[ contents ]
The sanitizer was tested on my 525Mhz Celeron (bus OC'ed to 95Mhz), with the following messages.
file size description
--------- --------- -----------
Dev.test1 2206 a plain RFC822 message with no attachment
Dev.test2 26227 3 parts:
a text part with a UU-encoded evil HTML snippet
a html part with evil html
a harmless plain text part
Dev.test3 2342 a multipart/signed message containing clean text
Dev.test4 17139 3 parts:
a uu-encoded text part
a plain text part with an UU-encoded perl script
an unencoded perl script (8bit, text/plain)
Dev.test6 4984617 a multipart mixed message with a big base64-encoded
jpeg attachment.
[bre@diskordiah bin]$ time ./sanitizer.pl </dev/null 0.10user 0.01system 0:00.10elapsed 101%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (282major+194minor)pagefaults 0swaps [bre@diskordiah bin]$ time ./sanitizer.pl <../Dev.test1 >/dev/null 0.12user 0.00system 0:00.14elapsed 85%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (287major+201minor)pagefaults 0swaps [bre@diskordiah bin]$ time ./sanitizer.pl <../Dev.test2 >/dev/null 0.47user 0.00system 0:00.47elapsed 98%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (289major+283minor)pagefaults 0swaps [bre@diskordiah bin]$ time ./sanitizer.pl <../Dev.test3 >/dev/null 0.13user 0.00system 0:00.12elapsed 101%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (287major+204minor)pagefaults 0swaps [bre@diskordiah bin]$ time ./sanitizer.pl <../Dev.test4 >/dev/null 0.20user 0.03system 0:00.25elapsed 91%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (288major+223minor)pagefaults 0swaps [bre@diskordiah bin]$ time ./sanitizer.pl <../Dev.test6 >/dev/null 12.63user 0.05system 0:13.00elapsed 97%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (970major+257minor)pagefaults 0swaps
Is this good enough? Please let me know what you think.
Since the performance is almost entirely CPU bound, throughput could be increased linearly by simply adding more processing power, e.g. by adding more or faster CPUs to your mail server, or by creating a sanitizer farm.
Another method to speed things up would be to change the sanitizer into some sort of daemon, thus avoiding the startup- and compilation costs of perl entirely. Since initialization accounts for 25-45% of the time it takes to process the "average message", and over 75% of the time for the small messages (which are very common), this would make quite a difference.
OTOH, the performance is only going to get worse, once external virus scanners are added to the mix...
[ contents ]
Note: read this if you are having problems with excessive memory consumption when sanitizing very large messages.
While scanning the big message (Dev.test6), top consistantly reported memory usage as (SIZE, RSS, SHARE) = (2084, 2084, 1052). For Dev.test4 the numbers were (1952, 1952, 1056) and for Dev.test1 they were (1860, 1860, 1052).
The difference is probably due to Dev.test6 maxing out all the IO buffers it had available, which the other tests were too small to do. I verified this theory by tripling the size of Dev.test6 - the resulting numbers were almost identical (2088 instead of 2084). Cool!
This doesn't mean that more memory usage is impossible - the sanitizer allocates a new set of buffers for each level of nesting within the message. A memory DoS attack could be launched by deeply nesting uuencoded parts within each other - this could at the moment raise the memory (and CPU) usage arbitraily. But this would be a deliberate attack, such messages are rarely, if at all, created by normal mailers.
This could be addressed by adding a maximum recursion limit to the sanitizer, but I haven't done so yet and am not sure it's necessary. Aren't there easier ways to attack a mail server?
[ contents ]
The real world configuration example illustrates this.
[ contents ]
Which method is best is simply a matter of taste.
PATH="/usr/bin:$PATH" SHELL=/bin/sh
Special thanks to Peter Burkholde for his detailed feedback.
Patrick Duane Dunston <duane@duane.yi.org> and Bill Kenworthy contributed a short how-to on configuring Postfix to filter messages through the sanitizer before delivery. Their instructions may be found in the contrib/ directory of the program distribution.
[ contents ]
Some people have reported problems with very large messages and excessive memory consumption when invoking the sanitizer from within procmail. These problem is caused by procmail, not the sanitizer. If you have this problem, consider limiting incoming message size to something that will fit in your mail server's memory or invoking the sanitizer directly (without procmail).
[ contents ]
Q:
My problem is that attachments from Exchange/Outlook users get
corrupted. The end result is that the document is completely unreadable
when detached. One of the symptoms is that it ends up with the word
"DEFANGED" being inserted into the body of the attachment:
M````````````````><DEFANGED.35 M`````````````````````````
A: This is HTML defanging, defanging the contents of an UU-encoded attachment. This only happens when the following conditions are all met:
The solution is to turn on uuencoded attachment support, or turn off HTML defanging. The latter is not recommended.
[ contents ]
Note: This problem was hopefully solved when the HTML cleanup code was rewritten for revision 1.45 of the sanitizer.
Q: I'm not sure if this is a bug per se, but mail received from Outlook XP using Word as the editor in HTML format looks very ugly. I've attached an example. I'm using anomy 1.35. I'd really appreciate any hints on how to configure or patch anomy to handle this!
A: This is a known issue with the sanitizer, inherited from John Hardin's procmail ruleset.
It has to do with the defanging of <STYLE>...</STYLE> blocks, which were invented by someone with no clue of HTML design philosopy. Instead of the style settings being attributes or "funny tags" they are simply written out as a CSS definition following the <STYLE> tag - when the <STYLE> tag gets defanged, the CSS info is revealed as text where it used to be invisible.
The reason this is all so stupid is the exact same thing happens if the un-defanged HTML is viewed in a browser that doesn't know about STYLE tags.
[ contents ]
[ contents ]
The pros of using a stream-based model:
[ contents ]
These problems will be fixed Real Soon Now.
RFC2231: MIME Parameter Value and Encoded Word Extensions.
Partially compliant, as of 1.45. This on my TODO list.
RFC2311: S/MIME Version 2 Message Specification
RFC2312: S/MIME Version 2 Certificate Handling
Please let me know if you use this program!
My email address is bre@netverjar.is, please put "sanitizer" somewhere in the subject line.
Some questions:
Finally, if the program proves useful to you and you haven't time to contribute code, documentation or bug reports - then please consider supporting the project with a cash donation. I'm doing this in my spare time, and all encouragement helps.
Thanks!
[ contents ]
Copyright (C) 2000
Bjarni R. Einarsson
<bre@netverjar.is>.
All rights reserved.
Development of the Anomy Sanitizer, from versions 1.35 onwards, has been primarily sponsored by FRISK Software International. Please consider buying their anti-virus products to show your appreciation.
The sanitizer contains code and implements ideas by John D. Hardin <jhardin@wolfenet.com>.
Kim Johnny Mathisen
<Kim.Mathisen@haukeland.no>
contributed the instructions for
in-transit sanitizing with qmail.
Mark Salazar
<msalazar@schaferdc.com>
submitted improvements to the qmail chapter as well.
Sterling Hanenkamp
<Sterling@nrg-inc.com>
contributed pointers on in-transit configuration of sendmail, using the
recommended m4 method.
Ideas were also borrowed from AMaViS and Inflex.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
[ contents ]
$Id: sanitizer.html,v 1.20 2003/04/30 01:45:24 bre Exp $