diff src/dnsbl.cpp @ 72:e6a2d0be7c5e

start coding on new config syntax
author carl
date Sun, 10 Jul 2005 13:28:33 -0700
parents 1ab70970c8c8
children 2b369f7db7bf
line wrap: on
line diff
--- a/src/dnsbl.cpp	Sat Jul 09 19:24:41 2005 -0700
+++ b/src/dnsbl.cpp	Sun Jul 10 13:28:33 2005 -0700
@@ -67,28 +67,15 @@
 
 // misc stuff needed here
 #include <ctype.h>
-#include <fstream>
 #include <syslog.h>
 #include <pwd.h>
 #include <sys/wait.h>   /* header for waitpid() and various macros */
 #include <signal.h>     /* header for signal functions */
 
-static char* dnsbl_version="$Id$";
-
-#define DEFAULT "default"
-#define WHITE   "white"
-#define BLACK   "black"
-#define OK      "ok"
-#define MANY    "many"
+#include "includes.h"
 
-enum status {oksofar,       // not rejected yet
-             white,         // whitelisted by envelope from
-             black,         // blacklisted by envelope from or to
-             reject,        // rejected by a dns list
-             reject_tag,    // too many bad html tags
-             reject_host};  // too many hosts/urls in body
+static char* dnsbl_version="$Id:";
 
-using namespace std;
 
 extern "C" {
     #include "libmilter/mfapi.h"
@@ -102,115 +89,57 @@
     void sig_chld(int signo);
 }
 
-struct ltstr {
-    bool operator()(char* s1, char* s2) const {
-        return strcmp(s1, s2) < 0;
-    }
-};
+bool debug_syslog  = false;
+bool syslog_opened = false;
+bool loader_run    = true;   // used to stop the config loader thread
+CONFIG * config = NULL;      // protected by the config_mutex
+int  generation = 0;         // protected by the config_mutex
 
-struct DNSBL {
-    char    *suffix;    // blacklist suffix like blackholes.five-ten-sg.com
-    char    *message;   // error message with one or two %s operators for the ip address replacement
-    DNSBL(char *s, char *m);
-};
-DNSBL::DNSBL(char *s, char *m) {
-    suffix  = s;
-    message = m;
-}
+pthread_mutex_t  config_mutex;
+pthread_mutex_t  syslog_mutex;
+pthread_mutex_t  resolve_mutex;
+pthread_mutex_t  fd_pool_mutex;
 
-typedef DNSBL *                           DNSBLP;
-typedef list<DNSBLP>                      DNSBLL;
-typedef DNSBLL *                          DNSBLLP;
-typedef map<char *, char *, ltstr>        string_map;
-typedef map<char *, string_map *, ltstr>  from_map;
-typedef map<char *, DNSBLP, ltstr>        dnsblp_map;
-typedef map<char *, DNSBLLP, ltstr>       dnsbllp_map;
-typedef set<char *, ltstr>                string_set;
-typedef set<int>                          int_set;
-typedef list<char *>                      string_list;
-typedef map<char *, int, ltstr>           ns_mapper;
+std::set<int>    fd_pool;
+int    NULL_SOCKET       = -1;
+char  *resolver_port     = NULL;         // unix domain socket to talk to the dns resolver process
+int    resolver_socket   = NULL_SOCKET;  // socket used to listen for resolver requests
+time_t ERROR_SOCKET_TIME = 60;           // number of seconds between attempts to open the spam filter socket
+time_t last_error_time;
+int    resolver_sock_count = 0;          // protected with fd_pool_mutex
+int    resolver_pool_size  = 0;          // protected with fd_pool_mutex
+
 
 struct ns_map {
     // all the strings are owned by the keys/values in the ns_host string map
     string_map  ns_host;    // nameserver name -> host name that uses this name server
     ns_mapper   ns_ip;      // nameserver name -> ip address of the name server
+    ~ns_map();
+    void add(char *name, char *refer);
 };
 
