From 95a12d338bf18905002d96234227fb6aee898d10 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Thu, 11 Jun 2026 09:49:38 +0200 Subject: [PATCH] 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 --- pkg/iam/saml_domain_verifier.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/pkg/iam/saml_domain_verifier.go b/pkg/iam/saml_domain_verifier.go index 5b0ba2406..3dc2165d7 100644 --- a/pkg/iam/saml_domain_verifier.go +++ b/pkg/iam/saml_domain_verifier.go @@ -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 } }