User Tools

Site Tools


networking:dns:bind:spf_sender_policy_framework

Networking - DNS - Bind - SPF (Sender Policy Framework)

SPF (Sender Policy Framework), is an email-validation system which is designed to allow spoofed mails to be identified.

SPF allows you to specify, via a DNS-record, which hosts are allowed to send email on behalf of a particular domain.

Because SPF involves the use of DNS there is not anything to actually configure on your mail-server, when sending outgoing mail.

Instead you must merely be able to identify all the hosts which might send email with a particular domain - these are the hosts which must be included in the DNS-record.


DNS config

SPF-policies are published as TXT records, in DNS.

The basic record looks like this:

; spf record for example.com
$ORIGIN example.com.
....
example.com.  IN TXT "v=spf1 include:example.net -all"
; use the SPF details for example.net 
; in the above case to replace example.com's SPF
; or 
 
example.com.  IN TXT "v=spf1 mx include:example.net -all"
; additive - use MX RR for example.com
; AND if that fails use example.nets's SPF

SPF tags

The SPF record is a simple text string, in a TXT, record which contains a v=spf1 prefix, and a number of additional components.

For example:

ComponentMeaning
AIf the domain name has an address record (A or AAAA) that can be resolved to the sender's address, it will match.
MXIf the domain name has an MX record resolving to the sender's address, it will match (i.e. the mail comes from one of the domain's incoming mail servers).
IP4If the sender is in the given IPv4 address range, match.
IP6If the sender is in the given IPv6 address range, match.
PTRUse DNS PTR RRs for verification.
EXISTSTest for existence of domain.

Types of rejection levels

The domain-administrator may also decide whether violations should be regarded as hard-failure “FAIL” or soft-failures “SOFTFAIL”.

This is usually specified via “-all”, and “~all” respectively.

Rejection TypeDetail
-allReject or fail them - don't deliver the email if anything does not match.
~allSoft-fail them - accept them, but mark it as 'suspicious'.
+allPass regardless of match - accept anything from the domain.
?allNeutral - accept it, nothing can be said about the validity if there isn't an IP match.

Most records will have a “~all” listed in the SPF record because the domain owner leaves room for the possibility of a new server getting created and might forget to update the SPF record with the new IP address of that server. This also allows for regular machines to send email without causing too much of an interruption.

Very large domains such as gmail.com have “?all” in their records to leave it up to the recipient to determine what to do with the email when received.


The "all" mechanism

all

This mechanism always matches. It usually goes at the end of the SPF record.

# Allow domain's MXes to send mail for the domain, prohibit all others.
"v=spf1 mx -all"
 
# The domain sends no mail at all.
"v=spf1 -all"
 
# The domain owner thinks that SPF is useless and/or doesn't care.  It just allows all email.
"v=spf1 +all"

The "ip4" mechanism

ip4:<ip4-address>

ip4:<ip4-network>/<prefix-length>

The argument to the “ip4:” mechanism is an IPv4 network range. If no prefix-length is given, /32 is assumed (singling out an individual host address).

# Allows any IP address between 192.168.0.1 and 192.168.255.255.
"v=spf1 ip4:192.168.0.1/16 -all"

The "ip6" mechanism

ip6:<ip6-address>

ip6:<ip6-network>/<prefix-length>

The argument to the “ip6:” mechanism is an IPv6 network range. If no prefix-length is given, /128 is assumed (singling out an individual host address).

# Allow any IPv6 address between 1080::8:800:0000:0000 and 1080::8:800:FFFF:FFFF.
"v=spf1 ip6:1080::8:800:200C:417A/96 -all"
 
 
# Allow any IPv6 address between 1080::8:800:0000:0000 and 1080::8:800:FFFF:FFFF.
"v=spf1 ip6:1080::8:800:68.0.3.1/96 -all"

The "a" mechanism

a

a/<prefix-length>

a:<domain>

a:<domain>/<prefix-length>

All the A records for domain are tested. If the client IP is found among them, this mechanism matches.

If domain is not specified, the current-domain is used.

