github.com/letsencrypt/boulder@v0.20251208.0/bdns/mocks.go (about) 1 package bdns 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "net/netip" 9 "os" 10 11 "github.com/miekg/dns" 12 13 blog "github.com/letsencrypt/boulder/log" 14 ) 15 16 // MockClient is a mock 17 type MockClient struct { 18 Log blog.Logger 19 } 20 21 // LookupTXT is a mock 22 func (mock *MockClient) LookupTXT(_ context.Context, hostname string) ([]string, ResolverAddrs, error) { 23 // Use the example account-specific label prefix derived from 24 // "https://example.com/acme/acct/ExampleAccount" 25 const accountLabelPrefix = "_ujmmovf2vn55tgye._acme-challenge" 26 27 if hostname == accountLabelPrefix+".servfail.com" { 28 // Mirror dns-01 servfail behaviour 29 return nil, ResolverAddrs{"MockClient"}, fmt.Errorf("SERVFAIL") 30 } 31 if hostname == accountLabelPrefix+".good-dns01.com" { 32 // Mirror dns-01 good record 33 // base64(sha256("LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0" 34 // + "." + "9jg46WB3rR_AHD-EBXdN7cBkH1WOu0tA3M9fm21mqTI")) 35 return []string{"LPsIwTo7o8BoG0-vjCyGQGBWSVIPxI-i_X336eUOQZo"}, ResolverAddrs{"MockClient"}, nil 36 } 37 if hostname == accountLabelPrefix+".wrong-dns01.com" { 38 // Mirror dns-01 wrong record 39 return []string{"a"}, ResolverAddrs{"MockClient"}, nil 40 } 41 if hostname == accountLabelPrefix+".wrong-many-dns01.com" { 42 // Mirror dns-01 wrong-many record 43 return []string{"a", "b", "c", "d", "e"}, ResolverAddrs{"MockClient"}, nil 44 } 45 if hostname == accountLabelPrefix+".long-dns01.com" { 46 // Mirror dns-01 long record 47 return []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, ResolverAddrs{"MockClient"}, nil 48 } 49 if hostname == accountLabelPrefix+".no-authority-dns01.com" { 50 // Mirror dns-01 no-authority good record 51 // base64(sha256("LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0" 52 // + "." + "9jg46WB3rR_AHD-EBXdN7cBkH1WOu0tA3M9fm21mqTI")) 53 return []string{"LPsIwTo7o8BoG0-vjCyGQGBWSVIPxI-i_X336eUOQZo"}, ResolverAddrs{"MockClient"}, nil 54 } 55 if hostname == accountLabelPrefix+".empty-txts.com" { 56 // Mirror dns-01 zero TXT records 57 return []string{}, ResolverAddrs{"MockClient"}, nil 58 } 59 60 if hostname == "_acme-challenge.servfail.com" { 61 return nil, ResolverAddrs{"MockClient"}, fmt.Errorf("SERVFAIL") 62 } 63 if hostname == "_acme-challenge.good-dns01.com" { 64 // base64(sha256("LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0" 65 // + "." + "9jg46WB3rR_AHD-EBXdN7cBkH1WOu0tA3M9fm21mqTI")) 66 // expected token + test account jwk thumbprint 67 return []string{"LPsIwTo7o8BoG0-vjCyGQGBWSVIPxI-i_X336eUOQZo"}, ResolverAddrs{"MockClient"}, nil 68 } 69 if hostname == "_acme-challenge.wrong-dns01.com" { 70 return []string{"a"}, ResolverAddrs{"MockClient"}, nil 71 } 72 if hostname == "_acme-challenge.wrong-many-dns01.com" { 73 return []string{"a", "b", "c", "d", "e"}, ResolverAddrs{"MockClient"}, nil 74 } 75 if hostname == "_acme-challenge.long-dns01.com" { 76 return []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, ResolverAddrs{"MockClient"}, nil 77 } 78 if hostname == "_acme-challenge.no-authority-dns01.com" { 79 // base64(sha256("LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0" 80 // + "." + "9jg46WB3rR_AHD-EBXdN7cBkH1WOu0tA3M9fm21mqTI")) 81 // expected token + test account jwk thumbprint 82 return []string{"LPsIwTo7o8BoG0-vjCyGQGBWSVIPxI-i_X336eUOQZo"}, ResolverAddrs{"MockClient"}, nil 83 } 84 // empty-txts.com always returns zero TXT records 85 if hostname == "_acme-challenge.empty-txts.com" { 86 return []string{}, ResolverAddrs{"MockClient"}, nil 87 } 88 89 // Default fallback 90 return []string{"hostname"}, ResolverAddrs{"MockClient"}, nil 91 } 92 93 // makeTimeoutError returns a a net.OpError for which Timeout() returns true. 94 func makeTimeoutError() *net.OpError { 95 return &net.OpError{ 96 Err: os.NewSyscallError("ugh timeout", timeoutError{}), 97 } 98 } 99 100 type timeoutError struct{} 101 102 func (t timeoutError) Error() string { 103 return "so sloooow" 104 } 105 func (t timeoutError) Timeout() bool { 106 return true 107 } 108 109 // LookupHost is a mock 110 func (mock *MockClient) LookupHost(_ context.Context, hostname string) ([]netip.Addr, ResolverAddrs, error) { 111 if hostname == "always.invalid" || 112 hostname == "invalid.invalid" { 113 return []netip.Addr{}, ResolverAddrs{"MockClient"}, nil 114 } 115 if hostname == "always.timeout" { 116 return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, "always.timeout", makeTimeoutError(), -1, nil} 117 } 118 if hostname == "always.error" { 119 err := &net.OpError{ 120 Op: "read", 121 Net: "udp", 122 Err: errors.New("some net error"), 123 } 124 m := new(dns.Msg) 125 m.SetQuestion(dns.Fqdn(hostname), dns.TypeA) 126 m.AuthenticatedData = true 127 m.SetEdns0(4096, false) 128 return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil} 129 } 130 if hostname == "id.mismatch" { 131 err := dns.ErrId 132 m := new(dns.Msg) 133 m.SetQuestion(dns.Fqdn(hostname), dns.TypeA) 134 m.AuthenticatedData = true 135 m.SetEdns0(4096, false) 136 r := new(dns.Msg) 137 record := new(dns.A) 138 record.Hdr = dns.RR_Header{Name: dns.Fqdn(hostname), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} 139 record.A = net.ParseIP("127.0.0.1") 140 r.Answer = append(r.Answer, record) 141 return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil} 142 } 143 // dual-homed host with an IPv6 and an IPv4 address 144 if hostname == "ipv4.and.ipv6.localhost" { 145 return []netip.Addr{ 146 netip.MustParseAddr("::1"), 147 netip.MustParseAddr("127.0.0.1"), 148 }, ResolverAddrs{"MockClient"}, nil 149 } 150 if hostname == "ipv6.localhost" { 151 return []netip.Addr{ 152 netip.MustParseAddr("::1"), 153 }, ResolverAddrs{"MockClient"}, nil 154 } 155 return []netip.Addr{netip.MustParseAddr("127.0.0.1")}, ResolverAddrs{"MockClient"}, nil 156 } 157 158 // LookupCAA returns mock records for use in tests. 159 func (mock *MockClient) LookupCAA(_ context.Context, domain string) ([]*dns.CAA, string, ResolverAddrs, error) { 160 return nil, "", ResolverAddrs{"MockClient"}, nil 161 }