...
1
2
3
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
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
62
63
64
65
66
67
68
69
70
71
72
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
99
100
101
102
103
104
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
116
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
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