The A records have to match the client IP exactly, unless a prefix-length is provided, in which case each IP address returned by the A lookup will be expanded to its corresponding CIDR prefix, and the client IP will be sought within that subnet.

# The current-domain is used.
"v=spf1 a -all"
 
# Equivalent if the current-domain is example.com.
"v=spf1 a:example.com -all"
 
# Perhaps example.com has chosen to explicitly list all the outbound mailers in a special A record under mailers.example.com.
"v=spf1 a:mailers.example.com -all"
 
# If example.com resolves to 192.0.2.1, the entire class C of 192.0.2.0/24 would be searched for the client IP.
# Similarly for offsite.example.com.  
# If more than one A record were returned, each one would be expanded to a CIDR subnet.
"v=spf1 a/24 a:offsite.example.com/24 -all"

The "mx" mechanism

mx

mx/<prefix-length>

mx:<domain>

mx:<domain>/<prefix-length>

All the A records for all the MX records for domain are tested in order of MX priority. If the client IP is found among them, this mechanism matches.

If domain is not specified, the current-domain is used.

The A records have to match the client IP exactly, unless a prefix-length is provided, in which case each IP address returned by the A lookup will be expanded to its corresponding CIDR prefix, and the client IP will be sought within that subnet.

# Perhaps a domain sends mail through its MX servers plus another set of servers whose job is to retry mail for deferring domains.
"v=spf1 mx mx:deferrals.domain.com -all"
 
# Perhaps a domain's MX servers receive mail on one IP address, but send mail on a different but nearby IP address.
"v=spf1 mx/24 mx:offsite.domain.com/24 -all"

The "ptr" mechanism

ptr

ptr:<domain>

The hostname or hostnames for the client IP are looked up using PTR queries. The hostnames are then validated: at least one of the A records for a PTR hostname must match the original client IP. Invalid hostnames are discarded. If a valid hostname ends in domain, this mechanism matches.

If domain is not specified, the current-domain is used.

If at all possible, you should avoid using this mechanism in your SPF record, because it will result in a larger number of expensive DNS lookups.

# A domain which directly controls all its machines (unlike a dialup or broadband ISP) allows all its servers to send mail.
# For example, hotmail.com or paypal.com might do this.
"v=spf1 ptr -all"
 
# Any server whose hostname ends in otherdomain.com is designated.
"v=spf1 ptr:otherdomain.com -all"

The "exists" mechanism

exists:<domain>

Perform an A query on the provided domain. If a result is found, this constitutes a match. It doesn't matter what the lookup result is – it could be 127.0.0.2.

When you use macros with this mechanism, you can perform RBL-style reversed-IP lookups, or set up per-user exceptions.

# In the following example, the client IP is 1.2.3.4 and the current-domain is example.com.
#
# If example.com does not resolve, the result is fail.  If it does resolve, this mechanism results in a match.
"v=spf1 exists:example.com -all"

The "include" mechanism

include:<domain>

The specified domain is searched for a match. If the lookup does not return a match or an error, processing proceeds to the next directive.

WARNING: If the domain does not have a valid SPF record, the result is a permanent error. Some mail receivers will reject based on a PermError.

# In the following example, the client IP is 1.2.3.4 and the current-domain is example.com.
 
# If example.com has no SPF record, the result is PermError.
# Suppose example.com's SPF record were "v=spf1 a -all".
# Look up the A record for example.com.  If it matches 1.2.3.4, return Pass.
# If there is no match, other than the included domain's "-all", the include as a whole fails to match; the eventual result is still Fail from the outer directive set in this example.
"v=spf1 include:example.com -all"

Trust relationships — The “include:” mechanism is meant to cross administrative boundaries. Great care is needed to ensure that “include:” mechanisms do not place domains at risk for giving SPF Pass results to messages that result from cross user forgery. Unless technical mechanisms are in place at the specified otherdomain to prevent cross user forgery, “include:” mechanisms should give a Neutral rather than Pass result. This is done by adding “?” in front of “include:”. The example above would be:

