/
main.go
111 lines (95 loc) · 2.34 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main
import (
"crypto/tls"
"fmt"
"log"
"net"
"net/http"
"net/http/httputil"
"github.com/quic-go/quic-go/http3"
"github.com/missdeer/transfer/keypair"
flag "github.com/spf13/pflag"
)
var (
listenAddr string
certFile string
keyFile string
)
func printExamples() {
fmt.Println("Examples:")
fmt.Println("\tquicplugin")
fmt.Println("\tquicplugin -k example.com.key -t fullchain.cer")
}
func listenAndServe(certFile, keyFile string, handler http.Handler) error {
// Load certs
var err error
kpr, err := keypair.NewKeypairReloader(certFile, keyFile)
if err != nil {
return err
}
// We currently only use the cert-related stuff from tls.Config,
// so we don't need to make a full copy.
config := &tls.Config{GetCertificate: kpr.GetCertificateFunc()}
// Open the listeners
udpAddr, err := net.ResolveUDPAddr("udp", listenAddr)
if err != nil {
return err
}
udpConn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
return err
}
defer udpConn.Close()
// Start the servers
httpServer := &http.Server{
Addr: listenAddr,
TLSConfig: config,
}
quicServer := &http3.Server{
Addr: listenAddr,
TLSConfig: config,
}
if handler == nil {
handler = http.DefaultServeMux
}
httpServer.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handler.ServeHTTP(w, r)
})
hErr := make(chan error)
qErr := make(chan error)
go func() {
qErr <- quicServer.Serve(udpConn)
}()
select {
case err := <-hErr:
quicServer.Close()
return err
case err := <-qErr:
// Cannot close the HTTP server or wait for requests to complete properly :/
return err
}
}
func main() {
help := false
flag.StringVarP(&listenAddr, "listen", "l", "0.0.0.0:443", "listen address, server/proxy mode only")
flag.StringVarP(&certFile, "cert", "t", "cert.pem", "SSL certificate file path")
flag.StringVarP(&keyFile, "key", "k", "key.pem", "SSL key file path")
flag.BoolVarP(&help, "help", "h", false, "show this help message")
flag.Parse()
if help {
printExamples()
fmt.Printf("\n")
flag.PrintDefaults()
return
}
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
u := *r.URL
u.Host = "127.0.0.1"
u.Scheme = "http"
u.Path = "/"
proxy := httputil.NewSingleHostReverseProxy(&u)
proxy.ServeHTTP(w, r)
})
log.Fatal(listenAndServe(certFile, keyFile, mux))
}