]> Sergey Matveev's repositories - tofuproxy.git/blob - tls.go
Unused variable
[tofuproxy.git] / tls.go
1 /*
2 tofuproxy -- flexible HTTP/HTTPS proxy, TLS terminator, X.509 TOFU
3              manager, WARC/geminispace browser
4 Copyright (C) 2021-2023 Sergey Matveev <stargrave@stargrave.org>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 3 of the License.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package tofuproxy
20
21 import (
22         "crypto"
23         "crypto/tls"
24         "crypto/x509"
25         "fmt"
26         "log"
27         "net/http"
28         "time"
29
30         ttls "go.stargrave.org/tofuproxy/tls"
31 )
32
33 var (
34         TLSNextProtoS = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
35         CACert        *x509.Certificate
36         CAPrv         crypto.PrivateKey
37 )
38
39 type Handler struct{}
40
41 func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
42         if req.Method != http.MethodConnect {
43                 roundTrip(w, req)
44                 return
45         }
46         hj, ok := w.(http.Hijacker)
47         if !ok {
48                 log.Fatalln("no hijacking")
49         }
50         conn, _, err := hj.Hijack()
51         if err != nil {
52                 log.Fatalln(err)
53         }
54         defer conn.Close()
55         fmt.Fprintf(
56                 conn, "%s %d %s\r\n\r\n",
57                 req.Proto, http.StatusOK, http.StatusText(http.StatusOK),
58         )
59         host, _, _ := ttls.SplitHostPort(req.Host)
60         hostCertsM.Lock()
61         keypair, ok := hostCerts[host]
62         if !ok || !keypair.cert.NotAfter.After(time.Now().Add(time.Hour)) {
63                 keypair = newX509Keypair(host, CACert, CAPrv)
64                 hostCerts[host] = keypair
65         }
66         hostCertsM.Unlock()
67         tlsConn := tls.Server(conn, &tls.Config{
68                 Certificates: []tls.Certificate{{
69                         Certificate: [][]byte{keypair.cert.Raw},
70                         PrivateKey:  keypair.prv,
71                 }},
72         })
73         if err = tlsConn.Handshake(); err != nil {
74                 log.Printf("TLS error %s: %+v\n", host, err)
75                 return
76         }
77         srv := http.Server{
78                 Handler:      &HTTPSHandler{host: req.Host},
79                 TLSNextProto: TLSNextProtoS,
80         }
81         err = srv.Serve(&SingleListener{conn: tlsConn})
82         if err != nil {
83                 if _, ok := err.(AlreadyAccepted); !ok {
84                         log.Printf("TLS serve error %s: %+v\n", host, err)
85                         return
86                 }
87         }
88 }
89
90 type HTTPSHandler struct {
91         host string
92 }
93
94 func (h *HTTPSHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
95         req.URL.Scheme = "https"
96         req.URL.Host = h.host
97         roundTrip(w, req)
98 }