Compare commits
1 Commits
66f8ad4048
...
fix/make-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2819c34d9 |
4
Makefile
4
Makefile
@@ -18,7 +18,7 @@ fmt:
|
|||||||
goimports -w .
|
goimports -w .
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -v -race -cover ./...
|
go test -v -race -cover -timeout 30s ./...
|
||||||
|
|
||||||
# Check runs all validation without making changes
|
# Check runs all validation without making changes
|
||||||
# Used by CI and Docker build - fails if anything is wrong
|
# Used by CI and Docker build - fails if anything is wrong
|
||||||
@@ -28,7 +28,7 @@ check:
|
|||||||
@echo "==> Running linter..."
|
@echo "==> Running linter..."
|
||||||
golangci-lint run --config .golangci.yml ./...
|
golangci-lint run --config .golangci.yml ./...
|
||||||
@echo "==> Running tests..."
|
@echo "==> Running tests..."
|
||||||
go test -v -race ./...
|
go test -v -race -short -timeout 30s ./...
|
||||||
@echo "==> Building..."
|
@echo "==> Building..."
|
||||||
go build -ldflags "$(LDFLAGS)" -o /dev/null ./cmd/dnswatcher
|
go build -ldflags "$(LDFLAGS)" -o /dev/null ./cmd/dnswatcher
|
||||||
@echo "==> All checks passed!"
|
@echo "==> All checks passed!"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
queryTimeoutDuration = 700 * time.Millisecond
|
queryTimeoutDuration = 5 * time.Second
|
||||||
maxRetries = 2
|
maxRetries = 2
|
||||||
maxDelegation = 20
|
maxDelegation = 20
|
||||||
timeoutMultiplier = 2
|
timeoutMultiplier = 2
|
||||||
@@ -227,7 +227,7 @@ func (r *Resolver) followDelegation(
|
|||||||
|
|
||||||
authNS := extractNSSet(resp.Ns)
|
authNS := extractNSSet(resp.Ns)
|
||||||
if len(authNS) == 0 {
|
if len(authNS) == 0 {
|
||||||
return r.resolveNSIterative(ctx, domain)
|
return r.resolveNSRecursive(ctx, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
glue := extractGlue(resp.Extra)
|
glue := extractGlue(resp.Extra)
|
||||||
@@ -291,84 +291,60 @@ func (r *Resolver) resolveNSIPs(
|
|||||||
return ips
|
return ips
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveNSIterative queries for NS records using iterative
|
// resolveNSRecursive queries for NS records using recursive
|
||||||
// resolution as a fallback when followDelegation finds no
|
// resolution as a fallback for intercepted environments.
|
||||||
// authoritative answer in the delegation chain.
|
func (r *Resolver) resolveNSRecursive(
|
||||||
func (r *Resolver) resolveNSIterative(
|
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
domain string,
|
domain string,
|
||||||
) ([]string, error) {
|
) ([]string, error) {
|
||||||
if checkCtx(ctx) != nil {
|
|
||||||
return nil, ErrContextCanceled
|
|
||||||
}
|
|
||||||
|
|
||||||
domain = dns.Fqdn(domain)
|
domain = dns.Fqdn(domain)
|
||||||
servers := rootServerList()
|
msg := new(dns.Msg)
|
||||||
|
msg.SetQuestion(domain, dns.TypeNS)
|
||||||
|
msg.RecursionDesired = true
|
||||||
|
|
||||||
for range maxDelegation {
|
for _, ip := range rootServerList()[:3] {
|
||||||
if checkCtx(ctx) != nil {
|
if checkCtx(ctx) != nil {
|
||||||
return nil, ErrContextCanceled
|
return nil, ErrContextCanceled
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := r.queryServers(
|
addr := net.JoinHostPort(ip, "53")
|
||||||
ctx, servers, domain, dns.TypeNS,
|
|
||||||
)
|
resp, _, err := r.client.ExchangeContext(ctx, msg, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
nsNames := extractNSSet(resp.Answer)
|
nsNames := extractNSSet(resp.Answer)
|
||||||
if len(nsNames) > 0 {
|
if len(nsNames) > 0 {
|
||||||
return nsNames, nil
|
return nsNames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Follow delegation.
|
|
||||||
authNS := extractNSSet(resp.Ns)
|
|
||||||
if len(authNS) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
glue := extractGlue(resp.Extra)
|
|
||||||
nextServers := glueIPs(authNS, glue)
|
|
||||||
|
|
||||||
if len(nextServers) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
servers = nextServers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ErrNoNameservers
|
return nil, ErrNoNameservers
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveARecord resolves a hostname to IPv4 addresses using
|
// resolveARecord resolves a hostname to IPv4 addresses.
|
||||||
// iterative resolution through the delegation chain.
|
|
||||||
func (r *Resolver) resolveARecord(
|
func (r *Resolver) resolveARecord(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
hostname string,
|
hostname string,
|
||||||
) ([]string, error) {
|
) ([]string, error) {
|
||||||
if checkCtx(ctx) != nil {
|
|
||||||
return nil, ErrContextCanceled
|
|
||||||
}
|
|
||||||
|
|
||||||
hostname = dns.Fqdn(hostname)
|
hostname = dns.Fqdn(hostname)
|
||||||
servers := rootServerList()
|
msg := new(dns.Msg)
|
||||||
|
msg.SetQuestion(hostname, dns.TypeA)
|
||||||
|
msg.RecursionDesired = true
|
||||||
|
|
||||||
for range maxDelegation {
|
for _, ip := range rootServerList()[:3] {
|
||||||
if checkCtx(ctx) != nil {
|
if checkCtx(ctx) != nil {
|
||||||
return nil, ErrContextCanceled
|
return nil, ErrContextCanceled
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := r.queryServers(
|
addr := net.JoinHostPort(ip, "53")
|
||||||
ctx, servers, hostname, dns.TypeA,
|
|
||||||
)
|
resp, _, err := r.client.ExchangeContext(ctx, msg, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
continue
|
||||||
"resolving %s: %w", hostname, err,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for A records in the answer section.
|
|
||||||
var ips []string
|
var ips []string
|
||||||
|
|
||||||
for _, rr := range resp.Answer {
|
for _, rr := range resp.Answer {
|
||||||
@@ -380,24 +356,6 @@ func (r *Resolver) resolveARecord(
|
|||||||
if len(ips) > 0 {
|
if len(ips) > 0 {
|
||||||
return ips, nil
|
return ips, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Follow delegation if present.
|
|
||||||
authNS := extractNSSet(resp.Ns)
|
|
||||||
if len(authNS) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
glue := extractGlue(resp.Extra)
|
|
||||||
nextServers := glueIPs(authNS, glue)
|
|
||||||
|
|
||||||
if len(nextServers) == 0 {
|
|
||||||
// Resolve NS IPs iteratively — but guard
|
|
||||||
// against infinite recursion by using only
|
|
||||||
// already-resolved servers.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
servers = nextServers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
|
|||||||
@@ -34,8 +34,12 @@ func newTestResolver(t *testing.T) *resolver.Resolver {
|
|||||||
func testContext(t *testing.T) context.Context {
|
func testContext(t *testing.T) context.Context {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test requiring real DNS")
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(
|
ctx, cancel := context.WithTimeout(
|
||||||
context.Background(), 60*time.Second,
|
context.Background(), 15*time.Second,
|
||||||
)
|
)
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user