/* Cached SPF interface. Copyright (C) 2007 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #require safedb #pragma regex push +extended +icase set spf_database "%__statedir__/spf.db" set spf_negative_ttl interval("1 day") number spf_cached 0 const None 0 const Neutral 1 const Pass 2 const Fail 3 const SoftFail 4 const TempError 5 const PermError 6 func spf_status_string(number code) returns string do switch %code do case None: return "None" case Neutral: return "Neutral" case Pass: return "Pass" case Fail: return "Fail" case SoftFail: return "SoftFail" case TempError: return "TempError" case PermError: return "PermError" done return "UNKNOWN (" %code ")" done func __spf_get_cache(string ip, string domain, string sender) returns number do string record safedbget(%spf_database, "%ip-%domain-%sender") number timestamp number ttl number result if %record = "" set result -1 elif %record matches '([^ ]+) ([^ ]+) <(.*)> <(.*)>' set timestamp \1 if time() >= %timestamp echo "$i: CLEARING record %record" set result -1 else set result \2 set spf_mechanism \3 set spf_explanation \4 fi else echo "$i: ERROR: Malformed DB line: %record" set result -1 fi return %result done func __spf_put_cache(number result, string ip, string domain, string sender) do safedbput(%spf_database, "%ip-%domain-%sender", (time() + %spf_ttl) " %result <%spf_mechanism> <%spf_explanation>") done func __spf_log(number result, string ip, string domain, string sender) do string logmsg "SPF check_host(%ip, %domain, %sender) = " spf_status_string(%result) if %spf_cached set logmsg %logmsg " [CACHED]" fi if %spf_mechanism != "" set logmsg %logmsg "; matching mechanism \"%spf_mechanism\"" fi if %spf_explanation != "" set logmsg %logmsg "; %spf_explanation" fi echo "$i: %logmsg" done func check_host(string ip, string domain, string sender, string helo) returns number do number result __spf_get_cache(%ip, %domain, %sender) if %result == -1 set result spf_check_host(%ip, %domain, %sender, %helo, %ehlo_domain) set spf_cached 0 if %result = None set spf_ttl %spf_negative_ttl fi __spf_put_cache(%result, %ip, %domain, %sender) else set spf_cached 1 fi __spf_log(%result, %ip, %domain, %sender) return %result done #pragma regex pop