In part 1 I showed how one can use tcp_wrappers to patch graymilter in order to support dns based whitelists (as opposed to IP based whitelists that it supports by default).
But what if you need something faster than having graymilter open /etc/hosts.allow for every message passed to it in order to decide whether the sending host is whitelisted or not?
Basically you need a strcmp(3) function with a twist. While the strcmp(3) family of functions compare from left to right, you need the opposite:
#ifndef _RIGHT_STRCMP_C_
#define _RIGHT_STRCMP_C_ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Think of this as a rightmost strcmp() */
static int
right_strcmp(char *x, char *y)
{
int xl, yl, l;
char *s;
xl = strlen(x);
yl = strlen(y);
l = xl - yl;
if (l < 0) {
return l;
} else {
s = x + l;
return (strncmp(s, y, yl));
}
}
#endif /* _RIGHT_STRCMP_C_ */
Now you can include the file right_strcmp.c at the top of graymilter.c (remember right_strcmp() is declared as a static function). If you are using graymilter version 1.26 you then scroll down at line 680 and add this snippet of code:
$ diff graymilter.c graymilter.c-
76d75
< #include "right_strcmp.c"
680,692d678
< if (right_strcmp(connhost, ".example.com") == 0) {
< syslog(LOG_INFO, "accepting host %s", connhost);
< return SMFIS_ACCEPT;
< }
< if (right_strcmp(connhost, ".example.org") == 0) {
< syslog(LOG_INFO, "accepting host %s", connhost);
< return SMFIS_ACCEPT;
< }
< if (right_strcmp(connhost, ".example.net") == 0) {
< syslog(LOG_INFO, "accepting host %s", connhost);
< return SMFIS_ACCEPT;
< }
<
Yes, the above example hardcodes the domains into the graymilter executable. One is free to play around and write a simple function that reads a domain list from a file and wraps around right_strcmp() with the help of stdarg(3). That way you only have to write one if statement. This is left as an exercise to the reader.
