From b95f5ec1d83519c603f6e2145865c14932c4a813 Mon Sep 17 00:00:00 2001
From: John Denker <jsd@av8n.com>
Date: Tue, 31 Jul 2012 19:23:01 -0700
Subject: smarter about top-level domains, smarter about avoiding duplicate
 checks

---
 tools/sepofra.c | 32 ++++++++++++++++++++++----------
 tools/sepofra.h |  4 ++++
 2 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/tools/sepofra.c b/tools/sepofra.c
index d41e5ad..69575c4 100644
--- a/tools/sepofra.c
+++ b/tools/sepofra.c
@@ -22,12 +22,19 @@ string domain_part(const string ema){
   return ema;
 }
 
-string subdomain(const string ema){
-  size_t where = ema.find('.');
-  if (where != ema.npos){
-    return ema.substr(1+where);
-  }
-  return ema;
+// strips off one level of domain name,
+//  provided that at least two levels remain.
+//      foo.bar.com --> bar.com
+//          bar.com --> bar.com
+//    ..foo.bar.com --> bar.com
+string subdomain2plus(const string ema){
+  string sub(ema);
+  while (sub[0] == '.') sub = sub.substr(1);
+  size_t where = sub.find('.');
+  if (where == string::npos) return ema;
+  sub = sub.substr(1+where);
+  if (sub.find(".") == string::npos) return ema;
+  return sub;
 }
 
 SPF_result_t sepofra::check1(const string _host,
@@ -38,6 +45,11 @@ SPF_result_t sepofra::check1(const string _host,
         host = host.substr(1+where);
       }
       if (!host.length()) return SPF_RESULT_INVALID;
+      if (seen.find(host) != seen.end()) {
+        // already checked this one
+        return SPF_RESULT_SOFTFAIL;
+      }
+      seen[host] = 1;
 
       authorities.push_back(host);
       if (SPF_request_set_env_from( spf_request,
@@ -62,8 +74,8 @@ void sepofra::check(
   SPF_server_t*     spf_server = NULL;
   sepofra rslt;
   ip = opt_ip;
-  helo = opt_helo;
-  mailfrom = trim(opt_mailfrom, " \t\r\n<>");
+  helo = trim(opt_helo, " \t\r\n<.>");
+  mailfrom = trim(opt_mailfrom, " \t\r\n<.>");
   string mailfrom_domain = domain_part(opt_mailfrom);
 
   do {
@@ -92,11 +104,11 @@ void sepofra::check(
     if (result == SPF_RESULT_PASS) break;
     if (result == SPF_RESULT_FAIL) break;
 
-    result = check1(subdomain(opt_helo), "HELO subdomain", opt_debug);
+    result = check1(subdomain2plus(opt_helo), "HELO subdomain", opt_debug);
     if (result == SPF_RESULT_PASS) break;
     if (result == SPF_RESULT_FAIL) break;
 
-    result = check1(subdomain(mailfrom), "MAILFROM domain", opt_debug);
+    result = check1(subdomain2plus(mailfrom), "MAILFROM domain", opt_debug);
     if (result == SPF_RESULT_PASS) break;
     if (result == SPF_RESULT_FAIL) break;
 
diff --git a/tools/sepofra.h b/tools/sepofra.h
index 2e4b831..60a404f 100644
--- a/tools/sepofra.h
+++ b/tools/sepofra.h
@@ -1,5 +1,6 @@
 #include <string>
 #include <list>
+#include <map>
 # include <sys/socket.h>   /* inet_ functions / structs */
 # include <netinet/in.h>   /* inet_ functions / structs */
 # include <arpa/inet.h> /* in_addr struct */
@@ -15,10 +16,13 @@ extern "C" {
 #include <string.h>
 #include "bad_thing.h"
 
+typedef std::map<std::string,int> MSI;
+
 class sepofra{
 public:
   SPF_result_t result;
   std::list<std::string> authorities;
+  MSI seen;
   std::string ip;
   std::string mailfrom;
   std::string helo;
-- 
cgit v1.2.3