Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/mitm-socket/go/dialer_proxy_http.go
1029 views
1
package main
2
3
import (
4
"bufio"
5
"crypto/tls"
6
"encoding/base64"
7
"errors"
8
"fmt"
9
"io"
10
"io/ioutil"
11
"net"
12
"net/http"
13
"net/url"
14
"strings"
15
)
16
17
func DialAddrViaHttpProxy(dialer net.Dialer, addr string, proxyUrl *url.URL, allowInsecure bool) (net.Conn, error) {
18
isSecure, proxyHost, err := getCleanHost(proxyUrl)
19
20
fmt.Printf("Dialing proxy connect %s to %s\n", proxyHost, addr)
21
connectReq := &http.Request{
22
Method: "CONNECT",
23
URL: proxyUrl,
24
Host: addr,
25
Header: make(http.Header),
26
}
27
28
if proxyUrl.User != nil {
29
proxyAuth := proxyUrl.User.String()
30
connectReq.Header.Set("Proxy-Authorization", fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(proxyAuth))))
31
}
32
33
conn, err := dialer.Dial("tcp", proxyHost)
34
if err != nil {
35
responseMessage := fmt.Sprintf("HTTP_PROXY_ERR dial failed (%s)", err)
36
return nil, errors.New(responseMessage)
37
}
38
39
if isSecure {
40
proxyTlsConfig := &tls.Config{}
41
if allowInsecure {
42
proxyTlsConfig.InsecureSkipVerify = true
43
} else {
44
proxyTlsConfig.ServerName = proxyHost
45
}
46
47
// NOTE: this is just the "wrapper" tls connection to the proxy. NOT to the destination
48
conn = tls.Client(conn, proxyTlsConfig)
49
}
50
51
err = connectReq.Write(conn)
52
if err != nil {
53
responseMessage := fmt.Sprintf("HTTP_PROXY_ERR writing CONNECT request failed (%s)", err)
54
return nil, errors.New(responseMessage)
55
}
56
// Read response.
57
// Okay to use and discard buffered reader here, because
58
// TLS server will not speak until spoken to.
59
br := bufio.NewReader(conn)
60
61
resp, err := http.ReadResponse(br, connectReq)
62
if err != nil {
63
conn.Close()
64
responseMessage := fmt.Sprintf("HTTP_PROXY_ERR reading CONNECT response failed (%s)", err)
65
return nil, errors.New(responseMessage)
66
}
67
defer resp.Body.Close()
68
69
if resp.StatusCode != 200 {
70
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 500))
71
if err != nil {
72
return nil, err
73
}
74
conn.Close()
75
responseMessage := fmt.Sprintf("HTTP_PROXY_ERR connection refused (%d)\n%s", resp.StatusCode, string(body))
76
return nil, errors.New(responseMessage)
77
}
78
return conn, nil
79
}
80
81
func getCleanHost(proxyUrl *url.URL) (bool, string, error) {
82
var isSecure = false
83
84
proxyHost := proxyUrl.Host
85
86
if proxyUrl.Scheme == "" || proxyUrl.Scheme == "http" {
87
if strings.IndexRune(proxyHost, ':') == -1 {
88
proxyHost += ":80"
89
}
90
}
91
92
if proxyUrl.Scheme == "https" || proxyUrl.Scheme == "wss" {
93
isSecure = true
94
if strings.IndexRune(proxyHost, ':') == -1 {
95
proxyHost += ":443"
96
}
97
}
98
99
return isSecure, proxyHost, nil
100
}
101
102