Installing Milter-SPF with Sendmail

Here are step-by-step instructions for installing Milter-SPF with Sendmail 8.13.1 on Solaris. You should also read the installation instructions provided with Milter-SPF available here.

A multi-threaded Perl 5.8.0 or later is required for the Sendmail::Milter Perl module. Since the version of Perl installed on my system was not multi-threaded, I built a multi-threaded Perl from source.

If your version of Perl is multi-threaded, it will have been compiled with USE_ITHREADS:

# perl -V | grep "Compile-time options:"
  Compile-time options: MULTIPLICITY USE_ITHREADS USE_LARGE_FILES PERL_IMPLICIT_CONTEXT

Step 1: Build and install a multi-threaded Perl

You may download Perl source here.

gzip -cd perl-5.8.5.tar.gz | tar xvf -
cd perl-5.8.5
sh Configure

During the Perl build process, I accepted the default choices for all but two options. First, I chose to build a threading Perl:

Perl can be built to take advantage of threads on some systems.
To do so, Configure can be run with -Dusethreads.

Note that Perl built with threading support runs slightly slower
and uses more memory than plain Perl. The current implementation
is believed to be stable, but it is fairly new, and so should be
treated with caution.

If this doesn't make any sense to you, just accept the default 'n'.
Build a threading Perl? [n] y

Second, I chose to use the gcc compiler to build Perl:

Use which C compiler? [cc] gcc

make

Note: Since I already had a third-party Perl package installed from Sunfreeware, I removed it prior to performing make install. Do not remove the Perl package that is bundled with the Solaris operating system!

make install

Step 2: Install Milter-SPF prerequisites

I installed the following Perl modules as prerequisites for Milter-SPF:

Digest-HMAC
Digest-SHA1
Mail-SPF-Query
Mail-SRS
Net-CIDR
Net-CIDR-Lite
Net-DNS
Sendmail-Milter
Sys-Hostname-Long
URI

I recommend using the CPAN Perl module to install the above modules.

Note: before building Sendmail-Milter, make sure that libmilter.a exists in $SENDMAIL_SRC/obj*/libmilter. If this file does not exist, build libmilter:

cd
$SENDMAIL_SRC/libmilter
./Build

Otherwise, you may receive the following error when attempting to start SPF-Milter:

ld.so.1: /usr/local/bin/perl: fatal: relocation error: file /usr/local/lib/perl5/site_perl/5.8.5/sun4-solaris-thread-multi/auto/Sendmail/Milter/Milter.so: symbol smfi_setconn: referenced symbol not found

Step 3: Configure Sendmail to use SPF-Milter

First, check to see if Sendmail has been built with libmilter support. By default, Sendmail 8.13.x versions and later are built with libmilter support.

sendmail -d0.8 < /dev/null

 Compiled with: DNSMAP HESIOD HES_GETMAILHOST LDAPMAP LOG MAP_REGEX
                MATCHGECOS MILTER MIME7TO8 MIME8TO7 NAMED_BIND NETINET NETINET6
                NETUNIX NEWDB NIS PIPELINING SASLv2 SCANF STARTTLS TCPWRAPPERS
                USERDB USE_LDAP_INIT

If you not see MILTER when running this command, add the following two lines to $SENDMAIL_SOURCE/devtools/Site/site.config.m4:

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

and
rebuild and reinstall Sendmail:

cd $SENDMAIL_SOURCE
./Build -c
./Build install

Once Sendmail has been built with libmilter support, add the following three lines to the Sendmail macro configuration file $SENDMAIL_SOURCE/cf/cf/sendmail.mc:

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')

Note: I remove "F=T," in the INPUT_MAIL_FILTER line so that Sendmail will continue processing the message if spf-milter is not available. I also use a Milter.LogLevel of "0" to reduce the size of the mail logs; I would only do this after verifying that the milter is working correctly.

From $SENDMAIL_SOURCE/libmilter/README:

The current flags (F=) are:

        R               Reject connection if filter unavailable
        T               Temporary fail connection if filter unavailable

If neither F=R nor F=T is specified, the message is passed through sendmail
in case of filter errors as if the failing filters were not present.

Build and install the Sendmail configuration file /etc/mail/sendmail.cf:

cd $SENDMAIL_SOURCE/cf/cf
./Build install-cf

Step 4: Install and execute Milter-SPF

In this example, I installed sendmail-milter-spf-1.41.pl into /usr/local/bin, and executed the Milter-SPF Perl script as the daemon user using an /etc/init.d/milter-spf startup and shutdown script.

