Retry DNS TXT lookup over TCP on truncated UDP response

When a domain has multiple TXT records (SPF, DKIM, etc.), the UDP
response can exceed 512 bytes and the server sets the TC bit. The
verifier was not handling this case, so any truncated response that
omitted the probo-verification record would silently fail as a
mismatch.

Fix by checking resp.Truncated after the UDP exchange and retrying
over TCP when set. Also pass the caller's context instead of
context.Background(), and simplify message construction with
dns.NewMsg.

Closes #1335

Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
Bryan Frimin
2026-06-11 09:49:38 +02:00
parent c3936a7173
commit 95a12d338b

View File

@@ -168,7 +168,7 @@ func (v *SAMLDomainVerifier) tryVerifyDomain(ctx context.Context, configID gid.G
expectedValue := txtRecordValuePrefix + *config.DomainVerificationToken
if err := v.checkDNSTXTRecord(config.EmailDomain, expectedValue); err != nil {
if err := v.checkDNSTXTRecord(ctx, config.EmailDomain, expectedValue); err != nil {
return err
}
@@ -194,22 +194,23 @@ func (v *SAMLDomainVerifier) tryVerifyDomain(ctx context.Context, configID gid.G
)
}
func (v *SAMLDomainVerifier) checkDNSTXTRecord(emailDomain string, expectedValue string) error {
fqdn := emailDomain
if !strings.HasSuffix(fqdn, ".") {
fqdn = fqdn + "."
}
msg := &dns.Msg{MsgHeader: dns.MsgHeader{ID: dns.ID(), RecursionDesired: true}}
msg.Question = []dns.RR{&dns.TXT{Hdr: dns.Header{Name: fqdn, Class: dns.ClassINET}}}
func (v *SAMLDomainVerifier) checkDNSTXTRecord(ctx context.Context, emailDomain string, expectedValue string) error {
msg := dns.NewMsg(emailDomain, dns.TypeTXT)
client := dns.NewClient()
resp, _, err := client.Exchange(context.Background(), msg, "udp", v.resolverAddr)
resp, _, err := client.Exchange(ctx, msg, "udp", v.resolverAddr)
if err != nil {
return fmt.Errorf("cannot query TXT record for %q: %w", emailDomain, err)
}
if resp.Truncated {
resp, _, err = client.Exchange(ctx, msg, "tcp", v.resolverAddr)
if err != nil {
return fmt.Errorf("cannot query TXT record for %q over TCP: %w", emailDomain, err)
}
}
if resp.Rcode != dns.RcodeSuccess {
return fmt.Errorf("cannot query TXT record for %q: %s", emailDomain, dns.RcodeToString[resp.Rcode])
}
@@ -224,9 +225,7 @@ func (v *SAMLDomainVerifier) checkDNSTXTRecord(emailDomain string, expectedValue
continue
}
value := strings.Join(txt.Txt, "")
if value == expectedValue {
if strings.Join(txt.Txt, "") == expectedValue {
return nil
}
}