Skip to content

Commit f78b71e

Browse files
committed
Fix resolve/tunnel failing on valid setups: use TXT query instead of NS
NS queries return empty on most dnstt/dnstm setups because the authoritative server doesn't serve NS records. Query a random subdomain TXT record instead, which is what dnstt-client actually does. Fixes #1
1 parent ad41e84 commit f78b71e

2 files changed

Lines changed: 16 additions & 18 deletions

File tree

internal/scanner/check.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77
"regexp"
88
"runtime"
99
"strconv"
10-
"strings"
1110
"time"
11+
12+
"github.com/miekg/dns"
1213
)
1314

1415
// Regex for Linux/macOS: "rtt min/avg/max/mdev = 4.123/5.456/6.789/..."
@@ -103,15 +104,16 @@ func TunnelCheck(domain string, count int) CheckFunc {
103104
for i := 0; i < count; i++ {
104105
start := time.Now()
105106

106-
// Step 1: Query NS for the tunnel domain
107-
hosts, ok := QueryNS(ip, domain, timeout)
108-
if !ok || len(hosts) == 0 {
107+
// Query a random subdomain TXT record — same as what dnstt-client does.
108+
// If the resolver forwards it to the authoritative server, the tunnel works.
109+
// NS queries fail on most setups because dnstt-server/dnstm don't serve NS records.
110+
qname := fmt.Sprintf("tun-%s.%s", randLabel(8), domain)
111+
r, ok := queryRaw(ip, qname, dns.TypeTXT, timeout)
112+
if !ok || r == nil {
109113
continue
110114
}
111-
112-
// Step 2: Resolve the first NS hostname to verify glue record
113-
nsHost := strings.TrimRight(hosts[0], ".")
114-
if !QueryA(ip, nsHost, timeout) {
115+
// SERVFAIL/REFUSED = resolver can't reach the authoritative server
116+
if r.Rcode == dns.RcodeServerFailure || r.Rcode == dns.RcodeRefused {
115117
continue
116118
}
117119

internal/scanner/doh.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,25 +138,21 @@ func DoHResolveCheck(domain string, count int) CheckFunc {
138138
}
139139
}
140140

141-
// DoHTunnelCheck tests NS delegation via DoH resolver.
141+
// DoHTunnelCheck tests if a DoH resolver can forward queries to the tunnel domain.
142142
func DoHTunnelCheck(domain string, count int) CheckFunc {
143143
return func(url string, timeout time.Duration) (bool, Metrics) {
144144
var successes []float64
145145

146146
for i := 0; i < count; i++ {
147147
start := time.Now()
148148

149-
hosts, ok := QueryDoHNS(url, domain, timeout)
150-
if !ok || len(hosts) == 0 {
149+
// Query a random subdomain TXT record — same as what dnstt-client does.
150+
qname := fmt.Sprintf("tun-%s.%s", randLabel(8), domain)
151+
r, ok := queryDoHRaw(url, qname, dns.TypeTXT, timeout)
152+
if !ok || r == nil {
151153
continue
152154
}
153-
154-
// Verify glue record via same DoH resolver
155-
nsHost := hosts[0]
156-
if last := len(nsHost) - 1; last >= 0 && nsHost[last] == '.' {
157-
nsHost = nsHost[:last]
158-
}
159-
if !QueryDoHA(url, nsHost, timeout) {
155+
if r.Rcode == dns.RcodeServerFailure || r.Rcode == dns.RcodeRefused {
160156
continue
161157
}
162158

0 commit comments

Comments
 (0)