...

Source file src/golang.org/x/crypto/acme/autocert/listener.go

Documentation: golang.org/x/crypto/acme/autocert

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

View as plain text