-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathhttp_proxy.go
143 lines (135 loc) · 3.25 KB
/
http_proxy.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
138
139
140
141
142
143
package main
import (
"bytes"
"fmt"
"log"
"net"
"strconv"
"strings"
ss "shadowsocks-go/shadowsocks"
)
func httpProxy(addr string) {
ln, err := net.Listen("tcp", addr)
if err != nil {
log.Fatal(err)
}
debug.Printf("starting local http proxy server at %v ...\n", addr)
for {
conn, err := ln.Accept()
if err != nil {
debug.Printf("listen accept error %v\n", err)
break
}
go handleHttpProxyConn(conn)
}
}
func readHttpHead(conn net.Conn, stop int) *bytes.Buffer {
cur := &bytes.Buffer{}
bts := make([]byte, 1)
var last byte
for {
_, err := conn.Read(bts)
if err != nil {
break
} else if bts[0] == '\r' {
continue
} else if bts[0] == '\n' {
if stop == 1 {
break
} else if last == '\n' && stop == 2 {
break
}
}
last = bts[0]
cur.Write(bts)
}
return cur
}
func getHostPortType(line []byte) (host, port, tp string, err error) {
if n := len(line); n > 0 && line[n-1] == '\r' {
line = line[:n-1]
}
slc := strings.Split(string(line), " ")
if len(slc) < 2 {
err = fmt.Errorf("first line err %v", string(line))
return
}
switch slc[0] {
case "CONNECT":
hp := strings.Split(slc[1], ":")
if len(hp) != 2 {
err = fmt.Errorf("connect extract host,port err %v", slc[1])
return
}
host, port, tp = hp[0], hp[1], "https"
default:
thp := strings.Split(slc[1], "/")
if len(thp) < 3 {
err = fmt.Errorf("%v host err %v", slc[0], slc[1])
return
}
hp := strings.Split(thp[2], ":")
if len(hp) == 1 {
host, port, tp = hp[0], "80", "http"
} else if len(hp) == 2 {
host, port, tp = hp[0], hp[1], "http"
} else {
err = fmt.Errorf("%v extract host,port err %v", slc[0], slc[1])
return
}
}
return
}
func handleHttpProxyConn(conn net.Conn) {
defer conn.Close()
first := readHttpHead(conn, 1)
later := readHttpHead(conn, 2)
hosts, ports, tps, err := getHostPortType(first.Bytes())
if err != nil {
debug.Printf("get host,port,type error %v", err)
return
}
var remote net.Conn
topDomain := getTopDomain(hosts)
if _, ok := gfwList[topDomain]; !fgfw && !ok {
remote, err = net.Dial("tcp", hosts+":"+ports)
debug.Printf("direct to %v:%v,topDomain:%v\n", hosts, ports, topDomain)
} else {
addr := bytes.Buffer{}
addr.WriteByte(0x03)
addr.WriteByte(byte(uint8(len(hosts))))
addr.WriteString(hosts)
var port int64
port, err = strconv.ParseInt(ports, 10, 0)
if err != nil {
debug.Printf("https host port conv err,%v\n", ports)
return
}
//大端序
port16 := uint16(port)
addr.WriteByte(byte(uint8(port16 >> 8)))
addr.WriteByte(byte(uint8(port16 & 0x00ff)))
debug.Printf("connecting to %v:%v over %v\n", hosts, ports, tps)
debug.Printf("\n%v\n%v", first.String(), later.String())
remote, err = createServerConn(addr.Bytes(), hosts+":"+ports)
}
if err != nil {
debug.Printf("%v\n", err)
if len(servers.srvCipher) > 1 {
debug.Println("Failed connect to all avaiable shadowsocks server")
}
return
}
defer remote.Close()
if tps == "https" {
conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
} else {
remote.Write(first.Bytes())
remote.Write([]byte{'\n'})
remote.Write(later.Bytes())
remote.Write([]byte{'\n'})
}
go ss.PipeThenClose(conn, remote)
ss.PipeThenClose(remote, conn)
debug.Printf("closed connection to %v:%v", hosts, ports)
}