diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | NEWS | 12 | ||||
-rw-r--r-- | doc/mailfromd.texi | 322 |
3 files changed, 335 insertions, 3 deletions
@@ -1,3 +1,7 @@ +2007-04-04 Sergey Poznyakoff <gray@gnu.org.ua> + + * doc/mailfromd.texi, NEWS: Document SPF functions + 2007-04-03 Sergey Poznyakoff <gray@gnu.org.ua> * src/engine.c (concat_args): Print all arguments in debuging @@ -1,4 +1,4 @@ -Mailfromd NEWS -- history of user-visible changes. 2007-04-01 +Mailfromd NEWS -- history of user-visible changes. 2007-04-04 Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff See the end of file for copying conditions. @@ -7,6 +7,16 @@ Please send mailfromd bug reports to <bug-mailfromd@gnu.org.ua> Version 3.1.91, SVN +* SPF support + +The function check_host() tests the SPF record for the given +identity/host name. The syntax is: + + number check_host(string ip, string domain, string sender, string helo) + +See the documentation, node `SPF functions' for the detailed +description of this function and the related functions and variables. + * next and pass Use `pass' instead of `next'. diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi index 75577cdc..f5512206 100644 --- a/doc/mailfromd.texi +++ b/doc/mailfromd.texi @@ -4522,6 +4522,7 @@ netmask_to_len(inet_aton("254.0.0.0")) @result{} 7 @deftypefn {Library Function} boolean match_cidr (string @var{ip}, @ string @var{cidr}) +@flindex match_cidr.mf This function becomes available after including @file{match_cidr.mf}. It returns @code{true} if the IP address @var{ip} pertains to the @@ -5567,43 +5568,360 @@ The range of IP addresses in @acronym{CIDR} notation. @subsubsection SPF Functions @UNREVISED{} + @dfn{Sender Policy Framework}, or @acronym{SPF} for short, is an +extension to @acronym{SMTP} protocol that allows to identify forged +identities supplied with the @code{MAIL FROM} and @code{HELO} +commands. The framework is explained in detail in RFC 4408 +(@uref{http://tools.ietf.org/html/rfc4408}) and on the +@uref{http://www.openspf.org/, SPF Project Site}. The following is a +short introduction, the users are encouraged to refer to the original +specification for the detailed description of the framework. + + The domain holder publishes an @dfn{SPF record} -- a special +@acronym{DNS} resource record that contains a set of rules declaring +which hosts are, and are not, authorized to use a domain name for +@code{HELO} and @code{MAIL FROM} identities. This resource record is +usually of type @code{TXT}.@footnote{Although RFC4408 introduces a special +@code{SPF} record type for this purpose, it is not yet widely used. +As of version @value{VERSION}, @acronym{MFL} does not support +@code{SPF} @acronym{DNS} records.} + + The @acronym{MFL} script can verify if the identity matches the +published @acronym{SPF} record by calling @code{check_host} function +and analyzing its return code. The function can be called either in +@code{helo} or in @code{envfrom} handler. Its arguments are: + +@table @var +@item ip + The IP address of the SMTP client that is emitting the mail. +Usually it is @code{$client_addr}. + +@item domain + The domain that provides the sought-after authorization information; +Normally it is the domain portion of the @code{MAIL FROM} or +@code{HELO} identity. + +@item sender + The @code{MAIL FROM} identity. + +@item helo_domain + The @code{HELO} identity. + +@item my_domain + The @acronym{SMTP} domain served by the local server. +@end table + + The function returns a numeric result code. For convenience, all +possible return values are defined as macros in file @file{spf.mf}. +The table below describes each value along with the recommended +actions for it: + +@table @code +@cindex None, SPF result code +@item None + A result of @code{None} means that no records were published by the domain +or that no checkable sender domain could be determined from the given +identity. The checking software cannot ascertain whether or not the +client host is authorized. Such a message can be subject to +further checks that will decide about its fate. + +@cindex Neutral, SPF result code +@item Neutral + The domain owner has explicitly stated that he cannot or does not +want to assert whether or not the IP address is authorized. This +result must be treated exactly like @code{None}; the distinction +between them exists only for informational purposes + +@cindex Pass, SPF result code +@item Pass + The client is authorized to send mail with the given identity. The +message can be subject to further policy checks with confidence in the +legitimate use of the identity or it can be accepted in the absence of +such checks. + +@cindex Fail, SPF result code +@item Fail + The client is not authorized to use the domain in the given +identity. The proper action in this case can be to mark the message +with a header explicitely stating it is spam, or to reject it +outright. + + If you choose to reject such mails, we suggest to use @code{reject +550 5.7.1}, as recommended by RFC 4408. The reject can return either +a default explanation string, or the one supplied by the domain that +published the SPF records, as in the example below: + +@smallexample + reject 550 5.7.1 "SPF check failed:\n%spf_explanation" +@end smallexample + +@noindent +(see below for the description of @code{spf_explanation} variable.) + +@cindex SoftFail, SPF result code +@item SoftFail + The domain believes the host is not authorized but is not willing to +make that strong of a statement. This result code should be treated +as somewhere in between a @code{Fail} and a @code{Neutral}. It is not +recommended to reject the message based solely on this result. + +@item TempError + A transient error occured while performing @acronym{SPF} check. The +proper action in this case is to accept or temporarily reject the +message. If you choose the latter, we suggest to use @acronym{SMTP} +reply code of @samp{451} and DSN code @samp{4.4.3}, for example: + +@smallexample + tempfail 451 4.4.3 + "Transient error while performing SPF verification" +@end smallexample + +@item PermError + This result means that the domain's published records could not be +correctly interpreted. This signals an error condition that requires +manual intervention to be resolved, as opposed to the @code{TempError} +result. +@end table + + The following example illustrates the use of @acronym{SPF} +verification in @code{envfrom} handler: + +@smallexample +#include_once <status.mfh> +#include_once <spf.mf> + +prog envfrom +do + switch check_host($client_addr, domainpart($f), $f, $s) + do + case Fail: + string text "" + if %spf_explanation != "" + set text %text "\n" %spf_explanation + fi + reject 550 5.7.1 "SPF MAIL FROM check failed" %text + + case Pass: + accept + + case TempError: + tempfail 451 4.4.3 + "Transient error while performing SPF verification" + + default: + on poll $f do + when success: + accept + when not_found or failure: + reject 550 5.1.0 "Sender validity not confirmed" + when temp_failure: + tempfail 450 4.7.0 "Temporary failure during sender verification" + done + done +done +@end smallexample + + The @acronym{SPF} support is implemented in @acronym{MFL} in two +layers: a built-in layer that provides basic support, and a library +layer that implements result caching. + +@flindex spf.mf + The library layer is implemented in @file{spf.mf}. + + The rest of this node describes available @acronym{SPF} functions +and variables. + @deftypefn {Built-in Function} number spf_check_host (string @var{ip}, @ string @var{domain}, string @var{sender}, string @var{helo_domain}, @ string @var{my_domain}) + This function is the basic implementation of the @code{check_host} +function, defined in RFC 4408, chapter 4. It fetches @acronym{SPF} +records, parses them, and evaluates them to determine whether a +particular host (@var{ip}) is or is not permitted to send mail from a +given email address (@var{sender}). The function returns an @dfn{SPF +result code}. + + Arguments are: + +@table @var +@item ip + The IP address of the SMTP client that is emitting the mail. +Usually it is @code{$client_addr}. + +@item domain + The domain that provides the sought-after authorization information; +Normally it is the domain portion of the @code{MAIL FROM} or +@code{HELO} identity. + +@item sender + The @code{MAIL FROM} identity. + +@item helo_domain + The @code{HELO} identity. + +@item my_domain + The @acronym{SMTP} domain served by the local server. +@end table + +@anchor{spf-globals} + Before returning the @code{spf_check_host} function stores +additional information in global variables: + +@table @code +@item spf_explanation + If the result code is not @code{Pass}, this variable contains the +explanation string as returned by the publishing domain, prefixed with +the value of the global variable @code{spf_explanation_prefix}. + + For example, if @code{spf_explanation_prefix} contains @samp{%@{o@} +explains: }, and the publishing domain @samp{example.com} returns the +explanation string @samp{Please see +http://www.example.com/mailpolicy.html}, than the value of +@code{spf_explanation} will be: + +@smallexample +@group +The domain example.com explains: +Please see http://www.example.com/mailpolicy.html +@end group +@end smallexample + +(see @uref{http://tools.ietf.org/html/rfc4408, RFC 4408}, chapter 8, +for the description of @acronym{SPF} macro facility). + +@item spf_mechanism + Set to the name of a @acronym{SPF} mechanism that decided about the +result code of the @acronym{SPF} record. + +@item spf_ttl + Set to the minimum interval of time, in seconds, during which it is +safe to cache the result value. This value is used by +@code{check_host} function. +@end table + @end deftypefn @deftypefn {Built-in Function} number spf_test_record (string @var{record}, @ string @var{ip}, string @var{domain}, string @var{sender}, @ string @var{helo_domain}, string @var{my_domain}) + Evaluate @acronym{SPF} record @var{record} as if it were published +by @var{domain}. The rest of arguments are the same as for +@code{spf_check_host} above. + + This function is designed primarily for testing and debugging +purposes. You would hardly need to use it. + + The @code{spf_test_record} function sets the same global variables +as @code{spf_check_host}. @end deftypefn @deftypefn {Library Function} number check_host (string @var{ip}, @ string @var{domain}, string @var{sender}, string @var{helo}) + + This function implements the @code{check_host} function, defined in +RFC 4408, chapter 4. It fetches @acronym{SPF} records, parses them, +and evaluates them to determine whether a particular host (@var{ip}) +is or is not permitted to send mail from a given email address +(@var{sender}). The function returns an @dfn{SPF result code}. + + This function differs from the built-in @code{spf_check_host} in +that it implements caching of the results, thereby reducing network +traffic. + + The arguments are: + +@table @var +@item ip + The IP address of the SMTP client that is emitting the mail. +Usually it is @code{$client_addr}. + +@item domain + The domain that provides the sought-after authorization information; +Normally it is the domain portion of the @code{MAIL FROM} or +@code{HELO} identity. + +@item sender + The @code{MAIL FROM} identity. + +@item helo + The @code{HELO} identity. +@end table + + Before returning the @code{check_host} function stores +additional information in the same global variables, as +@code{spf_check_host}. @xref{spf-globals, the list}, for the +description of these. In addition, it sets the variable +@code{spf_cached} to @samp{1} if cached data were used, or to @samp{0} +otherwise. +@end deftypefn + +@deftypefn {Library Function} string spf_status_string (number @var{code}) + Converts numeric @acronym{SPF} result @var{code} to its string +representation. @end deftypefn @deftypevar {Built-in variable} string spf_explanation + If the result code of @code{check_host} (or @code{spf_check_host} or +@code{spf_test_record} function is not @code{Pass}, this variable contains the +explanation string as returned by the publishing domain, prefixed with +the value of the global variable @code{spf_explanation_prefix}. + + For example, if @code{spf_explanation_prefix} contains @samp{%@{o@} +explains: }, and the publishing domain @samp{example.com} returns the +explanation string @samp{Please see +http://www.example.com/mailpolicy.html}, than the value of +@code{spf_explanation} will be: + +@smallexample +@group +The domain example.com explains: +Please see http://www.example.com/mailpolicy.html +@end group +@end smallexample + @end deftypevar @deftypevar {Built-in variable} string spf_mechanism + Set to the name of a @acronym{SPF} mechanism that decided about the +result code of the @acronym{SPF} record. @end deftypevar @deftypevar {Built-in variable} number spf_ttl + Set to the minimum interval of time, in seconds, during which it is +safe to cache the result value. This value is used by +@code{check_host} function. @end deftypevar @deftypevar {Built-in variable} string spf_explanation_prefix + The prefix to be appended to the explanation string before storing +it in the @code{spf_explanation} variable. This string can contain +valid @acronym{SPF} macros (see +@uref{http://tools.ietf.org/html/rfc4408, RFC 4408}, chapter 8), for +example: + +@smallexample +set spf_explanation_prefix "%@{o@} explains: " +@end smallexample + + The default value is @samp{""} (an empty string). @end deftypevar @deftypevar {Library variable} string spf_database -@FIXME{@code{"%__statedir__/spf.db"}.} + Sets the full name of @acronym{DBM} file used to cache the results +of the @acronym{SPF} functions. By default is is +@file{@code{%__statedir__/spf.db}}. @end deftypevar @deftypevar {Library variable} number spf_negative_ttl -@FIXME{interval("1 day")} + Sets the interval of time during which negative replies (result code +@code{None}) will be stored in the database. By default it is 1 day. @end deftypevar @deftypevar {Library variable} number spf_cached + Set by @code{check_host} function to @samp{1} if the function made +the decision based on the cached data, or to @samp{0} otherwise. @end deftypevar @node Debugging Functions |