You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

listener.go 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2017 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package autocert
  5. import (
  6. "crypto/tls"
  7. "log"
  8. "net"
  9. "os"
  10. "path/filepath"
  11. "runtime"
  12. "time"
  13. )
  14. // NewListener returns a net.Listener that listens on the standard TLS
  15. // port (443) on all interfaces and returns *tls.Conn connections with
  16. // LetsEncrypt certificates for the provided domain or domains.
  17. //
  18. // It enables one-line HTTPS servers:
  19. //
  20. // log.Fatal(http.Serve(autocert.NewListener("example.com"), handler))
  21. //
  22. // NewListener is a convenience function for a common configuration.
  23. // More complex or custom configurations can use the autocert.Manager
  24. // type instead.
  25. //
  26. // Use of this function implies acceptance of the LetsEncrypt Terms of
  27. // Service. If domains is not empty, the provided domains are passed
  28. // to HostWhitelist. If domains is empty, the listener will do
  29. // LetsEncrypt challenges for any requested domain, which is not
  30. // recommended.
  31. //
  32. // Certificates are cached in a "golang-autocert" directory under an
  33. // operating system-specific cache or temp directory. This may not
  34. // be suitable for servers spanning multiple machines.
  35. //
  36. // The returned listener uses a *tls.Config that enables HTTP/2, and
  37. // should only be used with servers that support HTTP/2.
  38. //
  39. // The returned Listener also enables TCP keep-alives on the accepted
  40. // connections. The returned *tls.Conn are returned before their TLS
  41. // handshake has completed.
  42. func NewListener(domains ...string) net.Listener {
  43. m := &Manager{
  44. Prompt: AcceptTOS,
  45. }
  46. if len(domains) > 0 {
  47. m.HostPolicy = HostWhitelist(domains...)
  48. }
  49. dir := cacheDir()
  50. if err := os.MkdirAll(dir, 0700); err != nil {
  51. log.Printf("warning: autocert.NewListener not using a cache: %v", err)
  52. } else {
  53. m.Cache = DirCache(dir)
  54. }
  55. return m.Listener()
  56. }
  57. // Listener listens on the standard TLS port (443) on all interfaces
  58. // and returns a net.Listener returning *tls.Conn connections.
  59. //
  60. // The returned listener uses a *tls.Config that enables HTTP/2, and
  61. // should only be used with servers that support HTTP/2.
  62. //
  63. // The returned Listener also enables TCP keep-alives on the accepted
  64. // connections. The returned *tls.Conn are returned before their TLS
  65. // handshake has completed.
  66. //
  67. // Unlike NewListener, it is the caller's responsibility to initialize
  68. // the Manager m's Prompt, Cache, HostPolicy, and other desired options.
  69. func (m *Manager) Listener() net.Listener {
  70. ln := &listener{
  71. m: m,
  72. conf: &tls.Config{
  73. GetCertificate: m.GetCertificate, // bonus: panic on nil m
  74. NextProtos: []string{"h2", "http/1.1"}, // Enable HTTP/2
  75. },
  76. }
  77. ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
  78. return ln
  79. }
  80. type listener struct {
  81. m *Manager
  82. conf *tls.Config
  83. tcpListener net.Listener
  84. tcpListenErr error
  85. }
  86. func (ln *listener) Accept() (net.Conn, error) {
  87. if ln.tcpListenErr != nil {
  88. return nil, ln.tcpListenErr
  89. }
  90. conn, err := ln.tcpListener.Accept()
  91. if err != nil {
  92. return nil, err
  93. }
  94. tcpConn := conn.(*net.TCPConn)
  95. // Because Listener is a convenience function, help out with
  96. // this too. This is not possible for the caller to set once
  97. // we return a *tcp.Conn wrapping an inaccessible net.Conn.
  98. // If callers don't want this, they can do things the manual
  99. // way and tweak as needed. But this is what net/http does
  100. // itself, so copy that. If net/http changes, we can change
  101. // here too.
  102. tcpConn.SetKeepAlive(true)
  103. tcpConn.SetKeepAlivePeriod(3 * time.Minute)
  104. return tls.Server(tcpConn, ln.conf), nil
  105. }
  106. func (ln *listener) Addr() net.Addr {
  107. if ln.tcpListener != nil {
  108. return ln.tcpListener.Addr()
  109. }
  110. // net.Listen failed. Return something non-nil in case callers
  111. // call Addr before Accept:
  112. return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443}
  113. }
  114. func (ln *listener) Close() error {
  115. if ln.tcpListenErr != nil {
  116. return ln.tcpListenErr
  117. }
  118. return ln.tcpListener.Close()
  119. }
  120. func homeDir() string {
  121. if runtime.GOOS == "windows" {
  122. return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
  123. }
  124. if h := os.Getenv("HOME"); h != "" {
  125. return h
  126. }
  127. return "/"
  128. }
  129. func cacheDir() string {
  130. const base = "golang-autocert"
  131. switch runtime.GOOS {
  132. case "darwin":
  133. return filepath.Join(homeDir(), "Library", "Caches", base)
  134. case "windows":
  135. for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
  136. if v := os.Getenv(ev); v != "" {
  137. return filepath.Join(v, base)
  138. }
  139. }
  140. // Worst case:
  141. return filepath.Join(homeDir(), base)
  142. }
  143. if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
  144. return filepath.Join(xdg, base)
  145. }
  146. return filepath.Join(homeDir(), ".cache", base)
  147. }