diff src/dnsbl.cpp @ 76:81f1e400e8ab

start coding on new config syntax
author carl
date Sat, 16 Jul 2005 13:47:19 -0700
parents 1142e46be550
children 8487650c98ee
line wrap: on
line diff
--- a/src/dnsbl.cpp	Wed Jul 13 23:04:14 2005 -0700
+++ b/src/dnsbl.cpp	Sat Jul 16 13:47:19 2005 -0700
@@ -12,23 +12,15 @@
 -t sec   The timeout value.
 -c       Check the config, and print a copy to stdout. Don't start the
          milter or do anything with the socket.
+-s       Stress test by loading and deleting the current config in a loop.
 -d       Add debug syslog entries
+-e f|t   Print the results of looking up from address f and to address
+         t in the current config
 
 
 TODO:
-1) Add config for max_recipients for each mail domain. Recipients in
-excess of that limit will be rejected, and the entire data will be
-rejected if it is sent.
 
-2) Add config for poison addresses. If any recipient is poison, all
-recipients are rejected even if they would be whitelisted, and the
-data is rejected if sent.
-
-3) Add option to only allow one recipient if the return path is empty.
-
-4) Check if the envelope from domain name primary MX points 127.0.0.0/8
-
-5) Add option for using smtp connections to verify addresses from backup
+1) Add option for using smtp connections to verify addresses from backup
 mx machines. This allows the backup mx to learn the valid addresses
 on the primary machine.
 
@@ -95,6 +87,7 @@
 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
+const int maxlen = 1000;    // used for snprintf buffers
 
 pthread_mutex_t  config_mutex;
 pthread_mutex_t  syslog_mutex;
@@ -163,6 +156,7 @@
         char *x = (*i).first;
         free(x);
     }
+    cm.clear();
 }
 
 
@@ -241,8 +235,11 @@
     authenticated = false;
     have_whites   = false;
     only_whites   = true;
-    memory        = new recorder(this, pc->get_html_tags(), pc->get_content_tlds());
-    scanner       = new url_scanner(memory);
+    memory              = NULL;
+    scanner             = NULL;
+    content_suffix      = NULL;
+    content_message     = NULL;
+    content_host_ignore = NULL;
 }
 
 mlfiPriv::~mlfiPriv() {
@@ -254,20 +251,25 @@
 }
 
 void mlfiPriv::reset(bool final) {
+    if (debug_syslog) my_syslog(this, "mlfiPriv::reset");
     if (mailaddr) free(mailaddr);
     if (queueid)  free(queueid);
     discard(env_to);
-    delete memory;
-    delete scanner;
+    if (memory)  delete memory;
+    if (scanner) delete scanner;
     if (!final) {
         mailaddr      = NULL;
         queueid       = NULL;
         authenticated = false;
         have_whites   = false;
         only_whites   = true;
-        memory        = new recorder(this, pc->get_html_tags(), pc->get_content_tlds());
-        scanner       = new url_scanner(memory);
+        memory              = NULL;
+        scanner             = NULL;
+        content_suffix      = NULL;
+        content_message     = NULL;
+        content_host_ignore = NULL;
     }
+    if (debug_syslog) my_syslog("mlfiPriv::reset exit");
 }
 
 void mlfiPriv::get_fd() {
@@ -368,7 +370,18 @@
 }
 
 void mlfiPriv::need_content_filter(char *rcpt, CONTEXT &con) {
+    if (debug_syslog) my_syslog(this, "need_content_filter");
     register_string(env_to, rcpt, &con);
+    if (!memory) {
+        // first recipient that needs content filtering sets all
+        // the content filtering parameters
+        memory        = new recorder(this, con.get_html_tags(), con.get_content_tlds());
+        scanner       = new url_scanner(memory);
+        content_suffix      = con.get_content_suffix();
+        content_message     = con.get_content_message();
+        content_host_ignore = &con.get_content_host_ignore();
+    }
+    if (debug_syslog) my_syslog(this, "need_content_filter exit");
 }
 
 #define MLFIPRIV    ((struct mlfiPriv *) smfi_getpriv(ctx))
