Emserver will maintain, in addition to 'greylisting' entries, white and
black-listing entries.
These entries must be made in a strict format, as follows:-
White-list entries:
Y[sender@]domain<sender.i.p.address
or Black-list entries:
N
If 'sender@' is omitted white/black listing is done on the whole domain,
otherwise it is done on the specific sender only.
The sender.i.p.address may be 'wildcarded' to some degree:
A simple * will match any sender IP address
123.* will match any address commencing 123.
123.123.123.* will match any address commencing 123.123.123.
123.123.123.1* will match any address commencing 123.123.123.1
Note that matching is done on the literal IP address string, NOT its
numeric value. Accordingly to match a range of IP addresses such as
123.123.123.49 - 123.123.123.51, you would need three separate entries.
If you wish to white-list a given domain and do not know the sending IP
address, you can simply use the 'domain<*' form.
My personal experience is that most known sender domains can be white-listed
in the 'domain<*' form - except for the ones that will inevitably be forged by
spammers and scammers (eg hotmail.com, barclaysbank.co.uk etc etc).
Likewise known senders@domain can nearly always be listed in the same form,
as specific users@domain are generally not forged.
You will need to adopt the strategy most appropriate to your situation.
It may be best to start with a fairly 'loose' white-listing strategy
and 'tighten up' on any senders/domains that prove to be problematical.
In all probability if you are black-listing a domain, you will always want
to use the same 'domain<*' form as there is little point in discriminating
by IP address in this case.
IP-MASKING FOR GREYLISTING:
Note that the program creates greylist entries ordinarily with the full IP
address of the sending machine. However, to cater for senders who may use a
'pool' of machines to send emails (each with a slightly different address
within a nnn.nnn.nnn.0-254 range), the program can be compiled to 'mask'
the last octet of all IP addresses before creating the greylist entry,
eg IP address 123.123.123.123 would be greylisted as 123.123.123.0.
To compile with this facility, specify -DIPMASK on the compile line.
You can, of course, change the mask within the program source from FFFFFF00
to something more restrictive, eg FFFFFFF8, if you wish.
HOUSEKEEPING/MAINTENANCE:
Greylisting entries created by emserver are automatically flushed from the
table after approximately 4 hours (assuming there are at least 50 to be flushed
- to reduce cpu utilisation!), if they have not already been deleted as a result
of a second successful delivery attempt. Accordingly the number of entries in
the memory-resident table at any one time will be the sum of:
user(recipient) entries, and
white and black listing entries, and
greylisting entries which have not yet 'expired' and no second delivery
attempt has yet been received.
Unless you receive inordinately high amounts of 'spam', the greylisting entries
should not be too huge (and should in any event be limited to 4 hours worth of
'spam').
Various 'commands' can be issued to emserver via emsclient as follows:-
Ystring
- add 'whitelist' entry to table (see above)
Nstring
- add 'blacklist' entry to table (see above)
Ttime:string
- add 'temporary' entry to table (see below - 'debugging'
only)
Dstring
- delete entry from table, where string is the table entry
of form '>recipient', or 'sender[@domain]>ip.address.
Cstring
- return table-entry status (using same form as D above)
L
- list permanent table entries (loaded or inserted as
Y or N)
LX[Z]
- list 'temporary' table entries [ and terminate ]
LZ[Z]
- list all table entries [ and terminate ]
F[nnn]
- flush expired 'temporary' entries
[ nnn = minutes old or more ]
U
- report 'memory usage'
Z0
- debug off
Zn
debug on (note this will have no effect unless emserver
invoked with D option in the first place - as stdout will
be redirected to /dev/null !) where n = 1 or 2
In all cases the square brackets are not part of the command, they simply
delimit optional items.
F on its own will flush expired temporary entries using the compiled-in 'flush'
time, whereas Fnnn will flush temporary entries of over nnn minutes 'old'.
T='temporary' entries must be added in the following form:
Tnnnnnnnnnn:sender@domain<sender.I.P.address>recipient
where nnnnn is Unix epoch time (seconds). This feature is really only used
to reload the table from a file previously extracted with the LZ command.
Exim4 sends the following command, which may also be entered via emsclient
for testing purposes:
Qsender@senderdomain<sender.i.p.address>recipient
Note that emsclient does NOT check the validity of any command/query you type.
Invalid command letters will result in a response of X.
The results of other invalid commands/queries are indeterminate.
For exmple, if you enter the command:
Nxyz.com<
(to create black-listing entry)
the command will be accepted and a table-entry created, but the entry will
never be found upon a query since the string format is invalid (no IP address
or wildcard *).
SAVING THE MEMORY TABLE AND RESTARTING:
It may be that, on occasions, it is necessary to stop the emserver daemon.
In this event the memory table will clearly 'evaporate'. Any pending
emails temporarily rejected on the first attempt would then also be
temporariliy rejected on the second attempt, which is undesirable (although
not disastrous!). Accordingly, the table can be effectively saved to a
file by use of the emsclient program as follows:
emsclient LZZ > file
The table will be saved to the file and the daemon terminated before it can
process any further enquires. All table-entries including recipients/users,
black/white-listed senders/domains and greylist entries will be saved.
If you have a 'master' list of entries, then the following could also be done:
emsclient LXZ > file; cat master-list >> file
A fresh master-list can be created at any time using:
emsclient LZ > master-list
the daemon will not be stopped).
RUNNING THE DAEMON IN 'SUPERVISED' MODE:
It is possible, if you wish to be ultra-safe, to run the emserver daemon
in 'supervised' mode using the program mdaemon. In this event, you need to
compile emserver.c with the -DNODAEMON flag. It will then not demonise itself.
By running mdaemon (which is is simply compiled: cc mdaemon.c -s -o whatever),
with the arguments of flag interval /usr/local/sbin/emserver file-name (where
flag has the meaning as shown below and interval is the number of seconds
between 'restarts' - must be 0 or more),
mdaemon will daemonise itself and then execute emserver and 'supervise' it
- ie restart it if it should terminate prematurely.
To be sure of not losing too many greylist entries in the event of a restart,
you can also also run:
mdaemon 1 600 /usr/local/sbin/emsclient LZ > file-name
which will result in an entire 'dump' of the emserver table to file-name
every 10 minutes.
Other variations are of course possible, using mdaemon to start a shell-script
which itself constructs a load file and then executes emserver, for example.
TESTING
The Z0, Z1 and Z2 commands set the debugging levels to 'none' 'some' or 'all'.
However emserver must be invoked with the D 'flag' for these to be of any use,
as without the 'D' flag the program will disconnect stdout and re-connect it
to /dev/null (so you will bever see its output!). If you think you will need
the debug output, simply do the following:
emserver input-file D > debug-output-file-or-device; ems Z0
This will start the daemon in debug mode with stdout redirected suitably
and immediately switch off the actual debug output.
PROCESSOR UTILISATION:
Emserver keeps its table in memory and accordingly the amount of memory used
is dependent on the size of the table. However, memory is cheap and plentiful,
so this should not be an issue! Memory consumed will be approximately the
size of each 'string' entered into the table + 20 bytes for each entry (table
and 'malloc' overhead). The size of each string is effectively rounded up to
the nearest multiple of 4.
As a very rough guide, 5000 entries would probably consume about 1/2 Megabyte.
Actual CPU usage should be very low. On a Athlon 2800, a individual query to a
large table of 5000 entries takes subtsantially less than 1 millisecond, using
the standard compiled hashentry size of 839. Doubling the hashentry size would
use up about another 3400 bytes approximately, and would probably speed up
search time marginally - however it seems much of the CPU time is actually
consumed on 'socket' operations (the socket must be opened and closed for each
query) and accordingly increasing the hashentry size is not really worthwile.
In this connection, it is a pity that Exim4 does not support UDP queries, as
there is far less overhead with connectionless datagrams! But maybe I am being
'picky' !!
The programs use a Unix domain socket '/tmp/ems' by default - and therefore
must run on the same machine as the mail server. However, they can be compiled
(see the sources for details of the complie-time defines required) to use
I.P. sockets - which would allow them to be run on different machines across
a local network (serving for example more than one Exim MTA). Also in this
configuration, emclient could exist and be run on all the different machines
on the network if need be.