/
server.go
102 lines (81 loc) · 2.29 KB
/
server.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
package proxy
import (
. "../config"
"../logg"
"../lookup"
"net"
"net/http"
)
type ProxyUpstreamHttpServer struct {
Tr *http.Transport
}
func (proxy *ProxyUpstreamHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if dh := r.Header.Get(dnsHeader); r.Method == "GET" && dh != "" {
if x := DecryptHost(dh, "!"); x != "" {
w.Write([]byte(lookup.LookupIP(x)))
return
}
}
if host := DecryptHost(r.Host, "*"); r.Method == "GET" && host != "" {
// dig tunnel
hij, ok := w.(http.Hijacker)
if !ok {
XorWrite(w, r, []byte("webserver doesn't support hijacking"), http.StatusInternalServerError)
return
}
downstreamConn, _, err := hij.Hijack()
if err != nil {
XorWrite(w, r, []byte(err.Error()), http.StatusInternalServerError)
return
}
// we are outside GFW and should pass data to the real target
targetSiteConn, err := net.Dial("tcp", host)
if err != nil {
logg.E("[HOST] - ", err)
return
}
// response HTTP 200 OK to downstream, and it will not be xored in IOCopyCipher
downstreamConn.Write(OK200)
TwoWayBridge(targetSiteConn, downstreamConn, r.Header.Get(rkeyHeader), *G_Throttling > 0)
} else {
// normal http requests
if !r.URL.IsAbs() {
XorWrite(w, r, []byte("abspath only"), http.StatusInternalServerError)
return
}
// decrypt req from inside GFW
rkey := DecryptRequest(r)
r.Header.Del("Proxy-Authorization")
r.Header.Del("Proxy-Connection")
resp, err := proxy.Tr.RoundTrip(r)
if err != nil {
logg.E("[HTTP] - ", r.URL, " - ", err)
XorWrite(w, r, []byte(err.Error()), http.StatusInternalServerError)
return
}
origBody := resp.Body
defer origBody.Close()
if resp.StatusCode >= 400 {
logg.L("[", resp.Status, "] - ", r.URL)
}
if origBody != resp.Body {
resp.Header.Del("Content-Length")
}
copyHeaders(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
iocc := getIOCipher(w, resp.Body, rkey, *G_Throttling > 0)
iocc.Partial = false // HTTP must be fully encrypted
nr, err := iocc.DoCopy()
tryClose(resp.Body)
if err != nil {
logg.E("[COPYS] ", err, " - bytes: ", nr)
}
}
}
func StartServer(addr string) {
proxy := &ProxyUpstreamHttpServer{
Tr: &http.Transport{TLSClientConfig: tlsSkip},
}
logg.L("listening on ", addr)
logg.F(http.ListenAndServe(addr, proxy))
}