It’s very common for any organization’s first attempt at a DMARC record to get the syntax or content wrong in some respect. This post will share some of the missteps and oddities seen while reviewing a dataset of captured Domain Name System (DNS) queries provided by Farsight Security.

Listing of rejected DMARC records

Listing of rejected DMARC records

To be clear, all of the records or values discussed below were retrieved from lookups of what should be DMARC records, with names or labels of the form _dmarc.example.com.

Things That Aren’t DMARC Records

The most common values that are completely wrong aren’t even DMARC records – they are other types of records returned when a DMARC record is looked up. The typical reason for this is that a domain has published a wildcard record, whether they meant to or not.

  • SPF records, “v=spf1 ip4:200.6.YY.ZZZ +a +mx + ?all”
  • DKIM records, “v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADC…”
  • Google domain ownership verification, “google-site-verification=SsnIA89IMCk8T…”
  • Other similar schemes, “globalsign-domain-verification=S6CtPWZk…”, “MS=ms85739041”, “bio=4d31a43fab984…”, and “v=msv1 t=74B7935…”
  • Random blobs of Base64-encoded data, “hDw2p0AZ0IGPEM4YUHfnGeMB47s7m+m20RYezh0MeAxKLi8sgFjiKl3KWSyIG3Fl4e4xETpp+BR1pn4oYJTu5Q==”

To give an idea of the scale, just in the dataset provided there were 300,000 DMARC records that returned SPF record data. There could easily be millions of domains on the Internet publishing wildcard SPF records.

There are other interesting values to be found in wildcard records. They don’t match the volume mentioned above, but they include default values, error messages, and even some advertising.

  • *
  • *** No IN A records for this domain
  • “dont do this”
  • ERROR
  • Please contact your registration service provider if you believe the deactivation occurred in error or you have resolved the problem.
  • Records dynamically generated by dnspackage
  • Text
  • Text Information
  • This domain may be available. For information, contact xxx@yyy.zzz
  • This domain’s zone has been disabled

Another category includes cases where the domain owner – or their contractor – publishes their name as the wildcard record’s value.

  • Shannon Development Authority
  • Koninklijke Nederlandsche Voetbalbond
  • Red Cactus Design Limited
  • Dare Contract Service NZ
  • Computer Reseller News/Russian Edition
  • PC Magazine/Russian Edition
  • Entwickler, Admin, Techie? http://www.XXXXXXXX.com/jobs.php

Identifying the organization responsible for a domain in a TXT record at the domain level (e.g. as example.com, not _dmarc.example.com) was very likely a recommended practice in the early years of the DNS, but not doing so with a wildcard record.

Not Following Directions

There are cases where the instructions for setting up DMARC records, or perhaps DNS records in general, were not clear enough. Extra text, or parts of the instructions, can wind up in the DMARC record.

  • “For” “text” “record” “put:” “v=DMARC1; p=none; sp=none; rua=mailto:dmarc@XXXXXXXX.cf; ruf=mailto:dmarc@XXXXXXXX.cf; rf=afrf; pct=100; ri=14400″
  • “_dmarc.clementine.XXXXXXXX.fr descriptive text v=DMARC1; p=reject;…”
    • To be clear, neither the name of the DNS record nor the phrase “descriptive text” should have been included here.

Common Formatting Errors

The previous examples may have shown the danger of indiscriminately using wildcard DNS records, or of not carefully reading instructions. This section focuses on the most common syntax or formatting problems observed in DMARC records.

Basic DMARC Record Requirements

DMARC makes as few demands as possible to produce clear, understandable records. But there are a few areas where the requirements are non-negotiable, and these records didn’t meet them.

  • p=none; v=DMARC1; rua=mailto:mail@XXXXXXXX.com
    • The “v=DMARC1” tag must appear first in the record.
  • v=DMARC1; fo=1; p=none; rua=mailto:agg@XXXXXXXX.com
    • The “p=” policy tag must appear immediately following the “v=” tag.
  • v=dmarc1; P=Reject; rua=mailto:dmarc_agg_rep@XXXXXXXX.it
    • The string “DMARC” must always appear in capital letters.
Missing or Incorrect Characters

In many cases part of the record just didn’t make it – there may be a few missing characters, or an extra space in a place that invalidates a key part of the record. Some DMARC implementations may allow lower case characters when upper case is called for, or vice versa, but then treatment of the domain’s email may vary at different receivers for no readily apparently reason.

  • DMARC1;p=none;rua=mailto:dmarc@XXXXXXXX.com
    • The record must start with “v=DMARC1”.
  • v=DMARC1: p=none: rua=mailto: mail@XXXXXXXX.ru
    • Note the use of colons as separators, instead of semi-colons.
  • v=DMARC1 p=none pct=100 rua=mailto:admin@XXXXXXXX.es
    • This example completely lacks the required semi-colon separators between tag/value pairs.
  • v=DMARC; p=reject; rua=mailto:dmarc@XXXXXXXX.eu;
    • In this case the “v=DMARC” pair is missing the number 1.