"v=spf1 ?include:example.com -all"

In hindsight, the name “include” was poorly chosen. Only the evaluated result of the referenced SPF record is used, rather than acting as if the referenced SPF record was literally included in the first. For example, evaluating a “-all” directive in the referenced record does not terminate the overall processing and does not necessarily result in an overall Fail. (Better names for this mechanism would have been “if-pass”, “on-pass”, etc.)


Modifiers

Modifiers are optional.

A modifier may appear only once per record.

Unknown modifiers are ignored.

The "redirect" modifier

redirect=<domain>

The SPF record for domain replace the current record. The macro-expanded domain is also substituted for the current-domain in those look-ups.

# In the following example, the client IP is 1.2.3.4 and the current-domain is example.com.
# 
# If example.com has no SPF record, that is an error; the result is unknown.
# Suppose example.com's SPF record was "v=spf1 a -all".
# Look up the A record for example.com. If it matches 1.2.3.4, return Pass.
# If there is no match, the exec fails to match, and the -all value is used.
"v=spf1 redirect=example.com"

The "exp" modifier

exp=<domain>

If an SMTP receiver rejects a message, it can include an explanation. An SPF publisher can specify the explanation string that senders see. This way, an ISP can direct nonconforming users to a web page that provides further instructions about how to configure SASL.

The domain is expanded; a TXT lookup is performed. The result of the TXT query is then macro-expanded and shown to the sender. Other macros can be used to provide an customized explanation.

Example Records

If we pretend that mail from the host example.com can only come from the IPv4 address 1.2.3.4 we would create this record:

"v=spf1 ip4:1.2.3.4 -all"

This record lists a single IP-address, but CIDR-formatted ranges are also supported. The -all suffix means that any mail coming from different IP addresses should be treated as bogus/spoofed/droppable.

A more complex record, for the domain steve.org.uk, looks like this:

"v=spf1 a mx p4:5.42.134.35/27 ip6:2001:41c8:10b:102::/64 ip6:2001:41c8:10b:103::/64 -all"

That record shows that mail may come from a small IPv4 range, a pair of IPv6 ranges, and mail should also be accepted if it comes from the MX-host of the domain, along with the host having the IP address which matches the hostname (i.e. sharewiz.net).

Finally this record shows that mail can only be sent from hosts listed as the MX-machine(s) for the domain, but it is configured with a soft-fail, because the domain-owner isn't 100% sure that that is sufficient:

"v=spf1 mx ~all"

Checking SPF

To publish a policy you must merely define a TXT-record, in DNS, for the domain you're sending from.

To test that the policy is visible you can query that record, like so:

dig -t txt +short sharewiz.net

From a Windows machine use:

nslookup -type=txt sharewiz.net

returns:

Non-authoritative answer:
sharewiz.net    text =
 
        "v=spf1 a ip4:5.42.134.35 -all"

result:

"v=spf1 mx a ptr ip4:5.42.134.35/27 ip6:2001:41c8:10b:102::/64 ip6:2001:41c8:10b:103::/64 -all"

An SPF record may also include a “redirect” in the record, such as gmail's:

v=spf1 redirect=_spf.google.com

This tells the receiving server to check the SPF record of google.com instead of gmail.com.

An “include” in the record tells the receiving server to also consider the IP addresses listed in the SPF record of another domain to make a match for which servers can send email.

This is commonly set up with multi-domain organizations.

Those SPF records will be listed as such:

v=spf1 ip4:123.123.123.0/19 include:example.com include:other.com -all

Drawbacks of SPF

The single biggest problem with SPF is that testing records at SMTP-time can fail if your mail is handled via a forward.

There are several online sites which allow mail to be received at a vanity-domain, then redirected to the real location, such as iki.fi.

If these vanity-forwarders do not rewrite the sender-addresses, when forwarding the mail, then testing any SPF-policy present will fail, since the forwarding host will not be included as a valid-source of email for the sender's domain.


References

networking/dns/bind/spf_sender_policy_framework.txt · Last modified: 2020/07/15 10:30 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki