when suggesting DNS records, leave "IN" out

people will either paste the records in their zone file. in that case, the
records will inherit "IN" from earlier records, and there will always be one
record. if anyone uses a different class, their smart enough to know they need
to add IN manually.

plenty of people will add their records through some clunky web interface of
their dns operator. they probably won't even have the choice to set the class,
it'll always be IN.
This commit is contained in:
Mechiel Lukkien 2023-10-13 08:16:46 +02:00
parent 52e71167a9
commit 850f4444d4
No known key found for this signature in database
9 changed files with 52 additions and 52 deletions

2
doc.go
View file

@ -660,7 +660,7 @@ Common DANE TLSA record parameters are: dane-ee spki sha2-256, or 3 1 1,
followed by a sha2-256 hash of the DER-encoded "SPKI" (subject public key info)
from the certificate. An example DNS zone file entry:
_25._tcp.example.com. IN TLSA 3 1 1 133b919c9d65d8b1488157315327334ead8d83372db57465ecabf53ee5748aee
_25._tcp.example.com. TLSA 3 1 1 133b919c9d65d8b1488157315327334ead8d83372db57465ecabf53ee5748aee
The first usable information from the pem file is used to compose the TLSA
record. In case of selector "cert", a certificate is required. Otherwise the

View file

@ -133,7 +133,7 @@ func autoconfHandle(w http.ResponseWriter, r *http.Request) {
}
// Autodiscover from Microsoft, also used by Thunderbird.
// User should create a DNS record: _autodiscover._tcp.<domain> IN SRV 0 0 443 <hostname or autodiscover.<domain>>
// User should create a DNS record: _autodiscover._tcp.<domain> SRV 0 0 443 <hostname>
//
// In practice, autodiscover does not seem to work wit microsoft clients. A
// connectivity test tool for outlook is available on

View file

