Last active
April 23, 2024 04:50
-
-
Save chenset/9ea0ffd9e1647d46eada5757b9db0f3f to your computer and use it in GitHub Desktop.
http-proxy.go http proxy in go, Support socks5 forward proxy
This file contains hidden or 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" | |
| "context" | |
| "flag" | |
| "fmt" | |
| "golang.org/x/net/proxy" | |
| "io" | |
| "log" | |
| "net" | |
| "net/http" | |
| "net/http/httputil" | |
| "strings" | |
| ) | |
| func init() { | |
| log.SetFlags(log.LstdFlags | log.Lshortfile) | |
| } | |
| func main() { | |
| listen := flag.String("listen", "127.0.0.1:8080", "Http Proxy Listen address: client => http-proxy => server") | |
| socks5 := flag.String("socks5", "", "Socks5 forward proxy, if not empty: client => http-proxy => socks5 proxy => server") | |
| flag.Parse() | |
| dialer, err := getDialer(*socks5) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| l, err := net.Listen("tcp", *listen) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer l.Close() | |
| for { | |
| conn, err := l.Accept() | |
| if err != nil { | |
| fmt.Println(err) | |
| continue | |
| } | |
| go handleConnection(conn, dialer) | |
| } | |
| } | |
| //handleConnection | |
| func handleConnection(conn net.Conn, dialer proxy.Dialer) { | |
| defer conn.Close() | |
| request, err := http.ReadRequest(bufio.NewReader(conn)) | |
| if err != nil { | |
| log.Println(err) | |
| return | |
| } | |
| if strings.ToUpper(request.Method) == "CONNECT" { | |
| responseTunnel(conn, request, dialer) | |
| } else { | |
| responseHttp(conn, request, dialer) | |
| } | |
| } | |
| func getDialer(addr string) (dialer proxy.Dialer, err error) { | |
| if addr != "" { | |
| dialer, err = proxy.SOCKS5("tcp", addr, nil, proxy.Direct) | |
| } else { | |
| dialer, err = &net.Dialer{}, nil | |
| } | |
| return | |
| } | |
| //responseTunnel handle https ws etc.. | |
| func responseTunnel(conn net.Conn, request *http.Request, dialer proxy.Dialer) { | |
| remote, err := dialer.Dial("tcp", request.URL.Host) | |
| if err != nil { | |
| log.Println(err) | |
| return | |
| } | |
| conn.Write([]byte("HTTP/1.0 200 Connection Established\r\n\r\n")) | |
| defer remote.Close() | |
| ch := make(chan bool,1) | |
| go func() { | |
| io.Copy(remote, conn) | |
| ch <- true | |
| }() | |
| io.Copy(conn, remote) | |
| <-ch | |
| } | |
| //responseHttp get post, regular http request | |
| func responseHttp(conn net.Conn, request *http.Request, dialer proxy.Dialer) { | |
| request.RequestURI = "" | |
| client := &http.Client{ | |
| CheckRedirect: func(req *http.Request, via []*http.Request) error { | |
| return http.ErrUseLastResponse | |
| }, | |
| Transport: func() http.RoundTripper { | |
| t := http.DefaultTransport | |
| t.(*http.Transport).Proxy = nil //disable system proxy | |
| t.(*http.Transport).DialContext = func(ctx context.Context, network, addr string) (conn net.Conn, err error) { | |
| return dialer.Dial(network, addr) | |
| } | |
| return t | |
| }(), | |
| } | |
| resp, err := client.Do(request) | |
| if err != nil { | |
| log.Println(err) | |
| return | |
| } | |
| responseDump, _ := httputil.DumpResponse(resp, true) | |
| conn.Write(responseDump) | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage:
Help: