github.com/letsencrypt/boulder@v0.20251208.0/test/chall-test-srv/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "log" 8 "net/http" 9 "os" 10 "strings" 11 "time" 12 13 "github.com/letsencrypt/challtestsrv" 14 15 "github.com/letsencrypt/boulder/cmd" 16 ) 17 18 // managementServer is a small HTTP server that can control a challenge server, 19 // adding and deleting challenge responses as required 20 type managementServer struct { 21 // A managementServer is a http.Server 22 *http.Server 23 log *log.Logger 24 // The challenge server that is under control by the management server 25 challSrv *challtestsrv.ChallSrv 26 } 27 28 func (srv *managementServer) Run() { 29 srv.log.Printf("Starting management server on %s", srv.Server.Addr) 30 // Start the HTTP server in its own dedicated Go routine 31 go func() { 32 err := srv.ListenAndServe() 33 if err != nil && !strings.Contains(err.Error(), "Server closed") { 34 srv.log.Print(err) 35 } 36 }() 37 } 38 39 func (srv *managementServer) Shutdown() { 40 if err := srv.Server.Shutdown(context.Background()); err != nil { 41 srv.log.Printf("Err shutting down management server") 42 } 43 } 44 45 func filterEmpty(input []string) []string { 46 var output []string 47 for _, val := range input { 48 trimmed := strings.TrimSpace(val) 49 if trimmed != "" { 50 output = append(output, trimmed) 51 } 52 } 53 return output 54 } 55 56 func main() { 57 httpOneBind := flag.String("http01", ":5002", 58 "Comma separated bind addresses/ports for HTTP-01 challenges. Set empty to disable.") 59 httpsOneBind := flag.String("https01", ":5003", 60 "Comma separated bind addresses/ports for HTTPS HTTP-01 challenges. Set empty to disable.") 61 dohBind := flag.String("doh", ":8443", 62 "Comma separated bind addresses/ports for DoH queries. Set empty to disable.") 63 dohCert := flag.String("doh-cert", "", "Path to certificate file for DoH server.") 64 dohCertKey := flag.String("doh-cert-key", "", "Path to certificate key file for DoH server.") 65 dnsOneBind := flag.String("dns01", ":8053", 66 "Comma separated bind addresses/ports for DNS-01 challenges and fake DNS data. Set empty to disable.") 67 tlsAlpnOneBind := flag.String("tlsalpn01", ":5001", 68 "Comma separated bind addresses/ports for TLS-ALPN-01 and HTTPS HTTP-01 challenges. Set empty to disable.") 69 managementBind := flag.String("management", ":8055", 70 "Bind address/port for management HTTP interface") 71 defaultIPv4 := flag.String("defaultIPv4", "127.0.0.1", 72 "Default IPv4 address for mock DNS responses to A queries") 73 defaultIPv6 := flag.String("defaultIPv6", "::1", 74 "Default IPv6 address for mock DNS responses to AAAA queries") 75 76 flag.Parse() 77 78 if len(flag.Args()) > 0 { 79 fmt.Printf("invalid command line arguments: %s\n", strings.Join(flag.Args(), " ")) 80 flag.Usage() 81 os.Exit(1) 82 } 83 84 httpOneAddresses := filterEmpty(strings.Split(*httpOneBind, ",")) 85 httpsOneAddresses := filterEmpty(strings.Split(*httpsOneBind, ",")) 86 dohAddresses := filterEmpty(strings.Split(*dohBind, ",")) 87 dnsOneAddresses := filterEmpty(strings.Split(*dnsOneBind, ",")) 88 tlsAlpnOneAddresses := filterEmpty(strings.Split(*tlsAlpnOneBind, ",")) 89 90 logger := log.New(os.Stdout, "chall-test-srv - ", log.Ldate|log.Ltime) 91 92 // Create a new challenge server with the provided config 93 srv, err := challtestsrv.New(challtestsrv.Config{ 94 HTTPOneAddrs: httpOneAddresses, 95 HTTPSOneAddrs: httpsOneAddresses, 96 DOHAddrs: dohAddresses, 97 DOHCert: *dohCert, 98 DOHCertKey: *dohCertKey, 99 DNSOneAddrs: dnsOneAddresses, 100 TLSALPNOneAddrs: tlsAlpnOneAddresses, 101 Log: logger, 102 }) 103 cmd.FailOnError(err, "Unable to construct challenge server") 104 105 // Create a new management server with the provided config 106 oobSrv := managementServer{ 107 Server: &http.Server{ 108 Addr: *managementBind, 109 ReadTimeout: 30 * time.Second, 110 }, 111 challSrv: srv, 112 log: logger, 113 } 114 // Register handlers on the management server for adding challenge responses 115 // for the configured challenges. 116 if *httpOneBind != "" || *httpsOneBind != "" { 117 http.HandleFunc("/add-http01", oobSrv.addHTTP01) 118 http.HandleFunc("/del-http01", oobSrv.delHTTP01) 119 http.HandleFunc("/add-redirect", oobSrv.addHTTPRedirect) 120 http.HandleFunc("/del-redirect", oobSrv.delHTTPRedirect) 121 } 122 if *dnsOneBind != "" { 123 http.HandleFunc("/set-default-ipv4", oobSrv.setDefaultDNSIPv4) 124 http.HandleFunc("/set-default-ipv6", oobSrv.setDefaultDNSIPv6) 125 // TODO(@cpu): It might make sense to revisit this API in the future to have 126 // one endpoint that accepts the mock type required (A, AAAA, CNAME, etc) 127 // instead of having separate endpoints per type. 128 http.HandleFunc("/set-txt", oobSrv.addDNS01) 129 http.HandleFunc("/clear-txt", oobSrv.delDNS01) 130 http.HandleFunc("/add-a", oobSrv.addDNSARecord) 131 http.HandleFunc("/clear-a", oobSrv.delDNSARecord) 132 http.HandleFunc("/add-aaaa", oobSrv.addDNSAAAARecord) 133 http.HandleFunc("/clear-aaaa", oobSrv.delDNSAAAARecord) 134 http.HandleFunc("/add-caa", oobSrv.addDNSCAARecord) 135 http.HandleFunc("/clear-caa", oobSrv.delDNSCAARecord) 136 http.HandleFunc("/set-cname", oobSrv.addDNSCNAMERecord) 137 http.HandleFunc("/clear-cname", oobSrv.delDNSCNAMERecord) 138 http.HandleFunc("/set-servfail", oobSrv.addDNSServFailRecord) 139 http.HandleFunc("/clear-servfail", oobSrv.delDNSServFailRecord) 140 141 srv.SetDefaultDNSIPv4(*defaultIPv4) 142 srv.SetDefaultDNSIPv6(*defaultIPv6) 143 if *defaultIPv4 != "" { 144 logger.Printf("Answering A queries with %s by default", 145 *defaultIPv4) 146 } 147 if *defaultIPv6 != "" { 148 logger.Printf("Answering AAAA queries with %s by default", 149 *defaultIPv6) 150 } 151 } 152 if *tlsAlpnOneBind != "" { 153 http.HandleFunc("/add-tlsalpn01", oobSrv.addTLSALPN01) 154 http.HandleFunc("/del-tlsalpn01", oobSrv.delTLSALPN01) 155 } 156 157 http.HandleFunc("/clear-request-history", oobSrv.clearHistory) 158 http.HandleFunc("/http-request-history", oobSrv.getHTTPHistory) 159 http.HandleFunc("/dns-request-history", oobSrv.getDNSHistory) 160 http.HandleFunc("/tlsalpn01-request-history", oobSrv.getTLSALPNHistory) 161 162 // Start all of the sub-servers in their own Go routines so that the main Go 163 // routine can spin forever looking for signals to catch. 164 go srv.Run() 165 go oobSrv.Run() 166 167 cmd.CatchSignals(func() { 168 srv.Shutdown() 169 oobSrv.Shutdown() 170 }) 171 }