summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2012-07-31 18:08:21 -0700
committerJohn Denker <jsd@av8n.com>2012-07-31 18:08:21 -0700
commit159a3f448ad2caf9468921a4387c2dbafe09c3a3 (patch)
treeb16f9593b43e0cada94d6a87c4380fd0ed1d56eb /tools
parent3f3c46c8ee8ef118ce73da7d3235364edf390cfe (diff)
bring sepofra over from ~/hack/
Diffstat (limited to 'tools')
-rw-r--r--tools/bad_thing.h45
-rw-r--r--tools/makefile4
-rw-r--r--tools/sepofra.c178
-rw-r--r--tools/sepofra.h49
4 files changed, 274 insertions, 2 deletions
diff --git a/tools/bad_thing.h b/tools/bad_thing.h
new file mode 100644
index 0000000..ee988dc
--- /dev/null
+++ b/tools/bad_thing.h
@@ -0,0 +1,45 @@
+#ifndef BAD_THING_H
+#define BAD_THING_H
+class payloader{
+public:
+ int refcount;
+ char str[0];
+};
+
+class bad_thing: public std::exception{
+ payloader* load;
+ char* &raw;
+
+public:
+ virtual const char* what() const throw() {
+ return load->str;
+ }
+ bad_thing();
+// copy constructor.
+// It's OK to copy a pointer to the refcount,
+// but it would not be OK to copy the refcount!
+ bad_thing(const bad_thing &other)
+ : load(other.load), raw((char*&) load)
+ {
+ load->refcount++;
+ //xx std::cerr << "Copied! --> " << load->refcount << std::endl;
+ }
+
+ bad_thing(const std::string msg)
+ : raw((char*&) load)
+ {
+ size_t len = msg.size();
+ raw = new char[1+len + sizeof(payloader)];
+ load->refcount = 1;
+ for (unsigned int ii = 0; ii < len; ii++){
+ load->str[ii] = msg[ii];
+ }
+ load->str[len] = 0;
+ }
+ ~bad_thing() throw() {
+ if (--load->refcount) return;
+ //xx std::cerr << "delete!" << std::endl;
+ delete[] raw;
+ }
+};
+#endif
diff --git a/tools/makefile b/tools/makefile
index 723d756..5bd5711 100644
--- a/tools/makefile
+++ b/tools/makefile
@@ -47,8 +47,8 @@ fixown2: fixown.o utils.o
chmod o-rwx $@
./fixown $@
-skrewt: skrewt.o utils.o
- $(CC) $^ -lboost_filesystem-mt -lboost_system -o $@
+skrewt: skrewt.o utils.o sepofra.o
+ $(CC) $^ -lboost_filesystem-mt -lboost_system -lspf2 -o $@
./fixown $@
greylist: greylist.o utils.o
diff --git a/tools/sepofra.c b/tools/sepofra.c
new file mode 100644
index 0000000..5072b36
--- /dev/null
+++ b/tools/sepofra.c
@@ -0,0 +1,178 @@
+#include <iostream>
+#include <sstream>
+
+#include "sepofra.h"
+
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+using namespace std;
+
+string domain_part(const string ema){
+ size_t where = ema.find('@');
+ if (where != ema.npos){
+ return ema.substr(1+where);
+ }
+ return ema;
+}
+
+string subdomain(const string ema){
+ size_t where = ema.find('.');
+ if (where != ema.npos){
+ return ema.substr(1+where);
+ }
+ return ema;
+}
+
+SPF_result_t sepofra::check1(const string host,
+ const string msg, const int debug){
+ if (!host.length()) return SPF_RESULT_INVALID;
+
+ authorities.push_back(host);
+ if (SPF_request_set_env_from( spf_request,
+ host.c_str() ) ) {
+ throw bad_thing (("Invalid " + msg + ": " + host).c_str());
+ }
+
+ if (spf_response) SPF_response_free(spf_response);
+ SPF_request_query_mailfrom(spf_request, &spf_response);
+ if (debug) dumpit(debug, spf_response, "");
+ return SPF_response_result(spf_response);
+}
+
+
+void sepofra::check(
+ const string opt_ip,
+ const string opt_helo,
+ const string opt_mailfrom,
+ const string opt_rcpt_to,
+ const int opt_debug)
+{
+ SPF_server_t* spf_server = NULL;
+ sepofra rslt;
+ ip = opt_ip;
+ mailfrom = opt_mailfrom;
+ string mailfrom_domain = domain_part(opt_mailfrom);
+ string auth;
+
+ do {
+ spf_server = SPF_server_new(SPF_DNS_CACHE, opt_debug);
+ if (spf_server == NULL) {
+ cerr << "SPF_server_new failed" << endl;
+ break;
+ }
+
+ spf_request = SPF_request_new(spf_server);
+ if (spf_request == NULL) {
+ cerr << "SPF_request_new failed" << endl;
+ break;
+ }
+
+ if ( SPF_request_set_ipv4_str( spf_request, opt_ip.c_str() ) ) {
+ cerr << "Invalid IP address: " << opt_ip << endl;
+ break;
+ }
+
+ result = check1(opt_helo, "HELO domain", opt_debug);
+ if (result == SPF_RESULT_PASS) break;
+ if (result == SPF_RESULT_FAIL) break;
+
+ result = check1(mailfrom, "MAILFROM domain", opt_debug);
+ if (result == SPF_RESULT_PASS) break;
+ if (result == SPF_RESULT_FAIL) break;
+
+ result = check1(subdomain(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);
+ if (result == SPF_RESULT_PASS) break;
+ if (result == SPF_RESULT_FAIL) break;
+
+ } while(0);
+
+ if (spf_response) SPF_response_free(spf_response);
+ if (spf_request) SPF_request_free(spf_request);
+ if (spf_server) SPF_server_free(spf_server);
+
+ return;
+}
+
+string sepofra::explain() const {
+ if (result == SPF_RESULT_INVALID) return "";
+// now build a string
+ stringstream build;
+ string summary = SPF_strresult(result);
+ if (result != SPF_RESULT_PASS
+ && result != SPF_RESULT_FAIL) summary = "neutral";
+
+ char hostname[1+HOST_NAME_MAX];
+ gethostname(hostname, 1+HOST_NAME_MAX);
+ build << "Received-SPF: ";
+ build << summary;
+ build << " (" << hostname; /* ) */
+ build << ": sender " << ip;
+ if (result == SPF_RESULT_PASS){
+ build << " is approved by {"
+ << authorities.back()
+ << "}";
+ } else if (result == SPF_RESULT_FAIL){
+ build << " is forbidden by {"
+ << authorities.back()
+ << "}";
+ } else {
+ build << " is neither approved nor forbidden by {";
+ int didsome(0);
+ for (list<string>::const_iterator ptr = authorities.begin();
+ ptr != authorities.end(); ptr++) {
+ if (didsome++) build << " ";
+ build << *ptr;
+ }
+ build << "}";
+ }
+ /* ( */ build << ")";
+ build << " client-ip=" << ip << ";";
+ build << " envelope-from=" << mailfrom << ";";
+ return build.str();
+}
+
+void dumpit(const int opt_debug,
+ SPF_response_t* spf_response,
+ const char* msg) {
+ int i;
+ printf("---- %s\n", msg);
+ if ( opt_debug > 0 ) {
+ printf ( "result = %s (%d)\n",
+ SPF_strresult(SPF_response_result(spf_response)),
+ SPF_response_result(spf_response));
+ printf ( "err = %s (%d)\n",
+ SPF_strerror(SPF_response_errcode(spf_response)),
+ SPF_response_errcode(spf_response));
+ for (i = 0; i < SPF_response_messages(spf_response); i++) {
+ SPF_error_t *err = SPF_response_message(spf_response, i);
+ printf ( "%s_msg = (%d) %s\n",
+ (SPF_error_errorp(err) ? "warn" : "err"),
+ SPF_error_code(err),
+ SPF_error_message(err));
+ }
+ }
+
+#define VALID_STR(x) (x ? x : "")
+
+ printf("Bottom line result: %s\n",
+ SPF_strresult( SPF_response_result(spf_response)));
+
+ printf("Reason: %s\n", SPF_strreason(spf_response->reason));
+
+ printf("SMTP comment: %s\n",
+ VALID_STR(SPF_response_get_smtp_comment(spf_response)));
+
+ printf("Header comment: %s\n",
+ VALID_STR(SPF_response_get_header_comment(spf_response)));
+
+ printf("Received spf: %s\n",
+ VALID_STR(SPF_response_get_received_spf(spf_response)));
+
+}
diff --git a/tools/sepofra.h b/tools/sepofra.h
new file mode 100644
index 0000000..89719fb
--- /dev/null
+++ b/tools/sepofra.h
@@ -0,0 +1,49 @@
+#include <string>
+#include <list>
+# include <sys/socket.h> /* inet_ functions / structs */
+# include <netinet/in.h> /* inet_ functions / structs */
+# include <arpa/inet.h> /* in_addr struct */
+
+#ifdef __cplusplus
+extern "C" {
+# include "spf2/spf.h"
+}
+#else
+# include "spf2/spf.h"
+#endif
+
+#include <string.h>
+#include "bad_thing.h"
+
+class sepofra{
+public:
+ SPF_result_t result;
+ std::list<std::string> authorities;
+ std::string ip;
+ std::string mailfrom;
+ SPF_request_t* spf_request;
+ SPF_response_t* spf_response;
+
+ sepofra()
+ : result(SPF_RESULT_INVALID),
+ spf_request(NULL),
+ spf_response(NULL)
+ {}
+ void check(
+ const std::string opt_ip,
+ const std::string opt_helo,
+ const std::string opt_mailfrom,
+ const std::string opt_rcpt_to,
+ const int opt_debug);
+
+ std::string explain() const;
+ SPF_result_t check1(
+ const std::string host,
+ const std::string msg,
+ const int debug);
+};
+
+
+void dumpit(const int opt_debug,
+ SPF_response_t* spf_response,
+ const char* msg);