7.6 The Milter Library
Beginning with V8.12,
sendmail offers hooks to access external
programs via sockets, and a library to build external programs to
listen on sockets. We first
discuss the hooks inside the configuration file in support of
external programs, and after that briefly discuss building your own
program.
7.6.1 Enable with -DMILTER
To access external programs via sockets from
sendmail, you need to compile
sendmail with the MILTER compile-time macro
defined. To build sendmail in this way, simply
add a line such as this to your m4
Build file:
APPENDDEF(`confENVDEF', `-DMILTER')
Then, build sendmail in the usual manner.
If you are using precompiled sendmail, you can
detect if it was built with the MILTER compile-time macro defined by
running the following command:
% /usr/sbin/sendmail -bt -d0.4 < /dev/null
If MILTER was defined, it will appear among a list of other defined
macros in a line that will look something like this:
Compiled with: DNSMAP LOG MAP_REGEX MILTER MIME7TO8 MIME8TO7
note
If it doesn't appear, you will need to either
download the sendmail source and build it
yourself, or contact your operating system vendor and request a
properly compiled version in binary form.
7.6.2 The X Configuration Command
With MILTER enabled,
sendmail offers a way to submit messages to
external programs that can be used to screen messages for spam
indicators, viruses, or other content that you might want to reject.
At the end of this chapter, we will show you the library routines to
use when making this decision. Here, we discuss the hooks inside the
configuration file that allow you to run external programs.
External programs are defined for use by
sendmail using the X
configuration file command. The form for that command looks like
this:
Xname, equates ... cf file
INPUT_MAIL_FILTER(`name', `equates ...') mc file
MAIL_FILTER(`name', `equates ...') mc file
The X in the first line, like all configuration
commands, must begin a line. It is immediately followed by the name
you will assign the external program, with no intervening spaces.
That name is for
sendmail's use only, and does
not need to be the actual name of the program. The name is followed
by a comma. If you accidentally prefix the name with a space (in the
cf or mc form), or omit the
name, the following error will print and the
sendmail program will exit:
cf file: line number name required for mail filter
The equates in this configuration command is a
sequence of comma-separated expressions that are formed by a
key-letter, an equal sign, and a value:
key-letter=value
The recognized key-letters and their meanings are shown in Table 7-4.
Table 7-4. X configuration command key-letters
F
|
Controlling flags
|
S
|
Description of the socket to use
|
T
|
The timeout to impose on the connection
|
For example, the following three mc file lines
define three possible external program hooks:
INPUT_MAIL_FILTER(`progA', `S=local:/var/run/f1.sock, F=R')
INPUT_MAIL_FILTER(`progB', `S=inet6:999@localhost, F=T, T=S:1s;R:1s;E:5m')
INPUT_MAIL_FILTER(`progC', `S=inet:3333@localhost')
The first example shows how to attach to a Unix-domain socket in the
/var/run directory. The second example shows how
to connect to an IPv6 socket on port 999 of the local host. The third
example shows how to connect to an IPv4 socket on port 3333 of the
local host. We will describe each equate in detail in the following
three sections, but first, the following details should be noted.
If the = is missing from an equate, the following
error is printed and sendmail exits:
cf file: line number Xname `=' expected
If the key-letter prefixing the = character is not
one of the three shown in Table 7-4, the following
error is printed and sendmail exits:
cf file: line number Xname unknown filter equate badequate=
The three external programs will be used in the order declared. First
progA will be contacted on a Unix-domain socket.
If it accepts the message, progB will be contacted
on a network socket. If progB accepts the message,
progC will be given the final crack at the
message. When the nature of the sockets allows, some of these
connections might be in parallel.
If you want to declare external programs, but don't
want to set the order in which they are called, use the MAIL_FILTER
mc macro instead:
MAIL_FILTER(`progA', `S=local:/var/run/f1.sock, F=R')
MAIL_FILTER(`progB', `S=inet6:999@localhost, F=T, T=S:1s;R:1s;E:5m')
MAIL_FILTER(`progC', `S=inet:3333@localhost')
This is the same declaration as before, except that it omits the
declaration of the order in which the programs sockets will be
called. With this form, you will have to separately declare the order
with the InputMailFilters option (Section 7.6.3):
define(`confINPUT_MAIL_FILTERS', `progB, progA, progC')
Note that if sendmail was not compiled with
-DMILTER, declaring a socket
with these commands will cause the following error to be printed, and
sendmail will exit:
Warning: Filter usage ('X') requires Milter support (-DMILTER)
7.6.2.1 The X configuration command F= equate
The F= equate, which stands for
"Flags," can cause a message to be
rejected or deferred if the connection to the socket fails or if the
filter program gives a nonstandard response. If you want the message
rejected on failure, you use the letter R, which
stands for "reject." If you want
the message to be deferred, you use the letter T,
which stands for "temporary
failure":
F=R reject connection if the filter is unavailable or if it has an error
F=T temporary fail and defer if the filter is unavailable or if it has an error
If any letter other than R or T
is specified following the F=, or if the
F= equate is missing, the message is passed
through sendmail as if the entire
X configuration-file command were omitted, or as
if the socket could not be contacted.
7.6.2.2 The X configuration command S= equate
The S= equate, which stands for
"Socket," is mandatory and
specifies one of three different types of sockets as its value:
local a Unix-domain socket
unix synonym for local
inet an IPv4 network socket
inet6 an IPv6 network socket
If you use a socket type other than one of those listed, the
following error will print and sendmail will
exit:
cf file: line number Xname unknown socket type type: Protocol not supported
The format for the S= equate looks like this:
S=type:specification
The type is one of the three main types
shown earlier. The colon is literal and must be present. The
specification is particular to each type.
For the local (or unix) type,
the specification is the full pathname to a Unix-domain socket. For
example:
S=local:/var/run/progA.soc
Note that the socket must not already exist. The MILTER library will
automatically create a socket when one is needed.
The inet and inet6-type sockets
use a specification that is a port number, immediately followed by an
@ character, which is again immediately followed
by a host or address specification. For example:
S=inet:1099@localhost port 1099 on the local machine, using IPv4
S=inet:1099@host.your.domain port 1099 on another machine on your network,
using IPv4
S=inet6:1099@localhost port 1099 on the local machine, using IPv6
S=inet:1099@123.45.67.89 port 1099 at IPv4 number 123.45.67.89
S=inet6:1099@2002:c0a8:51d2::23f4 port 1099 at IPv6 number 2002:c0a8:51d2::23f4
As we have seen in the previous section, the F=
equate determines what will happen to a message should the connection
to a socket fail.
7.6.2.3 The X configuration command T= equate
There are four timeouts that can affect the use of an external
program connected via a socket. They are tunable in your configuration file. Table 7-5 shows all four timeouts, the key-letter for
each, and the default value for each.
Table 7-5. X configuration command T= letters
E
|
5 minutes
|
Overall timeout from sending EOM to filter to final EOM reply
|
R
|
10 seconds
|
Timeout for reading reply from the filter
|
S
|
10 seconds
|
Timeout for sending information from the MTA to a filter
|
C
|
5 minutes
|
Connection timeout
|
The form for each key-letter looks like this:
letter:value
Space can surround the colon. If you specify more than one key-letter
with a value, you must separate each from the other with a semicolon.
Again, space can surround each semicolon:
letter:value;letter :value
For example, the following code sets a timeout of 600 seconds for the
connection to the socket, and 20 seconds for reads and writes:
T=C:600s; R:20s; S:20s
The letter s following each number stands for
seconds. Instead, you can choose to use the letter
m, which stands for minutes. The letters
h for hours, d for days, and
w for weeks are also available, but they
don't make sense for use with this equate.
Note that for the C: key-letter, if you set the
value to zero, the default timeout for the
connect(2) system call will be used. See your
system documentation to determine that
default.
7.6.3 The InputMailFilters Option
Filters to connect to for processing
messages through external programs are declared with the
X configuration command (Section 7.6.2). One form of that command (for use in your
mc file) not only declares the filter, but also
defines the order in which the filters will be called:
INPUT_MAIL_FILTER(`progA', `S=local:/var/run/f1.sock, F=R')
INPUT_MAIL_FILTER(`progB', `S=inet6:999@localhost, F=T, T=S:1s;R:1s;E:5m')
Here, the filters will be called in the order
progA first and progB second,
for each phase of the message. Table 7-6 shows
which portion of the message is checked by each filter in time order.
Note the change in order when the DATA phase begins (header/body).
Table 7-6. Filters called in time order
progA
|
Connection information, such as hostname and IP address
|
progB
|
Connection information, such as hostname and IP address
|
progA
|
HELO/EHLO greeting information
|
progB
|
HELO/EHLO greeting information
|
progA
|
MAIL FROM: address and ESMTP arguments
|
progB
|
MAIL FROM: address and ESMTP arguments
|
progA
|
RCPT TO: address and ESMTP arguments
|
progB
|
RCPT TO: address and ESMTP arguments
|
progA
|
The message headers
|
progA
|
The message body
|
progA
|
The end of a message (a semaphore)
|
progB
|
The message headers
|
progB
|
The message body
|
progB
|
The end of a message (a semaphore)
|
Each filter is handed portions of a message envelope and body, in
phases. For each phase, the filter can advise
sendmail of one decision among several possible
decisions. See libmilter/docs for a full
description of this process.
Filters can also be declared with the MAIL_FILTER
mc macro, but it does not set the order:
MAIL_FILTER(`progA', `S=local:/var/run/f1.sock, F=R')
MAIL_FILTER(`progB', `S=inet6:999@localhost, F=T, T=S:1s;R:1s;E:5m')
When the order is not set, or when it is set but you wish to change
it, you can use the InputMailFilters option. It
defines the order for calling filters:
O InputMailFilters=progB, progA cf file
define(`confINPUT_MAIL_FILTERS', `progB, progA') mc file
Here, the InputMailFilters option defines the
order that the filters will be called to be the reverse of what was
defined with the MAIL_FILTER mc command.
If you fail to define an order for the filters, no filters will be
called, and no message screening will happen.
If your version of sendmail was not compiled
with -DMILTER defined and you declare this option, you will get the
following error, and sendmail will exit:
Warning: Option: InputMailFilters requires Milter support (-DMILTER)
If you list more than the number of filters permitted by MAXFILTERS
(which defaults to 25), the following error will print and the extra
filters will be ignored:
Too many filters defined, 25 max
If you misspell one of the filter names, the following error will
print and that filter will be ignored:
InputFilter probB not defined
Note that all external programs and filters are connected to when the
message is received via SMTP (either over the network or with the
-bs command-line switch). None is called just
before the message is transmitted. Such output filtering might appear
in a future release of
sendmail.
7.6.4 Build a Filter
A mail filter is
a program that listens on a socket. It receives a message on that
socket from sendmail interactively and in
pieces. The sendmail program first offers the
connection information, and the filter can take it for review, or
decline it. If it accepts, it will screen that information and either
reject the message based on its review, or allow the message. Then
the next piece is offered and reviewed in the same manner. The order
of the review is:
- Connect
-
Review based on the IP address and hostname of the connecting site.
- helo/ehlo
-
Review based on the hostname given as part of the SMTP HELO or EHLO
command.
- Sender
-
Review the envelope-sender as supplied as part of the SMTP MAIL FROM:
command.
- Recipient
-
Review the envelope-recipient as supplied as part of the SMTP RCPT
TO: command.
- Headers
-
Review the header portion of the email message.
- EOH
-
Signals the end of the header portion of the message.
- Body
-
Review the message body, which can include MIME-encoded portions.
- EOM
-
Signals the end of the body portion of the message.
The program must quickly (within the timeouts defined by the
X configuration command) parse the pieces and
decide if the message should be accepted or rejected. The program
then advises sendmail of its decision, using the
libmilter API.
The sendmail source distribution includes a
library and sample program that you should use to create your own
filter program. Look in the directory libmilter.
It contains the source for the library, a README file with the latest
information, and a subdirectory libmilter/docs
that contains all the documentation you will need in HTML format.
We recommend you build your filter program using the supplied
library. Don't dig through the source to divine the
current protocol because that protocol will evolve from version to
version. Instead, use the API provided by the library.
If you don't wish to write your own filter program,
consider the following, and search the Web for others:
- http://www.milter.org/
-
A guide to and discussions about MILTERs in general.
- http://mailbox.univie.ac.at/~at/vilter/
-
The vilter program scans incoming email and
rejects or flags with a header line the infected messages.
- http://www.amavis.org/
-
The amavis program is a mail virus scanner.
- http://aeschi.ch.eu.org/milter/
-
The vbsfilter program will rename a variety of
executable attachments to .txt, thus rendering
them harmless.
- http://sendmail.com/
-
Sendmail, Inc. offers several commercial filters.
|