SKEM(8) BSD System Manager's Manual SKEM(8)NAMEskem — State KEeping Milter
SYNOPSISskem-h
skem-v
skem [-d] [-C directory] [-u uid | user] -b | -w ip.add.res.s1
[ip.add.res.s2 ... ip.add.res.sN]
skem [-d] [-C directory] [-u uid | user] [-g seconds] [-B seconds]
[-l seconds] [-p pid-filename] [-L]
skem [-d] [-C directory] [-u uid | user] [-g seconds] [-B seconds]
[-l seconds] [-p pid-filename] [-2] [-4] [-S spamword] [-s pattern]
[-r reject-string] socket
DESCRIPTION
The skem utility is a sendmail milter, that checks and maintains a list
of whitelisted, temporary banned, and permanently blacklisted IP-
addresses. How you obtain the entries is up to you, but the included
logwatcher, module provides one possibility.
The list is stored in a directory (see the -C option), each entry being a
file (usually -- zero sized) or a symlink (usually -- a "broken" one).
Such entries are stored efficiently (within the directory itself) and the
directories are searched using the hash tables on modern file systems. At
the same time, they can be listed, added, and removed with the simple
ls(1), touch(1) and rm(1).
The current release considers the following attributes of each entry:
mtime The time of creation
mode Setuid means the entry is "white-" and setgid -- "black‐
listed".
ctime The time, this blacklisted entry last tried to contact us.
Keeping this record allows for periodic purging of black‐
list of the IPs not seen in a while, to keep the list from
growing indefinitely.
This milter does not itself filter spam, instead it memorizes the ver‐
dicts issued by your other anti-spam defenses to reduce the system load
and resource consumption, by temporarily rejecting the relays suspected
of spamming (banned) and, optionally, by permanently rejecting the relays
"convicted" of spamming (blacklisted).
The idea is to stem the spam from real spam sources, while reducing the
ill effects of false-positives to merely delaying, rather than rejecting
future messages.
The following options are available:
-2 Do the check twice -- at the beginning (connection) and at the
end of headers. This is to allow a ban, issued by other milters
(and/or our own logwatcher, if enabled) based on the headers
arriving from a previously not banned source, to have effect.
For example, if you have spamtrap-addresses, which trigger black‐
listing, an e-mail coming from a previously unseen IP may contain
them mixed with regular addresses. Without this option, skem will
let the message through, even if subsequent transmissions from
this address will be banned. With this option, even the first e-
mail will be rejected. Only use if you employ such detectors and
if they don't have the capability to reject the whole message
themselves, otherwise it is just a waste.
-4 Use only if sendmail supports closing connection at the conn-
time. At the time of this writing (8.12.x being the latest ver‐
sion), sendmail must be rebuilt with the -D_FFR_MILTER_421 flag
(a C define). This lets us issue temporary rejections right at
the connection time and make sendmail close the connection on the
spot, saving resources. If the sendmail does not support this,
however (and by default it does not), any attempts by skem to do
this will be interpreted as its own temporary failures by
sendmail.
Without this option, skem will work with any sendmail issuing the
temporary bans at the helo-time. The permanent bans are always
acted upon at the conn-time.
-B seconds
This specifies the amount of time a blacklist entry is allowed to
exist in the list since it was last triggered. This is to avoid
wasting storage on IPs, that have once offended us, but are not
doing this any more. The default value is 3 weeks (1814400 sec‐
onds).
-C directory
This is the database directory. If not specified, "." is assumed.
skem will chdir(3) into this directory, and -- if started by root
-- will also chroot(3) there.
-L This option will cause skem to run in the cleanup mode only. If
the -l options was not specified prior, skem will make one
cleanup run and exit. Otherwise, it will be doing the cleanups
periodically, but without becoming a milter.
-S spamword
Tells the logwatcher to treat the occurrence of this spamword in
addition to the reject (see -r below) and pattern (see -s below)
as a sign of definite spam. This will cause the logwatcher to
issue a permanent (setgid), rather than a normal temporary ban.
Use carefully. Without it logwatcher will only create temporary
bans.
-b ip1 [ip2 ... ipN]
Blacklist the specified IPs and exit. If an entry already exists,
it is skipped without change of status.
-d Allow logging at the LOG_DEBUG level. Without this, skem only
logs messages up to the LOG_INFO level.
-g seconds
Expire the temporary bans after this many seconds. The default
is hour and a half (1800 seconds). Keep it below 4 hours, or some
legitimate mail, that might be delayed on the temporarily banned
server may generate a warning to the sender. Such warnings are
remarkably confusing to the laymen and women, who can't, for some
reason, distinguish them from real bounces -- even though they
begin with: "THIS IS A WARNING MESSAGE ONLY. YOU DO NOT NEED TO
RESEND..."
-h Print out an the help screen and exit with code 0.
-l seconds
Perform the cleanup this often. If not specified, no cleanup will
be performed at all (in which case, you may wish to rebuild skem
with the -DSKEM_NO_CLEANUP define). During cleanups, the expired
temporary bans are removed, as well as the permanent bans, which
were not triggered for the last 3 weeks (but see the -B option
above).
-p filename
Write our process ID into the file specified.
-r reject-string
Tells logwatcher what to look for in the log messages. The
default is "reject=5".
-s pattern
This turns on the logwatcher thread, which reads log entries from
stdin and applies the pattern to those of them, that contain the
reject-string. The pattern is expected to be either a "-" (dash)
to use the default pattern, or an extended regular expression
with exactly one parenthesized expression -- the IP address of
the relay.
-u username | uid
Switch identity to the specified username or (numeric) uid. skem
will refuse to become a milter as root, so this argument is
mandatory, unless e are starting as a non-root already.
-v Print the version string(s) and exit.
-w ip1 [ip2 ... ipN]
Whitelist the specified IPs and exit. If an entry already exists,
it is skipped without change of status. Whitelists are never
removed by the cleanup. If you have lower priority Mail eXchang‐
ers for your domain, or other legitimate machines, which fre‐
quently forward mail (ham and spam) to you, you should whitelist
them.
CLEANUP
The cleanup thread cleans up the directory off the expired temporary bans
and the long-unseen permanent bans. See the description of -l -L -B
options above for details. You can have the skem-milter do that, or, if
that's how you like it, use the -L option launching skem from cron(8).
(Not that I can see a single reason to do it that way in normal opera‐
tion.)
Note, that the expired entries are always removed by the milter thread
itself, when triggered -- whether or not the cleanup thread is activated.
To avoid building the cleanup functionality, be sure to NOT use the
-DSKEM_CLEANUP define.
LOGWATCHER
The current milter architecture does not provide a way for milters to
learn the fate of each message. They can not request to be notified, when
a message is rejected by one of the many different mechanisms (such as
another milter, non-existent domain, spamtrap, etc.). The only way to get
this information is by watching the log files. You can cook something up
with awk(1) / perl(1) / python(1) / Tcl(n) / whatever your poison -- all,
your logwatcher needs to do, is place entries in the directory, where
skem is looking for them -- with correct mode.
skem by default includes its own logwatcher thread, which is reasonably
useful (but see the Security Considerations section below). If used, it
expects stdin to contain the arriving log messages. Those of the lines,
that contain the reject string (see the -r options above), are examined
closer with IP-address pattern as provided by the -s option. If the
string yielded by the pattern's parenthesized expression looks like an IP
address, the address is banned. If the spamword is specified (by -S
option) and the string contains it as well, the ban is permanent. Other‐
wise, it is temporary. No ban is created if the IP is already listed as
anything.
To avoid building the logwatcher functionality, be sure to NOT use the
-DSKEM_LOGWATCHER define.
Security Considerations
Although believed to be secure anyway, skem will refuse to become a mil‐
ter as root insisting on the alternative username to be passed with the
-u switch. If started as root, it will also chroot(3) itself into the
database directory prior to dropping root privileges.
However, using the logwatcher may expose you to denial of service attacks
if your installation logs network-obtained data. For example, MIMEDefang
milter logs the subjects of the messages it analyzes. If a subject con‐
tains the reject string and matches the IP pattern, the IP may be banned
-- any IP, that an attacker puts into subject.
The FreeBSD example below does not have this problem, but the
syslog.conf(5) syntax on other systems may not be as powerful.
Even on FreeBSD, a local user can use logger(1) to pretend to be
sendmail. This is, however, intentional. It gives the users the power to
request bans through logwatcher directly by something like
logger -t sendmail -p mail.notice "Please, reject=55x relay=[ip.ad.res.s]"
But if you can not trust local users, you, probably, can not rely on log-
watching anyway.
EXAMPLES
Here is the "live" syslog.conf(5) entry on my server
!sendmail
mail.notice,mail.info |exec /home/mi/skem/skem -C /var/db/skem -S spammer -2 -s - -g 12000 -u mi -l 6000 -4 -B 604800 -d /var/db/skem/skem.sock
This has a disadvantage of being shut down every time the syslogd(8) is
HUP-ed, and not restarted until sendmail(8) has something to say (like
complain about a missing skem-milter).
A different way would be to log into a named pipe (see mkfifo(1)) with
skem reading from the pipe. However, this is likely to hang the syslogd
should skem ever go down (which is very unlikely, but still).
FILES
No configuration files are considered by skem-- all settings are given
on command line.
When started as root, skem will chroot to the directory specified with
the -C option (or to "."), so be sure the socket and the optional
pid-filename specify paths underneath it. For convenience, skem will try
to automatically adjust the paths specified so that they are correct
after the chroot-ing.
INSTALL
The skem executable and the manual page should be installed according to
your OS standards and customs (probably, under /usr/local/sbin and
/usr/local/man/man8). To tell sendmail about the milter, please, refer to
the sendmail's libmilter documentation (in libmilter/README).
Future enhancements being considered
Depending on user interest (if any), the following features might be
implemented:
grey list delay IPs, not yet listed, or listed less than a given num‐
ber of seconds ago
accept syslog messages
enhance the logwatcher module to accept the syslog messages
directly through an inet or a domain socket
interpret the values of the links
Although reading a file is unpleasant, the readlink(2) is a
fast way to obtain information. skem can use the targets
of the symlink-entries for various "interesting" purposes.
For example, logwatcher can record the perceived reasons
for adding an entry, like:
ln -s "caught in spam-trap nospam@example.com" ip.ad.dre.ss
This is fun, but wasteful, because all the information is
in the maillogs too, one just needs to fgrep(1) for a par‐
ticular IP-address to find out the reasons, it was added to
the list.
SEE ALSOlogger(1), rm(1), touch(1), sendmail(8), syslogd(8), umask(1)AUTHORS
Mikhail Teterin ⟨mi+skem@aldan.algebra.com⟩
BSD May 15, 2024 BSD