feat: add full Zonemaster stack with Docker and Spanish UI

- Clone all 5 Zonemaster component repos (LDNS, Engine, CLI, Backend, GUI)
- Dockerfile.backend: 8-stage multi-stage build LDNS→Engine→CLI→Backend
- Dockerfile.gui: Astro static build served via nginx
- docker-compose.yml: backend (internal) + frontend (port 5353)
- nginx.conf: root redirects to /es/, /api/ proxied to backend
- zonemaster-gui/config.ts: defaultLanguage set to 'es' (Spanish)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 08:19:24 +02:00
commit 8d4eaa1489
1567 changed files with 204155 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
# Zone Test Plan
These are tests of the zone content in DNS, such as SOA and MX records.
This document uses the terminology defined in the [Master Test Plan].
[Master Test Plan]: ../MasterTestPlan.md
[Test Case README]: ../README.md
<!-- Content until EOF generated by script updateTestPlanReadme.pl from Zonemaster/Zonemaster utils directory -->
## Test cases list
|Test Case |Test Case Description|
|:---------|:--------------------|
|[ZONE01](zone01.md)|Fully qualified master nameserver in SOA|
|[ZONE02](zone02.md)|SOA 'refresh' minimum value|
|[ZONE03](zone03.md)|SOA 'retry' lower than 'refresh'|
|[ZONE04](zone04.md)|SOA 'retry' at least 1 hour|
|[ZONE05](zone05.md)|SOA 'expire' minimum value|
|[ZONE06](zone06.md)|SOA 'minimum' maximum value|
|[ZONE07](zone07.md)|SOA master is not an alias|
|[ZONE08](zone08.md)|MX is not an alias|
|[ZONE09](zone09.md)|MX record present|
|[ZONE10](zone10.md)|No multiple SOA records|
|[ZONE11](zone11.md)|SPF policy validation|

View File

