mtasim
— a testing toolThe mtasim
utility is a MTA simulator for testing
mailfromd
filter scripts. By default it operates in
stdio mode, similar to that of sendmail -bs
. In this
mode it reads SMTP commands from standard input and sends
its responses to the standard output. There is also another mode,
called daemon, where mtasim
opens a TCP
socket and listens on it much like any MTA does. In both
modes no actual delivery is performed, the tool only simulates the
actions an MTA would do and responses it would give.
This tool is derived from the program mta
, which I wrote
for GNU Anubis test suite.
• interactive mode | ||
• expect commands | ||
• traces | ||
• daemon mode | ||
• command summary | ||
• option summary |
Next: expect commands, Up: mtasim [Contents][Index]
mtasim
interactive mode modeIf you start mtasim
without options, you will see the
following:
220 mtasim (mailfromd 9.0) ready (mtasim) _
The first line is an usual RFC 2821 reply. The second one is
a prompt, indicating that mtasim
is in interactive mode and
ready for input. The prompt appears only if the package is compiled
with GNU Readline and mtasim
determines that its standard
input is connected to the terminal. This is called interactive
mode and is intended to save the human user some typing by offering
line editing and history facilities (see Command Line Editing in GNU Readline Library). If the package
is compiled without GNU Readline, you will see:
220 mtasim (mailfromd 9.0) ready _
where ‘_’ represents the cursor. Whatever the mode,
mtasim
will wait for further input.
The input is expected to consist of valid SMTP commands
and special mtasim
statements. The utility will act exactly
like a RFC 2821-compliant MTA, except that it will
not do actual message delivery or relaying. Try typing HELP
to
get the list of supported commands. You will see something similar
to:
250-mtasim (mailfromd 9.0); supported SMTP commands: 250- EHLO 250- HELO 250- MAIL 250- RCPT 250- DATA 250- HELP 250- QUIT 250- HELP 250 RSET
You can try a simple SMTP session now:
220 mtasim (mailfromd 9.0) ready (mtasim) ehlo localhost 250-pleased to meet you 250 HELP (mtasim) mail from: <me@localhost> 250 Sender OK (mtasim) rcpt to: <him@domain> 250 Recipient OK (mtasim) data 354 Enter mail, end with `.' on a line by itself (mtasim) . 250 Mail accepted for delivery (mtasim) quit 221 Done
Notice, that mtasim
does no domain checking, so such thing
as ‘rcpt to: <him@domain>’ was eaten without complaints.
So far so good, but what all this has to do with
mailfromd
? Well, that’s what we are going to explain. To
make mtasim
consult any milter, use --port
(-X) command line option. This option takes a single
argument that specifies the milter port to use. The port can be given
either in the usual Milter format (See milter port specification,
for a short description), or as a full sendmail.cf style
X
command, in which case it allows to set timeouts as well:
$ mtasim --port=inet:999@localhost
# This is also valid:
$ mtasim --port='mailfrom, S=inet:999@localhost, F=T, T=C:100m;R:180s'
If the milter is actually listening on this port, mtasim
will connect to it and you will get the following initial prompt:
220-mtasim (mailfromd 9.0) ready 220 Connected to milter inet://localhost:999 (mtasim)
Notice, that it makes no difference what implementation is listening
on that port, it may well be some other filter, not necessarily
mailfromd
.
However, let’s return to mailfromd
. If you do not want to
connect to an existing mailfromd
instance, but prefer
instead to create a new one and run your tests with it (a preferred
way, if you already have a stable filter running but wish to test a
new script without disturbing it), use --port=auto. This
option instructs mtasim
to do the following:
mailfromd
. This instance is
configured to communicate over a UNIX socket in that temporary
directory. Additional arguments and options for the new instance may
be given in the command line after a double-dash marker (‘--’).
When mtasim
exits, it terminates the subsidiary
mailfromd
process and removes the temporary directory it has
created. For example, the following command will start
mailfromd -I. -I../mflib test.rc
:
$ mtasim -Xauto -- -I. -I../mflib test.rc 220-mtasim (mailfromd 9.0) ready 220 Connected to milter unix:/tmp/mtasim-j6tRLC/socket (mtasim)
The /tmp/mtasim-j6tRLC directory and any files within it will
exist as long as mtasim
is running and will be removed when
you exit from it.30 You can also instruct the subsidiary
mailfromd
to use this directory as its state directory
(see statedir). This is done by --statedir command line
option:
$ mtasim -Xauto --statedir -- -I. -I../mflib test.rc
(notice that --statedir is the mtasim
option,
therefore it must appear before ‘--’)
You can use an existing directory instead of creating a temporary one. To do so, use the -Xdir:name option, e.g.:
$ mtasim -Xdir:/var/lib/teststate --statedir -- -I. -I../mflib test.rc
Special care should be taken when using mtasim
from root
account, especially if used with -Xauto and
--statedir. The mailfromd
utility executed by it
will switch to privileges of the user given in its configuration
(see Starting and Stopping) and will not be able to create data in
its state directory, because the latter was created using ‘root’
as owner. To help in this case, mtasim
understands
--user and --group command line options, that have
the same meaning as for mailfromd
.
Now, let’s try HELP
command again:
250-mtasim (mailfromd 9.0); supported SMTP commands: 250- EHLO 250- HELO 250- MAIL 250- RCPT 250- DATA 250- HELP 250- QUIT 250- HELP 250- RSET 250-Supported administrative commands: 250- \Dname=value [name=value...] Define Sendmail macros 250- \Ecode [regex] Expect given SMTP reply code 250- \L[name] [name...] List macros 250- \Uname [name...] Undefine Sendmail macros 250 \Sfamily hostname address [port] Define sender socket address
While the SMTP commands do not need any clarification, some words about the administrative commands are surely in place. These commands allow to define, undefine and list arbitrary Sendmail macros. Each administrative command consists of a backslash followed by a command letter. Just like SMTP ones, administrative commands are case-insensitive. If a command takes arguments, the first argument must follow the command letter without intervening whitespace. Subsequent arguments can be delimited by arbitrary amount of whitespace.
For example, the \D
command defines Sendmail macros:
(mtasim) \Dclient_addr=192.168.10.1 f=sergiusz@localhost i=testmsg (mtasim)
Notice that mailfromd
does not send any response to the
command, except if there was some syntactic error, in which case it
will return a ‘502’ response.
Now, you can list all available macros:
(mtasim) \L 220-client_addr=192.168.10.1 220-f=sergiusz@localhost 220 i=testmsg (mtasim)
or just some of them:
(mtasim) \Lclient_addr 220 client_addr=192.168.10.1 (mtasim)
To undefine a macro, use \U
command:
(mtasim) \Ui (mtasim) \l 220-client_addr=192.168.10.1 220 f=sergiusz@localhost (mtasim)
The \S
command declare sender socket and host name. These
parameters are passed to the connect
handler, if one is
declared (see connect handler). To give you a chance to use this
command, mtasim
does not invoke connect
handler right
after connecting to the milter. Instead it waits until either the
\S
command or any SMTP command (except ‘HELP’)
is given. After calling connect
handler the \S
is
disabled (to reflect it, it also disappears from the HELP
output).
The \S
command takes 1 to 4 arguments. The first argument
supplies the socket family (see Table 4.3). Allowed values
are: ‘stdio’, ‘unix’, ‘inet’, ‘inet6’ or
numbers from ‘0’ to ‘3’.
The \S stdio
(or \S 0
) command needs no additional
arguments. It indicates that the SMTP connection is
obtained from the standard input. It is the default if sender socket
is not declared explicitly.
The command \S unix
indicates that the connection is accepted
from a UNIX socket. It requires two more argument. The first one
supplies sender host name and the second one supplies full
path name of the socket file. For example:
\S unix localhost /var/run/smtp.sock
The commands \S inet
and \S inet6
indicate that the
connection came from an ‘INET’ IPv4 or IPv6 socket,
correspondingly31. They require all
four arguments to be specified. The additional arguments are:
host name, IP address, and port number, in that order. For example:
\S inet relay.gnu.org.ua 213.130.31.41 34567
or
\S inet6 relay.gnu.org.ua 2001:470:1f0a:1be1::2 34567
Sender socket address can also be configured from the command line (see sender-socket).
Now, let’s try a real-life example. Suppose you wish to test the
greylisting functionality of the filter script described in Filter Script Example. To do this, you start mtasim
:
$ mtasim -Xauto -- -I. -I../mflib test.rc 220-mtasim (mailfromd 9.0) ready 220 Connected to milter unix:/tmp/mtasim-ak3DEc/socket (mtasim)
The script in test.rc needs to know client_addr
macro,
so you supply it to mtasim
:
(mtasim) \Dclient_addr=10.10.1.13
Now, you try an SMTP session:
(mtasim) ehlo yahoo.com 250-pleased to meet you 250 HELP (mtasim) mail from: <gray@yahoo.com> 250 Sender OK (mtasim) rcpt to: <gray@localhost> 450 4.7.0 You are greylisted for 300 seconds
OK, this shows that the greylisting works. Now quit the session:
(mtasim) quit 221 Done
Next: traces, Previous: interactive mode, Up: mtasim [Contents][Index]
mtasim
expect commandsUntil now we were using mtasim
interactively. However, it
is often useful in shell scripts, for example the mailfromd
test suite is written in shell and mtasim
. To avoid the
necessity to use auxiliary programs like expect
or
DejaGNU
, mtasim
contains a built-in expect
feature. The administrative command \E
introduces the
SMTP code that the next command is expected to yield. For
example,
\E250 rcpt to: <foo@bar.org>
tells mtasim
that the response to RCPT TO
command
must begin with ‘250’ code. If it does, mtasim
continues execution. Otherwise, it prints an error message and
terminates with exit code 1. The error message it prints looks like:
Expected 250 but got 470
The expected code given with the \E
command may have less than
3 digits. In this case it specifies the first digits of expected
reply. For example, the command ‘\E2’ matches replies
‘200’, ‘220’, etc.
If \E
is passed two arguments, the second one is treated as
an extended regular expression. The subsequent command will then
succeed if its return code matches the one supplied as the first
argument, and its extended SMTP code and textual message match the
supplied regular expression. If the regular expression contains
whitespace, enclose it in a pair of double quotes. Within double
quotes, backslash can be used to escape double quote, and backslash
character.
This feature can be used to automate your tests. For example, the following script tests the greylisting functionality (see the previous section):
# Test the greylisting functionality
#
\E220
\Dclient_addr=10.10.1.13
\E250
ehlo yahoo.com
\E250
mail from: <gray@yahoo.com>
\E450
rcpt to: <gray@localhost>
\E221
quit
This example also illustrates the fact that you can use
‘#’-style comments in the mtasim
input.
mtasim
scripts can be used in shell programs, for example:
mtasim -Xauto --statedir -- -P../mflib test.rc < scriptfile if $? -ne 0; then echo "Greylisting test failed" fi
Next: daemon mode, Previous: expect commands, Up: mtasim [Contents][Index]
It is possible to log an entire SMTP session to a file. This is called session tracing. Two options are provided for this purpose:
Sets the name of the trace file, i.e. a file to which the session
transcript will be written. Both the input commands, and the
mtasim
responses are logged. If the file file exists,
it will be truncated before logging. This, however, can be changed
using the following option:
If the trace file exists, append new trace data to it.
Next: command summary, Previous: traces, Up: mtasim [Contents][Index]
To start mtasim
in daemon mode, use the
--daemon (or -bd) command line option. This mode
is not quite the same as Sendmail -bd mode. When started in
daemon mode, mtasim
selects the first available
TCP port to use from the range ‘1024 -- 65535’.
It prints the selected port number on the standard output and
starts listening on it. When a connection comes, it serves a
single SMTP session and exits immediately when it is
ended.
This mode is designed for use in shell scripts and automated test cases.
Next: option summary, Previous: daemon mode, Up: mtasim [Contents][Index]
mtasim
Administrative CommandsThis section provides a summary of administrative commands available
in mtasim
.
Defines Sendmail macro name to the given value. Any number of name=value pairs can be given as arguments.
See D command.
Instructs mtasim
to expect next SMTP command to
return given code (a three-digit decimal number). Optional
regex argument is an extended POSIX regular expression. If
supplied, the program will also require that the extended SMTP
code (if any) and textual message returned by the command match this
expression.
See expect commands.
Lists defined macros. See L command.
Undefines macros given as its arguments.
Declares the sender socket parameters. See S command, for a detailed description and examples.
This command is available only at the initial stage of a
mtasim
session, before the first SMTP command was
given. It is disabled if the --sender-socket option was
given in the command line (see sender-socket).
The help
output reflects whether or not this command is available.
If neither this command nor the --sender-socket option were
given, mtasim
behaves as if given the \S stdio
command.
The family argument
supplies the socket family, i.e. the first argument to the
connect
handler (see connect handler). It can have either
literal or numeric value, as described in the table below:
Literal | Numeric | Meaning |
---|---|---|
stdio | 0 | Standard input/output (the MTA is run with -bs option) |
unix | 1 | UNIX socket |
inet | 2 | IPv4 protocol |
inet6 | 3 | IPv6 protocol |
See also Table 4.3.
Depending on the family, the rest of arguments supply additional parameters:
The hostname argument can be specified. It defines the first
argument of the connect
handler (see hostname in connect handler).
All arguments must be specified.
argument | connect argument | meaning |
---|---|---|
hostname | 1 | Sender host name |
address | 4 | Sender IP address |
port | 3 | Sender port number |
Hostname and address must be supplied. The address argument must be a full pathname of the UNIX socket.
Previous: command summary, Up: mtasim [Contents][Index]
mtasim
command line optionsThis section summarizes all available mtasim
command line options.
Append to the trace file. See traces.
Set the body chunk length (bytes) for xxfi_body
calls.
Run as daemon. See daemon mode.
Define Sendmail macro macro to the given value. It is
similar to the \D
administrative command (see D command)
Set desired logging level for gacopyz
library
(see Gacopyz). See gacopyz-log option, for a detailed
description of level. Notice, that unless this option is used,
the --verbose (-v) command line option implies
--gacopyz-log=debug.
When switching to user’s privileges as requested by the --user command line option, retain the additional group name. Any number of --group options may be given to supply a list of additional groups.
Run with this user privileges. This option and the --group
option have effect only if mtasim
was started with root
privileges.
Display a short help summary
Force using the given Milter protocol version number. The version argument is either a numeric version (e.g. ‘2’), or a version string in form ‘major.minor[.patch]’, where square brackets indicate optional part. The default is ‘1.0.0’. If version is any of ‘2’, ‘3’ or ‘1.0.0’, the default protocol capabilities and actions for that version are set automatically. This option is intended for development and testing of the Gacopyz library (see Gacopyz).
Set Milter protocol capabilities. See gacopyz/gacopyz.h for the meaning of various bits in the bitmask. Look for the C macros with the prefix ‘SMFIP_’.
Set timeouts for various Milter operations. Values is a comma-separated list of assignments ‘T=V’, where T is a timeout code, indicating which timeout to set, and V is its new value. Valid timeout codes are:
Timeout for connecting to a filter.
Timeout for sending information from the simulator to a filter.
Timeout for reading reply from the filter.
Overall timeout between sending end-of-message to filter and receiving
final acknowledgment. Indirectly, it configures the upper
limit on the execution time of the eom
handler (see eom handler).
Set Milter actions. See gacopyz/gacopyz.h for the meaning of various bits in the bitmask. Look for the C macros with the prefix ‘SMFIF_’.
Not-interactive mode (disable readline). See Command Line Editing in GNU Readline Library.
Communicate with given Milter port. Valid values for port are:
See milter port specification, for a detailed discussion. Example:
--port inet:999@localhost
X
command formatFor example:
--port='mailfrom, S=inet:999@localhost, F=T, T=C:100m;R:180s'
auto
Create a temporary directory and start an instance of
mailfromd
configured to communicate over a UNIX socket in
that directory. If --statedir is also given, the created
mailfromd
instance will use that directory as its state
directory (see statedir). Additional arguments for
mailfromd
may be supplied after the --
delimiter.
Before termination, mtasim
will stop the mailfromd
instance it created and remove the temporary directory.
dir
:dirnameSame as auto
, except that instead of the temporary directory
the directory dirname is used. This directory is not removed
when mtasim
terminates. Example:
--port dir:/tmp/state
See mtasim milter port, for a detailed discussion of the --port option and its use.
Set readline prompt. The default prompt string is ‘(mtasim) ’.
Declare sender socket address. This option has the same effect as
the S command
. See S command, for a detailed discussion
and a description of its arguments.
When using -Xauto, use the temporary directory name as
mailfromd
state directory (see statedir mtasim option).
Use the SMTP protocol on standard input and output. This
is the default mode for mtasim
. See interactive mode.
Set name of the trace file. See traces.
Display option summary
Increase verbosity level. Implies --gacopyz-log=debug, unless that option is used explicitly.
Print program version
However, this is true only if the program
is exited the usual way (via QUIT
or end-of-file). If it is
aborted with a signal like SIGINTR
, the temporary directory is
not removed.
Depending on how mailfromd
is
configured, ‘inet6’ may be not available.
Previous: command summary, Up: mtasim [Contents][Index]