-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathhttpconnect.go
More file actions
89 lines (72 loc) · 2.7 KB
/
httpconnect.go
File metadata and controls
89 lines (72 loc) · 2.7 KB
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
package main
// This file contains the HTTP CONNECT implementation of the proxy interface defined in proxy.go
import (
"bufio"
"encoding/base64"
"fmt"
"net"
"strings"
"time"
)
type httpConnect struct {
baseProxy
}
// address returns the address where the HTTP CONNECT proxy is exposed, i.e. proxy.host:proxy.port
func (p httpConnect) address() string {
return fmt.Sprintf("%s:%s", p.host, p.port)
}
// alias returns the name given to the proxy in the configuration file, for logging purpose
func (p httpConnect) alias() string {
return p.name
}
// handshake takes net.Conn (representing a TCP socket) and an address and returns the same net.Conn connected to the provided address through the HTTP CONNECT proxy
func (p httpConnect) handshake(conn net.Conn, address string, tcpReadTimeout int64) (err error) {
gMetaLogger.Debugf("Entering CONNECT handshake(%v, %v)", conn, address)
defer func() { gMetaLogger.Debugf("Exiting CONNECT handshake(%v, %v)", conn, address) }()
if conn == nil {
err = fmt.Errorf("nil conn was provided")
return
}
reader := bufio.NewReader(conn)
host, _, err := net.SplitHostPort(address)
if err != nil {
return
}
var buff []byte
if p.user != "" {
gMetaLogger.Debugf("user is not empty, adding Proxy-Authorization header")
auth := base64.StdEncoding.EncodeToString([]byte(p.user + ":" + p.pass))
buff = []byte("CONNECT " + address + " HTTP/1.1\nHost: " + host + "\nProxy-Authorization: Basic " + auth + "\n\n")
} else {
buff = []byte("CONNECT " + address + " HTTP/1.1\nHost: " + host + "\n\n")
}
_, err = conn.Write(buff)
if err != nil {
return
}
gMetaLogger.Debugf("Wrote '%v' to the connection ", buff)
gMetaLogger.Debugf("Wrote '%v' to the connection ", string(buff))
conn.SetReadDeadline(time.Now().Add(time.Duration(tcpReadTimeout) * time.Millisecond))
response_line, err := reader.ReadString('\n')
conn.SetReadDeadline(time.Time{})
if err != nil {
return
}
gMetaLogger.Debugf("proxy answer: %v", response_line)
if !(strings.HasPrefix(response_line, "HTTP/1.0 2") || strings.HasPrefix(response_line, "HTTP/1.1 2") || strings.HasPrefix(response_line, "HTTP/2 2")) {
err = fmt.Errorf("the proxy did not accept the connection and returned '%v'", response_line)
return
}
gMetaLogger.Debug("Connection accepted, reading headers")
for response_line != string([]byte{10}) && response_line != string([]byte{13, 10}) {
gMetaLogger.Debug("reading new header line")
conn.SetReadDeadline(time.Now().Add(time.Duration(tcpReadTimeout) * time.Millisecond))
response_line, err = reader.ReadString('\n')
conn.SetReadDeadline(time.Time{})
if err != nil {
return
}
gMetaLogger.Debugf("Header line:\n%v%v", response_line, []byte(response_line))
}
return
}