@@ -0,0 +1,269 @@
## ZONE01: Fully qualified master nameserver in SOA
### Test case identifier
**ZONE01** Fully qualified master nameserver in SOA
## Table of contents
* [Objective](#objective)
* [Scope](#scope)
* [Inputs](#inputs)
* [Summary](#summary)
* [Test procedure](#test-procedure)
* [Outcome(s)](#outcomes)
* [Special procedural requirements](#special-procedural-requirements)
* [Intercase dependencies](#intercase-dependencies)
* [Terminology](#terminology)
## Objective
The MNAME field from the SOA record of a zone is supposed to contain the master
name server for that zone. The hostname of the MNAME field may not be listed
in the NS records in the zone among the delegated name servers, but should
still be authoritative for the zone. MNAME may be used for other services
such as DNS NOTIFY described in [RFC1996].
[RFC1035], section 3.3.13, specifies that "the *domain-name* of the name server
that was the original or primary source of data for this zone".
[RFC1996], section 2, and [RFC2136], section 1, add that "the primary master is
named in the zone's SOA MNAME field and optionally by an NS RR.
There is by definition only one primary master server per zone".
[RFC2181], section 7.2, clarifies that "it is quite clear in the specifications,
yet seems to have been widely ignored, that the MNAME field of the SOA record
should contain the name of the primary (master) server for the zone identified
by the SOA. It should not contain the name of the zone itself. That information
would be useless, as to discover it, one needs to start with the domain name of
the SOA record - that is the name of the zone".
There exists an unstandardized practice to set the SOA MNAME to ".", which
should not be interpreted that there is no primary master server, but to
indicate that there is no default server for dynamic updates. With ".", SOA
MNAME has no server name. There is at least one old and expired Internet-Draft
that attempted to standardize that behavior, [draft-jabley-dnsop-missing-mname].
If the SOA MNAME is an empty name (".") this Test Case will not try to connect
to a server behind it since there will never be a server behind that name, as
the purpose is most definitely to follow that practice. Instead, a special
message will be outputted.
The operational consequences of errors on SOA MNAME are, however, limited. It is
never used for finding authoritative name servers for the zone, and is not part
of normal lookup. Therefore, the level set by this test case on SOA MNAME errors
is not higher than NOTICE.
This Test Case will check that:
- the SOA MNAME contains the master name server of *Child Zone*,
as best as it can be determined.
- the SOA MNAME name server is authoritative of *Child Zone*.
- the SOA SERIAL of the SOA MNAME is at least equal to the ones found
from the name servers in the NS record set of *Child Zone*.
This comparison must be done following [RFC1982].
- the SOA MNAME name server is listed as part of the NS record set of *Child Zone*.
## Scope
It is assumed that *Child Zone* is tested and reported by [CONNECTIVITY01].
This Test Case will just ignore non-responsive name servers or name servers
not giving a correct DNS response for an authoritative name server, except
if the name server is listed in the SOA MNAME.
The syntax of the SOA MNAME for *Child Zone* is not tested in this Test
Case, see [SYNTAX07].
The consistency of the SOA MNAME between different servers of *Child Zone*
is not tested by this Test Case, see [CONSISTENCY06].
## Inputs
* "Child Zone" - The domain name to be tested.
## Summary
Message Tag | Level | Arguments | Message ID for message tag
:---------------------------- |:--------|:-------------------------------------|:---------------------------------------------------------------------------------------
Z01_MNAME_HAS_LOCALHOST_ADDR | NOTICE | nsname, ns_ip | SOA MNAME name server "{nsname}" resolves to a localhost IP address ({ns_ip}).
Z01_MNAME_IS_DOT | NOTICE | ns_ip_list | SOA MNAME is specified as "." which usually means "no server". Fetched from name servers "{ns_ip_list}".
Z01_MNAME_IS_LOCALHOST | NOTICE | ns_ip_list | SOA MNAME name server is "localhost", which is invalid. Fetched from name servers "{ns_ip_list}".
Z01_MNAME_IS_MASTER | DEBUG | ns_list | SOA MNAME name server(s) "{ns_list}" appears to be master.
Z01_MNAME_MISSING_SOA_RECORD | NOTICE | ns | SOA MNAME name server "{ns}" responds to an SOA query with no SOA records in the answer section.
Z01_MNAME_NO_RESPONSE | NOTICE | ns | SOA MNAME name server "{ns}" does not respond to an SOA query.
Z01_MNAME_NOT_AUTHORITATIVE | NOTICE | ns | SOA MNAME name server "{ns}" is not authoritative for the zone.
Z01_MNAME_NOT_IN_NS_LIST | INFO | nsname | SOA MNAME name server "{nsname}" is not listed as NS record for the zone.
Z01_MNAME_NOT_MASTER | NOTICE | ns_list, soaserial, soaserial_list | SOA MNAME name server(s) "{ns_list}" do(es) not have the highest SOA SERIAL (expected "{soaserial}" but got "{soaserial_list}")
Z01_MNAME_NOT_RESOLVE | NOTICE | nsname | SOA MNAME name server "{nsname}" cannot be resolved into an IP address.
Z01_MNAME_UNEXPECTED_RCODE | NOTICE | ns, rcode | SOA MNAME name server "{ns}" gives unexpected RCODE name ("{rcode}") in response to an SOA query.
The value in the Level column is the default severity level of the message. The
severity level can be changed in the [Zonemaster-Engine profile]. Also see the
[Severity Level Definitions] document.
The argument names in the Arguments column lists the arguments used in the
message. The argument names are defined in the [argument list].
## Test procedure
In this section and unless otherwise specified below, the terms "[DNS Query]"
follow the specification for DNS queries as specified in [DNS Query and Response Defaults].
The handling of the DNS responses on the DNS queries follow, unless otherwise
specified below, what is specified for [DNS Response] in the same specification.
1. Create a [DNS Query] with query type SOA and query name *Child Zone* ("SOA Query").
2. Create the following empty sets:
1. Name server SOA MNAME name, SOA MNAME IP address(es), SOA SERIAL(s) ("MNAME Nameservers")
2. Name server SOA SERIAL ("SERIAL Nameservers")
3. Name server SOA MNAME name, SOA MNAME IP address, SOA SERIAL ("MNAME Not Master")
4. Name server SOA MNAME name, SOA MNAME IP address ("MNAME Is Master")
5. Name server IP address ("MNAME Is Localhost")
6. Name server IP address ("MNAME Is Dot")
3. Obtain the set of name server IP addresses using
[Method4] and [Method5] ("Name Server IP").
4. For each name server IP address in *Name Server IP* do:
1. Send *SOA Query* to the name server IP and collect the response.
2. Go to next name server IP address if at least one of
the following criteria is met:
1. There is no DNS response.
2. [RCODE Name] of the response is not "NoError".
3. The AA flag is not set in the response.
4. There is no SOA record with owner name matching the query.
3. From the DNS response, extract the name server name from the SOA MNAME field:
1. If the name is "localhost", then add name server IP address to
the *MNAME Is Localhost* set.
2. Else if the name is ".", then add name server IP address to
the *MNAME Is Dot* set.
3. Else, add SOA MNAME name server name to the *MNAME Nameservers* set.
4. From the SOA record in the DNS response, extract the value from the SOA SERIAL
field and add it to the *SERIAL Nameservers* set.
5. Go to next name server IP address.
5. If the set *MNAME Is Localhost* is non-empty, then output
*[Z01_MNAME_IS_LOCALHOST]* with name server(s) IP address(es).
6. If the set *MNAME Is Dot* is non-empty, then output
*[Z01_MNAME_IS_DOT]* with name server(s) IP address(es).
7. If the set *MNAME Nameservers* is empty, then terminate these procedures.
8. Obtain the set of name server names using [Method3] ("Child Nameservers").
9. For each SOA MNAME name server name in *MNAME Nameservers* do:
1. If the SOA MNAME name server name is not part of the
*Child Nameservers* set, then output *[Z01_MNAME_NOT_IN_NS_LIST]* with
SOA MNAME name server name.
2. Do a [DNS Lookup] of SOA MNAME name server name (A and AAAA) and add the
SOA MNAME name server IP address(es) found to the *MNAME Nameservers* set
for the same entry as the SOA MNAME name server name.
3. If at least one IP address from the previous step was found, then:
1. For each SOA MNAME name server IP address for the SOA MNAME name server name do:
1. If the IP address is a localhost address (127.0.0.1 or ::1), then output
*[Z01_MNAME_HAS_LOCALHOST_ADDR]* with SOA MNAME name server name and IP.
2. Else, send *SOA Query* to the name server IP and collect the response.
1. If there is a DNS response, with [RCODE Name] "NoError" and
an SOA record in the answer section, then:
1. If the AA flag is not set, then output *[Z01_MNAME_NOT_AUTHORITATIVE]*
with SOA MNAME name server name and IP address.
2. Else, add the SOA SERIAL value to the *MNAME Nameservers* set
for the SOA MNAME name server name and IP pair.
2. Else if [RCODE Name] is not "NoError", then output
*[Z01_MNAME_UNEXPECTED_RCODE]* with [RCODE Name], SOA MNAME name server
name and IP address.
3. Else if there is no SOA record in the answer section, then output
*[Z01_MNAME_MISSING_SOA_RECORD]* with SOA MNAME name server
name and IP address.
4. Else, output *[Z01_MNAME_NO_RESPONSE]* with SOA MNAME name server
name and IP address.
3. Go to next SOA MNAME name server IP.
4. Else, output *[Z01_MNAME_NOT_RESOLVE]* with SOA MNAME name server name.
5. Go to next SOA MNAME name server name.
10. If there is no SOA SERIAL in the *MNAME Nameservers* set, then
terminate these procedures.
11. For each SOA SERIAL (per SOA MNAME name server name and IP address pair)
in *MNAME Nameservers* do:
1. For each SOA SERIAL in *SERIAL Nameservers* do:
1. Compare both SOA SERIAL values (using the arithmetic in [RFC1982]).
2. If the one from *SERIAL Nameservers* is higher, then add SOA MNAME name
server name, IP address and SOA SERIAL of the current SOA SERIAL value from
the *MNAME Nameservers* set to the *MNAME Not Master* set, and go
to next SOA SERIAL (from the *MNAME Nameservers* set).
2. Add SOA MNAME name server name and IP address to the *MNAME Is Master* set.
12. If the set *MNAME Not Master* is non-empty, then output *[Z01_MNAME_NOT_MASTER]*
with SOA MNAME name server name(s), IP address(es) and SOA SERIAL from the set,
along with the SOA SERIAL values from the *SERIAL Nameservers* set.
13. If the set *MNAME Is Master* is non-empty, then output *[Z01_MNAME_IS_MASTER]*
with SOA MNAME name server name(s) and IP address(es) from the set.
## Outcome(s)
The outcome of this Test Case is "fail" if there is at least one message
with the severity level *[ERROR]* or *[CRITICAL]*.
The outcome of this Test Case is "warning" if there is at least one message
with the severity level *[WARNING]*, but no message with severity level
*ERROR* or *CRITICAL*.
In other cases, no message or only messages with severity level
*[INFO]* or *[NOTICE]*, the outcome of this Test Case is "pass".
## Special procedural requirements
If either IPv4 or IPv6 transport is disabled, skip sending queries over that
transport protocol. A message will be outputted reporting that the transport
protocol has been skipped.
## Intercase dependencies
None.
## Terminology
* "DNS Lookup" - The term is used when a recursive lookup is used, though
any changes to the DNS tree introduced by an [undelegated test] must be
respected.
[Argument list]: ../ArgumentsForTestCaseMessages.md
[CONNECTIVITY01]: ../Connectivity-TP/connectivity01.md
[CONSISTENCY06]: ../Consistency-TP/consistency06.md
[CRITICAL]: ../SeverityLevelDefinitions.md#critical
[DNS Lookup]: #terminology
[DNS Query and Response Defaults]: ../DNSQueryAndResponseDefaults.md
[DNS Query]: ../DNSQueryAndResponseDefaults.md#default-setting-in-dns-query
[DNS Response]: ../DNSQueryAndResponseDefaults.md#default-handling-of-a-dns-response
[draft-jabley-dnsop-missing-mname]: https://www.ietf.org/archive/id/draft-jabley-dnsop-missing-mname-00.html
[ERROR]: ../SeverityLevelDefinitions.md#error
[INFO]: ../SeverityLevelDefinitions.md#info
[Message Tag Specification]: MessageTagSpecification.md
[Methods]: ../Methods.md
[Method3]: ../Methods.md#method-3-obtain-name-servers-from-child
[Method4]: ../Methods.md#method-4-obtain-glue-address-records-from-parent
[Method5]: ../Methods.md#method-5-obtain-the-name-server-address-records-from-child
[NOTICE]: ../SeverityLevelDefinitions.md#notice
[RCODE Name]: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
[RFC1035]: https://datatracker.ietf.org/doc/html/rfc1035#section-3.3.13
[RFC1982]: https://datatracker.ietf.org/doc/html/rfc1982
[RFC1996]: https://datatracker.ietf.org/doc/html/rfc1996#section-2
[RFC2136]: https://datatracker.ietf.org/doc/html/rfc2136#section-1
[RFC2181]: https://datatracker.ietf.org/doc/html/rfc2181#section-7.3
[Severity Level Definitions]: ../SeverityLevelDefinitions.md
[SYNTAX07]: ../Syntax-TP/syntax07.md
[Test Case Identifier Specification]: TestCaseIdentifierSpecification.md
[Undelegated test]: ../../test-types/undelegated-test.md
[WARNING]: ../SeverityLevelDefinitions.md#warning
[Zonemaster-Engine profile]: ../../../configuration/profiles.md
[Z01_MNAME_HAS_LOCALHOST_ADDR]: #summary
[Z01_MNAME_IS_DOT]: #summary
[Z01_MNAME_IS_LOCALHOST]: #summary
[Z01_MNAME_IS_MASTER]: #summary
[Z01_MNAME_MISSING_SOA_RECORD]: #summary
[Z01_MNAME_NO_RESPONSE]: #summary
[Z01_MNAME_NOT_AUTHORITATIVE]: #summary
[Z01_MNAME_NOT_IN_NS_LIST]: #summary
[Z01_MNAME_NOT_MASTER]: #summary
[Z01_MNAME_NOT_RESOLVE]: #summary
[Z01_MNAME_UNEXPECTED_RCODE]: #summary

View File

@@ -0,0 +1,47 @@
## ZONE02: SOA 'refresh' minimum value
### Test case identifier
**ZONE02** SOA 'refresh' minimum value
### Objective
The SOA refresh value is the number of seconds that describes
how often a secondary name server will poll the primary name server
to see if there is any updates. The SOA refresh value is described
in section 3.3.13 in [RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035),
and clarified in section 2.2 of
[RFC 1912](https://datatracker.ietf.org/doc/html/rfc1912).
Setting the refresh value low will increase the DNS traffic between
the servers, and also increase the load on the master name server.
The primary name server will in most cases send DNS notifications to
tell the secondary name servers that zone content has been updated,
as described in [RFC 1996](https://datatracker.ietf.org/doc/html/rfc1996).
The [RIPE-203](https://www.ripe.net/publications/docs/ripe-203) recommendation
for the refresh value is 24 hours (86400 seconds). Older DNSCheck code
had a four hour minimum value, and this is the minimum value we
recommend.
### Inputs
The domain name to be tested.
### Ordered description of steps to be taken to execute the test case
1. Retrieve the SOA record from a delegated name server for the domain.
2. If the answer from step 1 is not authoritative, iterate step 1 until there is an authoritative answer.
3. Retrieve the refresh value from the SOA record.
4. If the refresh value is less than 14400 (four hours in seconds)
this test case fails.
### Outcome(s)
If the SOA refresh value is less than 14400 this test case fails.
### Special procedural requirements
None.
### Intercase dependencies
None.

View File

@@ -0,0 +1,43 @@
## ZONE03: SOA 'retry' lower than 'refresh'
### Test case identifier
**ZONE03** SOA 'retry' lower than 'refresh'
### Objective
The SOA retry value is the number of seconds that describes
minimum time elapsed since a failed zone refresh from the primary
name server. The SOA refresh value is described
in section 3.3.13 in [RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035),
and clarified in section 2.2 of
[RFC 1912](https://datatracker.ietf.org/doc/html/rfc1912).
> It's typically some fraction of the refresh interval.
Setting the retry value low will increase the DNS traffic between
the servers, and also increase the load on the master name server.
### Inputs
The domain name to be tested.
### Ordered description of steps to be taken to execute the test case
1. Retrieve the SOA record from a delegated name server for the domain.
2. If the answer from step 1 is not authoritative, iterate step 1 until there is an authoritative answer.
3. Retrieve the retry value from the SOA record.
4. If the retry value is higher than or equal to the refresh value,
this test case fails.
### Outcome(s)
If the SOA retry value is higher than or equal to the refresh value,
this test case fails.
### Special procedural requirements
None.
### Intercase dependencies
None.

View File

@@ -0,0 +1,44 @@
## ZONE04: SOA 'retry' at least 1 hour
### Test case identifier
**ZONE04** SOA 'retry' at least 1 hour
### Objective
The SOA retry value is the number of seconds that describes
minimum time elapsed since a failed zone refresh from the primary
name server. The SOA refresh value is described
in section 3.3.13 in [RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035),
and clarified in section 2.2 of
[RFC 1912](https://datatracker.ietf.org/doc/html/rfc1912).
Setting the retry value low will increase the DNS traffic between
the servers, and also increase the load on the master name server.
The [RIPE-203](https://www.ripe.net/publications/docs/ripe-203) recommendation
for the retry value is 2 hours (7200 seconds). Older DNSCheck code
had a one hour minimum value (3600 seconds), and this is the minimum
value we recommend.
### Inputs
The domain name to be tested.
### Ordered description of steps to be taken to execute the test case
1. Retrieve the SOA record from a delegated name server for the domain.
2. If the answer from step 1 is not authoritative, iterate step 1 until there is an authoritative answer.
3. Retrieve the retry value from the SOA record.
4. If the retry value is less than 3600 seconds, this test case fails.
### Outcome(s)
If the retry value is less than 3600 seconds, this test case fails.
### Special procedural requirements
None.
### Intercase dependencies
None.

View File

@@ -0,0 +1,50 @@
## ZONE05: SOA 'expire' minimum value
### Test case identifier
**ZONE05** SOA 'expire' minimum value
### Objective
The SOA expire value specifies for how long any secondary name server
keeps the zone valid without any contact with the primary name server.
This value should be greater than how long a major outage would
typically last. The expire value should also be larger than the
refresh and retry values, as described in section 3.3.13 in
[RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035), and clarified in
section 2.2 of [RFC 1912](https://datatracker.ietf.org/doc/html/rfc1912).
Setting the expire value low will increase the risk of any unwanted
non-availability of the zone because of any failures in contacting
the primary name server.
The [RIPE-203](https://www.ripe.net/publications/docs/ripe-203) recommendation
for the expire value is 1000 hours (roughly 41 days). Older DNSCheck code
had a 7 day minimum value (604800 seconds), and this is the minimum
value we recommend as an absolute minimum.
### Inputs
The domain name to be tested.
### Ordered description of steps to be taken to execute the test case
1. Retrieve the SOA record from a delegated name server for the domain.
2. If the answer from step 1 is not authoritative, iterate step 1 until there is an authoritative answer.
3. Retrieve the expire value and the refresh value from the SOA record.
4. If the expire value is less than 604800 seconds (7 days), this test
case fails.
5. If the expire value is lower than the refresh value, this test case
fails.
### Outcome(s)
If the expire value is less than 604800 seconds or if the expire value is
lower than the refresh value, this test case fails.
### Special procedural requirements
None.
### Intercase dependencies
None.

View File

@@ -0,0 +1,59 @@
## ZONE06: SOA 'minimum' maximum value
### Test case identifier
**ZONE06** SOA 'minimum' maximum value
### Objective
The SOA minimum field sets the default TTL for all records in a zone.
The recommended value is to be "cache-friendly". However, for a zone
that changes content often, there is a need to keep the TTL values
shorter. The use of the SOA minimum value today is the negative cache
(where a resolver find content is missing).
The SOA minimum field is described in section 3.3.13 in
[RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035), and clarified in
section 2.2 of [RFC 1912](https://datatracker.ietf.org/doc/html/rfc1912).
The description of the implementation of negative caching is in
[RFC 2308](https://datatracker.ietf.org/doc/html/rfc2308) (although it has been
updated by several DNSSEC related RFCs, it is still relevant for this
purpose).
The [RIPE-203](https://www.ripe.net/publications/docs/ripe-203) recommendation
for the minimum value 2 days, but the negative caching is now the norm.
DNSCheck has a recommended value of between 300 seconds (5 minutes) and
86400 seconds (1 day).
### Inputs
The domain name to be tested.
### Ordered description of steps to be taken to execute the test case
1. Obtain a set of name server IP addresses using [Method4] and [Method5].
2. Create a SOA query for the zone.
3. Send the SOA query over UDP to each name server IP address until
a response is received or until the set is exhausted.
4. If the answer from step 3 is not authoritative, iterate step 3 until there is an authoritative answer.
5. Retrieve the SOA minimum value from the SOA record.
6. If the minimum value is larger than 86400 seconds (1 day), this test
case fails.
7. If the minimum value is lower than 300 seconds (5 minutes), this test case
fails.
### Outcome(s)
If the minimum value is larger than 86400 seconds or if the minimum value is
lower than 300 seconds, this test case fails.
### Special procedural requirements
None.
### Intercase dependencies
None.
-------
[Method4]: ../Methods.md#method-4-obtain-glue-address-records-from-parent
[Method5]: ../Methods.md#method-5-obtain-the-name-server-address-records-from-child

View File

@@ -0,0 +1,46 @@
## ZONE07: SOA master is not an alias
### Test case identifier
**ZONE07** SOA master is not an alias
### Objective
Any NS type record should not be a CNAME. The SOA MNAME should in this
respect not be a CNAME.
Quote from 2.4 in [RFC 1912](https://datatracker.ietf.org/doc/html/rfc1912):
> Having NS records pointing to a CNAME is bad and may conflict badly
> with current BIND servers.
The SOA MNAME field is described in section 3.3.13 in
[RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035).
The [RIPE-203](https://www.ripe.net/publications/docs/ripe-203) recommendation
for the minimum value 2 days, but the negative caching is now the norm.
DNSCheck has a recommended value of between 300 seconds (5 minutes) and
86400 seconds (1 day).
### Inputs
The domain name to be tested.
### Ordered description of steps to be taken to execute the test case
1. Retrieve the SOA record from a delegated name server for the domain.
2. If the answer from step 1 is not authoritative, iterate step 1 until there is an authoritative answer.
3. Retrieve the SOA MNAME value from the SOA record.
4. Query for A and AAAA records for the host from MNAME.
5. If the answer to the query is a CNAME, this test case fails.
### Outcome(s)
If the SOA MNAME field is pointing to a CNAME, this test case fails.
### Special procedural requirements
None.
### Intercase dependencies
None.

View File

@@ -0,0 +1,34 @@
## ZONE08: MX is not an alias
### Test case identifier
**ZONE08** MX is not an alias
### Objective
An MX type record for a domain must not resolve to a CNAME, following
the text in section 10.3 of [RFC 2181](https://datatracker.ietf.org/doc/html/rfc2181)
and section 2.3.5 in
[RFC 5321](https://datatracker.ietf.org/doc/html/rfc5321#section-2.3.5).
### Inputs
The domain name to be tested.
### Ordered description of steps to be taken to execute the test case
1. Query the MX record from a delegated name server for the domain.
2. If the answer from step 1 is not authoritative, iterate step 1 until there is an authoritative answer.
3. If the MX answer is a CNAME, this test case fails.
### Outcome(s)
If the MX record for the domain is pointing to a CNAME, this test case
fails.
### Special procedural requirements
None.
### Intercase dependencies
None.

View File

@@ -0,0 +1,302 @@
# ZONE09: MX record present
## Test case identifier
**ZONE09**
## Table of contents
* [Objective](#objective)
* [Scope](#scope)
* [Inputs](#inputs)
* [Summary](#summary)
* [Test procedure](#test-procedure)
* [Outcome(s)](#outcomes)
* [Special procedural requirements](#special-procedural-requirements)
* [Intercase dependencies](#intercase-dependencies)
* [Terminology](#terminology)
## Objective
It is strongly recommended in [RFC 2142][RFC 2142#section-7],
section 7, that every domain should have a mailbox named
HOSTMASTER@domain (where "domain" is *Child Zone* in this test case).
> For simplicity and regularity, it is strongly recommended that the
> well known mailbox name HOSTMASTER always be used
> \<HOSTMASTER@domain\>.
This test case therefore expects for every domain (zone), excluding some cases
described below, to publish an MX record in apex of the zone (i.e. in the same
node as the SOA record).
If MX is not present, SMTP *can* deliver email using an address record (A or
AAAA) as specified in [RFC 5321][RFC 5321#section-5.1], section 5.1, but that
possibility is not in common use. This test case only checks for MX record and
ignores the possibility to use address records for email.
Even if not mentioned in [RFC 2142], there are some exceptions to the
rule to include MX and mail target for a domain.
The purpose of a zone in the .ARPA tree is to hold infrastructural identifiers,
and it is not expected that such a zone name is used as [Email Domain]
([RFC 3172]). This also means that the well known mailbox is not expected for
reverse zones (zone under in-addr.arpa or ip6.arpa). Such zone are therefore
excluded by this test case from the requirement of MX in the apex.
The root zone cannot be an [Email Domain] since the email domain is
the part to the left of the trailing dot, and the root zone owner name has
nothing left of the trailing dot. The root zone is excluded by this test case from
the requirement of MX in the apex.
Top-level domains ([TLDs][TLD]) can technically function as
[Email Domains][Email Domain] ([RCF 5321][RFC 5321#section-2.3.5], section 2.3.5)
but they rarely have that function and are probably not meant to be included in
the specification in [RFC 2142]. [Internet Architecture Board]
concludes in a report "[Dotless Domains Considered Harmful][IAB Statement]" that
domain names that only consists of one label, e.g. "se", "fr" or "com", should
not be used for various Internet services. This means [TLD] names should not be
used as [Email Domains][Email Domain]. In this test case [TLDs][TLD] are not only
excluded from the requirement of being an [Email Domain], if found to be, a
message will be generated that points that out.
[RFC 7505] standardizes "[Null MX]" which means that there is no email service
for the domain. A "[Null MX]" is accepted for any type of domain.
[RFC 7505][RFC 7505#section-3], section 3, also specifies that the "[Null MX]"
must be the sole MX record and its preference must be zero.
In this test case, the following zone types are excluded from the requirement of
MX:
* Root zone
* [TLD] zone
* Zone in the .ARPA tree
The following zone type is expected not to have any MX (considered harmful,
see [IAB Statement]):
* [TLD] zone
## Scope
It is assumed that *Child Zone* is tested and reported by [Connectivity01]. This test
case will just ignore non-responsive name servers or name servers not giving a
correct DNS response for an authoritative name server.
## Inputs
* "Child Zone" - The domain name to be tested.
## Summary
* A notify is issued if MX is missing, except for root, a zone in the ARPA tree
or a [TLD].
* A warning is issued if a [TLD] *has* a [non-Null MX][Null MX].
Message Tag | Level | Arguments | Message ID for message tag
:--------------------------|:------|:----------------------------|:--------------------------------------------
Z09_INCONSISTENT_MX |WARNING| | Some name servers return an MX RRset while others return none.
Z09_INCONSISTENT_MX_DATA |WARNING| | The MX RRset data is inconsistent between the name servers.
Z09_MISSING_MAIL_TARGET | NOTICE| | The child zone has no mail target (no MX).
Z09_MX_DATA | INFO | ns_ip_list, mailtarget_list | The mail targets in the MX RRset, "{mailtarget_list}", as returned by name servers "{ns_ip_list}".
Z09_MX_FOUND | INFO | ns_ip_list | MX RRset was returned by name servers "{ns_ip_list}".
Z09_NON_AUTH_MX_RESPONSE |WARNING| ns_ip_list | Non-authoritative response on MX query from name servers "{ns_ip_list}".
Z09_NO_MX_FOUND | INFO | ns_ip_list | No MX RRset was returned by name servers "{ns_ip_list}".
Z09_NO_RESPONSE_MX_QUERY |WARNING| ns_ip_list | No response on MX query from name servers "{ns_ip_list}".
Z09_NULL_MX_NON_ZERO_PREF | NOTICE| | The zone has a Null MX with non-zero preference.
Z09_NULL_MX_WITH_OTHER_MX |WARNING| | The zone has a Null MX mixed with other MX records.
Z09_ROOT_EMAIL_DOMAIN | NOTICE| | Root zone with an unexpected MX RRset (non-Null MX).
Z09_TLD_EMAIL_DOMAIN |WARNING| | The zone is a TLD and has an unexpected MX RRset (non-Null MX).
Z09_UNEXPECTED_RCODE_MX |WARNING | ns_ip_list, rcode | Unexpected RCODE value ({rcode}) in response to MX query. Responses from name servers "{ns_ip_list}".
The value in the Level column is the default severity level of the message. The
severity level can be changed in the [Zonemaster-Engine profile]. Also see the
[Severity Level Definitions] document.
The argument names in the Arguments column lists the arguments used in the
message. The argument names are defined in the [argument list].
## Test procedure
In this section and unless otherwise specified below, the terms "[DNS Query]"
follow the specification for DNS queries as specified in
[DNS Query and Response Defaults]. The handling of the DNS responses on the DNS
queries follow, unless otherwise specified below, what is specified for
[DNS Response] in the same specification.
1. Create a [DNS Query] with query type SOA and query name *Child Zone*
("SOA Query").
2. Create a [DNS Query] with query type MX and query name *Child Zone*
("MX Query").
3. Obtain the set of name server IP addresses using [Method4] and [Method5]
("Name Server IP").
4. Create the following empty sets
1. Name server IP address ("No Response MX Query").
2. Name server IP address and associated RCODE value
("Unexpected RCODE MX Response").
3. Name server IP address ("Non-authoritative MX").
4. Name server IP address ("No MX RRset").
5. Name server IP address and associated MX RRset ("MX RRset").
5. For each name server IP in *Name Server IP* do:
1. Send *SOA Query* over UDP to the name server.
2. Go to next name server IP if at least one of the following criteria is
met:
1. There is no DNS response.
2. The RCODE of the response is not "NoError" ([IANA RCODE List]).
3. The AA flag is not set in the response.
4. There is no SOA record with owner name matching the query.
2. Send *MX Query* over UDP to the name server and collect the
response, and:
1. If the response has the TC flag set, re-query over TCP and use that
response instead.
2. If there is no DNS response, then add the name server IP to the
*No Response MX Query* set.
3. Else, if the RCODE of response is not "NoError" ([IANA RCODE List]),
then add the name server IP and the RCODE to the
*Unexpected RCODE MX Response* set.
4. Else, if the AA flag is not set in the response, then add the name
server IP to the *Non-authoritative MX* set.
5. Else, if there is no MX record with matching owner name in the answer
section, then add the name server (IP) to the *No MX RRset* set.
6. Else do:
1. Extract the MX RRset from the response.
2. Add the name server IP and the MX RRset to the *MX RRset* set.
6. If the set *No Response MX Query* is non-empty, then output
*[Z09_NO_RESPONSE_MX_QUERY]* with the name server IP addresses from the set.
7. If the set *Unexpected RCODE MX Response* is non-empty, then for each RCODE
in the set, do:
* Output *[Z09_UNEXPECTED_RCODE_MX]* with the RCODE value
([IANA RCODE List]) and the name server IP addresses from the set.
8. If the set *Non-authoritative MX* is non-empty, then output
*[Z09_NON_AUTH_MX_RESPONSE]* with the name server IP addresses from
the set.
9. If both *No MX RRset* set and *MX RRset* set are non-empty then:
1. Output *[Z09_INCONSISTENT_MX]*.
2. Output *[Z09_NO_MX_FOUND]* with the name server IP addresses from the
*No MX RRset* set.
3. Output *[Z09_MX_FOUND]* with the name server IP addresses from the
*MX RRset* set.
10. If the *MX RRset* set is non-empty (the *No MX RRset* set is empty or
non-empty), then do:
1. If the RRsets in *MX RRset* are not equal for all name servers then do:
1. Output *[Z09_INCONSISTENT_MX_DATA]*.
2. For each RRset in *MX RRset*, output *[Z09_MX_DATA]* with the mail
targets from the RDATA and the associated name server IP addresses in
the set.
2. Else do:
1. If the mailtarget of any of the MX records in the RRset in *MX RRset*
is a [Null MX] then do:
1. If there are more than one record in the MX RRset, then output
*[Z09_NULL_MX_WITH_OTHER_MX]* with the mail targets from the RDATA
of MX records.
2. If the preference of the [Null MX] is non-zero then output
*[Z09_NULL_MX_NON_ZERO_PREF]*.
2. Else, if *Child Zone* is a [TLD] with a [non-Null MX][Null MX] then
output *[Z09_TLD_EMAIL_DOMAIN]*.
3. Else, if *Child Zone* is the root zone with a [non-Null MX][Null MX] then
output *[Z09_ROOT_EMAIL_DOMAIN]*.
4. Else, output *[Z09_MX_DATA]* with the mail targets from the RDATA and
the associated name server IP addresses in the set.
11. If the *No MX RRset* set is non-empty and the *MX RRset* set is empty, then
output *[Z09_MISSING_MAIL_TARGET]* unless
1. *Child Zone* is the root zone ("."), or
2. *Child Zone* is a [TLD], or
3. *Child Zone* is a zone in the .ARPA tree.
## Outcome(s)
The outcome of this Test Case is "fail" if there is at least one message
with the severity level *[ERROR]* or *[CRITICAL]*.
The outcome of this Test Case is "warning" if there is at least one message
with the severity level *[WARNING]*, but no message with severity level
*ERROR* or *CRITICAL*.
In other cases, no message or only messages with severity level
*[INFO]* or *[NOTICE]*, the outcome of this Test Case is "pass".
## Special procedural requirements
If either IPv4 or IPv6 transport is disabled, ignore the evaluation of the
result of any test using this transport protocol and log a message reporting
the ignored result.
## Intercase dependencies
None.
## Terminology
The term "Null MX" is used for an MX record where the mail target is "." as
defined in [RFC 7505] with the specific restrictions given in
[section 3][RFC 7505#section-3] of that RFC.
The term "TLD" is used for "Top Level Domain", i.e. a zone whose name consists
of a single label (ignoring the empty label after the final dot).
The term "Email Domain" is used for the domain name at right of the at-sign ("@")
in an email address.
[Argument list]: ../ArgumentsForTestCaseMessages.md
[Connectivity01]: ../Connectivity-TP/connectivity01.md
[CRITICAL]: ../SeverityLevelDefinitions.md#critical
[DNS Query and Response Defaults]: ../DNSQueryAndResponseDefaults.md
[DNS Query]: ../DNSQueryAndResponseDefaults.md#default-setting-in-dns-query
[DNS Response]: ../DNSQueryAndResponseDefaults.md#default-handling-of-a-dns-response
[ERROR]: ../SeverityLevelDefinitions.md#error
[Email Domain]: #terminology
[IAB Statement]: https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/
[IANA RCODE List]: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
[INFO]: ../SeverityLevelDefinitions.md#info
[Internet Architecture Board]: https://en.wikipedia.org/wiki/Internet_Architecture_Board
[Method4]: ../Methods.md#method-4-obtain-glue-address-records-from-parent
[Method5]: ../Methods.md#method-5-obtain-the-name-server-address-records-from-child
[NOTICE]: ../SeverityLevelDefinitions.md#notice
[Null MX]: #terminology
[RFC 2142#section-7]: https://datatracker.ietf.org/doc/html/rfc2142#section-7
[RFC 2142]: https://datatracker.ietf.org/doc/html/rfc2142
[RFC 3172]: https://datatracker.ietf.org/doc/html/rfc3172
[RFC 5321#section-2.3.5]: https://datatracker.ietf.org/doc/html/rfc5321#section-2.3.5
[RFC 5321#section-5.1]: https://datatracker.ietf.org/doc/html/rfc5321#section-5.1
[RFC 7505#section-3]: https://datatracker.ietf.org/doc/html/rfc7505#section-3
[RFC 7505]: https://datatracker.ietf.org/doc/html/rfc7505
[Severity Level Definitions]: ../SeverityLevelDefinitions.md
[TLD]: #terminology
[WARNING]: ../SeverityLevelDefinitions.md#warning
[Z09_INCONSISTENT_MX]: #summary
[Z09_INCONSISTENT_MX_DATA]: #summary
[Z09_MISSING_MAIL_TARGET]: #summary
[Z09_MX_DATA]: #summary
[Z09_MX_FOUND]: #summary
[Z09_NON_AUTH_MX_RESPONSE]: #summary
[Z09_NO_MX_FOUND]: #summary
[Z09_NO_RESPONSE_MX_QUERY]: #summary
[Z09_NULL_MX_NON_ZERO_PREF]: #summary
[Z09_NULL_MX_WITH_OTHER_MX]: #summary
[Z09_ROOT_EMAIL_DOMAIN]: #summary
[Z09_TLD_EMAIL_DOMAIN]: #summary
[Z09_UNEXPECTED_RCODE_MX]: #summary
[Zonemaster-Engine profile]: ../../../configuration/profiles.md

View File

@@ -0,0 +1,100 @@
# ZONE10: No multiple SOA records
## Test case identifier
**ZONE10**
## Objective
The SOA record is crucial for the DNS zone and "exactly one SOA RR should
be present at the top of the zone" ([RFC 1035][RFC 1035#5.2], section 5.2).
This test case will verify that the zone of the domain to be tested return
exactly one SOA record.
## Scope
It is assumed that *Child Zone* is also tested by [Connectivity01]. This test
case will set DEBUG level on messages for non-responsive name servers.
## Inputs
* "Child Zone" - The domain name to be tested.
## Ordered description of steps to be taken to execute the test case
1. Obtain the set of name server IP addresses using [Method4] and [Method5]
("NS IP").
2. Create a SOA query for the apex of the *Child Zone* with RD flag unset.
3. For each name server in *NS IP* do:
1. Send the SOA query over UDP to the name server.
2. If the name server does not respond with a DNS response, then
output *[NO_RESPONSE]*.
3. Else, if the DNS response does not include a SOA record in the
answer section, then output *[NO_SOA_IN_RESPONSE]*.
4. Else, if the SOA record or records in the answer section do not
have *Child Zone* as owner name, then output *[WRONG_SOA]*.
5. Else, if the DNS response includes multiple SOA records in the
answer section, then output *[MULTIPLE_SOA]*.
4. If no message is outputted for any server, then output *[ONE_SOA]*.
## Outcome(s)
The outcome of this Test Case is "fail" if there is at least one message
with the severity level *ERROR* or *CRITICAL*.
The outcome of this Test Case is "warning" if there is at least one message
with the severity level *WARNING*, but no message with severity level
*ERROR* or *CRITICAL*.
In other cases the outcome of this Test Case is "pass".
Message | Default severity level
:-----------------------------|:-----------------------------------
MULTIPLE_SOA | ERROR
NO_RESPONSE | DEBUG
NO_SOA_IN_RESPONSE | DEBUG
ONE_SOA | INFO
WRONG_SOA | DEBUG
## Special procedural requirements
If either IPv4 or IPv6 transport is disabled, ignore the evaluation of the
result of any test using this transport protocol. Log a message reporting
on the ignored result.
## Intercase dependencies
None.
## Terminology
When the term "using Method" is used, names and IP addresses are fetched
using the defined [Methods].
The term "send" (to an IP address) is used when a DNS query is sent to
a specific name server.
[Connectivity01]: ../Connectivity-TP/connectivity01.md
[MULTIPLE_SOA]: #outcomes
[Method4]: ../Methods.md#method-4-obtain-glue-address-records-from-parent
[Method5]: ../Methods.md#method-5-obtain-the-name-server-address-records-from-child
[Methods]: ../Methods.md
[NO_RESPONSE]: #outcomes
[NO_SOA_IN_RESPONSE]: #outcomes
[ONE_SOA]: #outcomes
[RFC 1035#5.2]: https://datatracker.ietf.org/doc/html/rfc1035#section-5.2
[WRONG_SOA]: #outcomes
[terminology]: #terminology

View File

@@ -0,0 +1,287 @@
# ZONE11: SPF policy validation
## Test case identifier
**ZONE11**
## Table of contents
* [Objective](#objective)
* [Scope](#scope)
* [Inputs](#inputs)
* [Summary](#summary)
* [Test procedure](#test-procedure)
* [Outcome(s)](#outcomes)
* [Special procedural requirements](#special-procedural-requirements)
* [Intercase dependencies](#intercase-dependencies)
* [Terminology](#terminology)
## Objective
Sender Policy Framework (SPF) version 1, defined in [RFC 7208], is a mechanism
allowing domain name owners to specify which hosts are allowed to send mail
claiming to be from that domain. It is implemented by means of TXT records in
a structured format.
This test case looks up SPF records in the apex of *Child Zone*. It checks
that there is at most one published SPF policy and, if present, also checks
its syntax.
The root zone ("."), [TLD] zones and zones under .ARPA are treated
differently. These zones are not expected to be used as [Email Domains][Email
Domain]. For these zones, this test case generates a message if an [non-null
SPF][Null SPF] policy is found.
The root zone cannot be an [Email Domain] because according to the syntax
rules in [RFC 5321, section 4.1.2][RFC 5321#4.1.2], it is not possible to
construct an email address having the root name (".") as domain part.
Although top-level domains ([TLDs][TLD]) can technically function as [Email
Domains][Email Domain] ([RFC 5321, section 2.3.5][RFC 5321#2.3.5]), they
usually do not have this purpose. The [Internet Architecture Board] concludes
in a report named "[Dotless Domains Considered Harmful]" that domain names
that only consists of one label, e.g. "se", "fr" or "com", should not be used
for various Internet services. This means [TLD] names should not be used as
[Email Domains][Email Domain].
As for .ARPA, [RFC 3172] states that "This domain is termed an 'infrastructure
domain', as its role is to support the operating infrastructure of the
Internet. In particular, the 'arpa' domain is not to be used in the same
manner (e.g., for naming hosts) as other generic Top Level Domains are
commonly used". This means any name under .ARPA should not be used as [Email
Domains][Email Domain].
## Scope
It is assumed that *Child Zone* has been tested and reported by
[Connectivity01]. This test case will just ignore non-responsive name servers
or name servers not giving a correct DNS response for an authoritative name
server.
## Inputs
* "Child Zone" - The domain name to be tested.
## Summary
Message Tag | Level | Arguments | Message ID for message tag
:--------------------------------|:--------|:----------------|:--------------------------------------------
Z11_DIFFERENT_SPF_POLICIES_FOUND | NOTICE | ns_list | The following name servers returned the same SPF policy. Name servers: {ns_list}.
Z11_INCONSISTENT_SPF_POLICIES | WARNING | | One or more name servers do not publish the same SPF policy as the others.
Z11_NO_SPF_FOUND | NOTICE | domain | No SPF policy was found for {domain}.
Z11_NO_SPF_NON_MAIL_DOMAIN | INFO | domain | No SPF policy was found for {domain}, which is a type of domain (root, TLD or under .ARPA) not expected to be used for email.
Z11_NON_NULL_SPF_NON_MAIL_DOMAIN | NOTICE | domain | A non-null SPF policy was found on {domain}, although this type of domain (root, TLD or under .ARPA) is not expected to be used for email.
Z11_NULL_SPF_NON_MAIL_DOMAIN | INFO | domain | A null SPF policy was found on {domain}, which is a type of domain (root, TLD or under .ARPA) not expected to be used for email.
Z11_SPF_MULTIPLE_RECORDS | WARNING | ns_list | The following name servers returned more than one SPF policy. Name servers: {ns_list}.
Z11_SPF_SYNTAX_ERROR | WARNING | domain, ns_list | The SPF policy of {domain} has a syntax error. Policy retrieved from the following nameservers: {ns_list}.
Z11_SPF_SYNTAX_OK | INFO | domain | The SPF policy of {domain} has correct syntax.
Z11_UNABLE_TO_CHECK_FOR_SPF | WARNING | | None of the zones name servers responded with an authoritative response to queries for SPF policies.
The value in the Level column is the default severity level of the message. The
severity level can be changed in the [Zonemaster-Engine profile]. Also see the
[Severity Level Definitions] document.
The argument names in the Arguments column lists the arguments used in the
message. The argument names are defined in the [argument list].
Name servers may have multiple IP addresses bound to the same name, and the
same IP address may be used by multiple name server names. Message tags whose
argument lists include "ns_list" shall contain all such name and IP address
pairs.
## Test procedure
In this section and unless otherwise specified below, the term "[DNS Query]"
follows the specification for DNS queries as specified in [DNS Query and
Response Defaults]. The handling of the DNS responses on the DNS queries follow,
unless otherwise specified below, what is specified for [DNS Response] in the
same specification.
1. Create a [DNS Query] with query type TXT and query name *Child Zone* ("TXT
query").
2. Create an empty set of pairs of (names and IP address) pairs and strings,
"SPF-Policies".
3. Retrieve all name server names and IP addresses for *Child Zone* using
methods [Get-Del-NS-Names-and-IPs] and [Get-Zone-NS-Names-and-IPs] ("Name
Servers").
4. For each distinct name server IP address in *Name Servers* do:
1. Send *TXT Query* to the name server and collect the [DNS Response].
2. Go to the next name server if at least one of the following criteria is
met:
1. There is no DNS response.
2. [RCODE Name] of the response is not "NoError".
3. The AA flag is not set in the response.
3. If the name server responds with no TXT record, then add the pair
consisting of the *Name Servers* and the empty string to the
*SPF-Policies* set.
4. If the name server responds with at least one TXT record and none is an
[SPF TXT record], then add the pair consisting of the *Name Servers*
and the empty string to the *SPF-Policies* set.
5. If the name server responds with at least one TXT record that is an [SPF
TXT record], then, for each [SPF TXT record] do:
1. [Concatenate] all strings in the RDATA field.
2. Lowercase the resulting string.
3. Add a pair consisting of the *Name Servers* and the lowercase
string thus derived from the RDATA field to the *SPF-Policies* set.
6. Go to the next name server.
5. If the *SPF-Policies* set is empty, then output
*[Z11_UNABLE_TO_CHECK_FOR_SPF]* and terminate the test.
6. If all the name server IPs in the *SPF-Policies* set contain empty strings
(no "SPF policy"), then:
1. If the *Child Zone* is the root zone ("."), a [TLD] or a zone under
.ARPA, then output *[Z11_NO_SPF_NON_MAIL_DOMAIN]* for *Child Zone* and
terminate the test.
2. Else, output *[Z11_NO_SPF_FOUND]* for *Child Zone* and terminate the
test.
7. For all messages outputted below, if an IP address in *Name Servers* is
connected to more than one name server name, then all names should be
included with the message tag.
8. Compare the set of *SPF-Policies* retrieved from all name servers (in the
*SPF-Policies* set). If at least two different name servers have returned
different sets of SPF policies, then:
1. Output *[Z11_INCONSISTENT_SPF_POLICIES]*.
2. Group *SPF-Policies* by equal sets of SPF policies, such that a set of
SPF policies is mapped to the list of *Name Servers* that returned it.
3. For each such group of name servers, output
*[Z11_DIFFERENT_SPF_POLICIES_FOUND]* with the set of name servers
("ns_list") in the group.
4. Terminate the test.
9. If the *SPF-Policies* set contains at least two entries with the same IP
address, then output *[Z11_SPF_MULTIPLE_RECORDS]* with the list of
name servers that returned more than one SPF policy and terminate the test.
10. The following steps assume that all name server IPs in the *SPF-Policies*
set have the same string ("SPF policy").
11. If the *SPF Policy* does not [pass the syntax check][passing the syntax
check] for SPF records, then output *[Z11_SPF_SYNTAX_ERROR]* for *Child
Zone* and the set of name servers from which the *SPF Policy* was
retrieved, and terminate the test.
12. If the *Child Zone* is the root zone ("."), a [TLD] or a zone under
.ARPA, then:
1. If the *SPF Policy* is a [Null SPF] policy, then output
*[Z11_NULL_SPF_NON_MAIL_DOMAIN]* for *Child Zone* and terminate the
test.
2. If the *SPF Policy* is not a [Null SPF] policy, then output
*[Z11_NON_NULL_SPF_NON_MAIL_DOMAIN]* for *Child Zone* and terminate the
test.
13. If no other message was outputted by this test case, then output
*[Z11_SPF_SYNTAX_OK]* for *Child Zone*.
## Outcome(s)
The outcome of this Test Case is "fail" if there is at least one message
with the severity level *[ERROR]* or *[CRITICAL]*.
The outcome of this Test Case is "warning" if there is at least one message
with the severity level *[WARNING]*, but no message with severity level
*ERROR* or *CRITICAL*.
In other cases, no message or only messages with severity level
*[INFO]* or *[NOTICE]*, the outcome of this Test Case is "pass".
## Special procedural requirements
If either IPv4 or IPv6 transport is disabled, skip sending queries over that
transport protocol. A message will be outputted reporting that the transport
protocol has been skipped.
## Intercase dependencies
None.
## Terminology
* "concatenate" - The term is used to refer to the conversion of a TXT
resource records data to a single contiguous string, as specified in [RFC
7208, section 3.3][RFC 7208#3.3].
* "Email Domain" - the domain name at the right of the at-sign ("@") in an
email address.
* "passing the syntax check" - The term is used in this document to refer to
text that is valid according to the ABNF grammar published in [RFC 7208]
starting from [section 4.5][RFC 7208#4.5]. Alternatively, the reader may use
an [online SPF syntax validator]; however, such online validators should not
be used as normative references.
* "Null SPF" - The term is used to refer to a SPF policy record which contains
a single term, `-all`. It designates no server as permitted sender and
evaluation of such an SPF policy is therefore guaranteed to return a failure.
* "SPF TXT record" - The term is used to refer to a TXT resource record which,
after [concatenating][concatenate] all strings within that resource record
into one string, yields a string either equal to `v=spf1` or starting with
`v=spf1` followed by a space, irrespective of character case.
* "TLD" - The term is used to refer to a "Top Level Domain", i.e. a zone whose
name consists of a single label (ignoring the empty label after the final
dot).
[Argument list]: ../ArgumentsForTestCaseMessages.md
[argument]: #terminology
[concatenate]: #terminology
[Connectivity01]: ../Connectivity-TP/connectivity01.md
[CRITICAL]: ../SeverityLevelDefinitions.md#critical
[DNS Query and Response Defaults]: ../DNSQueryAndResponseDefaults.md
[DNS Query]: ../DNSQueryAndResponseDefaults.md#default-setting-in-dns-query
[DNS Response]: ../DNSQueryAndResponseDefaults.md#default-handling-of-a-dns-response
[Dotless Domains Considered Harmful]: https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/
[Email Domain]: #terminology
[ERROR]: ../SeverityLevelDefinitions.md#error
[Get-Del-NS-Names-and-IPs]: ../MethodsV2.md#method-get-delegation-ns-names-and-ip-addresses
[Get-Zone-NS-Names-and-IPs]: ../MethodsV2.md#method-get-zone-ns-names-and-ip-addresses
[INFO]: ../SeverityLevelDefinitions.md#info
[Internet Architecture Board]: https://www.iab.org/
[Message Tag Specification]: MessageTagSpecification.md
[Null SPF]: #terminology
[NOTICE]: ../SeverityLevelDefinitions.md#notice
[online SPF syntax validator]: https://vamsoft.com/support/tools/spf-syntax-validator
[passing the syntax check]: #terminology
[RCODE Name]: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
[RFC 3172]: https://datatracker.ietf.org/doc/html/rfc3172
[RFC 5321#2.3.5]: https://datatracker.ietf.org/doc/html/rfc5321#section-2.3.5
[RFC 5321#4.1.2]: https://datatracker.ietf.org/doc/html/rfc5321#section-4.1.2
[RFC 7208#3.3]: https://www.rfc-editor.org/rfc/rfc7208#section-3.3
[RFC 7208#4.5]: https://www.rfc-editor.org/rfc/rfc7208#section-4.5
[RFC 7208]: https://www.rfc-editor.org/rfc/rfc7208
[Severity Level Definitions]: ../SeverityLevelDefinitions.md
[SPF TXT record]: #terminology
[Test Case Identifier Specification]: TestCaseIdentifierSpecification.md
[TLD]: #terminology
[Undelegated test]: ../../test-types/undelegated-test.md
[WARNING]: ../SeverityLevelDefinitions.md#warning
[Z11_DIFFERENT_SPF_POLICIES_FOUND]: #summary
[Z11_INCONSISTENT_SPF_POLICIES]: #summary
[Z11_NO_SPF_FOUND]: #summary
[Z11_NO_SPF_NON_MAIL_DOMAIN]: #summary
[Z11_NON_NULL_SPF_NON_MAIL_DOMAIN]: #summary
[Z11_NULL_SPF_NON_MAIL_DOMAIN]: #summary
[Z11_SPF_MULTIPLE_RECORDS]: #summary
[Z11_SPF_SYNTAX_ERROR]: #summary
[Z11_SPF_SYNTAX_OK]: #summary
[Z11_UNABLE_TO_CHECK_FOR_SPF]: #summary
[Zone09 test specification]: zone09.md
[Zonemaster-Engine profile]: ../../../configuration/profiles.md