diff --git a/acme/client.go b/acme/client.go index f5fa8cef..5357c86f 100644 --- a/acme/client.go +++ b/acme/client.go @@ -9,6 +9,7 @@ import ( "fmt" "io/ioutil" "log" + "net" "net/http" "regexp" "strconv" @@ -99,20 +100,38 @@ func NewClient(caDirURL string, user User, keyBits int) (*Client, error) { return &Client{directory: dir, user: user, jws: jws, keyBits: keyBits, solvers: solvers}, nil } -// SetHTTPPort specifies a custom port to be used for HTTP based challenges. -// If this option is not used, the default port 80 will be used. -func (c *Client) SetHTTPPort(port string) { - if chlng, ok := c.solvers["http-01"]; ok { - chlng.(*httpChallenge).optPort = port +// SetHTTPAddress specifies a custom interface:port to be used for HTTP based challenges. +// If this option is not used, the default port 80 and all interfaces will be used. +// To only specify a port and no interface use the ":port" notation. +func (c *Client) SetHTTPAddress(iface string) error { + host, port, err := net.SplitHostPort(iface) + if err != nil { + return err } + + if chlng, ok := c.solvers["http-01"]; ok { + chlng.(*httpChallenge).iface = host + chlng.(*httpChallenge).port = port + } + + return nil } -// SetTLSPort specifies a custom port to be used for TLS based challenges. -// If this option is not used, the default port 443 will be used. -func (c *Client) SetTLSPort(port string) { - if chlng, ok := c.solvers["tls-sni-01"]; ok { - chlng.(*tlsSNIChallenge).optPort = port +// SetTLSAddress specifies a custom interface:port to be used for TLS based challenges. +// If this option is not used, the default port 443 and all interfaces will be used. +// To only specify a port and no interface use the ":port" notation. +func (c *Client) SetTLSAddress(iface string) error { + host, port, err := net.SplitHostPort(iface) + if err != nil { + return err } + + if chlng, ok := c.solvers["tls-sni-01"]; ok { + chlng.(*tlsSNIChallenge).iface = host + chlng.(*tlsSNIChallenge).port = port + } + + return nil } // ExcludeChallenges explicitly removes challenges from the pool for solving. diff --git a/acme/http_challenge.go b/acme/http_challenge.go index 00ad5895..69a7ea36 100644 --- a/acme/http_challenge.go +++ b/acme/http_challenge.go @@ -10,7 +10,8 @@ import ( type httpChallenge struct { jws *jws validate validateFunc - optPort string + iface string + port string } func (s *httpChallenge) Solve(chlng challenge, domain string) error { @@ -24,18 +25,19 @@ func (s *httpChallenge) Solve(chlng challenge, domain string) error { } // Allow for CLI port override - port := ":80" - if s.optPort != "" { - port = ":" + s.optPort + port := "80" + if s.port != "" { + port = s.port } - listener, err := net.Listen("tcp", domain+port) + iface := "" + if s.iface != "" { + iface = s.iface + } + + listener, err := net.Listen("tcp", net.JoinHostPort(iface, port)) if err != nil { - // if the domain:port bind failed, fall back to :port bind and try that instead. - listener, err = net.Listen("tcp", port) - if err != nil { - return fmt.Errorf("Could not start HTTP server for challenge -> %v", err) - } + return fmt.Errorf("Could not start HTTP server for challenge -> %v", err) } defer listener.Close() diff --git a/acme/tls_sni_challenge.go b/acme/tls_sni_challenge.go index ad099d54..e2511ad3 100644 --- a/acme/tls_sni_challenge.go +++ b/acme/tls_sni_challenge.go @@ -6,13 +6,15 @@ import ( "crypto/tls" "encoding/hex" "fmt" + "net" "net/http" ) type tlsSNIChallenge struct { jws *jws validate validateFunc - optPort string + iface string + port string } func (t *tlsSNIChallenge) Solve(chlng challenge, domain string) error { @@ -33,15 +35,20 @@ func (t *tlsSNIChallenge) Solve(chlng challenge, domain string) error { } // Allow for CLI port override - port := ":443" - if t.optPort != "" { - port = ":" + t.optPort + port := "443" + if t.port != "" { + port = t.port + } + + iface := "" + if t.iface != "" { + iface = t.iface } tlsConf := new(tls.Config) tlsConf.Certificates = []tls.Certificate{cert} - listener, err := tls.Listen("tcp", port, tlsConf) + listener, err := tls.Listen("tcp", net.JoinHostPort(iface, port), tlsConf) if err != nil { return fmt.Errorf("Could not start HTTPS server for challenge -> %v", err) }