@ -1809,7 +1809,7 @@ Common DANE TLSA record parameters are: dane-ee spki sha2-256, or 3 1 1,
followed by a sha2-256 hash of the DER-encoded "SPKI" (subject public key info)
from the certificate. An example DNS zone file entry:
_25._tcp.example.com. IN TLSA 3 1 1 133b919c9d65d8b1488157315327334ead8d83372db57465ecabf53ee5748aee
_25._tcp.example.com. TLSA 3 1 1 133b919c9d65d8b1488157315327334ead8d83372db57465ecabf53ee5748aee
The first usable information from the pem file is used to compose the TLSA
record. In case of selector "cert", a certificate is required. Otherwise the
@ -2131,7 +2131,7 @@ The DNS should be configured as a TXT record at $selector._domainkey.$domain.
record, err := r.Record()
xcheckf(err, "making record")
fmt.Print("<selector>._domainkey.<your.domain.> IN TXT ")
fmt.Print("<selector>._domainkey.<your.domain.> TXT ")
for record != "" {
s := record
if len(s) > 255 {

View file

@ -495,9 +495,9 @@ func DomainRecords(domConf config.Domain, domain dns.Domain, hasDNSSEC bool) ([]
}
var s string
if hasDNSSEC {
s = fmt.Sprintf("_25._tcp.%-*s IN TLSA %s", 20+len(d)-len("_25._tcp."), h+".", tlsaRecord.Record())
s = fmt.Sprintf("_25._tcp.%-*s TLSA %s", 20+len(d)-len("_25._tcp."), h+".", tlsaRecord.Record())
} else {
s = fmt.Sprintf(";; _25._tcp.%-*s IN TLSA %s", 20+len(d)-len(";; _25._tcp."), h+".", tlsaRecord.Record())
s = fmt.Sprintf(";; _25._tcp.%-*s TLSA %s", 20+len(d)-len(";; _25._tcp."), h+".", tlsaRecord.Record())
}
records = append(records, s)
return nil
@ -518,7 +518,7 @@ func DomainRecords(domConf config.Domain, domain dns.Domain, hasDNSSEC bool) ([]
if d != h {
records = append(records,
"; For the machine, only needs to be created once, for the first domain added.",
fmt.Sprintf(`%-*s IN TXT "v=spf1 a -all"`, 20+len(d), h+"."), // ../rfc/7208:2263 ../rfc/7208:2287
fmt.Sprintf(`%-*s TXT "v=spf1 a -all"`, 20+len(d), h+"."), // ../rfc/7208:2263 ../rfc/7208:2287
"",
)
}
@ -561,7 +561,7 @@ func DomainRecords(domConf config.Domain, domain dns.Domain, hasDNSSEC bool) ([]
"; of multiple strings (max size of each is 255 bytes).",
)
}
s := fmt.Sprintf("%s._domainkey.%s. IN TXT %s", name, d, TXTStrings(txt))
s := fmt.Sprintf("%s._domainkey.%s. TXT %s", name, d, TXTStrings(txt))
records = append(records, s)
}
@ -582,14 +582,14 @@ func DomainRecords(domConf config.Domain, domain dns.Domain, hasDNSSEC bool) ([]
"; Specify the MX host is allowed to send for our domain and for itself (for DSNs).",
"; ~all means softfail for anything else, which is done instead of -all to prevent older",
"; mail servers from rejecting the message because they never get to looking for a dkim/dmarc pass.",
fmt.Sprintf(`%s. IN TXT "v=spf1 mx ~all"`, d),
fmt.Sprintf(`%s. TXT "v=spf1 mx ~all"`, d),
"",
"; Emails that fail the DMARC check (without aligned DKIM and without aligned SPF)",
"; should be rejected, and request reports. If you email through mailing lists that",
"; strip DKIM-Signature headers and don't rewrite the From header, you may want to",
"; set the policy to p=none.",
fmt.Sprintf(`_dmarc.%s. IN TXT "%s"`, d, dmarcr.String()),
fmt.Sprintf(`_dmarc.%s. TXT "%s"`, d, dmarcr.String()),
"",
)
@ -598,8 +598,8 @@ func DomainRecords(domConf config.Domain, domain dns.Domain, hasDNSSEC bool) ([]
"; Remote servers can use MTA-STS to verify our TLS certificate with the",
"; WebPKI pool of CA's (certificate authorities) when delivering over SMTP with",
"; STARTTLSTLS.",
fmt.Sprintf(`mta-sts.%s. IN CNAME %s.`, d, h),
fmt.Sprintf(`_mta-sts.%s. IN TXT "v=STSv1; id=%s"`, d, sts.PolicyID),
fmt.Sprintf(`mta-sts.%s. CNAME %s.`, d, h),
fmt.Sprintf(`_mta-sts.%s. TXT "v=STSv1; id=%s"`, d, sts.PolicyID),
"",
)
} else {
@ -618,36 +618,36 @@ func DomainRecords(domConf config.Domain, domain dns.Domain, hasDNSSEC bool) ([]
tlsrptr := tlsrpt.Record{Version: "TLSRPTv1", RUAs: [][]string{{uri.String()}}}
records = append(records,
"; Request reporting about TLS failures.",
fmt.Sprintf(`_smtp._tls.%s. IN TXT "%s"`, d, tlsrptr.String()),
fmt.Sprintf(`_smtp._tls.%s. TXT "%s"`, d, tlsrptr.String()),
"",
)
}
records = append(records,
"; Autoconfig is used by Thunderbird. Autodiscover is (in theory) used by Microsoft.",
fmt.Sprintf(`autoconfig.%s. IN CNAME %s.`, d, h),
fmt.Sprintf(`_autodiscover._tcp.%s. IN SRV 0 1 443 autoconfig.%s.`, d, d),
fmt.Sprintf(`autoconfig.%s. CNAME %s.`, d, h),
fmt.Sprintf(`_autodiscover._tcp.%s. SRV 0 1 443 autoconfig.%s.`, d, d),
"",
// ../rfc/6186:133 ../rfc/8314:692
"; For secure IMAP and submission autoconfig, point to mail host.",
fmt.Sprintf(`_imaps._tcp.%s. IN SRV 0 1 993 %s.`, d, h),
fmt.Sprintf(`_submissions._tcp.%s. IN SRV 0 1 465 %s.`, d, h),
fmt.Sprintf(`_imaps._tcp.%s. SRV 0 1 993 %s.`, d, h),
fmt.Sprintf(`_submissions._tcp.%s. SRV 0 1 465 %s.`, d, h),
"",
// ../rfc/6186:242
"; Next records specify POP3 and non-TLS ports are not to be used.",
"; These are optional and safe to leave out (e.g. if you have to click a lot in a",
"; DNS admin web interface).",
fmt.Sprintf(`_imap._tcp.%s. IN SRV 0 1 143 .`, d),
fmt.Sprintf(`_submission._tcp.%s. IN SRV 0 1 587 .`, d),
fmt.Sprintf(`_pop3._tcp.%s. IN SRV 0 1 110 .`, d),
fmt.Sprintf(`_pop3s._tcp.%s. IN SRV 0 1 995 .`, d),
fmt.Sprintf(`_imap._tcp.%s. SRV 0 1 143 .`, d),
fmt.Sprintf(`_submission._tcp.%s. SRV 0 1 587 .`, d),
fmt.Sprintf(`_pop3._tcp.%s. SRV 0 1 110 .`, d),
fmt.Sprintf(`_pop3s._tcp.%s. SRV 0 1 995 .`, d),
"",
"; Optional:",
"; You could mark Let's Encrypt as the only Certificate Authority allowed to",
"; sign TLS certificates for your domain.",
fmt.Sprintf("%s. IN CAA 0 issue \"letsencrypt.org\"", d),
fmt.Sprintf("%s. CAA 0 issue \"letsencrypt.org\"", d),
)
return records, nil
}

