[Mimedefang] Next generation mimedefang-filter
Nik Clayton
nik at ngo.org.uk
Thu May 12 06:36:22 EDT 2005
Hi all,
I'm thinking out loud here.
I've got a number of different systems running MimeDefang, grouped in to
'classes'. Each system in the same class has identical functionality,
and some, but not all, functionality can be shared by different classes.
At the moment each class has a custom mimedefang-filter file. There's a
lot of duplication between files, which is bad, and it makes it tricky
to verify that the same functionality is implemented in the same way.
It's also a pain to test.
So here's a radical approach.
Ditch mimedefang-filter. Have mimedefang.pl use something like
Module::Pluggable to find everything in the MimeDefang::Filter::Plugin
namespace.
Then have every filter_* subroutine in mimedefang-filter be something like:
sub filter_sender {
# Assume @plugins is a list of references to
# MimeDefang::Filter::Plugin::* objects
foreach my $plugin (@plugins) {
if $plugin->can('filter_sender') {
$plugin->filter_sender(@_);
}
return if message_rejected();
}
}
In other words, it calls each plugin's filter_sender() method (if it
exists), and allows each plugin's method to reject the message (and
short circuit the rest of the processing) as necessary.
There needs to be some sort of ordering mechanism in here to ensure that
multiple plugins with a filter_sender() method get called in the right
order. That might be provided by the plugins themselves (perhaps they
specify whether or not they're 'heavy' or 'light', and MD runs all the
'light' plugins first; or perhaps there's a config file managed by the
user that specifies an implicit ordering).
A config file is probably the right approach -- this also lets you put
per-plugin configuration data in there. Perhaps .ini style;
# Assume something's in the MimeDefang::Filter::Plugin namespace
# unless it says otherwise
# Specify an order to run plugins
[global]
order=Whitelist, Blacklist, AntiVirus, SpamAssassin
# MimeDefang::Filter::Plugin::Whitelist options
[Whitelist]
whitelist=/path/to/whitelist.txt
# Options for the ::SpamAssassin plugin
[SpamAssassin]
bayes_db=/path/to/bayes.db
network_tests=1
and so on.
This abstracts specific functionality out in to separate modules --
these are then (hopefully) easier to understand, and, much more
importantly, easier to unit test outside of MimeDefang. It's also
easier to distribute them to others -- if you've come up with a great
way of doing greylisting, for example, you don't need to cut and paste
from your filter file, you just distribute your
M::F::Plugin::GreyListing file.
Bringing existing mimedefang-filter files in to line with this is
probably as simple as putting this at the top of the file:
package MimeDefang::Filter::Plugin::MyBigPluginThatDoesEverything;
use base 'MimeDefang::Filter::Plugin::base';
which pre-supposes the existence of a ::base class that provides methods
like "action_bounce()" (which would come from mimedefang.pl).
Poking through the suggested-minimum-filter-for-windows-clients that
ships with 2.51, a plugin split along the lines of:
Attachments - filters attachments based on filenames and extensions
Attachments::Zip - filters .zip files based on the files in Attachments
HTMLCleaner - cleans HTML in messages
Partial - blocks message/partial messages
Virus - scans for viruses
SpamAssassin - runs SpamAssassin over the message
Some additional plugins that would be easy to write:
Blacklist - filters messages according to a blacklist
Whitelist - filters messages according to a whitelist
SPF - carries out SPF checks
Headers - verifies that certain headers exist and have valid values
Thoughts? Would anyone use this? David, would you be happy to see
MimeDefang go in this sort of direction?
N
More information about the MIMEDefang
mailing list