Hello list, I think spamd users would like to try this small utility. Although its development is in the very beginning it does its job quite well for me it was written for the case where a big mass mailer like google is trying to send us mail.
The utility notices such mailers and white lists it by adding its allowed nets taken through spf queries to the white list. i.e. it reads output of spamdb, then checks spf records for all greylisted mails and produces 'whitelist.auto' file which can then be used with spamd-setup. it is small, so I put it into attachment. -- With best regards, Gregory Edigarov #include <sys/types.h> #include <netinet/in.h> #include <arpa/nameser.h> #include <resolv.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #define ERREXIT(_p) perror(_p); exit(-1); char *tok[] = {"v=spf1", "redirect=", "include:", "ip4:", "ip6:"}; FILE *out; void tspf(char *domain); char * txtquery(const char *domain, unsigned int *ttl) { unsigned char answer[PACKETSZ], host[128], *pt, *txt; int len, exp, cttl, size, txtlen, type; if (res_init() < 0) { ERREXIT("res_init"); } printf("*Querying %s\n", domain); memset(answer, 0, PACKETSZ); if ((len = res_query(domain, C_IN, T_TXT, answer, PACKETSZ)) < 0) { ERREXIT("res_query"); } pt = answer + sizeof(HEADER); if ((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { ERREXIT("dn_expand"); } pt += exp; GETSHORT(type, pt); if (type != T_TXT) { ERREXIT("type"); } pt += INT16SZ; /* class */ if ((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { ERREXIT("dn_expand"); } pt += exp; GETSHORT(type, pt); if (type != T_TXT) { ERREXIT("type"); } pt += INT16SZ; /* class */ GETLONG(cttl, pt); *ttl = cttl; GETSHORT(size, pt); txtlen = *pt; if (txtlen >= size || !txtlen) { ERREXIT("txtlen"); } if (!(txt = malloc(txtlen + 2))) { ERREXIT("malloc") } pt++; strlcpy(txt, pt, txtlen + 1); return txt; } void do_redirect(char *p) { char *txt; unsigned ttl; p += strlen(tok[1]); puts(p); txt = txtquery(p, &ttl); tspf(txt); } void do_include(char *p) { char *txt; unsigned ttl; p += strlen(tok[2]); txt = txtquery(p, &ttl); tspf(txt); } void do_ipv4(char *p) { p += strlen(tok[3]); fprintf(out, "%s\n", p); } void do_ipv6(char *p) { p += strlen(tok[3]); fprintf(out, "%s\n", p); } void tspf(char *dom) { char *ans, *p, *last; int spf_v = 0; unsigned int ttl; ans = txtquery(dom, &ttl); for (p = strtok_r(ans, " ", &last); p; p = strtok_r(NULL, " ", &last)) { if (!strncmp(p, tok[0], strlen(tok[0]))) spf_v = 1; if (!strncmp(p, tok[1], strlen(tok[1])) && spf_v) do_redirect(p); if (!strncmp(p, tok[2], strlen(tok[2])) && spf_v) do_include(p); if (!strncmp(p, tok[3], strlen(tok[3])) && spf_v) do_ipv4(p); if (!strncmp(p, tok[4], strlen(tok[4])) && spf_v) do_ipv6(p); } free(ans); } int main(int argc, char **argv) { FILE *in; char buf[1024]; char type[64], ip[256], helo[1024], mailfrom[1024], rcptto[1024], td1[1024], td2[1024], td3[1024], trig1[2], trig2[2]; char *p; system("mv whitelist.auto whitelist.old"); if (argc > 1) out = fopen(argv[1], "a+"); else out = fopen("whitelist.new", "a+"); if (out == NULL) { ERREXIT("fopen"); } in = popen("spamdb", "r"); if (in == NULL) { ERREXIT(p); } while (fgets(buf, sizeof(buf), in)) { if (!strncmp(buf, "GREY", 4)) { for (p = (char *) &buf; *p; p++) if (*p == '|') *p = ' '; sscanf(buf, "%s %s %s %s %s %s %s %s %s %s", (char *) &type, (char *) &ip, (char *) &helo, (char *) &mailfrom, (char *) &rcptto, (char *) &td1, (char *) &td2, (char *) &td3, (char *) &trig1, (char *) &trig2); puts((char *) &type); puts((char *) &mailfrom); } p = strchr((char *) &mailfrom, '>'); *p = '\0'; p = strchr((char *) &mailfrom, '@'); ++p; tspf(p); } fclose(out); system("cat whitelist.old whitelist.new|sort|uniq>whitelist.auto"); exit(0); } PROG= spf2whitelist NOMAN= noman .include <bsd.prog.mk>