-struct CONFIG {
-    // the only mutable stuff once it has been loaded from the config file
-    int         reference_count;    // protected by the global config_mutex
-    // all the rest is constant after loading from the config file
-    int         generation;
-    time_t      load_time;
-    string_list config_files;
-    dnsblp_map  dnsbls;
-    dnsbllp_map dnsblls;
-    from_map    env_from;
-    string_map  env_to_dnsbll;      // map recipient to a named dnsbll
-    string_map  env_to_chkfrom;     // map recipient to a named from map
-    char *      content_suffix;     // for sbl url body filtering
-    char *      content_message;    // ""
-    string_set  content_host_ignore;// hosts to ignore for content sbl checking
-    char *      host_limit_message; // error message for excessive host names
-    int         host_limit;         // limit on host names
-    bool        host_random;        // pick a random selection of host names rather than error for excessive hosts
-    char *      tag_limit_message;  // error message for excessive bad html tags
-    int         tag_limit;          // limit on bad html tags
-    string_set  html_tags;          // set of valid html tags
-    string_set  tlds;               // set of valid tld components
-    CONFIG();
-    ~CONFIG();
-};
-CONFIG::CONFIG() {
-    reference_count    = 0;
-    generation         = 0;
-    load_time          = 0;
-    content_suffix     = NULL;
-    content_message    = NULL;
-    host_limit_message = NULL;
-    host_limit         = 0;
-    host_random        = false;
-    tag_limit_message  = NULL;
-    tag_limit          = 0;
+
+void ns_map::~ns_map() {
+    for (string_map::iterator i=ns_host.begin(); i!=ns_host.end(); i++) {
+        char *x = (*i).first;
+        char *y = (*i).second;
+        free(x);
+        free(y);
 }
-CONFIG::~CONFIG() {
-    for (dnsblp_map::iterator i=dnsbls.begin(); i!=dnsbls.end(); i++) {
-        DNSBLP d = (*i).second;
-        // delete the underlying DNSBL objects.
-        delete d;
-    }
-    for (dnsbllp_map::iterator i=dnsblls.begin(); i!=dnsblls.end(); i++) {
-        DNSBLLP d = (*i).second;
-        // *d is a list of pointers to DNSBL objects, but
-        // the underlying objects have already been deleted above.
-        delete d;
-    }
-    for (from_map::iterator i=env_from.begin(); i!=env_from.end(); i++) {
-        string_map *d = (*i).second;
-        delete d;
-    }
+    ns_ip.clear();
+    ns_host.clear();
 }
 
-static bool debug_syslog = false;
-static bool loader_run   = true;    // used to stop the config loader thread
-static string_set all_strings;      // owns all the strings, only modified by the config loader thread
-static CONFIG * config = NULL;      // protected by the config_mutex
-static int  generation = 0;         // protected by the config_mutex
 
-static pthread_mutex_t  config_mutex;
-static pthread_mutex_t  syslog_mutex;
-static pthread_mutex_t  resolve_mutex;
-static pthread_mutex_t  fd_pool_mutex;
+void ns_map::add(char *name, char *refer) {
+    string_map::iterator i = ns_host.find(name);
+    if (i != ns_host.end()) return;
+    char *x = strdup(name);
+    char *y = strdup(refer);
+    ns_ip[x]   = 0;
+    ns_host[x] = y;
 
-static std::set<int>    fd_pool;
-static int    NULL_SOCKET       = -1;
-static char  *resolver_port     = NULL;         // unix domain socket to talk to the dns resolver process
-static int    resolver_socket   = NULL_SOCKET;  // socket used to listen for resolver requests
-static time_t ERROR_SOCKET_TIME = 60;           // number of seconds between attempts to open the spam filter socket
-static time_t last_error_time;
-static int    resolver_sock_count = 0;          // protected with fd_pool_mutex
-static int    resolver_pool_size  = 0;          // protected with fd_pool_mutex
-
+}
 
 // packed structure to allow a single socket write to dump the
 // length and the following answer. The packing attribute is gcc specific.
@@ -223,77 +152,36 @@
     #endif
 } __attribute__ ((packed));
 
-struct mlfiPriv;
+
+////////////////////////////////////////////////
+// helper to discard the strings held by a context_map
+//
+void discard(context_map &cm);
+void discard(context_map &cm) {
+    for (context_map::iterator i=cm.begin(); i!=cm.end(); i++) {
+        char *x = (*i).first;
+        free(x);
+    }
+}
 
 
 ////////////////////////////////////////////////
-// helper to discard the strings and objects held by an ns_map
+// helper to register a string in a context_map
 //
-static void discard(ns_map &s);
-static void discard(ns_map &s) {
-    for (string_map::iterator i=s.ns_host.begin(); i!=s.ns_host.end(); i++) {
-        char *x = (*i).first;
-        char *y = (*i).second;
-        free(x);
-        free(y);
-    }
-    s.ns_ip.clear();
-    s.ns_host.clear();
-}
-
-////////////////////////////////////////////////
-// helper to register a string in an ns_map
-//
-static void register_string(ns_map &s, char *name, char *refer);
-static void register_string(ns_map &s, char *name, char *refer) {
-    string_map::iterator i = s.ns_host.find(name);
-    if (i != s.ns_host.end()) return;
+void register_string(context_map &cm, char *name, CONTEXT *con);
+void register_string(context_map &cm, char *name, CONTEXT *con) {
+    context_map::iterator i = cm.find(name);
+    if (i != cm.end()) return;
     char *x = strdup(name);
-    char *y = strdup(refer);
-    s.ns_ip[x]   = 0;
-    s.ns_host[x] = y;
-
+    cm[x] = con;
 }
 
-////////////////////////////////////////////////
-// helper to discard the strings held by a string_set
-//
-static void discard(string_set &s);
-static void discard(string_set &s) {
-    for (string_set::iterator i=s.begin(); i!=s.end(); i++) {
-        free(*i);
-    }
-    s.clear();
-}
-
-////////////////////////////////////////////////
-// helper to register a string in a string set
-//
-static char* register_string(string_set &s, char *name);
-static char* register_string(string_set &s, char *name) {
-    string_set::iterator i = s.find(name);
-    if (i != s.end()) return *i;
-    char *x = strdup(name);
-    s.insert(x);
-    return x;
-}
-
-////////////////////////////////////////////////
-// syslog a message
-//
-static void my_syslog(mlfiPriv *priv, char *text);
-
-
-// include the content scanner
-#include "scanner.cpp"
-
 
 ////////////////////////////////////////////////
 // disconnect the fd from the dns resolver process
 //
 void my_disconnect(int sock, bool decrement = true);
-void my_disconnect(int sock, bool decrement)
-{
+void my_disconnect(int sock, bool decrement) {
     if (sock != NULL_SOCKET) {
         if (decrement) {
             pthread_mutex_lock(&fd_pool_mutex);
@@ -310,8 +198,7 @@
 // return fd connected to the dns resolver process
 //
 int my_connect();
-int my_connect()
-{
+int my_connect() {
     // if we have had recent errors, don't even try to open the socket
     time_t now = time(NULL);
     if ((now - last_error_time) < ERROR_SOCKET_TIME) return NULL_SOCKET;
@@ -341,35 +228,6 @@
 }
 
 
-////////////////////////////////////////////////
-// mail filter private data, held for us by sendmail
-//
-struct mlfiPriv
-{
-    // connection specific data
-    CONFIG  *pc;                    // global context with our maps
-    int     fd;                     // to talk to dns resolvers process
-    bool    err;                    // did we get any errors on the resolver socket?
-    int     ip;                     // ip4 address of the smtp client
-    map<DNSBLP, status> checked;    // status from those lists
-    // message specific data
-    char    *mailaddr;      // envelope from value
-    char    *queueid;       // sendmail queue id
-    bool    authenticated;  // client authenticated? if so, suppress all dnsbl checks
-    bool    have_whites;    // have at least one whitelisted recipient? need to accept content and remove all non-whitelisted recipients if it fails
-    bool    only_whites;    // every recipient is whitelisted?
-    string_set  non_whites; // remember the non-whitelisted recipients so we can remove them if need be
-    recorder    *memory;    // memory for the content scanner
-    url_scanner *scanner;   // object to handle body scanning
-    mlfiPriv();
-    ~mlfiPriv();
-    void reset(bool final = false); // for a new message
-    void get_fd();
-    void return_fd();
-    int  my_read(char *buf, int len);
-    int  my_write(char *buf, int len);
-};
-
 mlfiPriv::mlfiPriv() {
     pthread_mutex_lock(&config_mutex);
         pc = config;
@@ -382,7 +240,7 @@
     authenticated = false;
     have_whites   = false;
     only_whites   = true;
-    memory        = new recorder(this, &pc->html_tags, &pc->tlds);
+    memory        = new recorder(this, pc->get_html_tags(), pc->get_content_tlds());
     scanner       = new url_scanner(memory);
 }
 
@@ -397,7 +255,7 @@
 void mlfiPriv::reset(bool final) {
     if (mailaddr) free(mailaddr);
     if (queueid)  free(queueid);
-    discard(non_whites);
+    discard(env_to);
     delete memory;
     delete scanner;
     if (!final) {
@@ -406,13 +264,12 @@
         authenticated = false;
         have_whites   = false;
         only_whites   = true;
-        memory        = new recorder(this, &pc->html_tags, &pc->tlds);
+        memory        = new recorder(this, pc->get_html_tags(), pc->get_content_tlds());
         scanner       = new url_scanner(memory);
     }
 }
 
-void mlfiPriv::get_fd()
-{
+void mlfiPriv::get_fd() {
     err = true;
     fd  = NULL_SOCKET;
     int result = pthread_mutex_lock(&fd_pool_mutex);
@@ -441,8 +298,7 @@
     }
 }
 
-void mlfiPriv::return_fd()
-{
+void mlfiPriv::return_fd() {
     if (err) {
         // this fd got a socket error, so close it, rather than returning it to the pool
         my_disconnect(fd);
@@ -470,8 +326,7 @@
     }
 }
 
-int mlfiPriv::my_write(char *buf, int len)
-{
+int mlfiPriv::my_write(char *buf, int len) {
     if (err) return 0;
     int rs = 0;
     while (len) {
@@ -491,8 +346,7 @@
     return rs;
 }
 
-int mlfiPriv::my_read(char *buf, int len)
-{
+int mlfiPriv::my_read(char *buf, int len) {
     if (err) return 0;
     int rs = 0;
     while (len > 1) {
@@ -512,133 +366,42 @@
     return rs;
 }
 
+void mlfiPriv::need_content_filter(char *rcpt, CONTEXT &con) {
+    register_string(env_to, rcpt, &con);
+}
+
 #define MLFIPRIV    ((struct mlfiPriv *) smfi_getpriv(ctx))
 
 
 ////////////////////////////////////////////////
 // syslog a message
 //
-static void my_syslog(mlfiPriv *priv, char *text) {
+void my_syslog(mlfiPriv *priv, char *text) {
     char buf[1000];
     if (priv) {
         snprintf(buf, sizeof(buf), "%s: %s", priv->queueid, text);
         text = buf;
     }
     pthread_mutex_lock(&syslog_mutex);
+        if (!syslog_opened) {
         openlog("dnsbl", LOG_PID, LOG_MAIL);
+            syslog_opened = true;
+        }
         syslog(LOG_NOTICE, "%s", text);
-        closelog();
     pthread_mutex_unlock(&syslog_mutex);
 }
 
-static void my_syslog(char *text);
-static void my_syslog(char *text) {
+void my_syslog(char *text) {
     my_syslog(NULL, text);
 }
 
-////////////////////////////////////////////////
-// register a global string
-//
-static char* register_string(char *name);
-static char* register_string(char *name) {
-    return register_string(all_strings, name);
-}
-
-
-static char* next_token(char *delim);
-static char* next_token(char *delim) {
-    char *name = strtok(NULL, delim);
-    if (!name) return name;
-    return register_string(name);
-}
-
-
-////////////////////////////////////////////////
-// lookup an email address in the env_from or env_to maps
-//
-static char* lookup1(char *email, string_map map);
-static char* lookup1(char *email, string_map map) {
-    string_map::iterator i = map.find(email);
-    if (i != map.end()) return (*i).second;
-    char *x = strchr(email, '@');
-    if (!x) return DEFAULT;
-    x++;
-    i = map.find(x);
-    if (i != map.end()) return (*i).second;
-    return DEFAULT;
-}
-
-
-////////////////////////////////////////////////
-// lookup an email address in the env_from or env_to maps
-// this email address is passed in from sendmail, and will
-// always be enclosed in <>. It may have mixed case, just
-// as the mail client sent it.
-//
-static char* lookup(char* email, string_map map);
-static char* lookup(char* email, string_map map) {
-    int n = strlen(email)-2;
-    if (n < 1) return DEFAULT;  // malformed
-    char *key = strdup(email+1);
-    key[n] = '\0';
-    for (int i=0; i<n; i++) key[i] = tolower(key[i]);
-    char *rc = lookup1(key, map);
-    free(key);
-    return rc;
-}
-
-
-////////////////////////////////////////////////
-//  find the dnsbl with a specific name
-//
-static DNSBLP find_dnsbl(CONFIG &dc, char *name);
-static DNSBLP find_dnsbl(CONFIG &dc, char *name) {
-    dnsblp_map::iterator i = dc.dnsbls.find(name);
-    if (i == dc.dnsbls.end()) return NULL;
-    return (*i).second;
-}
-
-
-////////////////////////////////////////////////
-//  find the dnsbll with a specific name
-//
-static DNSBLLP find_dnsbll(CONFIG &dc, char *name);
-static DNSBLLP find_dnsbll(CONFIG &dc, char *name) {
-    dnsbllp_map::iterator i = dc.dnsblls.find(name);
-    if (i == dc.dnsblls.end()) return NULL;
-    return (*i).second;
-}
-
-
-////////////////////////////////////////////////
-//  find the envfrom map with a specific name
-//
-static string_map* find_from_map(CONFIG &dc, char *name);
-static string_map* find_from_map(CONFIG &dc, char *name) {
-    from_map::iterator i = dc.env_from.find(name);
-    if (i == dc.env_from.end()) return NULL;
-    return (*i).second;
-}
-
-
-static string_map& really_find_from_map(CONFIG &dc, char *name);
-static string_map& really_find_from_map(CONFIG &dc, char *name) {
-    string_map *sm = find_from_map(dc, name);
-    if (!sm) {
-        sm = new string_map;
-        dc.env_from[name] = sm;
-    }
-    return *sm;
-}
-
-
 
 ////////////////////////////////////////////////
 //  read a resolver request from the socket, process it, and
 //  write the result back to the socket.
 
-static void process_resolver_requests(int socket);
-static void process_resolver_requests(int socket) {
+void process_resolver_requests(int socket);
+void process_resolver_requests(int socket) {
 #ifdef NS_MAXDNAME
     char question[NS_MAXDNAME];
 #else
@@ -713,8 +476,8 @@
 //  If we cannot get an answer, we just accept the mail.
 //
 //
-static int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers);
-static int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers) {
+int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers);
+int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers) {
     // this part can be done without locking the resolver mutex. Each
     // milter thread is talking over its own socket to a separate resolver
     // process, which does the actual dns resolution.
@@ -772,7 +535,7 @@
                             }
                             if (n-nam) n--;             // remove trailing .
                             *n = '\0';                  // null terminate it
-                            register_string(ns, nam, question);     // ns host to lookup later
+                            ns.add(nam, question);      // ns host to lookup later
                         }
                     }
                     rrnum = 0;
@@ -817,8 +580,8 @@
 ////////////////////////////////////////////////
 //  check a single dnsbl
 //
-static status check_single(mlfiPriv &priv, int ip, char *suffix);
-static status check_single(mlfiPriv &priv, int ip, char *suffix) {
+bool check_single(mlfiPriv &priv, int ip, char *suffix);
+bool check_single(mlfiPriv &priv, int ip, char *suffix) {
     // make a dns question
     const u_char *src = (const u_char *)&ip;
     if (src[0] == 127) return oksofar;  // don't do dns lookups on localhost
@@ -829,15 +592,15 @@
 #endif
     snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix);
     // ask the question, if we get an A record it implies a blacklisted ip address
-    return (dns_interface(priv, question, false, NULL)) ? reject : oksofar;
+    return dns_interface(priv, question, false, NULL);
 }
 
 
 ////////////////////////////////////////////////
 //  check a single dnsbl
 //
-static status check_single(mlfiPriv &priv, int ip, DNSBL &bl);
-static status check_single(mlfiPriv &priv, int ip, DNSBL &bl) {
+bool check_single(mlfiPriv &priv, int ip, DNSBL &bl);
+bool check_single(mlfiPriv &priv, int ip, DNSBL &bl) {
     return check_single(priv, ip, bl.suffix);
 }
 
@@ -845,15 +608,13 @@
 ////////////////////////////////////////////////
 //  check the dnsbls specified for this recipient
 //
-static status check_dnsbl(mlfiPriv &priv, DNSBLLP dnsbllp, DNSBLP &rejectlist);
-static status check_dnsbl(mlfiPriv &priv, DNSBLLP dnsbllp, DNSBLP &rejectlist) {
+bool check_dnsbl(mlfiPriv &priv, dnsblp_list &dnsbll, DNSBLP &rejectlist);
+bool check_dnsbl(mlfiPriv &priv, dnsblp_list &dnsbll, DNSBLP &rejectlist) {
     if (priv.authenticated) return oksofar;
-    if (!dnsbllp)           return oksofar;
-    DNSBLL &dnsbll = *dnsbllp;
-    for (DNSBLL::iterator i=dnsbll.begin(); i!=dnsbll.end(); i++) {
+    for (dnsblp_list::iterator i=dnsbll.begin(); i!=dnsbll.end(); i++) {
         DNSBLP dp = *i;     // non null by construction
-        status st;
-        map<DNSBLP, status>::iterator f = priv.checked.find(dp);
+        bool st;
+        map<DNSBLP, bool>::iterator f = priv.checked.find(dp);
         if (f == priv.checked.end()) {
             // have not checked this list yet
             st = check_single(priv, priv.ip, *dp);
@@ -864,35 +625,37 @@
             st = (*f).second;
             rejectlist = (*f).first;
         }
-        if (st == reject) return st;
+        if (st) return st;
     }
-    return oksofar;
+    return false;
 }
 
 
 ////////////////////////////////////////////////
 //  check the hosts from the body against the content dnsbl
 //
-static status check_hosts(mlfiPriv &priv, char *&host, int &ip);
-static status check_hosts(mlfiPriv &priv, char *&host, int &ip) {
+bool check_hosts(mlfiPriv &priv, bool random, int limit, char *&host, int ip);
+bool check_hosts(mlfiPriv &priv) {
+    static buf[2000];
     CONFIG &dc = *priv.pc;
+    string_set &hosts  = priv.memory->hosts;
+    string_set &ignore = dc.get_content_host_ignore();
+
     int count = 0;
+    int   cnt = hosts.size();   // number of hosts we could look at
+    int_set ips;
     ns_map nameservers;
-    bool ran = priv.pc->host_random;
-    int  lim = priv.pc->host_limit;         // we should not look at more than this many hosts
-    int  cnt = priv.memory->hosts.size();   // number of hosts we could look at
-    int_set ips;    // remove duplicate ip addresses
-    for (string_set::iterator i=priv.memory->hosts.begin(); i!=priv.memory->hosts.end(); i++) {
-        host = *i;  // a reference into priv.memory->hosts, which will live until this smtp transaction is closed
+    for (string_set::iterator i=hosts.begin(); i!=hosts.end(); i++) {
+        host = *i;  // a reference into hosts, which will live until this smtp transaction is closed
 
         // don't bother looking up hosts on the ignore list
-        string_set::iterator j = priv.pc->content_host_ignore.find(host);
-        if (j != priv.pc->content_host_ignore.end()) continue;
+        string_set::iterator j = ignore.find(host);
+        if (j != ignore.end()) continue;
 
-        // try to only look at lim/cnt fraction of the available cnt host names in random mode
-        if ((cnt > lim) && (lim > 0) && ran) {
+        // try to only look at limit/cnt fraction of the available cnt host names in random mode
+        if ((cnt > limit) && (limit > 0) && random) {
             int r = rand() % cnt;
-            if (r >= lim) {
+            if (r >= limit) {
                 char buf[1000];
                 snprintf(buf, sizeof(buf), "host %s skipped", host);
                 my_syslog(&priv, buf);
@@ -900,10 +663,6 @@
             }
         }
         count++;
-        if ((count > lim) && (lim > 0) && (!ran)) {
-            discard(nameservers);
-            return reject_host;
-        }
         ip = dns_interface(priv, host, true, &nameservers);
         if (debug_syslog) {
             char buf[1000];
@@ -922,21 +681,18 @@
             int_set::iterator i = ips.find(ip);
             if (i == ips.end()) {
                 ips.insert(ip);
-                status st = check_single(priv, ip, dc.content_suffix);
-                if (st == reject) {
-                    discard(nameservers);
-                    return st;
+                if (check_single(priv, ip, dc.content_suffix)) {
+                    return true;
                 }
             }
         }
     }
-    lim *= 4;   // allow average of 3 ns per host name
+    limit *= 4;   // allow average of 3 ns per host name
     for (ns_mapper::iterator i=nameservers.ns_ip.begin(); i!=nameservers.ns_ip.end(); i++) {
         count++;
-        if ((count > lim) && (lim > 0)) {
-            if (ran) continue; // don't complain
-            discard(nameservers);
-            return reject_host;
+        if ((count > limit) && (limit > 0)) {
+            if (random) continue; // don't complain
+            return true;
         }
         host = (*i).first;  // a transient reference that needs to be replaced before we return it
         ip   = (*i).second;
@@ -958,32 +714,23 @@
             int_set::iterator i = ips.find(ip);
             if (i == ips.end()) {
                 ips.insert(ip);
-                status st = check_single(priv, ip, dc.content_suffix);
-                if (st == reject) {
+                if (check_single(priv, ip, dc.content_suffix)) {
                     string_map::iterator j = nameservers.ns_host.find(host);
                     if (j != nameservers.ns_host.end()) {
                         char *refer = (*j).second;
                         char buf[1000];
                         snprintf(buf, sizeof(buf), "%s with nameserver %s", refer, host);
-                        host = register_string(priv.memory->hosts, buf);    // put a copy into priv.memory->hosts, and return that reference
+                        host = register_string(hosts, buf);    // put a copy into hosts, and return that reference
                     }
                     else {
-                        host = register_string(priv.memory->hosts, host);   // put a copy into priv.memory->hosts, and return that reference
+                        host = register_string(hosts, host);   // put a copy into hosts, and return that reference
                     }
-                    discard(nameservers);
-                    return st;
+                    return true;
                 }
             }
         }
     }
-    discard(nameservers);
-    host = NULL;
-    int bin = priv.memory->binary_tags;
-    int bad = priv.memory->bad_html_tags;
-    lim = priv.pc->tag_limit;
-    if (3*bin > bad) return oksofar;    // probably .zip or .tar.gz with random content
-    if ((bad > lim) && (lim > 0)) return reject_tag;
-    return oksofar;
+    return false;
 }
 
 
@@ -1016,38 +763,23 @@
 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **rcpt)
 {
     DNSBLP rejectlist = NULL;   // list that caused the reject
-    status st = oksofar;
     mlfiPriv &priv = *MLFIPRIV;
     CONFIG &dc = *priv.pc;
     if (!priv.queueid) priv.queueid = strdup(smfi_getsymval(ctx, "i"));
     char *rcptaddr = rcpt[0];
-    char *dnsname  = lookup(rcptaddr, dc.env_to_dnsbll);
-    char *fromname = lookup(rcptaddr, dc.env_to_chkfrom);
-    if ((strcmp(dnsname,  BLACK) == 0) ||
-        (strcmp(fromname, BLACK) == 0)) {
-        st = black; // two options to blacklist this recipient
+    CONTEXT &con = *(dc.find_context(rcptaddr, priv.mailaddr));
+    char *fromvalue = con.find_from(priv.mailaddr);
+    status st;
+    if (fromvalue == token_black) {
+        st = black;
     }
-    else if (strcmp(fromname, WHITE) == 0) {
+    else if (fromvalue == token_white) {
         st = white;
     }
     else {
-        // check an env_from map
-        string_map *sm = find_from_map(dc, fromname);
-        if (sm != NULL) {
-            fromname = lookup(priv.mailaddr, *sm);  // returns default if name not in map
-            if (strcmp(fromname, BLACK) == 0) {
-                st = black; // blacklist this envelope from value
+        // check the dns based lists
+        st = check_dnsbl(priv, con.get_dnsbl_list(), rejectlist);
             }
-            if (strcmp(fromname, WHITE) == 0) {
-                st = white; // blacklist this envelope from value
-            }
-        }
-    }
-    if ((st == oksofar) && (strcmp(dnsname, WHITE) != 0)) {
-        // check dns lists
-        st = check_dnsbl(priv, find_dnsbll(dc, dnsname), rejectlist);
-    }
-
     if (st == reject) {
         // reject the recipient based on some dnsbl
         char adr[sizeof "255.255.255.255"];
@@ -1065,9 +797,10 @@
     }
     else {
         // accept the recipient
+        if (!con.get_content_filtering()) st = white;
         if (st == oksofar) {
             // but remember the non-whites
-            register_string(priv.non_whites, rcptaddr);
+            priv.need_content_filter(rcptaddr, con);
             priv.only_whites = false;
         }
         if (st == white) {
@@ -1082,7 +815,6 @@
     mlfiPriv &priv = *MLFIPRIV;
     if (priv.authenticated)       return SMFIS_CONTINUE;
     if (priv.only_whites)         return SMFIS_CONTINUE;
-    if (!priv.pc->content_suffix) return SMFIS_CONTINUE;
     priv.scanner->scan(data, len);
     return SMFIS_CONTINUE;
 }
@@ -1091,38 +823,53 @@
 {
     sfsistat  rc;
     mlfiPriv &priv = *MLFIPRIV;
+    CONFIG   &dc   = *priv.pc;
     char     *host = NULL;
     int       ip;
     status    st;
     // process end of message
-    if (priv.authenticated         ||
-        priv.only_whites           ||
-        (!priv.pc->content_suffix) ||
-        ((st=check_hosts(priv, host, ip)) == oksofar)) rc = SMFIS_CONTINUE;
+    if (priv.authenticated || priv.only_whites) rc = SMFIS_CONTINUE;
     else {
-        if (!priv.have_whites) {
-            // can reject the entire message
-            char buf[2000];
-            if (st == reject_tag) {
-                // rejected due to excessive bad html tags
-                snprintf(buf, sizeof(buf), priv.pc->tag_limit_message);
-            }
-            else if (st == reject_host) {
-                // rejected due to excessive unique host/urls
-                snprintf(buf, sizeof(buf), priv.pc->host_limit_message);
+        char *msg = NULL;
+        string_set alive;
+        bool random = false;
+        bool limit  = 0;
+        for (context_map::iterator i=env_to.begin(); i!=env_to.end(); i++) {
+            char *rcpt   = (*i).first;
+            CONTEXT &con = *((*i).second);
+            if (!con.acceptable_content(priv.memory, msg)) {
+                // bad html tags or excessive hosts
+                smfi_delrcpt(ctx, rcpt);
             }
             else {
+                alive.insert(rcpt);
+                random |= con.get_host_random();
+                limit   = max(limit, con.get_host_limit());
+            }
+        }
+        bool rejecting = alive.empty();
+        if (!rejecting) {
+            rejecting = check_hosts(priv, random, limit, host, ip);
+            if (rejecting) {
+                static char buf[2000];
                 char adr[sizeof "255.255.255.255"];
                 adr[0] = '\0';
                 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr));
-                snprintf(buf, sizeof(buf), priv.pc->content_message, host, adr);
+                snprintf(buf, sizeof(buf), dc.get_content_message(), host, adr);
+                msg = buf;
+            }
             }
-            smfi_setreply(ctx, "550", "5.7.1", buf);
+        if (!rejecting) {
+            rc = SMFIS_CONTINUE;
+        }
+        else if (!priv.have_whites && alive.empty()) {
+            // can reject the entire message
+            smfi_setreply(ctx, "550", "5.7.1", msg);
             rc = SMFIS_REJECT;
         }
         else {
             // need to accept it but remove the recipients that don't want it
-            for (string_set::iterator i=priv.non_whites.begin(); i!=priv.non_whites.end(); i++) {
+            for (string_set::iterator i=alive.begin(); i!=alive.end(); i++) {
                 char *rcpt = *i;
                 smfi_delrcpt(ctx, rcpt);
             }
@@ -1168,404 +915,11 @@
 };
 
 
-static void dumpit(char *name, string_map map);
-static void dumpit(char *name, string_map map) {
-    fprintf(stdout, "\n");
-    for (string_map::iterator i=map.begin(); i!=map.end(); i++) {
-        fprintf(stdout, "%s %s->%s\n", name, (*i).first, (*i).second);
-    }
-}
-
-
-static void dumpit(from_map map);
-static void dumpit(from_map map) {
-    for (from_map::iterator i=map.begin(); i!=map.end(); i++) {
-        char buf[2000];
-        snprintf(buf, sizeof(buf), "envelope from map for %s", (*i).first);
-        string_map *sm = (*i).second;
-        dumpit(buf, *sm);
-    }
-}
-
-
-static void dumpit(CONFIG &dc);
-static void dumpit(CONFIG &dc) {
-    dumpit(dc.env_from);
-    dumpit("envelope to (dnsbl list)", dc.env_to_dnsbll);
-    dumpit("envelope to (from map)", dc.env_to_chkfrom);
-    fprintf(stdout, "\ndnsbls\n");
-    for (dnsblp_map::iterator i=dc.dnsbls.begin(); i!=dc.dnsbls.end(); i++) {
-        fprintf(stdout, "%s %s %s\n", (*i).first, (*i).second->suffix, (*i).second->message);
-    }
-    fprintf(stdout, "\ndnsbl_lists\n");
-    for (dnsbllp_map::iterator i=dc.dnsblls.begin(); i!=dc.dnsblls.end(); i++) {
-        char *name = (*i).first;
-        DNSBLL &dl = *((*i).second);
-        fprintf(stdout, "%s", name);
-        for (DNSBLL::iterator j=dl.begin(); j!=dl.end(); j++) {
-            DNSBL &d = **j;
-            fprintf(stdout, " %s", d.suffix);
-        }
-        fprintf(stdout, "\n");
-    }
-    if (dc.content_suffix) {
-        fprintf(stdout, "\ncontent filtering enabled with %s %s\n", dc.content_suffix, dc.content_message);
-    }
-    for (string_set::iterator i=dc.content_host_ignore.begin(); i!=dc.content_host_ignore.end(); i++) {
-        fprintf(stdout, "ignore %s\n", (*i));
-    }
-    if (dc.host_limit && !dc.host_random) {
-        fprintf(stdout, "\ncontent filtering for host names hard limit %d %s\n", dc.host_limit, dc.host_limit_message);
-    }
-    if (dc.host_limit && dc.host_random) {
-        fprintf(stdout, "\ncontent filtering for host names soft limit %d\n", dc.host_limit);
-    }
-    if (dc.tag_limit) {
-        fprintf(stdout, "\ncontent filtering for excessive html tags enabled with limit %d %s\n", dc.tag_limit, dc.tag_limit_message);
-    }
-    fprintf(stdout, "\nfiles\n");
-    for (string_list::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) {
-        char *f = *i;
-        fprintf(stdout, "config includes %s\n", f);
-    }
-}
-
-
-////////////////////////////////////////////////
-//  check for redundant or recursive include files
-//
-static bool ok_to_include(CONFIG &dc, char *fn);
-static bool ok_to_include(CONFIG &dc, char *fn) {
-    if (!fn) return false;
-    bool ok = true;
-    for (string_list::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) {
-        char *f = *i;
-        if (strcmp(f, fn) == 0) {
-            my_syslog("redundant or recursive include file detected");
-            ok = false;
-            break;
-        }
-    }
-    return ok;
-}
-
-
-////////////////////////////////////////////////
-//  load a single config file
-//
-static void load_conf_dcc(CONFIG &dc, char *name, char *fn);
-static void load_conf_dcc(CONFIG &dc, char *name, char *fn) {
-    ifstream is(fn);
-    if (is.fail()) {
-        char buf[1000];
-        snprintf(buf, sizeof(buf), "include file %s not found", fn);
-        my_syslog(buf);
-        return;
-    }
-    dc.config_files.push_back(fn);
-    const int LINE_SIZE = 2000;
-    char line[LINE_SIZE];
-    char *list  = BLACK;
-    char *delim = " \t";
-    int curline = 0;
-    while (!is.eof()) {
-        is.getline(line, LINE_SIZE);
-        curline++;
-        int n = strlen(line);
-        if (!n) continue;
-        for (int i=0; i<n; i++) line[i] = tolower(line[i]);
-        if (line[0] == '#') continue;
-        char *head = line;
-        if (strspn(line, delim) == 0) {
-            // have a leading ok/many tag to fetch
-            char *cmd = strtok(line, delim);
-                 if (strcmp(cmd, MANY) == 0) list = BLACK;
-            else if (strcmp(cmd, OK) == 0)   list = WHITE;
-            head = cmd + strlen(cmd) + 1;
-        }
-        char *cmd = strtok(head, delim);
-        if (!cmd) continue;
-        if (strcmp(cmd, "env_from") == 0) {
-            char *from = next_token(delim);
-            if (from) {
-                string_map &fm = really_find_from_map(dc, name);
-                fm[from] = list;
-            }
-        }
-        else if (strcmp(cmd, "env_to") == 0) {
-            char *to = next_token(delim);
-            if (to) {
-                dc.env_to_dnsbll[to]  = list;
-                dc.env_to_chkfrom[to] = list;
-            }
-        }
-        else if (strcmp(cmd, "substitute") == 0) {
-            char *tag = next_token(delim);
-            if (tag && (strcmp(tag, "mail_host") == 0)) {
-                char *from = next_token(delim);
-                if (from) {
-                    string_map &fm = really_find_from_map(dc, name);
-                    fm[from] = list;
-                }
-            }
-        }
-        else if (strcmp(cmd, "include") == 0) {
-            char *fn = next_token(delim);
-            if (ok_to_include(dc, fn)) {
-                load_conf_dcc(dc, name, fn);
-            }
-        }
-
-    }
-    is.close();
-}
-
-
-static void load_conf(CONFIG &dc, char *fn);
-static void load_conf(CONFIG &dc, char *fn) {
-    ifstream is(fn);
-    if (is.fail()) {
-        char buf[1000];
-        snprintf(buf, sizeof(buf), "include file %s not found", fn);
-        my_syslog(buf);
-        return;
-    }
-    dc.config_files.push_back(fn);
-    map<char*, int, ltstr> commands;
-    enum {dummy, tld, content, ignore, hostlimit, hostslimit, htmllimit, htmltag, dnsbl, dnsbll, envfrom, envto, include, includedcc};
-    commands["tld"            ] = tld;
-    commands["content"        ] = content;
-    commands["ignore"         ] = ignore;
-    commands["host_limit"     ] = hostlimit;
-    commands["host_soft_limit"] = hostslimit;
-    commands["html_limit"     ] = htmllimit;
-    commands["html_tag"       ] = htmltag;
-    commands["dnsbl"          ] = dnsbl;
-    commands["dnsbl_list"     ] = dnsbll;
-    commands["env_from"       ] = envfrom;
-    commands["env_to"         ] = envto;
-    commands["include"        ] = include;
-    commands["include_dcc"    ] = includedcc;
-    const int LINE_SIZE = 2000;
-    char line[LINE_SIZE];
-    char orig[LINE_SIZE];
-    char *delim = " \t";
-    int curline = 0;
-    while (!is.eof()) {
-        is.getline(line, LINE_SIZE);
-        snprintf(orig, sizeof(orig), "%s", line);
-        curline++;
-        int n = strlen(line);
-        for (int i=0; i<n; i++) line[i] = tolower(line[i]);
-        char *cmd = strtok(line, delim);
-        if (cmd && (cmd[0] != '#') && (cmd[0] != '\0')) {
-            // have a decent command
-            bool processed = false;
-            switch (commands[cmd]) {
-                case tld: {
-                    char *tld = next_token(delim);
-                    if (!tld) break;                            // no tld value
-                    dc.tlds.insert(tld);
-                    processed = true;
-                    } break;
-
-                case content: {
-                    char *suff = strtok(NULL, delim);
-                    if (!suff) break;                           // no dns suffix
-                    char *msg = suff + strlen(suff);
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the dns suffix
-                    msg  = strchr(msg+1, '\'');
-                    if (!msg) break;                            // no reply message template
-                    msg++; // move over the leading '
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the leading quote
-                    char *last = strchr(msg, '\'');
-                    if (!last) break;                           // no trailing quote
-                    *last = '\0';                               // make it a null terminator
-                    dc.content_suffix  = register_string(suff);
-                    dc.content_message = register_string(msg);
-                    processed = true;
-                    } break;
-
-                case ignore: {
-                    char *host = next_token(delim);
-                    if (!host) break;
-                    dc.content_host_ignore.insert(host);
-                    processed = true;
-                    } break;
-
-                case hostlimit: {
-                    char *limit = strtok(NULL, delim);
-                    if (!limit) break;                          // no integer limit
-                    char *msg = limit + strlen(limit);
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the limit
-                    msg  = strchr(msg+1, '\'');
-                    if (!msg) break;                            // no reply message template
-                    msg++; // move over the leading '
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the leading quote
-                    char *last = strchr(msg, '\'');
-                    if (!last) break;                           // no trailing quote
-                    *last = '\0';                               // make it a null terminator
-                    dc.host_limit         = atoi(limit);
-                    dc.host_limit_message = register_string(msg);
-                    dc.host_random        = false;
-                    processed = true;
-                    } break;
-
-                case hostslimit: {
-                    char *limit = next_token(delim);
-                    if (!limit) break;                          // no integer limit
-                    dc.host_limit  = atoi(limit);
-                    dc.host_random = true;
-                    processed = true;
-                    } break;
-
-                case htmllimit: {
-                    char *limit = strtok(NULL, delim);
-                    if (!limit) break;                          // no integer limit
-                    char *msg = limit + strlen(limit);
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the limit
-                    msg  = strchr(msg+1, '\'');
-                    if (!msg) break;                            // no reply message template
-                    msg++; // move over the leading '
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the leading quote
-                    char *last = strchr(msg, '\'');
-                    if (!last) break;                           // no trailing quote
-                    *last = '\0';                               // make it a null terminator
-                    dc.tag_limit         = atoi(limit);
-                    dc.tag_limit_message = register_string(msg);
-                    processed = true;
-                    } break;
-
-                case htmltag: {
-                    char *tag = next_token(delim);
-                    if (!tag) break;                            // no html tag value
-                    dc.html_tags.insert(tag);                   // base version
-                    char buf[200];
-                    snprintf(buf, sizeof(buf), "/%s", tag);
-                    dc.html_tags.insert(register_string(buf));  // leading /
-                    snprintf(buf, sizeof(buf), "%s/", tag);
-                    dc.html_tags.insert(register_string(buf));  // trailing /
-                    processed = true;
-                    } break;
-
-                case dnsbl: {
-                    // have a new dnsbl to use
-                    char *name = next_token(delim);
-                    if (!name) break;                           // no name name
-                    if (find_dnsbl(dc, name)) break;            // duplicate entry
-                    char *suff = strtok(NULL, delim);
-                    if (!suff) break;                           // no dns suffic
-                    char *msg = suff + strlen(suff);
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the dns suffix
-                    msg  = strchr(msg+1, '\'');
-                    if (!msg) break;                            // no reply message template
-                    msg++; // move over the leading '
-                    if ((msg - line) >= strlen(orig)) break;    // line ended with the leading quote
-                    char *last = strchr(msg, '\'');
-                    if (!last) break;                           // no trailing quote
-                    *last = '\0';                               // make it a null terminator
-                    dc.dnsbls[name] = new DNSBL(register_string(suff), register_string(msg));
-                    processed = true;
-                    } break;
-
-                case dnsbll: {
-                    // define a new combination of dnsbls
-                    char *name = next_token(delim);
-                    if (!name) break;
-                    if (find_dnsbll(dc, name)) break;               // duplicate entry
-                    char *list = next_token(delim);
-                    if (!list || (*list == '\0') || (*list == '#')) break;
-                    DNSBLLP d = new DNSBLL;
-                    DNSBLP p = find_dnsbl(dc, list);
-                    if (p) d->push_back(p);
-                    while (true) {
-                        list = next_token(delim);
-                        if (!list || (*list == '\0') || (*list == '#')) break;
-                        DNSBLP p = find_dnsbl(dc, list);
-                        if (p) d->push_back(p);
-                    }
-                    dc.dnsblls[name] = d;
-                    processed = true;
-                    } break;
-
-                case envfrom: {
-                    // add an entry into the named string_map
-                    char *name = next_token(delim);
-                    if (!name) break;
-                    char *from = next_token(delim);
-                    if (!from) break;
-                    char *list = next_token(delim);
-                    if (!list) break;
-                    if ((strcmp(list, WHITE) == 0) ||
-                        (strcmp(list, BLACK) == 0)) {
-                        string_map &fm = really_find_from_map(dc, name);
-                        fm[from] = list;
-                        processed = true;
-                    }
-                    else {
-                        // list may be the name of a previously defined from_map
-                        string_map *m = find_from_map(dc, list);
-                        if (m && (strcmp(list,name) != 0)) {
-                            string_map &pm = *m;
-                            string_map &fm = really_find_from_map(dc, name);
-                            fm.insert(pm.begin(), pm.end());
-                            processed = true;
-                        }
-                    }
-                    } break;
-
-                case envto: {
-                    // define the dnsbl_list and env_from maps to use for this recipient
-                    char *to   = next_token(delim);
-                    if (!to) break;
-                    char *list = next_token(delim);
-                    if (!list) break;
-                    char *from = next_token(delim);
-                    if (!from) break;
-                    dc.env_to_dnsbll[to]  = list;
-                    dc.env_to_chkfrom[to] = from;
-                    processed = true;
-                    } break;
-
-                case include: {
-                    char *fn = next_token(delim);
-                    if (ok_to_include(dc, fn)) {
-                        load_conf(dc, fn);
-                        processed = true;
-                    }
-                    } break;
-
-                case includedcc: {
-                    char *name = next_token(delim);
-                    if (!name) break;
-                    char *fn = next_token(delim);
-                    if (ok_to_include(dc, fn)) {
-                        load_conf_dcc(dc, name, fn);
-                        processed = true;
-                    }
-                    } break;
-
-                default: {
-                    } break;
-            }
-            if (!processed) {
-                pthread_mutex_lock(&syslog_mutex);
-                    openlog("dnsbl", LOG_PID, LOG_MAIL);
-                    syslog(LOG_ERR, "ignoring file %s line %d : %s\n", fn, curline, orig);
-                    closelog();
-                pthread_mutex_unlock(&syslog_mutex);
-            }
-        }
-    }
-    is.close();
-}
-
-
 ////////////////////////////////////////////////
 //  reload the config
 //
-static CONFIG* new_conf();
-static CONFIG* new_conf() {
+CONFIG* new_conf();
+CONFIG* new_conf() {
     CONFIG *newc = new CONFIG;
     pthread_mutex_lock(&config_mutex);
         newc->generation = generation++;
@@ -1573,10 +927,13 @@
     char buf[200];
     snprintf(buf, sizeof(buf), "loading configuration generation %d", newc->generation);
     my_syslog(buf);
-    load_conf(*newc, "dnsbl.conf");
+    if (load_conf(*newc, "dnsbl.conf") {
     newc->load_time = time(NULL);
     return newc;
 }
+    delete newc;
+    return NULL;
+}
 
 
 ////////////////////////////////////////////////
@@ -1584,8 +941,8 @@
 //  and reload when needed. we also cleanup old
 //  configs whose reference count has gone to zero.
 //
-static void* config_loader(void *arg);
-static void* config_loader(void *arg) {
+void* config_loader(void *arg);
+void* config_loader(void *arg) {
     typedef set<CONFIG *> configp_set;
     configp_set old_configs;
     while (loader_run) {
@@ -1627,8 +984,8 @@
 }
 
 
-static void usage(char *prog);
-static void usage(char *prog)
+void usage(char *prog);
+void usage(char *prog)
 {
     fprintf(stderr, "Usage: %s  [-d] [-c] -r port -p sm-sock-addr [-t timeout]\n", prog);
     fprintf(stderr, "where port is for the connection to our own dns resolver processes\n");
@@ -1643,8 +1000,8 @@
 
 
 
-static void setup_socket(char *sock);
-static void setup_socket(char *sock) {
+void setup_socket(char *sock);
+void setup_socket(char *sock) {
     unlink(sock);
     //  sockaddr_un addr;
     //  memset(&addr, '\0', sizeof addr);
@@ -1672,6 +1029,7 @@
 
 int main(int argc, char**argv)
 {
+    token_init();
     bool check   = false;
     bool setconn = false;
     bool setreso = false;
@@ -1733,10 +1091,16 @@
     }
 
     if (check) {
-        CONFIG &dc = *new_conf();
-        dumpit(dc);
+        CONFIG *conf = new_conf();
+        if (conf) {
+            conf->dump();
+            delete conf;
         return 0;
     }
+        else {
+            return 1;   // config failed to load
+        }
+    }
 
     if (!setconn) {
         fprintf(stderr, "%s: Missing required -p argument\n", argv[0]);