aboutsummaryrefslogtreecommitdiff
path: root/mflib/spf.mf
blob: 8ce06aec735d99fbceb617f1a85d28cee6ecd517 (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
/* Cached SPF interface.
   Copyright (C) 2007, 2008 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/>. */

#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.