package tests
import (
"context"
"encoding/binary"
"io"
"net"
"net/netip"
"golang.org/x/net/dns/dnsmessage"
)
func StubResolver(records map[string]string) *net.Resolver {
return &net.Resolver{
PreferGo: true,
Dial: func(context.Context, string, string) (net.Conn, error) {
client, server := net.Pipe()
go serveStubDNS(server, records)
return client, nil
},
}
}
func serveStubDNS(conn net.Conn, records map[string]string) {
defer conn.Close()
var size [2]byte
if _, err := io.ReadFull(conn, size[:]); err != nil {
return
}
buf := make([]byte, binary.BigEndian.Uint16(size[:]))
if _, err := io.ReadFull(conn, buf); err != nil {
return
}
var msg dnsmessage.Message
if err := msg.Unpack(buf); err != nil || len(msg.Questions) != 1 {
return
}
msg.Response = true
q := msg.Questions[0]
if ip, err := netip.ParseAddr(records[q.Name.String()]); err == nil && q.Type == dnsmessage.TypeA {
msg.Answers = []dnsmessage.Resource{{
Header: dnsmessage.ResourceHeader{Name: q.Name, Type: q.Type, Class: q.Class},
Body: &dnsmessage.AResource{A: ip.As4()},
}}
}
resp, err := msg.Pack()
if err != nil {
return
}
_, _ = conn.Write(append(binary.BigEndian.AppendUint16(nil, uint16(len(resp))), resp...))
}