-
Notifications
You must be signed in to change notification settings - Fork 0
/
proxy_via_ws.go
137 lines (125 loc) · 3.01 KB
/
proxy_via_ws.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package sidecar
import (
"crypto/tls"
"io"
"net"
"net/http"
"net/url"
"os"
"strconv"
"time"
"github.com/gorilla/websocket"
)
type ProxyViaWss struct {
server *http.Server
logger *os.File
pac *Pac
port string
onlyListenIPv4 bool
destination string
complexPath string
customHeaders map[string]string
}
func NewProxyViaWss(fd *os.File, pac *Pac,
onlyListenIPv4 bool, port int, destination string, complex_path string, headers map[string]string,
) *ProxyViaWss {
server := &http.Server{
IdleTimeout: 5 * time.Second,
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
}
return &ProxyViaWss{
server: server,
logger: fd,
pac: pac,
port: ":" + strconv.Itoa(port),
onlyListenIPv4: onlyListenIPv4,
destination: destination,
complexPath: complex_path,
customHeaders: headers,
}
}
func (i *ProxyViaWss) Run() {
i.server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if ifHttpRequest(r.URL.Scheme) {
proxyHandleHttp(w, r)
return
}
if i.pac.Matcher == nil {
i.proxyHandleHttpsToWss(w, r)
} else {
if i.pac.Compare(r) {
i.proxyHandleHttpsToWss(w, r)
} else {
directHandleHttps(w, r)
}
}
})
if i.onlyListenIPv4 {
l, err := net.Listen("tcp4", "0.0.0.0"+i.port)
if err != nil {
Panic(err)
}
i.server.Serve(l)
}
i.server.Addr = i.port
i.server.ListenAndServe()
}
func (i *ProxyViaWss) proxyHandleHttpsToWss(w http.ResponseWriter, r *http.Request) {
hijacker, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
return
}
client_conn, _, err := hijacker.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
_, err = io.WriteString(client_conn, "HTTP/1.1 200 Connection Established\r\n\r\n")
if err != nil {
Error("Error in connection establish: ", err)
return
}
u := url.URL{Scheme: "wss", Host: i.destination, Path: "/" + i.complexPath + "/"}
wss_req_headers := http.Header{}
for k, v := range i.customHeaders {
wss_req_headers.Set(k, v)
}
wss_req_headers.Set("destination", r.Host)
Info("Send Request via Wss tunnel, Host: ", r.Host)
c, _, err := websocket.DefaultDialer.Dial(u.String(), wss_req_headers)
if err != nil {
Error("Error in proxy connect to remote Websocket: ", err)
return
}
defer func() {
c.Close()
}()
go func() {
for {
buff := make([]byte, 2048)
length, err := client_conn.Read(buff)
if err != nil {
Debug("Error in read from tcp connect: ", err)
return
}
err = c.WriteMessage(websocket.BinaryMessage, buff[:length])
if err != nil {
Debug("Error in write data to websocket: ", err)
return
}
}
}()
for {
_, message, err := c.ReadMessage()
if err != nil {
Debug("Error in read data from websocket: ", err)
return
}
_, err = client_conn.Write([]byte(message))
if err != nil {
Debug("Error in write data to tcp connect: ", err)
return
}
}
}