cp sendmail-milter-spf-1.41.pl /usr/local/bin

Note: I made changes to sendmail-milter-spf-1.41.pl to log all SPF results in $SPF_LOG_FILENAME instead of just SPF failures (and those are only logged if Milter-SPF is run in "tag-only" mode). Also, my multi-threaded Perl is located in /usr/local/bin.

Changes in "unified diff" format:

diff -u sendmail-milter-spf-1.41.pl sendmail-milter-spf-1.41.pl.bmh > sendmail-milter-spf-1.41.pl.patch
cat sendmail-milter-spf-1.41.pl.patch
--- sendmail-milter-spf-1.41.pl 2004-06-30 10:18:57.000000000 -0500
+++ sendmail-milter-spf-1.41.pl.bmh     2004-11-16 14:57:47.242629789 -0600
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/local/bin/perl
 #
 # Sendmail Milter to perform SPF lookups
 #
@@ -368,6 +368,11 @@
                            " helo = ".$priv_data->{'helo'}.
                            " from = ".$priv_data->{'from'});
             } else {
+               # Log SPF failure in $SPF_LOG_FILENAME in addition
+               # to rejecting message
+                write_log ("SPF \"fail\" from ip = ".$priv_data->{'ipaddr'}.
+                           " helo = ".$priv_data->{'helo'}.
+                           " from = ".$priv_data->{'from'});
                 $ctx -> setreply ('550', '5.7.1', "$priv_data->{'spf_smtp_comment'}");
                 return SMFIS_REJECT;
             }
@@ -567,6 +572,12 @@
                            " from = ".$priv_data->{'from'}.
                            " to = ".$priv_data->{'to'});
             } else {
+               # Log SPF failure in $SPF_LOG_FILENAME in addition
+                # to rejecting message
+                write_log ("SPF \"fail\" from ip = ".$priv_data->{'ipaddr'}.
+                           " helo = ".$priv_data->{'helo'}.
+                           " from = ".$priv_data->{'from'}.
+                           " to = ".$priv_data->{'to'});
                 $ctx -> setreply ('550', '5.7.1', "[RCPT TO: <$priv_data->{'to'}>] $priv_data->{'spf_smtp_comment'}");
                 return SMFIS_REJECT;
             }
@@ -590,6 +601,10 @@
     # prepend the new Received-SPF header.
 
     if ($priv_data->{'spf_result'}) {
+        write_log ("SPF $priv_data->{'spf_result'} from ip = ".$priv_data->{'ipaddr'}.
+            " helo = ".$priv_data->{'helo'}.
+            " from = ".$priv_data->{'from'}.
+            " to = ".$priv_data->{'to'});
         $ctx->addheader('Received-SPF', $priv_data->{'spf_result'} . ' (' . $priv_data->{'spf_header_comment'} . ')');
     }

To patch sendmail-milter-1.41.pl, execute patch < sendmail-milter-1.41.pl.patch with the original sendmail-milter-1.41.pl in the same directory.

I created the following /etc/init.d/milter-spf Milter-SPF startup and shutdown script:

#!/bin/sh

PERL=/usr/local/bin/perl
MILTER_SPF=/usr/local/bin/sendmail-milter-spf-1.41.pl

case "$1" in
   'start')
      $PERL $MILTER_SPF daemon
      ;;

   'stop')
      $PERL $MILTER_SPF -k
      ;;
   *)
      echo "Usage: $0 { start | stop }"
      exit 1
      ;;
esac
exit 0

chmod 744 /etc/init.d/milter-spf
chown root:sys /etc/init.d/milter-spf
ln -s /etc/init.d/milter-spf /etc/rc2.d/S89milter-spf
ln -s /etc/init.d/milter-spf /etc/rc1.d/K35milter-spf

Finally, start Milter-SPF and send Sendmail a SIGHUP to begin using it with Sendmail.

/etc/init.d/milter-spf start
kill -HUP Sendmail_PID

Step 5: Test Milter-SPF

From a remote system (i.e. do not execute this from Milter-SPF-enabled MTA), try the following test to confirm that Milter-SPF is properly installed:

telnet your_MTA 25
EHLO your_hostname
MAIL FROM: mengwong@vw.mailzone.com

You should see:

550 5.7.1 mengwong@vw.mailzone.com... Please see http://spf.pobox.com/why.html?sender=mengwong@vw.mailzone.com&ip=your_IP&receiver=your_MTA
 
Back to brandonhutchinson.com.
Last modified: 11/16/2004