View file

@ -5,14 +5,14 @@ $TTL 5m
@ NS dns.example.
moxacmepebble.mox1 IN A 172.28.1.10
moxmail2.mox2 IN A 172.28.1.20
dns IN A 172.28.1.30
acmepebble IN A 172.28.1.40
test IN A 172.28.1.50
localserve.mox1 IN A 172.28.1.60
postfixmail.postfix IN A 172.28.1.70
moxacmepebble.mox1 A 172.28.1.10
moxmail2.mox2 A 172.28.1.20
dns A 172.28.1.30
acmepebble A 172.28.1.40
test A 172.28.1.50
localserve.mox1 A 172.28.1.60
postfixmail.postfix A 172.28.1.70
postfix MX 10 postfixmail.postfix.example.
postfixdkim0._domainkey.postfix IN TXT "v=DKIM1;h=sha256;t=s;k=ed25519;p=a4IsBTuMsSQjU+xVyx8KEd8eObis4FrCiV72OaEkvDY="
postfix IN TXT "v=spf1 ip4:172.28.1.20 -all"
postfixdkim0._domainkey.postfix TXT "v=DKIM1;h=sha256;t=s;k=ed25519;p=a4IsBTuMsSQjU+xVyx8KEd8eObis4FrCiV72OaEkvDY="
postfix TXT "v=spf1 ip4:172.28.1.20 -all"

View file

@ -22,9 +22,9 @@ EOF
(
cat /integration/example.zone;
sed -n '/^;/,/IN CAA/p' output.txt |
sed -n '/^;/,/CAA /p' output.txt |
# allow sending from postfix for mox1.example.
sed 's/mox1.example. *IN TXT "v=spf1 mx ~all"/mox1.example. IN TXT "v=spf1 mx ip4:172.28.1.70 ~all"/'
sed 's/mox1.example. *TXT "v=spf1 mx ~all"/mox1.example. TXT "v=spf1 mx ip4:172.28.1.70 ~all"/'
) >/integration/example-integration.zone
unbound-control -s 172.28.1.30 reload # reload unbound with zone file changes

View file

@ -23,7 +23,7 @@ TLS:
EOF
# A fresh file was set up by moxacmepebble.
sed -n '/^;/,/IN CAA/p' output.txt >>/integration/example-integration.zone
sed -n '/^;/,/CAA /p' output.txt >>/integration/example-integration.zone
unbound-control -s 172.28.1.30 reload # reload unbound with zone file changes
mox -checkconsistency serve &

View file

@ -3,10 +3,10 @@ $TTL 5m
@ IN SOA dns.example. hostmaster.example. (1 0m 0m 0m 5m)
10.1 IN PTR moxacmepebble.mox1.example.
20.1 IN PTR moxmail2.mox2.example.
30.1 IN PTR dns.example.
40.1 IN PTR acmepebble.example.
50.1 IN PTR test.example.
60.1 IN PTR localserve.mox1.example.
70.1 IN PTR postfixmail.postfix.example.
10.1 PTR moxacmepebble.mox1.example.
20.1 PTR moxmail2.mox2.example.
30.1 PTR dns.example.
40.1 PTR acmepebble.example.
50.1 PTR test.example.
60.1 PTR localserve.mox1.example.
70.1 PTR postfixmail.postfix.example.

View file

