listener.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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: m.TLSConfig(),
  73. }
  74. ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
  75. return ln
  76. }
  77. type listener struct {
  78. m *Manager
  79. conf *tls.Config
  80. tcpListener net.Listener
  81. tcpListenErr error
  82. }
  83. func (ln *listener) Accept() (net.Conn, error) {
  84. if ln.tcpListenErr != nil {
  85. return nil, ln.tcpListenErr
  86. }
  87. conn, err := ln.tcpListener.Accept()
  88. if err != nil {
  89. return nil, err
  90. }
  91. tcpConn := conn.(*net.TCPConn)
  92. // Because Listener is a convenience function, help out with
  93. // this too. This is not possible for the caller to set once
  94. // we return a *tcp.Conn wrapping an inaccessible net.Conn.
  95. // If callers don't want this, they can do things the manual
  96. // way and tweak as needed. But this is what net/http does
  97. // itself, so copy that. If net/http changes, we can change
  98. // here too.
  99. tcpConn.SetKeepAlive(true)
  100. tcpConn.SetKeepAlivePeriod(3 * time.Minute)
  101. return tls.Server(tcpConn, ln.conf), nil
  102. }
  103. func (ln *listener) Addr() net.Addr {
  104. if ln.tcpListener != nil {
  105. return ln.tcpListener.Addr()
  106. }
  107. // net.Listen failed. Return something non-nil in case callers
  108. // call Addr before Accept:
  109. return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443}
  110. }
  111. func (ln *listener) Close() error {
  112. if ln.tcpListenErr != nil {
  113. return ln.tcpListenErr
  114. }
  115. return ln.tcpListener.Close()
  116. }
  117. func homeDir() string {
  118. if runtime.GOOS == "windows" {
  119. return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
  120. }
  121. if h := os.Getenv("HOME"); h != "" {
  122. return h
  123. }
  124. return "/"
  125. }
  126. func cacheDir() string {
  127. const base = "golang-autocert"
  128. switch runtime.GOOS {
  129. case "darwin":
  130. return filepath.Join(homeDir(), "Library", "Caches", base)
  131. case "windows":
  132. for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
  133. if v := os.Getenv(ev); v != "" {
  134. return filepath.Join(v, base)
  135. }
  136. }
  137. // Worst case:
  138. return filepath.Join(homeDir(), base)
  139. }
  140. if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
  141. return filepath.Join(xdg, base)
  142. }
  143. return filepath.Join(homeDir(), ".cache", base)
  144. }