Skip to content

Instantly share code, notes, and snippets.

@mwpcheung
Created January 11, 2021 09:11
Show Gist options
  • Save mwpcheung/8a62dea70262d9705e6cefea2a7953da to your computer and use it in GitHub Desktop.
Save mwpcheung/8a62dea70262d9705e6cefea2a7953da to your computer and use it in GitHub Desktop.
connect tls server with socks/https proxy
package main
import (
"bufio"
"bytes"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"fmt"
"log"
"net"
"net/http"
"net/url"
"strings"
"time"
"golang.org/x/net/proxy"
)
func dialProxy(sproxy, hostport string) (net.Conn, error) {
u, _ := url.Parse(sproxy)
switch u.Scheme {
case "socks5", "socks5h":
var pass bool
auth := new(proxy.Auth)
auth.User = u.User.Username()
auth.Password, pass = u.User.Password()
if pass {
dialer, _ := proxy.SOCKS5("tcp", u.Host, auth, proxy.Direct)
return dialer.Dial("tcp", hostport)
}
dialer, _ := proxy.SOCKS5("tcp", u.Host, nil, proxy.Direct)
return dialer.Dial("tcp", hostport)
case "http", "https":
username := u.User.Username()
password, _ := u.User.Password()
conn, err := net.Dial("tcp", u.Host)
if err != nil {
break
}
hdr := make(http.Header)
if u.User.String() != "" {
auth := username + ":" + password
hdr.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
}
connectReq := &http.Request{
Method: "CONNECT",
URL: &url.URL{Opaque: hostport},
Host: hostport,
Header: hdr,
}
if err = connectReq.Write(conn); err != nil {
break
}
br := bufio.NewReader(conn)
response, err := http.ReadResponse(br, connectReq)
if err != nil || response == nil {
log.Printf("http proxy connection error %v", err)
break
}
if response.StatusCode != 200 {
fmt.Printf("connect http tunnel faild: %d %+v", response.StatusCode, response)
break
}
return conn, nil
}
return net.Dial("tcp", hostport)
}
func clientTLSConnWithProxy(proxy, hostport string) (*tls.Conn, error) {
config := tls.Config{InsecureSkipVerify: true}
var err error
var conn net.Conn
conn, err = dialProxy(proxy, hostport)
if err != nil {
log.Printf("error %v", err)
return nil, err
}
tlsConn := tls.Client(conn, &config)
err = tlsConn.Handshake()
if err != nil {
log.Printf("handshake failed %v", err)
return nil, err
}
return tlsConn, nil
}
func unhex(hexStr string) []byte {
hexStr = strings.ReplaceAll(hexStr, " ", "")
hexStr = strings.ReplaceAll(hexStr, "\r", "")
hexStr = strings.ReplaceAll(hexStr, "\n", "")
hexStr = strings.ReplaceAll(hexStr, "\t", "")
bytes, _ := hex.DecodeString(hexStr)
return bytes
}
func main() {
conn, err := clientTLSConnWithProxy("http://localhost:8888", "www.google.com:443")
if err == nil {
bin := unhex("474554202f20485454502f312e310d0a486f73743a2037342e3132352e3230302e3130310d0a557365722d4167656e743a206375726c2f372e36342e310d0a4163636570743a202a2f2a0d0a0d0a")
_, err := conn.Write(bin)
if err != nil {
log.Printf("send http request error")
}
buf := new(bytes.Buffer)
for {
conn.SetReadDeadline(time.Now().Add(5 * time.Second))
p := make([]byte, 4096)
c, err := conn.Read(p)
if err != nil {
break
}
buf.Write(p[:c])
}
log.Printf("response text %s", buf.Bytes())
log.Printf("response hex %x", buf.Bytes())
} else {
log.Fatalf("error tls connection failed %v", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment