Initial commit: DNS Test - DNS health checking tool
Go backend (miekg/dns) + Nuxt 3 frontend (Tailwind CSS v4). 8 check categories, 52 checks total: - Overview: @ record, WWW, MX with ASN/provider lookup - Domain Registration: expiry, registrar (RDAP + whois fallback) - Parent Delegation: NS records, glue, consistency - Nameservers: 17 checks (reachability, auth, recursion, TCP/UDP, AXFR, etc.) - SOA: serial consistency, timing values - Mail (MX): 11 checks (CNAME, PTR, public IPs, consistency) - Mail Auth: SPF, DKIM, DMARC - WWW: A record, CNAME Features: - SSE streaming (results appear as each category completes) - SQLite history (modernc.org/sqlite) - Rate limiting, CORS, request logging - Dark mode, responsive design
This commit is contained in:
105
backend/internal/checker/www.go
Normal file
105
backend/internal/checker/www.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package checker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/intodns/backend/internal/resolver"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// checkWWW runs the 2 WWW checks.
|
||||
func checkWWW(domain string, r *resolver.Resolver) Category {
|
||||
cat := Category{Name: "www", Title: "WWW"}
|
||||
|
||||
domain = dns.Fqdn(domain)
|
||||
wwwName := "www." + domain
|
||||
|
||||
// 1. www-a-record
|
||||
cat.Checks = append(cat.Checks, checkWWWARecord(wwwName, r))
|
||||
|
||||
// 2. www-cname
|
||||
cat.Checks = append(cat.Checks, checkWWWCNAME(wwwName, r))
|
||||
|
||||
return cat
|
||||
}
|
||||
|
||||
func checkWWWARecord(wwwName string, r *resolver.Resolver) CheckResult {
|
||||
start := time.Now()
|
||||
res := CheckResult{ID: "www-a-record", Title: "WWW A Record"}
|
||||
defer func() { res.DurationMs = measureDuration(start) }()
|
||||
|
||||
resp, err := r.Query(wwwName, "8.8.8.8", dns.TypeA)
|
||||
if err != nil {
|
||||
res.Status = StatusWarn
|
||||
res.Message = fmt.Sprintf("Failed to query A record for %s: %v", wwwName, err)
|
||||
return res
|
||||
}
|
||||
|
||||
var ips []string
|
||||
for _, rr := range resp.Answer {
|
||||
if a, ok := rr.(*dns.A); ok {
|
||||
ips = append(ips, a.A.String())
|
||||
}
|
||||
}
|
||||
|
||||
if len(ips) == 0 {
|
||||
res.Status = StatusInfo
|
||||
res.Message = fmt.Sprintf("No A record found for %s", wwwName)
|
||||
return res
|
||||
}
|
||||
|
||||
allPublic := true
|
||||
for _, ipStr := range ips {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if isPublicIP(ip) {
|
||||
res.Details = append(res.Details, fmt.Sprintf("%s -> %s (public)", wwwName, ipStr))
|
||||
} else {
|
||||
allPublic = false
|
||||
res.Details = append(res.Details, fmt.Sprintf("%s -> %s (NOT public)", wwwName, ipStr))
|
||||
}
|
||||
}
|
||||
|
||||
if allPublic {
|
||||
res.Status = StatusPass
|
||||
res.Message = fmt.Sprintf("%s has A record(s) with public IP(s)", wwwName)
|
||||
} else {
|
||||
res.Status = StatusWarn
|
||||
res.Message = fmt.Sprintf("%s has A record(s) but some IPs are not public", wwwName)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func checkWWWCNAME(wwwName string, r *resolver.Resolver) CheckResult {
|
||||
start := time.Now()
|
||||
res := CheckResult{ID: "www-cname", Title: "WWW CNAME"}
|
||||
defer func() { res.DurationMs = measureDuration(start) }()
|
||||
|
||||
resp, err := r.Query(wwwName, "8.8.8.8", dns.TypeCNAME)
|
||||
if err != nil {
|
||||
res.Status = StatusInfo
|
||||
res.Message = fmt.Sprintf("Could not check CNAME for %s", wwwName)
|
||||
return res
|
||||
}
|
||||
|
||||
var targets []string
|
||||
for _, rr := range resp.Answer {
|
||||
if cname, ok := rr.(*dns.CNAME); ok {
|
||||
targets = append(targets, cname.Target)
|
||||
}
|
||||
}
|
||||
|
||||
if len(targets) > 0 {
|
||||
res.Status = StatusInfo
|
||||
res.Message = fmt.Sprintf("%s is a CNAME to %s", wwwName, strings.Join(targets, ", "))
|
||||
for _, t := range targets {
|
||||
res.Details = append(res.Details, fmt.Sprintf("CNAME target: %s", t))
|
||||
}
|
||||
} else {
|
||||
res.Status = StatusInfo
|
||||
res.Message = fmt.Sprintf("%s is not a CNAME (direct A/AAAA record)", wwwName)
|
||||
}
|
||||
return res
|
||||
}
|
||||
Reference in New Issue
Block a user