Other documentation

Installation instructions: INSTALL.txt

About spamdyke

spamdyke is a filter for monitoring and intercepting incoming SMTP connections to a qmail server. It acts as a transparent middleman, observing the conversation without interference unless it sees something it should block. Because it can silently monitor, it can also log traffic to syslog.

spamdyke is ©2007 Sam Clippinger, samc (at) silence (dot) org. It is distributed under the GNU General Public License (version 2 only) from http://www.spamdyke.org/

The "-h" (or "--help") command line option will give a brief summary of the available command line options. The "-v" (or "--version") command line option will give just the version and copyright statement.

Installing spamdyke

For installation instructions, see the INSTALL.txt file.

Troubleshooting / FAQs

For some answers to some frequently asked questions, see the FAQ page.

Support

spamdyke support is available from the spamdyke mailing list: www.spamdyke.org/mailman/listinfo/spamdyke-users.

The mailing list archives are searchable thanks to mail-archive.com: www.mail-archive.com/spamdyke-users@spamdyke.org.

If all else fails, email me directly at samc (at) silence (dot) org.

How spamdyke works: When a message is not blocked

spamdyke works by acting as a middleman between qmail and the network (in Unix terms, it's a pipe). When no spamdyke filters are triggered and a message is delivered normally, spamdyke silently passes data in both directions. As the SMTP conversation takes place, spamdyke collects a few pieces of data (e.g. the sender and recipient addresses) so they can be logged.

How spamdyke works: When a message is blocked

When a connection is intercepted (by one of the filters described below), several things happen.

If the filter is triggered before the SMTP conversation begins, qmail is not even started. spamdyke imitates an SMTP server and returns error codes to the remote server. During this conversation, spamdyke collects information about the sender and recipient so it can log information about the connection.

If the filter is triggered before the SMTP conversation starts but SMTP AUTH is being used, spamdyke will start qmail and allow it to begin the SMTP converstation. If authentication is successful, spamdyke disables all of its filters. If authentication is unsuccessful or does not take place, spamdyke intercepts the entire remainder of the conversation. In the background, it sends a QUIT command to qmail so qmail will exit normally.

If the filter is triggered part-way through the SMTP conversation, spamdyke intercepts the bad command(s) and returns an error code; qmail never sees them.

If the error is one that cannot allow the SMTP conversation to continue (e.g. a blacklisted sender address), spamdyke intercepts the entire remainder of the conversation. In the background, it sends a QUIT command to qmail so qmail will exit normally.

Logging to syslog

spamdyke will always log all errors to the syslog facility with the LOG_MAIL flag, which typically puts the messages in /var/log/maillog. Errors will always be preceded by the text "ERROR:" and are fairly self-explanatory. Whenever possible, spamdyke will recover from an error and continue processing mail. Philosophically, it's better to continue receiving spam than to block all mail.

The "log-level" flag controls how much logging takes place. The following values are supported:

0: No logging at all, even if errors occur. This is not recommended.
1: Errors only, including authentication failures. This is the default when "log-level" is not given.
2: Errors and information, including mail traffic. This is the value used when "log-level" is given with no value.
3: Errors, information and debugging messages, including more filenames and line numbers when matches are found in various files. This level is handy for troubleshooting but it can be rather verbose.

Each traffic log entry takes the following form (error messages and debugging statements are :

CODE from: SENDER to: RECIPIENT origin_ip: IPADDRESS origin_rdns: RDNSNAME auth: USERNAME [ reason: REALCODE ]
This format makes the logs very easy to parse from other scripts for monitoring and graphing.

CODE can be one of the following:

ALLOWED
The message passed all filters. qmail may still bounce the message for other reasons, however.
ALLOWED_AUTHENTICATED
The remote client successfully authenticated using SMTP AUTH with spamdyke. If qmail is patched to provide SMTP AUTH, this code will never be used.
ALLOWED_TLS
The remote client successfully started a TLS session with spamdyke.
TIMEOUT
The connection timed out, either in total time ("connection-timeout-secs") or idle time ("idle-timeout-secs"). If the connection was already being blocked for another reason, the code for that error is given as REALCODE.
DENIED_TOO_MANY_RECIPIENTS
The recipient was blocked because the limit ("max-recipients") was reached for this connection. The SMTP connection continues after this error occurs.
DENIED_UNQUALIFIED_RECIPIENT
The recipient was blocked because the address had no domain name. The SMTP connection continues after this error occurs.
DENIED_GRAYLISTED
The recipient was blocked because the sender/recipient combination was graylisted ("graylist-dir" or "no-graylist-dir"). The SMTP connection continues after this error occurs.
DENIED_RDNS_MISSING
The connection was blocked because the remote server has no rDNS name at all ("reject-empty-rdns").
DENIED_RDNS_RESOLVE
The connection was blocked because the remote server's rDNS name does not resolve ("reject-unresolvable-rdns").
DENIED_IP_IN_CC_RDNS
The connection was blocked because the remote server's IP address was found in the remote server's rDNS name _and_ the remote server's rDNS name ends in a country code ("reject-ip-in-cc-rdns").
DENIED_IP_IN_RDNS
The connection was blocked because the remote server's IP address was found in the remote server's rDNS name _and_ a prohibited keyword was found in the remote server's rDNS name ("ip-in-rdns-keyword-file").
DENIED_EARLYTALKER
The connection was blocked because the remote server began sending data before the SMTP greeting was issued ("greeting-delay-secs").
DENIED_BLACKLIST_NAME
The connection was blocked because the base domain of the remote server's rDNS name is blacklisted ("rdns-blacklist-file" or "rdns-blacklist-dir").
DENIED_BLACKLIST_IP
The connection was blocked because the remote server's IP address is blacklisted ("ip-blacklist-file").
DENIED_SENDER_BLACKLISTED
The connection was blocked because the sender's email address is blacklisted ("sender-blacklist-file").
DENIED_RECIPIENT_BLACKLISTED
The recipient was blocked because the recipient email address is blacklisted ("recipient-blacklist-file").
DENIED_RBL_MATCH
The connection was blocked because the remote server's IP address was found on a DNS RBL ("check-dnsrbl").
DENIED_RHSBL_MATCH
The connection was blocked because the remote server's reverse DNS name was found on a righthand-side DNS blacklist (RHSBL) OR the connection was blocked because the sender's domain name was found on a righthand-side DNS blacklist (RHSBL).
DENIED_SENDER_NO_MX
The connection was blocked because the sender's domain has no mail exchanger, making the sender address invalid ("reject-missing-sender-mx").
DENIED_ACCESS_DENIED
The connection was blocked because the remote server's IP address or rDNS name was found in the access file with a "deny" command ("access-file").
DENIED_RELAYING
The recipient was blocked because the recipient's domain is not locally hosted ("local-domains-file") and the remote server is not allowed to relay ("access-file").
DENIED_OTHER
The connection was rejected by qmail (or another downstream filter), not spamdyke.
FAILED_AUTH
The remote server attempted to authenticate but the given username and/or password were incorrect ("smtp-auth-command" or "smtp-auth-command-encryption").
UNKNOWN_AUTH
The remote server requested an authentication method spamdyke doesn't support. This shouldn't happen.
FAILED_TLS
The remote client attempted to start a TLS session but SSL negotiation failed.

SENDER is the sender email address, if known, or "(unknown)" otherwise. NOTE: According to RFC 821, it is legal to deliver messages with no sender address. Most bounce messages are delivered this way.

RECIPIENT is the recipient email address, if known, or "(unknown)" otherwise. If CODE is "ALLOWED", the recipient email address will be known.

IPADDRESS is the IP address of the remote server. This value is always known.

RDNSNAME is the rDNS name of the remote server, if known, or "(unknown)" otherwise.

USERNAME is the username given during authentication, if authentication was performed, or "(unknown)" otherwise.

REALCODE is only present if CODE is "TIMEOUT" and the connection was going to be blocked anyway. For example, if a remote server has no rDNS entry and the connection is going to be blocked but the connection times out instead, CODE will be "TIMEOUT" and REALCODE will be "DENIED_RDNS_MISSING".

SMTP error codes

When spamdyke blocks a connection and returns an error code to a remote server, the error text the remote server sees is different from what appears in syslog (above). It is more user-friendly, just in case a human ever reads it (no one ever does).

The messages that correspond to the syslog codes are:

TIMEOUT
Timeout. Talk faster next time.
DENIED_TOO_MANY_RECIPIENTS
Too many recipients. Try the remaining addresses again later.
DENIED_UNQUALIFIED_RECIPIENT
Improper recipient address. Try supplying a domain name.
DENIED_GRAYLISTED
Your address has been graylisted. Try again later.
DENIED_RDNS_MISSING
Refused. You have no reverse DNS entry.
DENIED_RDNS_RESOLVE
Refused. Your reverse DNS entry does not resolve.
DENIED_IP_IN_CC_RDNS
Refused. Your reverse DNS entry contains your IP address and a country code.
DENIED_IP_IN_RDNS
Refused. Your reverse DNS entry contains your IP address and a banned
keyword.
DENIED_EARLYTALKER
Refused. You are not following the SMTP protocol.
DENIED_BLACKLIST_NAME
Refused. Your domain name is blacklisted.
DENIED_BLACKLIST_IP
Refused. Your IP address is blacklisted.
DENIED_SENDER_BLACKLISTED
Refused. Your sender address has been blacklisted.
DENIED_RECIPIENT_BLACKLISTED
Refused. Mail is not being accepted at this address.
DENIED_RBL_MATCH
(The text returned from the DNS RBL OR if the DNS RBL does not return any text:)
Refused. Your IP address is listed in the DNS RBL at [RBLNAME]
DENIED_RHSBL_MATCH
(The text returned from the RHSBL OR if the RHSBL does not return any text:)
Refused. Your domain name is listed in the RHSBL at [RHSBLNAME]
DENIED_SENDER_NO_MX
Refused. The domain of your sender address has no mail exchanger (MX).
DENIED_ACCESS_DENIED
Refused. Access is denied.
DENIED_RELAYING
Refused. Sending to remote addresses (relaying) is not allowed.
FAILED_AUTH
Refused. Authentication failed.
UNKNOWN_AUTH
Refused. Unknown authentication method.
FAILED_TLS
Failed to negotiate TLS connection.

If a policy location URL is given with the "policy-url" flag, it will be appended to the end of the message, just in case a human ever reads it. This is mostly useful for debugging, in case someone is troubleshooting their connection to your server, trying to figure out why their email is being blocked. Regular users whose emails bounce won't see the message though; spammers have been delivering spam through bounce messages long enough that most MTAs now block the content of the bounce message.

Even if the user does get the text, there's a very slim chance the user will read it or click on anything inside -- most people see "returned mail" and click "delete".

Configuration files

Prior to version 3.0.0, all options to spamdyke were provided on the command line. This made the code simpler but made maintenance more difficult. Starting with version 3.0.0, spamdyke can read its configuration from files.

The configuration file format is very simple. Each line should use the following format:

DIRECTIVE=VALUE

DIRECTIVE is the long version of a command line parameter.

VALUE is the value that would be passed on the command line. One small change: multi-word values on the command line (e.g. SMTP AUTH commands) must be quoted. In the configuration file, quotes are not allowed. spamdyke reads the entire VALUE after the equals sign, even if it contains spaces, so no quoting is needed.

Blank lines and lines beginning with "#" are ignored.

For example:

rdns-blacklist-dir=/home/vpopmail/blacklist_rdns.d
graylist-dir=/home/vpopmail/graylist.d
check-dnsrbl=dul.dnsbl.sorbs.net
check-dnsrbl=zombie.dnsbl.sorbs.net
max-recipients=5

Options that are true/false flags can be given without a VALUE to activate them. The VALUEs "yes", "true" and "1" are also acceptable. The options can also be explicitly deactivated with the VALUEs "no", "false" or "0" (or the option can be simply removed). For example, the following lines all have the same effect:

reject-empty-rdns
reject-empty-rdns=yes
reject-empty-rdns=true
reject-empty-rdns=1

A configuration file is utilized by passing the command line option "config-file" to spamdyke:

spamdyke --config-file /etc/spamdyke.conf ...
The "config-file" directive can also be used within configuration files to include other configuration files if desired. When configuration files are in use, options may still be provided on the command line as well, in any combination. If contradictory directives are found, the last directive scanned will be used. For example, if the following command line were used:
spamdyke --reject-empty-rdns --config-file /etc/spamdyke.conf ...
And /etc/spamdyke.conf contained the following line:
reject-empty-rdns=false
The result would be spamdyke deactivating the "reject-empty-rdns" filter because the configuration file was scanned after the command line parameter. This can be confusing, so the best advice is to avoid specifying the same option in multiple places without good reason.

NOTE: It may seem that scanning a configuration file instead of the command line would impose a performance penalty each time spamdyke is started. However, the reverse seems to be true. Some rudimentary testing has indicated the configuration files are actually faster.

Configuration testing

Starting with version 3.0.0, spamdyke has the ability to scan its configuration and look for common setup mistakes. It will check file permissions, graylist folders, TLS certificates and more.

To use the new testing feature:

  1. Find and copy the entire spamdyke command from your "supervise" script or xinetd configuration file.
  2. At a command prompt, start a shell as the user who normally runs spamdyke for incoming connections (e.g. vpopmail, qmaild)
  3. Paste the spamdyke command without running it.
  4. Add the flag "--config-test" among the spamdyke options (before the qmail command).
  5. Run the command and carefully read the results. More output can be obtained by increasing the logging level at your prompt (no test output goes to syslog).

IMPORTANT! DANGER! WARNING! DO NOT, EVER, PUT THE "--config-test" OPTION IN THE SPAMDYKE COMMAND LINE THAT IS RUN FOR INCOMING CONNECTIONS! YOUR MAIL SERVER WILL IMMEDIATELY STOP RECEIVING MAIL AND REMOTE USERS WILL SEE ONLY THE DIAGNOSTIC OUTPUT! I reserve the right to publicly mock anyone who asks for my help after making this mistake. You have been warned.

IP address files

Some of the options described below search files for IP addresses. In all those cases, the format of the files is the same. Blank lines and lines beginning with "#" are ignored. Every other line in the file is expected to contain a single entry.

Individual IP addresses may be given in dotted quad format. Those IP addresses will be matched literally. For example:

11.22.33.44
23.34.45.56
Two IP addresses will be matched by these entries, 11.22.33.44 and 23.34.45.56. NOTE: In dotted quad format, leading zeroes are ignored, so the following is equivalent to the previous example:
011.022.033.044
023.034.045.056

IP address ranges may be given in one of four ways. First, one or more octets of an IP address may be given and will match any IP addresses with the same first few octets. For example, if the file contained the following entry:

11.22.33
The IP addresses 11.22.33.14, 11.22.33.25 and 11.22.33.236 will all match. A trailing dot is optional, so if the file contained the following entry:
11.22.
The IP addresses 11.22.33.44, 11.22.134.245 and 11.22.235.46 will all match.

Second, a full or partial IP address with ranges may be given an will match an IP addresses with octets that match the ranges given. For example, if the file contained the following entry:

11.22.33-44.55
The IP addresses 11.22.34.55, 11.22.38.55 and 11.22.41.55 will all match. If the file contained the following entry:
11.22-44
The IP addresses 11.22.134.7, 11.36.1.267 and 11.43.178.240 will all match.

Third, a full IP address may be given with a netmask, given as a number of bits. For example, if the file contained the following entry:

11.22.33.0/24
The IP addresses 11.22.33.2, 11.22.33.189 and 11.22.33.241 will all match. If the file contained the following entry:
11.22.0.0/16
The IP addresses 11.22.165.98, 11.22.8.135 and 11.22.0.254 will all match.

Fourth, a full IP address may be given with a netmask in dotted quad format. For example, if the file contained the following entry:

11.22.33.0/255.255.255.0
The IP addresses 11.22.33.13, 11.22.33.76 and 11.22.33.199 will all match. If the file contained the following entry:
11.22.0.0/255.255.0.0
The IP addresses 11.22.59.111, 11.22.7.189 and 11.22.83.213 will all match.

When a netmask is given, either as a number of bits or a dotted quad, ranges in the base IP address are ignored. If they're present, they don't cause errors but they have no effect.

rDNS files

Some of the options described below search files for rDNS names. In all those cases, the format of the files is the same. Blank lines and lines beginning with "#" are ignored. Every other line in the file is expected to contain a single entry.

Individual names may be given as separate entries. Those names will be matched literally. For example:

mail.example.com
smtp.example.com
Two names will be matched by these entries, mail.example.com and smtp.example.com.

The rDNS names may also use wildcards by beginning with dots (.). For example, if the file contained the following entry:

.example.com
The names example.com, mail.example.com and mail.internal.example.com will match. If the file contained the following entry:
.mail.example.com
The names mail.example.com and internal.mail.example.com will match but example.com and internal.example.com will NOT.

rDNS directories

Some of the options described below search directory structures for rDNS names. A directory structure is used because repeatedly searching a file full of domain names incurs a serious performance penalty. Querying the filesystem for the existance of a single file is very fast. Rule of thumb: if there are more than 100-200 entries in a file, consider switching to a directory structure instead.

To construct the directory path it uses, spamdyke takes the remote server's rDNS name, breaks it apart at the dots and reverses it using the following patterns:

e-five.d-four.c-three.b-two.a-one becomes
a-one/b/b-two/c-three/e-five.d-four.c-three.b-two.a-one
d-four.c-three.b-two.a-one becomes
a-one/b/b-two/c-three/d-four.c-three.b-two.a-one
c-three.b-two.a-one becomes
a-one/b/b-two/c-three.b-two.a-one
b-two.a-one becomes
a-one/b/b-two/b-two.a-one
a-one becomes
a-one/a/a-one
In essence, the last three sections of the name are reversed and become directory names. If there are more than three sections, no further directories are created. Also, the first letter of the next-to-last section is used as a directory name. This is done to keep the numbers of directories per folder lower, since the "com" folder has the potential to become unmanagable. The full rDNS name is always used as the filename.

The final filename is treated as a wildcard and matches any host that ends with the given name. For example, if the following file existed in the directory structure:

com/e/example/example.com
spamdyke would match the following rDNS names:
example.com
mail.example.com
internal.mail.example.com
2ndfloor.internal.mail.example.com

These directory and filenames can be constructed with the "domain2path" tool, included with spamdyke. domain2path takes one rDNS name as an argument and returns the correct path to that name. domain2path also accepts a "-d" flag, which makes it only return the directories in the path. This is useful in scripts:

mkdir -p /PATH/TO/DIR/`domain2path -d FQDN`
touch /PATH/TO/DIR/`domain2path FQDN`

NOTE: The names of all the directories and files used in the directory structure must be lowercase or spamdyke will not match them. Unfortunately, searching a case sensitive filesystem in a case insensitive manner is not practical.

Logging all traffic

spamdyke has the ability to log all SMTP traffic to files. This is very helpful when debugging but (depending on the mail server traffic levels) it can generate a huge number of files.

This feature is activated with the "full-log-dir" flag. Each connection will be logged to a different file in the folder given, with the following naming convention:

YYYYMMDD_HHMMSS_IPADDRESS_RDNSNAME
Or if the remote server has no rDNS name:
YYYYMMDD_HHMMSS_IPADDRESS

The traffic from the remote server and qmail are both logged to the file. Each transmission is preceded with a line showing its origin and destination as well as the time and date. The origin/destination markers are:

<<< = traffic sent from qmail to the remote server
>>> = traffic sent from the remote server
<FF = traffic sent from spamdyke to the remote server (imitating a server)
FF> = traffic sent from spamdyke to qmail (telling qmail to quit)
<XX = traffic sent from qmail but discarded by spamdyke

If the remote client establishes a TLS session with qmail and spamdyke passes the encrypted traffic, the logs will contain the traffic as hexadecimal bytes.

Log files are created with a 0600 mode to protect them from being read by unauthorized users. Please take other precautions to protect them and don't leave them lying around.

NOTE: This feature is intended to be used for debugging delivery problems, not for monitoring email content. Among other issues, the format of the log files does not make it easy to reconstruct a whole message. If you must monitor your users' email traffic, please use a packet sniffer on a separate machine or SMTP proxy software designed for the task.

TLS

TLS is another name for SSL, the same encryption protocol used by secure websites (I have no idea why they renamed it). TLS can be used during SMTP to provide secure communications between the remote client and the server.

spamdyke supports TLS in two ways. First, by itself with no other information, spamdyke will identify a TLS conversation and simply pass the traffic back and forth between qmail and the remote client. In this mode, spamdyke cannot read the SMTP traffic (due to the encryption). This prevents some of its filters from functioning, including graylisting, sender and recipient blacklisting, limiting the number of recipients, checking the sender's domain name for an MX record and preventing relaying.

Second, spamdyke can provide TLS itself. To do this, it must be compiled with TLS support, which requires the OpenSSL libraries to be available (see the INSTALL.txt file for details). The server certificate must also be provided with the "tls-certificate-file" parameter. In this mode, when the client asks to start a TLS session, spamdyke intercepts the request and negotiates TLS with the client. All of spamdyke's filters can remain active. qmail doesn't ever see the TLS traffic because spamdyke decrypts everything before passing it on to qmail. Because of this, spamdyke can offer TLS even if qmail hasn't been patched to provide it!

The server certificate file must be in PEM format. If the private key is not in the certificate file, it must be provided in PEM format with the "tls-privatekey-file" parameter. If the private key is encrypted with a password, the password must be provided with the "tls-privatekey-password" parameter. Because providing the private key password on the command line is very insecure, the password can also be contained in a file and loaded using the "tls-privatekey-password-file" parameter.

Generating self-signed certificates is very easy with OpenSSL. Countless tutorials are available on the web.

If there are any problems reading the certificate, the private key or decrypting the private key, spamdyke will log the errors to syslog and fall back to passing the TLS traffic through to qmail, if qmail has been patched to provide TLS (or spamdyke will send the remote client an error message if qmail doesn't provide TLS). spamdyke will also log the error messages produced by OpenSSL, even though they're rarely helpful.

NOTE: spamdyke does not disable any of its filters simply because a remote client uses TLS. In SMTP, TLS is simply a method of securing the communication channel. It is not an authentication method. While it's true spammers aren't using TLS and therefore any client that does use it is unlikely to be a spammer, there's no reason to assume that will be true forever. spamdyke will only disable its filters for clients it finds on its whitelists or ones that use SMTP AUTH.

If in doubt about enabling TLS, do it. Encrypting email traffic is always a good thing.

SMTP AUTH

SMTP AUTH is a mechanism for remote users to authenticate before sending email (defined in RFC 2554). This is very handy when users are likely to connect from remote locations (e.g. coffee shop hotspots) and want to bypass relaying restrictions and other filters.

spamdyke supports SMTP AUTH. If qmail has been patched to provide SMTP AUTH, spamdyke will observe the authentication and trust qmail's success/failure messages. When authentication is successful, spamdyke bypasses all of its filters. When authentication is unsuccessful, spamdyke enforces the enabled filters as normal.

If qmail has not been patched to provide SMTP AUTH, spamdyke will offer to do it instead. Because spamdyke runs as a middleman between the remote server and qmail, it can already add or remove data from the inbound or outbound traffic. At a specific point in the SMTP conversation, qmail should advertise an ability to process SMTP AUTH. If it does not, spamdyke inserts the advertisement. When the remote server responds, spamdyke processes the authentication and prevents qmail from seeing the authentication traffic it won't understand. Qmail doesn't know the authentication took place and spamdyke bypasses its filters. Clever, huh?

If qmail has been patched to provide SMTP AUTH, no flags need to be given to spamdyke. spamdyke will silently observe the authentication and trust qmail's responses.

If qmail has not been patched to provide SMTP AUTH, one of two flags should be used: "smtp-auth-command" or "smtp-auth-command-encryption". The parameter for both flags should be the full command line of the program used to process the authentications. If, for some reason, there are multiple places authentication can be checked, the flags can each be given multiple times. spamdyke will run each command in turn before rejecting the authentication.

The first flag, "smtp-auth-command", should be used if the program processing authentications does not have access to cleartext copies of the user passwords and therefore can't authenticate challenge/response protocols. This is the case when authenticating system accounts found in /etc/password using DJB's "checkpassword" program. This is also the case when vpopmail is installed but was not compiled with cleartext password support (e.g. qmailtoaster). Using this flag prevents spamdyke from advertising challenge/response protocols.

The second flag, "smtp-auth-command-encryption" should be used if the program processing authentications does have access to cleartext copies of the user passwords and can authenticate challenge/response protocols. This is the case when authenticating virtual accounts through vpopmail if vpopmail was compiled with cleartext password support.

Although both flags can be used, there's no reason to do so. Using "smtp-auth-command-encryption" even once will cause spamdyke to advertise challenge/response protocols.

For example, on a server with vpopmail installed where vpopmail has been compiled with cleartext password support, the spamdyke command might look like this:

spamdyke --smtp-auth-command-encryption "/home/vpopmail/bin/vchkpw /bin/true" /var/qmail/bin/qmail-smtpd /home/vpopmail/bin/vchkpw /bin/true
On a server with vpopmail installed where vpopmail has been compiled without cleartext password support, the spamdyke command might look like this:
spamdyke --smtp-auth-command "/home/vpopmail/bin/vchkpw /bin/true" /var/qmail/bin/qmail-smtpd /home/vpopmail/bin/vchkpw /bin/true
On a server without vpopmail, the spamdyke command might look like this:
spamdyke --smtp-auth-command "/bin/checkpassword /bin/true" /var/qmail/bin/qmail-smtpd

When using either flag in a place where quoted parameters are not allowed (for example, in stunnel's configuration file), spaces can be replaced with commas. In other words, the following:

--smtp-auth-command "/bin/checkpassword /bin/true"
can be given as:
--smtp-auth-command /bin/checkpassword,/bin/true
spamdyke will convert the comma to a space before executing the command.

Some challenge/response protocols, notably CRAM-MD5, use the name of the local host as part of their encrypted challenge. This is intended to frustrate known-plaintext attacks. spamdyke will attempt to find the local host's name several different ways. If the "hostname" flag is used, the given value will be used. If the "hostname-file" flag is used, the first line of the given file will be read and used as the name. If the "hostname-command" flag is used, the given command will be run and the first line of its output will be used as the name. If none of those flags are given, the environment variables "TCPLOCALHOST" and "HOSTNAME" will be checked. If either is set, its value will be used as the name. If no name can be found using any of those methods, spamdyke will use the name "unknown.server.unknown.domain".

Setting the host's name correctly is not critical. It's only used to construct the challenge challenge and the protocol will work fine with any value. Setting it correctly makes the protocol slightly more secure but the tiny benefit is not worth a large hassle. If you can set it, do so. If it's a problem for some reason, ignore it.

If in doubt about enabling SMTP AUTH, do it. Authenticating your users is always a good thing.

Relaying

By default, spamdyke allows all relaying. However, if an access file is given with the "access-file" flag, spamdyke will search the file for the incoming server's IP address and/or rDNS name. If the file doesn't allow the remote server to relay, spamdyke will block any attempts to do so. Whether a recipient is local is determined by searching the local domains file ("local-domains-file").

NOTE: spamdyke does not consider the sender address when deciding to block a recipient for relaying. Sender addresses can be (and usually are) forged by spammers.

Each line in the access file should use one of the following formats:

REMOTE_INFO@REMOTE_IP:ACCESS
REMOTE_INFO@=REMOTE_NAME:ACCESS
REMOTE_IP:ACCESS
REMOTE_NAME:ACCESS
:ACCESS

REMOTE_INFO is the value returned from an "info" query of the remote server. spamdyke doesn't perform info queries but tcpserver does by default and sets the TCPREMOTEINFO environment variable if it gets something. spamdyke uses TCPREMOTEINFO if it's set. (Does anyone actually use info any more?)

REMOTE_IP is the IP address of the remote server. It can also be a partial IP address, a dotted quad with ranges, a dotted quad with a number of bits or a dotted quad with a netmask. See "IP ADDRESS FILES" above for a full explanation of the acceptable formats.

REMOTE_NAME is the rDNS name of the remote server. It can also be a partial name. See "RDNS FILES" above for a full explanation of the acceptable formats.

ACCESS is the permission setting -- either "allow" or "deny". Connections are allowed by default (if no match is found). If access is denied, no mail is accepted at all, whether relayed or not.

Blank lines and lines starting with "#" are ignored.

The end of each line may optionally specify a series of environment variables to be set before qmail is started. They should use the following format and be separated by commas:

NAME="VALUE"
The double quotes shown above can actually be any character, if the value contains double quotes (escaped values are not supported). For example:
NAME=.VALUE.

If the remote server's IP address is 11.22.33.44 and its rDNS name is mail.example.com, each of the following lines will match, allow connections and set several environment variables:

11.22.33.44:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
11.20-100.33.44:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
11.22.:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
11.22.33.0/24:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
11.22.0.0/255.255.0.0:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
=mail.example.com:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
=.example.com:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
=.com:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-
:allow,FOOVAR="foovalue",BARVAR=.barvalue.,BAZVAR=-bazvalue-

Conveniently, this is exactly the format tcpserver uses for its /etc/tcp.smtp file. NOTE: spamdyke can't read CDB files, only the plain text file, so be careful which file you list on the command line.

Remote servers are allowed to relay if the environment variable RELAYCLIENT is set to any value. Most qmail guides recommend an entry like this one:

11.22.33.44:allow,RELAYCLIENT=""

NOTE: Because tcpserver and qmail already handle relaying using this same system, there are only two reasons to use spamdyke for it. First, spamdyke will log every relaying attempt it blocks. This can be handy for troubleshooting or tracking.

Second, if you're using a qmail installation that isn't patched to provide SMTP AUTH and you're using spamdyke to provide SMTP AUTH, you need to use spamdyke to block relaying instead of qmail. Otherwise, when users authenticate from remote locations, qmail won't know about it and will still block them for relaying. In that case, using "access-file" is required.

Reverse DNS

Reverse DNS is part of the DNS system that maps IP addresses back to names. IF YOU DON'T ALREADY UNDERSTAND REVERSE DNS, YOU SHOULD NOT BE RUNNING A MAIL SERVER, PERIOD.

spamdyke does a lot of work with rDNS names. The first and most basic test is to make sure the remote server _has_ an rDNS name, any name. This filter is activated with the "reject-empty-rdns" flag. AOL and most other major ISPs use this test. By default, this filter is not run.

The next test is to make sure the remote server's rDNS name resolves. This test only attempts to get at least one IP address from the name. It does not require the rDNS name's IP address to match the remote server's IP address. The name "localhost" is handled specially. If the rDNS name is "localhost" and the IP address is not 127.0.0.1, the test fails. For example, if the remote server's IP address is 11.22.33.44 and its rDNS name is "mail.example.com", this test will lookup "mail.example.com". If the lookup returns an IP address of 66.77.88.99, the test will pass. This filter is activated with the "reject-unresolvable-rdns" flag. By default, this filter is not run.

NOTE: "reject-unresolvable-rdns" does not imply "reject-empty-rdns". In other words, using just the "reject-unresolvable-rdns" flag will block connections from servers with unresolvable rDNS names but it will not block connections from servers with no rDNS names at all. Most users will want to use "reject-empty-rdns" if they use "reject-unresolvable-rdns".

spamdyke will also look for an IP address in the rDNS name, since that typically indicates a server sending email that shouldn't be (e.g. a compromised Windows machine on a cable modem). spamdyke looks for the IP address in many forms; for example, if the IP address is 11.22.33.44, spamdyke will look for the following patterns in the rDNS name (the dots in the examples below can be any single character):

11.22.33.44
011.022.033.044
44.33.22.11
44.11.22.33
33.22.11.44
44.33.1122
3344.11.22
11.22.8492 (last two octets combined and converted to an integer)
11223344
011022033044
11022033044
1122033044
112233044
44332211
044033022011
3930621781 (entire address converted to an integer)
5080d7e3 (each octet converted to hexadecimal)

If the IP address is found in the rDNS name, one of two conditions will trigger the filter. One is if the rDNS name contains a keyword listed in a specified file. This is activated with the "ip-in-rdns-keyword-file" flag. Each keyword must be listed on its own line. Blank lines and lines beginning with "#" are ignored. If the "ip-in-rdns-keyword-file" flag is given multiple times, each given keyword file will be checked before the connection is allowed.

For example, if the IP address is 11.22.33.44, the rDNS name is 11.22.33.44.dynamic.example.com and the keyword file contains "dynamic", the connection will be blocked. NOTE: The keyword will not match the domain name. So, using the previous example, if the keyword file contains "example" (but not "dynamic"), the connection will not be blocked. To use domain names as keywords, they must be preceded with a dot. To continue with the previous example, putting ".example.com" in the file (but not "dynamic") will block the connection.

Because ISPs don't use a consistent naming system for dynamic connections, sometimes more complex patterns are needed. For example, there may be a need to block connections with a keyword from a specific domain name but not apply that keyword to other domain names. To do this, the keywords should be separated by spaces and put on the same line.

For example, if the keyword file contains "customer .example.com", the remote server's IP address is 11.22.33.44 and the remote server's rDNS name is "customer-11.22.33.44.example.com", the connection will be blocked. The same IP address with a name of "customer-11.22.33.44.example.net" would be allowed.

One more IP/rDNS test is available. The rDNS name is searched for the IP address as above but instead of looking for a keyword, a country code will match. For example, if the remote server's IP address is 11.22.33.44 and its rDNS name is 11.22.33.44.example.com.us, the connection will be blocked. This test is available because it's simply not practical to list "dynamic" in every language. This is activated with the "reject-ip-in-cc-rdns" flag.

Blacklists

First, let's just say that blacklists are evil, arbitrary, unforgiving, unfair, etc, etc, blah blah blah. OK. If you feel that way, don't use one. No one's pointing a gun to your head.

BUT, if you decide to use one, it can block over half the spam you would otherwise receive. Blacklists are very effective against professional spammers who buy domain names by the thousands and run their own mail servers (constantly moving them around, of course). It's your call.

NOTE: Constructing and maintaining a blacklist is left as an exercise for the reader. spamdyke will use a blacklist but it won't help you build one.

spamdyke will search for the remote server's rDNS name in a file and block the connection if it is found. This is activated with the "rdns-blacklist-file" flag. See "RDNS FILES" above for details on the format of this file. If the "rdns-blacklist-file" flag is given multiple times, each given file will be checked before the connection is allowed.

spamdyke will also search for the remote server's rDNS name in a directory structure and block the connection if it is found. This is activated with the "rdns-blacklist-dir" flag. See "RDNS DIRECTORIES" above for details on the structure of this directory. If the "rdns-blacklist-dir" flag is given multiple times, each given directory will be checked before the connection is allowed.

spamdyke will also search for the remote server's IP address in a file and block the connection if it is found. This is activated with the "ip-blacklist-file" flag. See "IP ADDRESS FILES" above for details on the format of this file. If the "ip-blacklist-file" flag is given multiple times, each given blacklist file will be checked before the connection is allowed.

Whitelist

spamdyke will search for the base domain name of the remote server's rDNS name in a file and skip all filters if it is found. This is activated with the "rdns-whitelist-file" flag. See "RDNS FILES" above for details on the format of this file. If "rdns-whitelist-file" flag is given multiple times, each given whitelist file will be checked before the connection is blocked.

spamdyke will also search for the base domain name of the remote server's rDNS name in a directory structure and skip all filters if it is found. This is activated with the "rdns-whitelist-dir" flag. See "RDNS DIRECTORIES" above for details on the format of this directory structure. If "rdns-whitelist-dir" flag is given multiple times, each given directory will be checked before the connection is blocked.

spamdyke will also search for the remote server's IP address in a file and skip all filters if it is found. This is activated with the "ip-whitelist-file" flag. See "IP ADDRESS FILES" above for details on the format of this file. If the "ip-whitelist-file" flag is given multiple times, each whitelist file will be checked before the connection is blocked.

Blocking sender and recipient address

It's rare, but sometimes spammers will choose to target a specific address and pound it with millions of messages. Most often, this happens when a spammer chooses to use one of your email addresses as the sender address on a spam run. When that happens, you'll receive bounce messages for all of their spams.

spamdyke will block all incoming messages to a specific address with the "recipient-blacklist-file" flag. The given filename must contain one email address per line. Blank lines and lines beginning with "#" are ignored. If the "recipient-blacklist-file" flag is given multiple times, each given blacklist file will be checked before the connection is blocked.

The email addresses may also use wildcards by beginning with "at" signs (@). For example, if the file contained the following entry:

@example.com
spamdyke will block mail to fred@example.com, fred@mail.example.com, barney@mail.internal.example.com, etc.

Similarly, spammers will rarely (but occasionally) use the same sender address for a while. spamdyke will block all incoming messages from a specific address with the "sender-blacklist-file" flag. The given filename must contain one sender address per line. Blank lines and lines beginning with "#" are ignored. If the "sender-blacklist-file" flag is given multiple times, each given blacklist file will be checked before the connection is blocked.

The email addresses may also use wildcards by beginning with "at" signs (@). For example, if the file contained the following entry:

@example.com
spamdyke will block mail from fred@example.com, fred@mail.example.com, barney@mail.internal.example.com, etc.

spamdyke will also look at the sender's domain name to check if it has a mail exchanger or an IP address listed in DNS. If a mail exchanger is found, the mail exchanger must have an IP address. Without a valid mail exchanger or an IP address, no mail could possibly go to the sender address. This test tends to block a lot of mail from web servers that aren't supposed to be sending email. It is activated with the "reject-missing-sender-mx" flag. By default, this test is not run.

To use the "reject-missing-sender-mx" flag, a file must be provided that contains a list of the local domains. Obviously, if the server is willing to receive mail for a given domain, it is a mail exchanger for that domain, no matter what DNS says.

The local domain list is provided with the "local-domains-file" flag. The file should contain one domain name per line. For example, if the provided file contained "example.com", foo@example.com would be allowed to send messages with unlimited numbers of recipients. If the "local-domains-file" flag is given multiple times, each given file will be checked before any action is taken.

The domain list also supports wildcards. If a domain name in the file starts with a dot, any subdomain will also be allowed to send messages with unlimited recipients. For example, if the provided file contained ".example.com", then "fred@foo.example.com", "barney@bar.example.com" and "wilma@example.com" would all be allowed to send messages with unlimited numbers of messages.

Conveniently, this wildcard system matches the system used in qmail's controls/rcpthosts file.

Whitelisting sender and recipient addresses

Sometimes, adding IP addresses and reverse DNS names to whitelist files is not enough to satisfy some users. Either they continue to receive mail from unexpected places or the just think spamdyke is blocking their email. In those cases, the last resort can be to whitelist the sender or recipient address.

NOTE: Using these features is a bad idea! Sender addresses are very easy to forge; this is why spam is so hard to block. Recipient addresses are obviously already known to the spammers; this is why spam is delivered. Whitelisting any addresses this way will allow spam to get through.

To use the "sender-whitelist-file" flag, a file must be provided that contains a list of the sender addresses to be whitelisted. To use the "recipient-whitelist-flag", a file must be provided that contains a list of recipient addresses to be whitelisted.

The given file must contain one address per line. Blank lines and lines beginning with "#" are ignored. If the flag is given multiple times, each given file will be checked before the connection is blocked.

The email addresses may also use wildcards by beginning with "at" signs (@). For example, if the file contained the following entry:

@example.com
spamdyke will match fred@example.com, fred@mail.example.com, barney@mail.internal.example.com, etc.

Earlytalkers

Several years back, someone noticed that some spam software doesn't follow the SMTP protocol. Specifically, spammers were opening connections to remote mail servers and pushing out all of the mail commands as quickly as they could, without waiting for (or checking) responses. By delaying the sending of the greeting banner, it's possible to catch these spammers and block them.

Unfortunately, as of 2007, spammers have mostly updated their software so this test doesn't work any more. It still catches a few of them occasionally though.

spamdyke will delay sending the opening greeting in order to wait for the sender to send data. If that happens, spamdyke will block the connection. This is activated with the "greeting-delay-secs" flag.

Even if it doesn't catch the spammers any more, this is still a good test to run because it slows down the rate at which spammers can send email. Making it more expensive for them is not a bad thing.

Graylisting / Greylisting

Graylisting is the technique of denying mail delivery the first time a sender tries to deliver to a recipient. The next time the remote server attempts to deliver the message, it is accepted. All future messages from the sender to the recipient are also allowed.

Graylisting works because spammers don't use real mail servers, so when the initial delivery fails, they don't retry it. Even if they do, they change to a different random sender address, which is also graylisted.

spamdyke's graylisting is activated first with the "graylist-dir" or "no-graylist-dir" flags, then on a per-domain basis by creating a subfolder for the domain name. For example, if the graylist directory is "/tmp/graylist", the sender address is sender@example.com and the recipient address is recipient@foo.com, spamdyke will first look for a directory named "/tmp/graylist/foo.com". If it does not exist, the message is not graylisted.

NOTE: The names of the domain directories used for graylisting must be lowercase or spamdyke will not match them. Unfortunately, searching a case sensitive filesystem in a case insensitive manner is not practical.

If the directory "/tmp/graylist/foo.com" does exist, spamdyke will create the folder "/tmp/graylist/foo.com/recipient" if it doesn't exist. spamdyke will then look for a file named "/tmp/graylist/foo.com/recipient/sender@example.com".

If the file doesn't exist, it is created with a size of zero bytes and the message is blocked.

If the file exists and the "graylist-min-secs" flag was used, the message is blocked if the file is newer than the given number of seconds.

If the file exists and the "graylist-max-secs" flag was used, the message is allowed if the file is newer than the given number of seconds. If it is older than the given number of seconds, the file is deleted, recreated with a size of zero bytes and the message is blocked.

After all that, if the file exists and its size is greater than zero bytes, the message is passed. When spamdyke passes a message through the graylisting filter, it saves the IP address and rDNS name of the remote server to the file.

The "graylist-dir" flag activates graylisting for all connections. Connections can be exempted from graylisting if the IP address of the remote server matches a line in a file specified with the "never-graylist-ip-file" flag. See "IP ADDRESS FILES" above for details on the format of this file. If "never-graylist-ip-file" is given multiple times, each file will be searched before the connection is graylisted.

Connections can also be excepted from graylisting if the rDNS name of the remote server matches a line in a file specified with the "never-graylist-rdns-file" flag. See "RDNS FILES" above for details on the format of this file. If "never-graylist-rdns-file" is given multiple times, each file will be searched before the connection is graylisted.

Connections can also be excepted from graylisting if the rDNS name of the remote server matches a file in a directory structure specified with the "never-graylist-rdns-dir" flag. See "RDNS DIRECTORIES" above for details on the format of this directory structure. If "never-graylist-rdns-dir" is given multiple times, each directory will be searched before the connection is graylisted.

The "no-graylist-dir" flag dectivates graylisting for all connections. Connections will only be graylisted if the IP address of the remote server matches a line in a file specified with the "always-graylist-ip-file" flag. See "IP ADDRESS FILES" above for details on the format of this file. If the "always-graylist-ip-file" flag is given multiple times, each file will be searched before the connection is graylisted.

Alternatively, connections will be graylisted if the rDNS name of the remote server matches a line in a file specified with the "always-graylist-rdns-file" flag. See "RDNS FILES" above for details on the format of this file. If "always-graylist-rdns-file" flag is given multiple times, each file will be searched before the connection is graylisted.

Connections will also graylisted if the rDNS name of the remote server matches a file in a directory structure specified with the "always-graylist-rdns-dir" flag. See "RDNS DIRECTORIES" above for details on the format of this directory structure. If "always-graylist-rdns-dir" is given multiple times, each directory will be searched before the connection is graylisted.

NOTE: The two flags "graylist-dir" and "no-graylist-dir" are mutually exclusive. If they are both given, spamdyke will use the last one given on the command line.

Graylisting is a relatively new idea (as of 2007) and not very many ISPs are using it yet, so it's surprisingly effective. Spammers will undoubtedly work around it eventually.

Limiting the number of recipients

RFC 821 says an SMTP server must allow the remote server to specify as many recipients as the SMTP server has memory to hold. This allows spammers to send a single message to (potentially) thousands of users in one connection.

spamdyke offers a way to violate the RFC by limiting the number of recipients per message to some value. Once that number has been reached, the remaining recipients will be rejected. Legitimate mail servers use the multi-recipient feature as well, but they will retry their deliveries. Spammers generally don't.

This feature is activated by the "max-recipients" flag. By default, spamdyke allows unlimited recipients per connection.

If you enable this feature, make sure all of your users are using SMTP AUTH or are allowed to relay or are whitelisted. Otherwise, their MUAs will show them error messages when they try to send to large address book mailing lists and they will complain. Loudly.

Timeouts

Most spam software is pretty stupid and doesn't handle error codes from SMTP servers. Instead, they send their commands and wait for specific responses. When those responses don't come, the software just sits forever and waits.

spamdyke will timeout these connections in one of two ways. First, an absolute time limit can be imposed on a connection. This is activated with the "connection-timeout-secs" flag. If this feature is enabled, it should be set to a very high value. Large (legitimate) messages can take a very long time to deliver, especially if the link is slow. A value of 0 disables this feature. By default, this feature is not activated.

Second, an idle time limit can be imposed on a connection. This is activated with the "idle-timeout-secs" flag. If no data is received within the given time limit, the connection is closed. A value of disables this feature. By default, this feature is activated with a value of 60 seconds.

DNS RBLs

DNS Realtime Blackhole Lists are services maintained by third parties that list the IP addresses of offenders. The criteria for being put on a DNS RBL vary and it's often very hard to get delisted. Sometimes, listings are politically motivated and you can end up rejecting legitimate mail because the DNS RBL operator is trying to force a large ISP to cancel a spammer's account. If you choose to use a DNS RBL, please do some research first to understand their policies and history of complaints against them.

spamdyke will reject connections from an IP address listed in a given DNS RBL. This feature is activated with the "check-dnsrbl" flag. By default, spamdyke does not use a DNS RBL. If the "check-dnsrbl" flag is given multiple times, each given DNS RBL will be checked before the connection is allowed.

DNS RHSBLs

DNS Righthand-side Blacklists are services maintained by third parties that list the domain names of offenders. The criteria for being put on a DNS RHSBL vary and it's often very hard to get delisted. Sometimes, listing are politically motivated and you can end up rejecting legitimate mail because the DNS RHBL operating is trying to force a large ISP to cancel a spammer's account. If you choose to use a DNS RHSBL, please do some research first to understand their policies and history of complaints against them.

spamdyke will reject connections from servers whose reverse DNS names are listed in a given DNS RHSBL. spamdyke will also reject connections from senders whose email domain names are listed in a given DNS RHSBL. These features are activated with the "check-rhsbl" flag. By default, spamdyke does not use a DNS RHSBL. If the "check-rhsbl" flag is given multiple times, each given DNS RHSBL will be checked before the connection is allowed.

DNS whitelists

spamdyke has the ability to consult DNS whitelists and allow connections from hosts or senders who match entries on them. DNS whitelists are essentially DNS RBLs and DNS RHSBLs that list allowed IP addresses and domain names instead of blocked ones. All of the same cautionary statements apply to DNS whitelists as to DNS blacklists.

To use a DNS Realtime Whitelist (the opposite of a DNS RBL), the flag "check-dns-whitelist" should be given. To use a DNS Righthand-side Whitelist, the flag "check-rhs-whitelist" should be given. By default, spamdyke does not use a DNS whitelist. If either flag is given multiple times, each given list will be consulted before the connection is blocked.

Extra utilities

There are some additional programs included with spamdyke in the "utils" folder. They are:

passwordcheck
A utility for checking the SMTP AUTH command used with spamdyke.
domain2path
A utility for constructing blacklist folder paths from domain names. domain2path is discussed above.
domainsplit
A utility for finding the base domain name of a fully qualified domain name. For example, given "foo.bar.baz.example.com", domainsplit will return "example.com".
dnsa
A utility for finding IP addresses for fully qualified domain names.
dnsmx
A utility for finding the mail exchangers for a domain.
dnsns
A utility for finding the nameservers for a domain.
dnsptr
A utility for finding PTR records for an IP address.
dnssoa
A utility for finding SOA records for a domain.
dnstxt
A utility for finding TXT records for a domain.

passwordcheck is useful for diagnosing problems with SMTP AUTH commands. It will run the command and report the output, which can be easier to understand than an "authentication failed" message from spamdyke or qmail.

domain2path and domainsplit can be useful from scripts. dnsa, dnsmx, dnsns, dnsptr, dnssoa and dnstxt are probably not useful at all, except as examples of how to make A, MX, NS, PTR, SOA and TXT DNS queries using libc. Small, self-contained examples like these are very difficult to find on the internet. Hopefully someone will find them useful.

None of these utilities depend on being installed in any specific folder. None of them depend on the presence of the others or spamdyke. spamdyke does not depend on them or even use them.