aboutsummaryrefslogtreecommitdiff
path: root/mflib/spf.mf
blob: 45f2959dc8aa511c58c6eceaa7ac31ffdc2d953e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* Cached SPF interface.
   Copyright (C) 2007-2011, 2015-2016 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 <http://www.gnu.org/licenses/>. */

module 'spf'.
require 'safedb'

#pragma regex push +extended +icase

set spf_database "%__statedir__/spf.db"
set spf_negative_ttl interval("1 day")

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

static func __spf_msgid()
  returns string
do
  if macro_defined("i")
    return getmacro("i") . ": "
  else
    return ""
  fi
done

static 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 __spf_msgid() . "CLEARING record %record"
      set result -1
    else
      set result \2
      set spf_mechanism \3
      set spf_explanation \4
    fi
  else
    echo __spf_msgid() . "ERROR: Malformed DB line: %record"
    set result -1
  fi
  return result	
done

static 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

static func __spf_log(number cached, number result,
                      string ip, string domain, string sender)
do
  string logmsg "SPF check_host(%ip, %domain, %sender) = " .
	        spf_status_string(result)
  if 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 __spf_msgid() . logmsg
done

func check_host(string ip, string domain, string sender, string helo)
  returns number
do
  number cached 0
  number result __spf_get_cache(ip, domain, sender)
	
  if result == -1
    set result spf_check_host(ip, domain, sender, helo, ehlo_domain)

    if result = None
      set spf_ttl spf_negative_ttl
    fi
    __spf_put_cache(result, ip, domain, sender)
  else
    set cached 1
  fi
  __spf_log(cached, result, ip, domain, sender)
  return result
done

#pragma regex pop

Return to:

Send suggestions and report system problems to the System administrator.