       by Mark, System Administrator Asarian-host.org

1. INTRODUCTION
---------------

spf-milter is a Milter, which works with Sendmail 8.12 and up, and provides
an SPF-compliant extension to the SMTP communication between your MTA and
connecting clients. See http://spf.pobox.com/ for details about SPF itself.

spf-milter is written entirely in Perl, and uses the native threaded Milter
model. spf-milter is licensed under GPL.


2. PREREQUISITES
----------------

spf-milter requires:

1): Perl 5.8.x, or higher.

2): Perl modules:

    Sendmail::Milter (version 0.18)
    Mail::SPF::Query (at least version 1.99!)


3. INSTALLATION
---------------

Since spf-milter is written in Perl, you need, for starters,
Sendmail::Milter (at CPAN). The Milter API is threaded, so you need a
thread-enabled Perl (compiled with -Duseithreads) as well. If you do not
know whether you Perl supports threads, try and install Sendmail::Milter
first. It will itself test the ithread functionality of your Perl for
compatibility with Sendmail::Milter.

I built and tested spf-milter under Perl, v5.8.0 built for
i386-freebsd-thread-multi. Earlier versions of Perl versions may or may
not be suitable.


A) Sendmail

You must be using Sendmail 8.12.x
---------------------------------

Obtain the latest Sendmail 8.12.x source release from
http://www.sendmail.org. Unpack it. Add the following lines to
devtools/Site/site.config.m4:

  APPENDDEF(`conf_libmilter_ENVDEF', `-DMILTER')
  APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')

This enables the Milter functionality. Now build Sendmail as usual
("sh Build" in the sendmail/ directory).

Add the following lines to your Sendmail "m4" configuration file
(*.mc, in the cf/cf/ directory):

  define(`confMILTER_LOG_LEVEL',`9')dnl
  INPUT_MAIL_FILTER(`spf-milter', `S=local:/var/spf-milter/spf-milter.sock, F=T, T=C:4m;S:4m;R:8m;E:10m')

Adjust the MILTER_LOG_LEVEL and T timings to your liking. Now build
sendmail.cf as usual ("./Build sendmail.cf" in the cf/cf/ directory). Your
newly generated sendmail.cf will now contain a section that looks like this:

# Milter options
O Milter.LogLevel=9
O Milter.macros.connect=j, _, {daemon_name}, {if_name}, {if_addr}
O Milter.macros.helo={tls_version}, {cipher}, {cipher_bits}, {cert_subject}, {cert_issuer}
O Milter.macros.envfrom=i, {auth_type}, {auth_authen}, {auth_ssf}, {auth_author}, {mail_mailer}, {mail_host}, {mail_addr}
O Milter.macros.envrcpt={rcpt_mailer}, {rcpt_host}, {rcpt_addr}

And this:

######################################################################
######################################################################
#####
#####                   MAILER DEFINITIONS
#####
######################################################################
######################################################################

Xspf-milter, S=local:/var/spf-milter/spf-milter.sock, F=T, T=C:4m;S:4m;R:8m;E:10m

Inspect your new sendmail.cf, to see whether it does indeed contain these things.


B) Startup

You are already ready to start spf-milter! :)

Sendmail does not need to "find" the spf-milter script. You can run it from
pretty much every location. The only thing sendmail needs to do, is to be
able to find the local domain socket to connect to (spf-milter creates
"/var/spf-milter/spf-milter.sock" per default). If you successfully followed
the above steps, then your new sendmail.cf will contain the proper local
socket name.

Backup your old sendmail.cf. Now, stop sendmail, and copy the new
sendmail.cf to its proper location.

Now, start spf-milter first! Depending on where your thread-enabled Perl
resides, of course, you can, in its simplest form, start spf-milter like
this:

/usr/local/threadedperl/bin/perl /usr/local/spf/sendmail-milter.pl milter

We start spf-milter with at least one parameter, the user to run as.
spf-milter expects to create/read/write its log, pid, and socket, all in
/var/spf-milter/, and will itself create the directory, if need be, and set
all appropriate permissions/ownerships.

You cannot run spf-milter as root.

If everything went okay, try 'ps ax', and your spf-milter will show up as:

"spf-milter (perl)"

Restart sendmail. Now you're done. :)


C) Testing spf-milter functionality

Perform two basic tests:

1) Make sure legitimate mail gets through!

2) Confirm that forged mail is rejected; forging mail from
   mengwong@vw.mailzone.com will do the trick (address used
   with permission).

If properly rejected, you will get a 550 response, and a text with a
reference to "http://spf.pobox.com/why.html? ..." in the line.

N.B. The actual return-text may vary from MTA to MTA, but the 550 response
code SHOULD always be the same (an extended SMTP code, '550', '5.7.1').


4. COMMON QUESTIONS ANSWERED
----------------------------

1) Why does spf-milter use the native threaded Milter model?

Because Sendmail::Milter does.

2) How does spf-milter stay stable using ithreads?

Instead of using a multiplexor to split threads over individual child
processes (like MIMEDefang), spf-milter 'locks' (thread-locks) its
callbacks, thus effectively serializing the threads; so you get much of
the effect of what the MIMEDefang multiplexor does (kinda). And since the
'locked' attribute really prevents the threads from clobbering over one
another, you can even use thread-unsafe package calls within those subs,
like to DBI.

3) By serializing all callbacks, do you not reduce performance?

Without locking the subroutines, Sendmail::Milter is simply way too
unstable, and effectively unusable. However, since there are 10 callbacks in
total, each thread is only serialized for those occassions when two threads
try and access the same sub at the same time. Otherwise they run parallel
too: one thread may acces the eom_callback whilst another enters the
helo_callback, for instance. In fact, as long as all threads are just
slightly out of phase with one another (one callback difference minimum),
they all run nicely parallel.

4) Does spf-milter act prior to the DATA phase?

Yes, spf-milter makes its SPF checks before the DATA phase; at
envfrom_callback (at: "MAIL FROM: <address>"), or at envrcpt_callback (at:
"RCPT TO: <recipient>"), when running in "mx" mode.

5) Can spf-milter be used within the same sendmail configuration as
MIMEDefang (and other Milters)?

Yes. Quoting a bit from the libmilter documentation:

+----------------------------------------+
| SPECIFYING FILTERS IN SENDMAIL CONFIGS |
+----------------------------------------+

Filters are specified with a key letter ``X'' (for ``eXternal'').

For example:

    Xfilter1, S=local:/var/run/f1.sock, F=R
    Xfilter2, S=inet6:999@localhost, F=T, T=C:10m;S:1s;R:1s;E:5m
    Xfilter3, S=inet:3333@localhost

specifies three filters. Filters can be specified in your .mc file using
the following:

    INPUT_MAIL_FILTER(`filter1', `S=local:/var/run/f1.sock, F=R')
    INPUT_MAIL_FILTER(`filter2', `S=inet6:999@localhost, F=T')
    INPUT_MAIL_FILTER(`filter3', `S=inet:3333@localhost')

Which filters are invoked and their sequencing is handled by the 
InputMailFilters option:

    O InputMailFilters=filter1, filter2, filter3

This is is set automatically according to the order of the
INPUT_MAIL_FILTER commands in your .mc file. Alternatively, you can
reset its value by setting confINPUT_MAIL_FILTERS in your .mc file.
This options causes the three filters to be called in the same order
they were specified.

- Mark

        System Administrator Asarian-host.org
