Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Register Dialer Type for HTTP&HTTPS Proxy in golang
package main
import (
"bufio"
"fmt"
"net"
"net/http"
"net/url"
"crypto/tls"
"golang.org/x/net/proxy"
)
type direct struct{}
// Direct is a direct proxy: one that makes network connections directly.
var Direct = direct{}
func (direct) Dial(network, addr string) (net.Conn, error) {
return net.Dial(network, addr)
}
// httpsDialer
type httpsDialer struct {}
// HTTPSDialer is a https proxy: one that makes network connections on tls.
var HttpsDialer = httpsDialer{}
var TlsConfig = &tls.Config{}
func (d httpsDialer) Dial(network, addr string) (c net.Conn, err error) {
c, err = tls.Dial("tcp", addr, TlsConfig)
if err != nil {
fmt.Println(err)
}
return
}
// httpProxy is a HTTP/HTTPS connect proxy.
type httpProxy struct {
host string
haveAuth bool
username string
password string
forward proxy.Dialer
}
func newHTTPProxy(uri *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {
s := new(httpProxy)
s.host = uri.Host
s.forward = forward
if uri.User != nil {
s.haveAuth = true
s.username = uri.User.Username()
s.password, _ = uri.User.Password()
}
return s, nil
}
func (s *httpProxy) Dial(network, addr string) (net.Conn, error) {
// Dial and create the https client connection.
c, err := s.forward.Dial("tcp", s.host)
if err != nil {
return nil, err
}
// HACK. http.ReadRequest also does this.
reqURL, err := url.Parse("http://" + addr)
if err != nil {
c.Close()
return nil, err
}
reqURL.Scheme = ""
req, err := http.NewRequest("CONNECT", reqURL.String(), nil)
if err != nil {
c.Close()
return nil, err
}
req.Close = false
if s.haveAuth {
req.SetBasicAuth(s.username, s.password)
}
req.Header.Set("User-Agent", "Powerby Gota")
err = req.Write(c)
if err != nil {
c.Close()
return nil, err
}
resp, err := http.ReadResponse(bufio.NewReader(c), req)
if err != nil {
// TODO close resp body ?
resp.Body.Close()
c.Close()
return nil, err
}
resp.Body.Close()
if resp.StatusCode != 200 {
c.Close()
err = fmt.Errorf("Connect server using proxy error, StatusCode [%d]", resp.StatusCode)
return nil, err
}
return c, nil
}
func FromURL(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error){
return proxy.FromURL(u, forward)
}
func FromEnvironment() proxy.Dialer {
return proxy.FromEnvironment()
}
func init() {
proxy.RegisterDialerType("http", newHTTPProxy)
proxy.RegisterDialerType("https", newHTTPProxy)
}
func main() {
// http proxy
httpProxyURI, _ := url.Parse("http://your http proxy:3128")
httpDialer, err := proxy.FromURL(httpProxyURI, Direct)
conn, err := httpDialer.Dial("tcp", "google.com:80")
if err != nil {
panic(err)
}
fmt.Printf("Create http tunnel OK: %+v\n", conn)
httpsProxyURI, _ := url.Parse("https://your https proxy:443")
httpsDialer, err := proxy.FromURL(httpsProxyURI, HttpsDialer)
conn, err = httpsDialer.Dial("tcp", "google.com:443")
if err != nil {
panic(err)
}
fmt.Printf("Create https tunnel OK: %+v\n", conn)
// TODO use conn
}
@jim3ma

This comment has been minimized.

Copy link
Owner Author

jim3ma commented Jan 25, 2017

Copy from https://github.com/Yawning/obfs4/blob/master/obfs4proxy/obfs4proxy.go, but remove the deprecated httputil.ClientConn
Currently, the http.Client doesn't support hijack, so we just export the raw tcp or tls over tcp Conn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.