forked from mmmdbybyd/CNS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
http_tunnel.go
executable file
·107 lines (99 loc) · 3.15 KB
/
http_tunnel.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
package main
import (
"bytes"
"crypto/tls"
"log"
"net"
"time"
)
func isHttpHeader(header []byte) bool {
if bytes.HasPrefix(header, []byte("CONNECT")) == true ||
bytes.HasPrefix(header, []byte("GET")) == true ||
bytes.HasPrefix(header, []byte("POST")) == true ||
bytes.HasPrefix(header, []byte("HEAD")) == true ||
bytes.HasPrefix(header, []byte("PUT")) == true ||
bytes.HasPrefix(header, []byte("COPY")) == true ||
bytes.HasPrefix(header, []byte("DELETE")) == true ||
bytes.HasPrefix(header, []byte("MOVE")) == true ||
bytes.HasPrefix(header, []byte("OPTIONS")) == true ||
bytes.HasPrefix(header, []byte("LINK")) == true ||
bytes.HasPrefix(header, []byte("UNLINK")) == true ||
bytes.HasPrefix(header, []byte("TRACE")) == true ||
bytes.HasPrefix(header, []byte("PATCH")) == true ||
bytes.HasPrefix(header, []byte("WRAPPED")) == true {
return true
}
return false
}
func rspHeader(header []byte) []byte {
if bytes.Contains(header, []byte("WebSocket")) == true {
return []byte("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: CuteBi Network Tunnel, (%>w<%)\r\n\r\n")
} else if bytes.HasPrefix(header, []byte("CON")) == true {
return []byte("HTTP/1.1 200 Connection established\r\nServer: CuteBi Network Tunnel, (%>w<%)\r\nConnection: keep-alive\r\n\r\n")
} else {
return []byte("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nServer: CuteBi Network Tunnel, (%>w<%)\r\nConnection: keep-alive\r\n\r\n")
}
}
func handleTunnel(cConn net.Conn, payload []byte, tlsConfig *tls.Config) {
defer tcpBufferPool.Put(payload)
var payloadLen int
for {
cConn.SetReadDeadline(time.Now().Add(config.Tcp_timeout))
RLen, err := cConn.Read(payload)
if err != nil || RLen <= 0 {
cConn.Close()
return
}
payloadLen += RLen
if !isHttpHeader(payload[:payloadLen]) || bytes.HasSuffix(payload[:payloadLen], []byte("\n\r\n")) {
break
}
}
if isHttpHeader(payload[:payloadLen]) == false {
/* 转为tls的conn */
if tlsConfig != nil {
cConn = tls.Server(cConn, tlsConfig)
}
handleUdpSession(cConn, payload[:payloadLen])
} else {
if config.Enable_httpDNS == false || Respond_HttpDNS(cConn, payload[:payloadLen]) == false { /*优先处理httpDNS请求*/
if WLen, err := cConn.Write(rspHeader(payload[:payloadLen])); err != nil || WLen <= 0 {
cConn.Close()
return
}
/* 转为tls的conn */
if tlsConfig != nil {
cConn = tls.Server(cConn, tlsConfig)
}
if bytes.Contains(payload[:payloadLen], []byte(config.Udp_flag)) == true {
handleUdpSession(cConn, nil)
} else {
handleTcpSession(cConn, payload)
}
}
}
}
func startHttpTunnel(listen_addr string) {
var conn *net.TCPConn
listener, err := net.Listen("tcp", listen_addr)
if config.Enable_TFO {
enableTcpFastopen(listener)
}
defer listener.Close()
if err != nil {
log.Println(err)
return
}
tcpListener := listener.(*net.TCPListener)
for {
conn, err = tcpListener.AcceptTCP()
if err != nil {
log.Println(err)
time.Sleep(3 * time.Second)
continue
}
conn.SetKeepAlive(true)
conn.SetKeepAlivePeriod(time.Minute)
go handleTunnel(conn, tcpBufferPool.Get().([]byte), config.Tls.tlsConfig)
}
}