Legal Constructs That Might Not Be Recognized

Not every implementation adheres rigidly to the specification. While these exceptions are very rare with DMARC there are some that you may want to avoid to ensure your policy is recognized properly.

  • V=DMARC1; P=Reject; rua=mailto:dmarc_agg_rep@XXXXXXXX.it
    • The string “DMARC” is the only portion of the DMARC policy record that is case-sensitive, but it is not uncommon for people reading the specification to miss this fact. For best results, keep everything but “DMARC” lower case.
  • v=DMARC1; p=none; rua= mailto:dmarc_feedback@XXXXXXXX.de
    • There is a space after “rua=” in this example. While legal, some DMARC record parsers might not handle it correctly.
Extra Characters and Bad Quoting

There are many examples where excess characters find their way into otherwise good DMARC records.

  • v=DMARC1; p=none; rua=mailto:5124fb09d2@rep.XXXXXXXX.com; ruf=mailto:5124fb09d2@for.XXXXXXXX.com; rf=afrf; pct=100;frf; pct=100;
    • This fragment is most likely the result of a cut and paste editing error, but the stray characters “frf;” will cause some DMARC implementations to reject the entire record.
  • v=DMARC1\\;p=none\\;pct=100\\;fo=1\\;ri=86400\\;rua=mailto:XXXX_rua@dm.YYYY.net
    • Some DNS servers require that the semi-colon character be escaped. At least one popular package uses the backslash (\) character for such escaping. Here the user has entered a few escape characters too many.
  • v=DMARC1/; p=none/; sp=none/; adkim=s/; rua=mailto:postmaster@XXXXXXXX.edu.co/;
    • Here the user has probably confused the forward slash (/) and backslash (\) characters.
  • \”v=DMARC1; p=none; sp=reject; rua=mailto:domainreg@XXXXXXXX.dk; rf=afrf; pct=100; ri=86400\”
    • In this example the domain owner has included quotation marks at the start and end of the record, and they have either escaped them or their DNS server has done so automatically.
  • \226\128\156v=DMARC1; p=none; pct=100; rua=mailto:postmaster@XXXXXXXX.com.br; aspf=r;\226\128\157
    • Here extra formatting characters were most likely pasted and converted to their decimal character code representations (“\226” etc).
  • “v=DMARC1;” “p=quarantine;” “pct=25;” “rua=mailto:postmaster@XXXXXXXX.com”
    • This represents two different conditions. In one case, the domain owner’s DNS server is returning a DMARC record with quotes around each key/value pair. This output can also be seen in cases where the domain owner’s DNS server is returning each key/value pair as a separate response record. Each of these is most likely due to an error in entering the DMARC record into the nameserver’s database.
Bad Record Contents

The majority of these cases occur when the value of the policy tag (p=) is incorrectly specified.

  • v=DMARC1; p=blocked; rua=mailto:dmarc_agg@auth.returnpath.net; …
    • DMARC’s policy or “p=” tag can only have three values: none, quarantine, or reject.
  • v=DMARC1; p=quarintine; pct=20; rua=mailto:serafin@XXXXXXXX.es;
  •  v=DMARC1; p=quarantaine; rua=mailto:dmarc@XXXXXXXX.nl;
    • A common problem is the spelling of the word quarantine.
  • v=DMARC1; p=monitor; pct=100; rua=mailto:dmarcloop@XXXXXXXX.com;
    • A “monitor” policy was used in early, pre-public drafts of the DMARC specification, but was changed to “none” before publication to more clearly reflect the action the domain owner was requesting. However articles and speakers referred to “p=none” as “monitoring mode,” and some early examples may have used the older terminology.
  • v=DMARC1; p=none; rua=reports@XXXXXXXX.com; ruf=reports@XXXXXXXX.com
    • DMARC requires that the addresses for reporting features be written as URIs, so this record should read “rua=mailto:reports@XXXXXXXX.com; ruf=mailto:reports@XXXXXXXX.com”

Everything seen above with the policy tag (“p=”) can be observed when the subdomain policy tag (“sp=”) is used.

Summary

The overwhelming number of incorrect DMARC records are due to wildcard DNS entries returning non-DMARC records, usually SPF records but sometimes DKIM keys or other data. This accounts for hundreds of thousands of bad records. The next category would be bad formatting of various kinds – wrong separators, escape or quote characters where they shouldn’t be, et cetera. Finally, it is very common for incorrect policy values to be given in otherwise valid DMARC records, the most common example being the use of “monitor” instead of “none”.

Note: Some clarifications were made to DMARC policy record requirements on September 8, 2016.