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