@ -976,10 +976,10 @@ EOF
if err != nil {
addf(&r.SPF.Errors, "Making SPF record for instructions: %s", err)
}
domainspf := fmt.Sprintf("%s IN TXT %s", domain.ASCII+".", mox.TXTStrings(dtxt))
domainspf := fmt.Sprintf("%s TXT %s", domain.ASCII+".", mox.TXTStrings(dtxt))
// Check SPF record for sending host. ../rfc/7208:2263 ../rfc/7208:2287
hostspf := fmt.Sprintf(`%s IN TXT "v=spf1 a -all"`, mox.Conf.Static.HostnameDomain.ASCII+".")
hostspf := fmt.Sprintf(`%s TXT "v=spf1 a -all"`, mox.Conf.Static.HostnameDomain.ASCII+".")
addf(&r.SPF.Instructions, "Ensure DNS TXT records like the following exists:\n\n\t%s\n\t%s\n\nIf you have an existing mail setup, with other hosts also sending mail for you domain, you should add those IPs as well. You could replace \"-all\" with \"~all\" to treat mail sent from unlisted IPs as \"softfail\", or with \"?all\" for \"neutral\".", domainspf, hostspf)
}()
@ -1058,7 +1058,7 @@ EOF
addf(&r.DKIM.Errors, "Making DKIM record for instructions: %s", err)
continue
}
instr += fmt.Sprintf("\n\t%s._domainkey IN TXT %s\n", sel, mox.TXTStrings(txt))
instr += fmt.Sprintf("\n\t%s._domainkey TXT %s\n", sel, mox.TXTStrings(txt))
}
if instr != "" {
instr = "Ensure the following DNS record(s) exists, so mail servers receiving emails from this domain can verify the signatures in the mail headers:\n" + instr
@ -1111,7 +1111,7 @@ EOF
} else if !accepts {
addf(&r.DMARC.Errors, "External destination does not accept reports (%s)", err)
}
extInstr = fmt.Sprintf("Ensure a DNS TXT record exists in the domain of the destination address to opt-in to receiving reports from this domain:\n\n\t%s._report._dmarc.%s. IN TXT \"v=DMARC1;\"\n\n", domain.ASCII, domConf.DMARC.DNSDomain.ASCII)
extInstr = fmt.Sprintf("Ensure a DNS TXT record exists in the domain of the destination address to opt-in to receiving reports from this domain:\n\n\t%s._report._dmarc.%s. TXT \"v=DMARC1;\"\n\n", domain.ASCII, domConf.DMARC.DNSDomain.ASCII)
}
uri := url.URL{
@ -1124,7 +1124,7 @@ EOF
} else {
addf(&r.DMARC.Instructions, `Configure a DMARC destination in domain in config file.`)
}
instr := fmt.Sprintf("Ensure a DNS TXT record like the following exists:\n\n\t_dmarc IN TXT %s\n\nYou can start with testing mode by replacing p=reject with p=none. You can also request for the policy to be applied to a percentage of emails instead of all, by adding pct=X, with X between 0 and 100. Keep in mind that receiving mail servers will apply some anti-spam assessment regardless of the policy and whether it is applied to the message. The ruf= part requests daily aggregate reports to be sent to the specified address, which is automatically configured and reports automatically analyzed.", mox.TXTStrings(dmarcr.String()))
instr := fmt.Sprintf("Ensure a DNS TXT record like the following exists:\n\n\t_dmarc TXT %s\n\nYou can start with testing mode by replacing p=reject with p=none. You can also request for the policy to be applied to a percentage of emails instead of all, by adding pct=X, with X between 0 and 100. Keep in mind that receiving mail servers will apply some anti-spam assessment regardless of the policy and whether it is applied to the message. The ruf= part requests daily aggregate reports to be sent to the specified address, which is automatically configured and reports automatically analyzed.", mox.TXTStrings(dmarcr.String()))
addf(&r.DMARC.Instructions, instr)
if extInstr != "" {
addf(&r.DMARC.Instructions, extInstr)
@ -1166,7 +1166,7 @@ EOF
Ensure a DNS TXT record like the following exists:
_smtp._tls IN TXT %s
_smtp._tls TXT %s
`, mox.TXTStrings(tlsrptr.String()))
} else {
addf(&r.TLSRPT.Errors, `Configure a TLSRPT destination in domain in config file.`)
@ -1254,14 +1254,14 @@ When enabling MTA-STS, or updating a policy, always update the policy first (thr
addf(&r.MTASTS.Instructions, `Enable a policy through the configuration file. For new deployments, it is best to start with mode "testing" while enabling TLSRPT. Start with a short "max_age", so updates to your policy are picked up quickly. When confidence in the deployment is high enough, switch to "enforce" mode and a longer "max age". A max age in the order of weeks is recommended. If you foresee a change to your setup in the future, requiring different policies or MX records, you may want to dial back the "max age" ahead of time, similar to how you would handle TTL's in DNS record updates.`)
host := fmt.Sprintf("Ensure DNS CNAME/A/AAAA records exist that resolve mta-sts.%s to this mail server. For example:\n\n\t%s IN CNAME %s\n\n", domain.ASCII, "mta-sts."+domain.ASCII+".", mox.Conf.Static.HostnameDomain.ASCII+".")
host := fmt.Sprintf("Ensure DNS CNAME/A/AAAA records exist that resolve mta-sts.%s to this mail server. For example:\n\n\t%s CNAME %s\n\n", domain.ASCII, "mta-sts."+domain.ASCII+".", mox.Conf.Static.HostnameDomain.ASCII+".")
addf(&r.MTASTS.Instructions, host)
mtastsr := mtasts.Record{
Version: "STSv1",
ID: time.Now().Format("20060102T150405"),
}
dns := fmt.Sprintf("Ensure a DNS TXT record like the following exists:\n\n\t_mta-sts IN TXT %s\n\nConfigure the ID in the configuration file, it must be of the form [a-zA-Z0-9]{1,31}. It represents the version of the policy. For each policy change, you must change the ID to a new unique value. You could use a timestamp like 20220621T123000. When this field exists, an SMTP server will fetch a policy at https://mta-sts.%s/.well-known/mta-sts.txt. This policy is served by mox.", mox.TXTStrings(mtastsr.String()), domain.Name())
dns := fmt.Sprintf("Ensure a DNS TXT record like the following exists:\n\n\t_mta-sts TXT %s\n\nConfigure the ID in the configuration file, it must be of the form [a-zA-Z0-9]{1,31}. It represents the version of the policy. For each policy change, you must change the ID to a new unique value. You could use a timestamp like 20220621T123000. When this field exists, an SMTP server will fetch a policy at https://mta-sts.%s/.well-known/mta-sts.txt. This policy is served by mox.", mox.TXTStrings(mtastsr.String()), domain.Name())
addf(&r.MTASTS.Instructions, dns)
}()
@ -1318,7 +1318,7 @@ When enabling MTA-STS, or updating a policy, always update the policy first (thr
r.SRVConf.SRVs = map[string][]*net.SRV{}
for _, req := range reqs {
name := req.name + "_.tcp." + domain.ASCII
instr += fmt.Sprintf("\t%s._tcp.%-*s IN SRV 0 1 %d %s\n", req.name, len("_submissions")-len(req.name)+len(domain.ASCII+"."), domain.ASCII+".", req.port, req.host)
instr += fmt.Sprintf("\t%s._tcp.%-*s SRV 0 1 %d %s\n", req.name, len("_submissions")-len(req.name)+len(domain.ASCII+"."), domain.ASCII+".", req.port, req.host)
r.SRVConf.SRVs[req.name] = req.srvs
if err != nil {
addf(&r.SRVConf.Errors, "Looking up SRV record %q: %s", name, err)
@ -1337,7 +1337,7 @@ When enabling MTA-STS, or updating a policy, always update the policy first (thr
defer logPanic(ctx)
defer wg.Done()
addf(&r.Autoconf.Instructions, "Ensure a DNS CNAME record like the following exists:\n\n\tautoconfig.%s IN CNAME %s\n\nNote: the trailing dot is relevant, it makes the host name absolute instead of relative to the domain name.", domain.ASCII+".", mox.Conf.Static.HostnameDomain.ASCII+".")
addf(&r.Autoconf.Instructions, "Ensure a DNS CNAME record like the following exists:\n\n\tautoconfig.%s CNAME %s\n\nNote: the trailing dot is relevant, it makes the host name absolute instead of relative to the domain name.", domain.ASCII+".", mox.Conf.Static.HostnameDomain.ASCII+".")
host := "autoconfig." + domain.ASCII + "."
ips, ourIPs, notOurIPs, err := lookupIPs(&r.Autoconf.Errors, host)
@ -1364,7 +1364,7 @@ When enabling MTA-STS, or updating a policy, always update the policy first (thr
defer logPanic(ctx)
defer wg.Done()
addf(&r.Autodiscover.Instructions, "Ensure DNS records like the following exist:\n\n\t_autodiscover._tcp.%s IN SRV 0 1 443 autoconfig.%s\n\tautoconfig.%s IN CNAME %s\n\nNote: the trailing dots are relevant, it makes the host names absolute instead of relative to the domain name.", domain.ASCII+".", domain.ASCII+".", domain.ASCII+".", mox.Conf.Static.HostnameDomain.ASCII+".")
addf(&r.Autodiscover.Instructions, "Ensure DNS records like the following exist:\n\n\t_autodiscover._tcp.%s SRV 0 1 443 autoconfig.%s\n\tautoconfig.%s CNAME %s\n\nNote: the trailing dots are relevant, it makes the host names absolute instead of relative to the domain name.", domain.ASCII+".", domain.ASCII+".", domain.ASCII+".", mox.Conf.Static.HostnameDomain.ASCII+".")
_, srvs, _, err := resolver.LookupSRV(ctx, "autodiscover", "tcp", domain.ASCII+".")
if err != nil {