/*
NAME
mockmta - mock MTA server for use in test suites
SYNOPSIS
mockmta [-ad] [-c CERT] [-f CA] [-k KEY] [-p PORT] [-t SEC] [DUMPFILE]
DESCRIPTION
Starts a mock MTA, which behaves almost identically to the real one,
except that it does not actually inject messages to the mail transport
system. Instead, each accepted message is logged to the DUMPFILE.
Being a mailutils test tool, mockmta is written without relying on
the mailutils libraries. Only libc and, optionally, GnuTLS functions
are used.
No attempts are made to interpret the data supplied during the STMP
transaction, such as domain names, email addresses, etc, neither is
the material supplied in the DATA command verified to be a valid
email message. Except for being logged to DUMPFILE, these data are
ignored.
Incoming SMTP sessions are processed sequentially. Listening for
incoming requests is blocked while an SMTP session is active.
The utility listens for incoming requests on localhost. If the port
to listen on is not given explicitly via the -p option, mockmta
selects a random unused port and listens on it. The selected port
number is printed on the standard output.
By default, mockmta starts as a foreground process. If the DUMPFILE
argument is not supplied, messages will be logged to the standard
output.
If the -d option is given, mockmta detaches from the terminal and runs
in daemon mode. It prints the PID of the daemon process on the standard
output. The daemon will terminate after 60 seconds. This value can be
configured using the -t option. When running in daemon mode, the
DUMPFILE argument becomes mandatory.
To enable the STARTTLS ESMTP command, supply the names of the certificate
(-c CERT) and certificate key (-k KEY) files.
Output summary
Depending on the command line options given, mockmta can output port
number it listens on and the PID of the started daemon process. The
four possible variants are summarized in the table below:
1. Neither -d nor -p are given.
Prints the selected port number.
2. -p is given, but -d is not
Nothing is printed.
3. -d is given, but -p is not
Prints two numbers, each on a separate line:
Port number
PID
4. Both -d and -p are given.
Prints PID of the daemon process.
OPTIONS
-a Append to DUMPFILE instead of overwriting it.
-c CERT Name of the certificate file.
-d Daemon mode
-f CA Name of certificate authority file.
-k KEY Name of the certificate key file.
-p PORT Listen on this port.
-t SEC Terminate the daemon forcefully after this number of seconds.
Default is 60. Valid only in daemon mode (-d).
DUMP FORMAT
Each message is represented as a series of records:
MSGID: <numeric>
Four-digit sequential message identifier.
DOMAIN: <string>
EHLO (or HELO) domain.
SENDER: <string>
Sender email address as given by the MAIL command.
NRCPT: <numeric>
Number of recipients.
The list of recipients follows this line. Each record in the list is
RCPT[<I>]: <string>
where <I> is 0-based index of the recipient in recipient table.
LENGTH: <N>
Total length of the data section, including terminating dot and
newline. Notice, that line ending is changed from CRLF to LF
prior to length calculation, so that each line, including the
dot terminator, ends with one ASCII 10 character.
This line is followed by <N> bytes representing the material received
after the DATA SMTP keyword.
Message dump is terminated by a single LF character.
EXIT CODES
0 Success.
1 Failure (see stderr for details).
2 Command line usage error.
BUGS
At most 32 RCPT commands are allowed.
AUTHOR
Sergey Poznyakoff <gray@gnu.org>
LICENSE
This program is part of GNU Mailutils testsuite.
Copyright (C) 2020 Free Software Foundation, Inc.
Mockmta is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Mockmta is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
char *progname;
int daemon_opt;
int daemon_timeout = 60;
int port;
int msgid = 1;
FILE *logfile;
enum
{
EX_OK,
EX_FAILURE,
EX_USAGE
};
static void
terror (char const *fmt, ...)
{
va_list ap;
int m;
static char *fmtbuf = NULL;
static size_t fmtsize = 0;
int ec = errno;
char const *es = NULL;
size_t len;
for (m = 0; fmt[m += strcspn (fmt + m, "%")]; )
{
m++;
if (fmt[m] == 'm')
break;
}
len = strlen (fmt) + 1;
if (fmt[m])
{
es = strerror (ec);
len += strlen (es) - 2;
}
if (len > fmtsize)
{
fmtsize = len;
fmtbuf = realloc (fmtbuf, fmtsize);
if (!fmtbuf)
{
perror ("realloc");
exit (EX_FAILURE);
}
}
if (es)
{
memcpy (fmtbuf, fmt, m - 1);
memcpy (fmtbuf + m - 1, es, strlen (es) + 1);
strcat (fmtbuf, fmt + m + 1);
}
else
strcpy (fmtbuf, fmt);
fprintf (stderr, "%s: ", progname);
va_start (ap, fmt);
vfprintf (stderr, fmtbuf, ap);
va_end (ap);
fputc ('\n', stderr);
}
static void
nomemory (void)
{
terror ("out of memory");
exit (EX_FAILURE);
}
struct iodrv
{
int (*drv_read) (void *, char *, size_t, size_t *);
int (*drv_write) (void *, char *, size_t, size_t *);
void (*drv_close) (void *);
const char *(*drv_strerror) (void *, int);
};
#define IOBUFSIZE 1024
struct iobase
{
struct iodrv *iob_drv;
|