@@ -378,7 +391,7 @@
 // syslog a message
 //
 void my_syslog(mlfiPriv *priv, char *text) {
-    char buf[1000];
+    char buf[maxlen];
     if (priv) {
         snprintf(buf, sizeof(buf), "%s: %s", priv->queueid, text);
         text = buf;
@@ -390,6 +403,8 @@
                 syslog_opened = true;
             }
             syslog(LOG_NOTICE, "%s", text);
+            closelog();
+            syslog_opened = false;
         pthread_mutex_unlock(&syslog_mutex);
     }
     else {
@@ -644,8 +659,8 @@
 bool check_hosts(mlfiPriv &priv, bool random, int limit, char *&host, int ip) {
     CONFIG     &dc     = *priv.pc;
     string_set &hosts  = priv.memory->get_hosts();
-    string_set &ignore = dc.get_content_host_ignore();
-    char       *suffix = dc.get_content_suffix();
+    string_set &ignore = *priv.content_host_ignore;
+    char       *suffix = priv.content_suffix;
 
     int count = 0;
     int   cnt = hosts.size();   // number of hosts we could look at
@@ -662,7 +677,7 @@
         if ((cnt > limit) && (limit > 0) && random) {
             int r = rand() % cnt;
             if (r >= limit) {
-                char buf[1000];
+                char buf[maxlen];
                 snprintf(buf, sizeof(buf), "host %s skipped", host);
                 my_syslog(&priv, buf);
                 continue;
@@ -671,7 +686,7 @@
         count++;
         ip = dns_interface(priv, host, true, &nameservers);
         if (debug_syslog) {
-            char buf[1000];
+            char buf[maxlen];
             if (ip) {
                 char adr[sizeof "255.255.255.255"];
                 adr[0] = '\0';
@@ -704,7 +719,7 @@
         ip   = (*i).second;
         if (!ip) ip = dns_interface(priv, host, false, NULL);
         if (debug_syslog) {
-            char buf[200];
+            char buf[maxlen];
             if (ip) {
                 char adr[sizeof "255.255.255.255"];
                 adr[0] = '\0';
@@ -724,7 +739,7 @@
                     string_map::iterator j = nameservers.ns_host.find(host);
                     if (j != nameservers.ns_host.end()) {
                         char *refer = (*j).second;
-                        char buf[1000];
+                        char buf[maxlen];
                         snprintf(buf, sizeof(buf), "%s with nameserver %s", refer, host);
                         host = register_string(hosts, buf);    // put a copy into hosts, and return that reference
                     }
@@ -762,6 +777,7 @@
 //
 sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
 {
+    if (debug_syslog) my_syslog("mlfi_connect");
     // allocate some private memory
     mlfiPriv *priv = new mlfiPriv;
     if (hostaddr->sa_family == AF_INET) {
@@ -778,6 +794,7 @@
 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from)
 {
     mlfiPriv &priv = *MLFIPRIV;
+    if (debug_syslog) my_syslog(&priv, "mlfi_envfrom");
     priv.mailaddr      = to_lower_string(from[0]);
     priv.authenticated = (smfi_getsymval(ctx, "{auth_authen}") != NULL);
     return SMFIS_CONTINUE;
@@ -787,11 +804,20 @@
 {
     DNSBLP rejectlist = NULL;   // list that caused the reject
     mlfiPriv &priv = *MLFIPRIV;
+    if (debug_syslog) my_syslog(&priv, "mlfi_envrcpt");
     CONFIG &dc = *priv.pc;
     if (!priv.queueid) priv.queueid = strdup(smfi_getsymval(ctx, "i"));
     char *rcptaddr  = rcpt[0];
     char *loto      = to_lower_string(rcptaddr);
-    CONTEXT     con = *(dc.find_context(loto)->find_context(priv.mailaddr));
+    if (debug_syslog) my_syslog(&priv, "finding context");
+    CONTEXT    &con = *(dc.find_context(loto)->find_context(priv.mailaddr));
+    if (debug_syslog) {
+        char buf[maxlen];
+        char msg[maxlen];
+        snprintf(msg, sizeof(msg), "from <%s> to <%s> using context %s", priv.mailaddr, loto, con.get_full_name(buf,maxlen));
+        my_syslog(&priv, msg);
+    }
+    if (debug_syslog) my_syslog(&priv, "finding from value");
     char *fromvalue = con.find_from(priv.mailaddr);
     free(loto);
     status st;
@@ -803,6 +829,7 @@
     }
     else {
         // check the dns based lists
+        if (debug_syslog) my_syslog(&priv, "checking dns lists");
         st = (check_dnsbl(priv, con.get_dnsbl_list(), rejectlist)) ? black : oksofar;
     }
     if (st == reject) {
@@ -810,7 +837,7 @@
         char adr[sizeof "255.255.255.255"];
         adr[0] = '\0';
         inet_ntop(AF_INET, (const u_char *)&priv.ip, adr, sizeof(adr));
-        char buf[2000];
+        char buf[maxlen];
         snprintf(buf, sizeof(buf), rejectlist->message, adr, adr);
         smfi_setreply(ctx, "550", "5.7.1", buf);
         return SMFIS_REJECT;
@@ -822,6 +849,7 @@
     }
     else {
         // accept the recipient
+        if (debug_syslog) my_syslog(&priv, "checking content filtering");
         if (!con.get_content_filtering()) st = white;
         if (st == oksofar) {
             // but remember the non-whites
@@ -838,6 +866,7 @@
 sfsistat mlfi_body(SMFICTX *ctx, u_char *data, size_t len)
 {
     mlfiPriv &priv = *MLFIPRIV;
+    if (debug_syslog) my_syslog(&priv, "mlfi_body");
     if (priv.authenticated)       return SMFIS_CONTINUE;
     if (priv.only_whites)         return SMFIS_CONTINUE;
     priv.scanner->scan(data, len);
@@ -846,8 +875,10 @@
 
 sfsistat mlfi_eom(SMFICTX *ctx)
 {
+    if (debug_syslog) my_syslog("mlfi_eom");
     sfsistat  rc;
     mlfiPriv &priv = *MLFIPRIV;
+    if (debug_syslog) my_syslog(&priv, "mlfi_eom");
     CONFIG   &dc   = *priv.pc;
     char     *host = NULL;
     int       ip;
@@ -855,6 +886,8 @@
     // process end of message
     if (priv.authenticated || priv.only_whites) rc = SMFIS_CONTINUE;
     else {
+        // assert env_to not empty
+        char buf[maxlen];
         char *msg = NULL;
         string_set alive;
         bool random = false;
@@ -872,22 +905,21 @@
                 limit   = max(limit, con.get_host_limit());
             }
         }
-        bool rejecting = alive.empty();
+        bool rejecting = alive.empty(); // if alive is empty, we must have set msg above in acceptable_content()
         if (!rejecting) {
-            rejecting = check_hosts(priv, random, limit, host, ip);
-            if (rejecting) {
-                static char buf[2000];
+            if (check_hosts(priv, random, limit, host, ip)) {
                 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), dc.get_content_message(), host, adr);
+                snprintf(buf, sizeof(buf), priv.content_message, host, adr);
                 msg = buf;
+                rejecting = true;
             }
         }
         if (!rejecting) {
             rc = SMFIS_CONTINUE;
         }
-        else if (!priv.have_whites && alive.empty()) {
+        else if (!priv.have_whites) {
             // can reject the entire message
             smfi_setreply(ctx, "550", "5.7.1", msg);
             rc = SMFIS_REJECT;
@@ -909,6 +941,7 @@
 sfsistat mlfi_abort(SMFICTX *ctx)
 {
     mlfiPriv &priv = *MLFIPRIV;
+    if (debug_syslog) my_syslog(&priv, "mlfi_abort");
     priv.reset();
     return SMFIS_CONTINUE;
 }
@@ -916,6 +949,7 @@
 sfsistat mlfi_close(SMFICTX *ctx)
 {
     mlfiPriv *priv = MLFIPRIV;
+    if (debug_syslog) my_syslog(priv, "mlfi_close");
     if (!priv) return SMFIS_CONTINUE;
     delete priv;
     smfi_setpriv(ctx, NULL);
@@ -949,7 +983,7 @@
     pthread_mutex_lock(&config_mutex);
         newc->generation = generation++;
     pthread_mutex_unlock(&config_mutex);
-    char buf[200];
+    char buf[maxlen];
     snprintf(buf, sizeof(buf), "loading configuration generation %d", newc->generation);
     my_syslog(buf);
     if (load_conf(*newc, "dnsbl.conf")) {
@@ -996,7 +1030,7 @@
         for (configp_set::iterator i=old_configs.begin(); i!=old_configs.end(); ) {
             CONFIG *old = *i;
             if (!old->reference_count) {
-                char buf[200];
+                char buf[maxlen];
                 snprintf(buf, sizeof(buf), "freeing memory for old configuration generation %d", old->generation);
                 my_syslog(buf);
                 delete old; // destructor does all the work
@@ -1133,6 +1167,7 @@
 
     if (check) {
         use_syslog = false;
+        debug_syslog = true;
         CONFIG *conf = new_conf();
         if (conf) {
             conf->dump();
@@ -1167,7 +1202,6 @@
             CONFIG *conf = new_conf();
             if (conf) {
                 CONTEXTP con = conf->find_context(to);
-                const int maxlen = 1000;
                 char buf[maxlen];
                 fprintf(stdout, "envelope to   <%s> finds context %s\n", to, con->get_full_name(buf,maxlen));
                 CONTEXTP fc = con->find_context(from);