blob: a87782047938cc3123ff57b08a464938136e0454 [file] [log] [blame]
Jan Schär4a180222024-07-29 16:32:54 +02001package test
2
3// Taken and modified from CoreDNS, under Apache 2.0.
4
5import (
6 "fmt"
7 "net"
8
9 "github.com/miekg/dns"
10)
11
12// A Server is an DNS server listening on a system-chosen port on the local
13// loopback interface, for use in end-to-end DNS tests.
14type Server struct {
15 Addr string // Address where the server listening.
16
17 s1 *dns.Server // udp
18 s2 *dns.Server // tcp
19}
20
21// NewServer starts and returns a new Server. The caller should call Close when
22// finished, to shut it down.
23func NewServer(f dns.HandlerFunc) *Server {
24 ch1 := make(chan bool)
25 ch2 := make(chan bool)
26
27 s1 := &dns.Server{Handler: f} // udp
28 s2 := &dns.Server{Handler: f} // tcp
29
30 for i := 0; i < 5; i++ { // 5 attempts
31 s2.Listener, _ = net.Listen("tcp", "[::1]:0")
32 if s2.Listener == nil {
33 continue
34 }
35
36 s1.PacketConn, _ = net.ListenPacket("udp", s2.Listener.Addr().String())
37 if s1.PacketConn != nil {
38 break
39 }
40
41 // perhaps UDP port is in use, try again
42 s2.Listener.Close()
43 s2.Listener = nil
44 }
45 if s2.Listener == nil {
46 panic("dnstest.NewServer(): failed to create new server")
47 }
48
49 s1.NotifyStartedFunc = func() { close(ch1) }
50 s2.NotifyStartedFunc = func() { close(ch2) }
51 go s1.ActivateAndServe()
52 go s2.ActivateAndServe()
53
54 <-ch1
55 <-ch2
56
57 return &Server{s1: s1, s2: s2, Addr: s2.Listener.Addr().String()}
58}
59
60// Close shuts down the server.
61func (s *Server) Close() {
62 s.s1.Shutdown()
63 s.s2.Shutdown()
64}
65
66// RR parses s as a DNS resource record.
67func RR(s string) dns.RR {
68 rr, err := dns.NewRR(s)
69 if err != nil {
70 panic(fmt.Sprintf("Failed to parse rr %q: %v", s, err))
71 }
72 return rr
73}