aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--NEWS12
-rw-r--r--doc/mailfromd.texi322
3 files changed, 335 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 351c4ef1..d6ea4fe0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index abebdfc8..5c1d168d 100644
--- a/NEWS
+++ b/NEWS
@@ -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

Return to:

Send suggestions and report system problems to the System administrator.