graymilter with DNS based whitelists support – part 3

In part 2 we saw a simple way of whitelisting domain names in Jef Poskanzer’s graymilter. However, this is a solution that does not scale well enough for busy mail systems. Adding or removing a domain from the whitelist means recompiling graymilter which is not the most convenient thing, especially if one needs to do it (over and over) on multiple mail servers.

Wouldn’t it be easier if you could update only one file and have the information distributed to all mail servers? One way of doing this is by using rbldnsd:

“rbldnsd is a small and fast DNS daemon which is especially made to serve DNSBL zones. This daemon was inspired by Dan J. Bernstein’s rbldns program found in the djbdns package.”

Normally people use rbldnsd for publishing blacklists, but this should not stop you. After all you only need to publish a list. Whether it is a blacklist or a whitelist depends on how the program that consults it decides upon the information it gets. I start rbldnsd as follows:

/usr/sbin/rbldnsd -p /var/run/ -r/var/lib/rbldns -b1.2.3.4 \\

And assuming that I want to enlist the domains, and, looks like this:

; It is declared as a combined zonefile when rbldnsd statrs
$DATASET dnset: @

The next step is to patch graymilter so that it consults a nameserver. While we are at it why not use lwresd?

“[lwresd] provides resolution services to local clients using a combination of a lightweight resolver library and a resolver daemon process running on the local host. These communicate using a simple UDP-based protocol, the “lightweight resolver protocol” that is distinct from and simpler than the full DNS protocol.

To use the lightweight resolver interface, the system must run the resolver daemon lwresd or a local name server configured with a lwres statement.

The lwresd daemon is essentially a caching-only name server that responds to requests using the lightweight resolver protocol rather than the DNS protocol. Because it needs to run on each host, it is designed to require no or minimal configuration. Unless configured otherwise, it uses the name servers listed on nameserver lines in /etc/resolv.conf as forwarders, but is also capable of doing the resolution autonomously if none are specified.”

Now using the lwres(3) interface we can write a query function that consults the domain name whitelist that we serve via rbldnsd:

#ifndef _TEE_CHECKS_C_
#define _TEE_CHECKS_C_ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lwres/lwres.h>
#include <lwres/netdb.h>
static int
tee_check_domain(char *host, char *whitelist)
        char *name;
        int l, herr;
        struct hostent *he;
        l = strlen(host) + strlen(whitelist) + 1;
        name = (char *)malloc(l);
        if (name == NULL) {
                syslog(LOG_INFO, "tee_check_domain(): malloc() error: aborting");
        memset(name, '\0', l);
        sprintf(name, "%s%s", host, whitelist);
        /* syslog(LOG_INFO, "tee_check_domain(): %s", name); */
        he = lwres_getipnodebyname(name, AF_INET, 0, &herr);
        if (he == NULL) {
                if (herr == HOST_NOT_FOUND) {
                } else {
#endif /* _TEE_CHECKS_C_ */

and again after line 680 of graymilter.c (assuming graymilter-1.26):

if (tee_check_domain(connhost, "") == 0) {
  syslog(LOG_INFO, "accepting host %s from whitelist", connhost);
  return SMFIS_ACCEPT;

After you run ./configure you have to add -llwres to the generated Makefile.

So there, now rbldnsd distributes your domain name whitelist and you have local caching at every mail server with the help of lwresd.

(part 2) (final)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s