Subject: [PATCH links] Fix issue where system DNS cache is affecting the validation of a custom domain. Use custom domain validation via public Google DNS servers.

From: Peter Sanchez <[email-masked]>
Date: Sun, 21 Dec 2025 07:00:50 -0600

Also fixes the issue where erorrs validating domain DNS are not shown to
the user.

Fixes: https://todo.code.netlandish.com/~netlandish/links/131
Changelog-fixes: Issue validating custom domain dns and always show the
  error to the end user.
---
 admin/routes.go               |  4 ++--
 api/graph/schema.resolvers.go | 12 ++++++------
 domain/logic.go               | 13 ++++++++++++-
 3 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/admin/routes.go b/admin/routes.go
index cb2e926..a37d111 100644
--- a/admin/routes.go
+++ b/admin/routes.go
@@ -688,7 +688,7 @@ func (s *Service) DomainUpdate(c echo.Context) error {
 			}
 		}
 		type GraphQLResponse struct {
-			Domain models.Domain `json:"addDomain"`
+			Domain models.Domain `json:"updateAdminDomain"`
 		}
 		var result GraphQLResponse
 
@@ -817,7 +817,7 @@ func (s *Service) DomainCreate(c echo.Context) error {
 			}
 		}
 		type GraphQLResponse struct {
-			Domain models.Domain `json:"addDomain"`
+			Domain models.Domain `json:"addAdminDomain"`
 		}
 
 		op := gqlclient.NewOperation(
diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go
index b04fe6e..abfa3f9 100644
--- a/api/graph/schema.resolvers.go
+++ b/api/graph/schema.resolvers.go
@@ -2075,13 +2075,13 @@ func (r *mutationResolver) AddDomain(ctx context.Context, input model.DomainInpu
 	if err != nil {
 		validator.Error(
 			"%s", lt.Translate("Error checking the DNS entry for domain. Please try again later")).
-			WithField("lookup_name").
+			WithField("lookupName").
 			WithCode(valid.ErrValidationCode)
 		return nil, nil
 	}
 	if !dnsOK {
 		validator.Error("%s", lt.Translate("CNAME record for domain is incorrect")).
-			WithField("lookup_name").
+			WithField("lookupName").
 			WithCode(valid.ErrValidationCode)
 		return nil, nil
 	}
@@ -4647,13 +4647,13 @@ func (r *mutationResolver) AddAdminDomain(ctx context.Context, input model.Admin
 	if err != nil {
 		validator.Error(
 			"%s", lt.Translate("Error checking the DNS entry for domain. Please try again later")).
-			WithField("lookup_name").
+			WithField("lookupName").
 			WithCode(valid.ErrValidationCode)
 		return nil, nil
 	}
 	if !dnsOK {
 		validator.Error("%s", lt.Translate("CNAME record for domain is incorrect")).
-			WithField("lookup_name").
+			WithField("lookupName").
 			WithCode(valid.ErrValidationCode)
 		return nil, nil
 	}
@@ -4848,13 +4848,13 @@ func (r *mutationResolver) UpdateAdminDomain(ctx context.Context, input model.Up
 	if err != nil {
 		validator.Error(
 			"%s", lt.Translate("Error checking the DNS entry for domain. Please try again later")).
-			WithField("lookup_name").
+			WithField("lookupName").
 			WithCode(valid.ErrValidationCode)
 		return nil, nil
 	}
 	if !dnsOK {
 		validator.Error("%s", lt.Translate("CNAME record for domain is incorrect")).
-			WithField("lookup_name").
+			WithField("lookupName").
 			WithCode(valid.ErrValidationCode)
 		return nil, nil
 	}
diff --git a/domain/logic.go b/domain/logic.go
index 28c7e7c..ce6920c 100644
--- a/domain/logic.go
+++ b/domain/logic.go
@@ -7,6 +7,7 @@ import (
 	"links/models"
 	"net"
 	"strings"
+	"time"
 
 	sq "github.com/Masterminds/squirrel"
 	"golang.org/x/crypto/acme/autocert"
@@ -17,6 +18,16 @@ import (
 
 var ipMap map[string]net.IP
 
+// dnsResolver is a custom resolver to use the Google public DNS server for
+// domain dns validation.
+var dnsResolver = &net.Resolver{
+	PreferGo: true,
+	Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
+		d := net.Dialer{Timeout: 5 * time.Second}
+		return d.DialContext(ctx, "udp", "8.8.8.8:53")
+	},
+}
+
 func ValidDomain(
 	ctx context.Context, host string, service string, active bool) ([]*models.Domain, error) {
 	// Remove :PORT from host name
@@ -110,7 +121,7 @@ func CheckDomainDNS(ctx context.Context, domain string, service string) (bool, e
 		ipMap[cval] = ips[0]
 	}
 
-	ips, err := net.LookupIP(domain)
+	ips, err := dnsResolver.LookupIP(ctx, "ip", domain)
 	if err != nil {
 		return false, err
 	}
-- 
2.49.1