Created
January 25, 2017 02:11
-
-
Save jim3ma/3750675f141669ac4702bc9deaf31c6b to your computer and use it in GitHub Desktop.
Register Dialer Type for HTTP&HTTPS Proxy in golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 tcpConn
.