package main import ( "context" "fmt" "io" "math/rand" "net" "net/http" "time" log "github.com/fangdingjun/go-log/v5" ) func getLocalIP() string { n := rand.Int() % len(iplist) return iplist[n] } func proxyHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodConnect { handleConnect(w, r) return } if r.Method == http.MethodGet || r.Method == http.MethodPost { handleHTTP(w, r) return } http.Error(w, "unsupported method", http.StatusBadRequest) } func localDialer(ctx context.Context, network, addr string) (net.Conn, error) { ip := getLocalIP() laddr := &net.TCPAddr{ IP: net.ParseIP(ip), Port: 0, } dialer := &net.Dialer{ LocalAddr: laddr, Timeout: 10 * time.Second, } return dialer.DialContext(ctx, network, addr) } func handleHTTP(w http.ResponseWriter, r *http.Request) { r.Header.Del("proxy-connection") r.Header.Del("proxy-authorization") tr := &http.Transport{ DialContext: localDialer, } resp, err := tr.RoundTrip(r) if err != nil { log.Errorln(err) http.Error(w, err.Error(), http.StatusServiceUnavailable) return } defer resp.Body.Close() hdr := w.Header() resp.Header.Del("connection") for k, v := range resp.Header { for _, v1 := range v { hdr.Add(k, v1) } } w.WriteHeader(resp.StatusCode) io.Copy(w, resp.Body) } func handleConnect(w http.ResponseWriter, r *http.Request) { ip := getLocalIP() log.Debugf("connect to %s, use local ip %s", r.RequestURI, ip) addr := &net.TCPAddr{ IP: net.ParseIP(ip), Port: 0, } dialer := &net.Dialer{ LocalAddr: addr, Timeout: 10 * time.Second, } conn, err := dialer.Dial("tcp", r.RequestURI) if err != nil { log.Errorln(err) http.Error(w, "connection failed", http.StatusBadGateway) return } defer conn.Close() hj := w.(http.Hijacker) conn1, _, _ := hj.Hijack() defer conn1.Close() fmt.Fprintf(conn1, "HTTP/1.1 200 connection ok\r\n\r\n") ch := make(chan struct{}, 2) go func() { io.Copy(conn, conn1) ch <- struct{}{} }() go func() { io.Copy(conn1, conn) ch <- struct{}{} }() <-ch } type handler struct { } func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { proxyHandler(w, r) }