aboutsummaryrefslogtreecommitdiff
path: root/mflib/spf.mf
blob: 4458490491233e5ec96c57bab1efebe049104fa6 (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
/* 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 2, 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, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301 USA */

#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

Return to:

Send suggestions and report system problems to the System administrator.