       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://www.openspf.org 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!)
    Mail::SRS (version 0.30)


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
  define(`confMILTER_MACROS_HELO', confMILTER_MACROS_HELO`, {verify}')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}, {verify}
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/perl-threaded/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://www.openspf.org/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. SRS AND FAKE DSN DETECTION
-----------------------------


A) Outline

As of version 1.40, spf-milter comes with a new functionality: fake DSN
detection. It is activated by the -S option; and, when enabled, will spot
and REJECT unsigned DSN recipients. Signatures are based on SRS (Mail::SRS).
This is an advanced option; it requires an MTA counterpart installation to
sign outgoing envelope-from addresses, and should not be used unless you are
well familiar with the entire scheme and its possible ramifications.

The idea, in a nutshell, is as follows. Have an MTA sign all outgoing
envelope-from addresses. Then, when we receive a DSN (bounce message with a
MAIL FROM: <>), we will REJECT this DSN, unless the recipient was SRS
signed. Based on the old "what goes around, comes around" adage (or rather,
"what does not go around, should not come around"): if we do not ever send
out unsigned envelope-from addresses, then we know we are dealing with a
forgery when we receive an unsigned DSN recipient!

Only use this when you have implemented an SRS signing scheme in your MTA,
which will sign ALL outgoing envelope-from addresses. Unfortunately,
spf-milter cannot do that for you, as the Milter specs do not allow for a
method to change the envelope-from address. You may want to have a peek at
my SRS + sendmail integration project, at:

    http://asarian-host.net/srs/sendmailsrs.htm


B) How to use FAKE DSN DETECTION without SRS reversal in sendmail

If your incoming mail server differs from your outgoing one, then there is
way to use FAKE DSN DETECTION without setting up SRS reversal in the
sendmail configuration for you incoming mail server.

Since spf-milter handles your locally targeted SRS recipients, you would
think that suffices. And it does. However, the Milter specification does not
permit the changing of recipients at envrcpt_callback, and forces you to
wait until eom_callback; thereby leaving an intermediate window, between
callbacks, where sendmail itself will verify the recipients (upon return of
envrcpt_callback), and conclude that your nice SRS0 bounce address does not
exist on the system. The result? Sendmail will REJECT the recipient with a
"User unknown" after all.

The way to solve this, is to make use of sendmail's "plussed" user facility.
Define two users (virtusertable), like so:

    SRS0+*@yourdomain.com    user
    SRS1+*@yourdomain.com    user

(where "user" is the name of an existing user).

This will provide the necessary "fallback" for the undefined in-between
callback state. Mind you, these are 'dummy' addresses; they are never
actually used for delivery; they are just there to prevent sendmail from
bulking over your SRS addresses, in-between callbacks.

Now that sendmail has these fallback wildcard addresses, spf-milter can
proceed until eom_callback, where it will replace the SRS signed envelope
recipient(s) with their reversed counterparts.

For this to work, your SRS 'separator' character must be "+". Like so:

    my $srs = new Mail::SRS (Secret => 'yaddayadda', Separator => '+');

So that SRS0+, SRS1+ addresses are formed.


C) Start-up considerations

To use SRS on spf-milter, start it with the -S parameter; a minimum command
line usage would be:

    ./sendmail-milter-spf-1.40.pl -S milter

This will place spf-milter in FAKE DSN DETECTION mode, running as user
"milter".

There has been some discussion on whether people should become SRS1
forwarding hosts. To accomodate both parties, spf-milter can be started with
an additional option, "-r". If set, spf-milter will relay non-locally
resolving SRS0 addresses (reversed from SRS1 addresses). Per default,
spf-milter only accepts locally resolving SRS0 addresses. If you want full
SRS1 functionality, start spf-milter like so (minimal):

    ./sendmail-milter-spf-1.40.pl -S -r milter

Whether you start spf-milter with -S or not, when relaying, spf-milter is
always SRS aware (that is, when your own mailer is sending TO foreign SRS0,
SRS1 addresses). The "-r" option, outside -S, only has meaning when
relaying.


5. 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

-------
To unsubscribe, change your address, or temporarily deactivate your subscription, 
please go to http://v2.listbox.com/member/?listname=srs-discuss@v2.listbox.com
