github.com/zly-app/zapp@v1.3.3/pkg/utils/proxy.go (about)

     1  package utils
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"net/http"
     8  	"net/url"
     9  	"strings"
    10  
    11  	"golang.org/x/net/proxy"
    12  )
    13  
    14  type ISocks5Proxy interface {
    15  	Dial(network, addr string) (c net.Conn, err error)
    16  	DialContext(ctx context.Context, network, address string) (net.Conn, error)
    17  }
    18  
    19  type Socks5Proxy struct {
    20  	dial        func(network, addr string) (c net.Conn, err error)
    21  	dialContext func(ctx context.Context, network, address string) (net.Conn, error)
    22  }
    23  
    24  func (s *Socks5Proxy) Dial(network, addr string) (c net.Conn, err error) {
    25  	return s.dial(network, addr)
    26  }
    27  
    28  func (s *Socks5Proxy) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
    29  	return s.dialContext(ctx, network, address)
    30  }
    31  
    32  /*
    33  创建一个socks5代理
    34  
    35  	address 代理地址. 支持socks5, socks5h. 示例: socks5://127.0.0.1:1080 socks5://user:pwd@127.0.0.1:1080
    36  */
    37  func NewSocks5Proxy(address string) (ISocks5Proxy, error) {
    38  	// 解析地址
    39  	u, err := url.Parse(address)
    40  	if err != nil {
    41  		return nil, fmt.Errorf("address无法解析: %v", err)
    42  	}
    43  
    44  	scheme := strings.ToLower(u.Scheme)
    45  	switch scheme {
    46  	case "socks5", "socks5h":
    47  		var auth *proxy.Auth
    48  		if u.User != nil {
    49  			pwd, ok := u.User.Password()
    50  			auth = &proxy.Auth{User: u.User.Username()}
    51  			if ok {
    52  				auth.Password = pwd
    53  			}
    54  		}
    55  
    56  		dialer, err := proxy.SOCKS5("tcp", u.Host, auth, nil)
    57  		if err != nil {
    58  			return nil, fmt.Errorf("dialer生成失败: %v", err)
    59  		}
    60  
    61  		var dialCtx func(ctx context.Context, network, address string) (net.Conn, error)
    62  		if d, ok := dialer.(proxy.ContextDialer); ok {
    63  			dialCtx = d.DialContext
    64  		} else {
    65  			dialCtx = func(ctx context.Context, network, address string) (net.Conn, error) {
    66  				return dialer.Dial(network, address)
    67  			}
    68  		}
    69  
    70  		sp := &Socks5Proxy{
    71  			dial:        dialer.Dial,
    72  			dialContext: dialCtx,
    73  		}
    74  		return sp, nil
    75  	}
    76  	return nil, fmt.Errorf("address的scheme不支持: %s", scheme)
    77  }
    78  
    79  type IHttpProxy interface {
    80  	SetProxy(transport *http.Transport)
    81  }
    82  
    83  type HttpProxy struct {
    84  	p  func(request *http.Request) (*url.URL, error)
    85  	s5 ISocks5Proxy
    86  }
    87  
    88  func (h *HttpProxy) SetProxy(transport *http.Transport) {
    89  	if h.s5 != nil {
    90  		transport.DialContext = h.s5.DialContext
    91  		return
    92  	}
    93  
    94  	transport.Proxy = h.p
    95  }
    96  
    97  /*
    98  创建一个http代理
    99  
   100  	address 代理地址. 支持 http, https, socks5, socks5h. 示例: https://127.0.0.1:1080 https://user:pwd@127.0.0.1:1080
   101  */
   102  func NewHttpProxy(address string) (IHttpProxy, error) {
   103  	// 解析地址
   104  	u, err := url.Parse(address)
   105  	if err != nil {
   106  		return nil, fmt.Errorf("address无法解析: %v", err)
   107  	}
   108  
   109  	scheme := strings.ToLower(u.Scheme)
   110  	switch scheme {
   111  	case "http", "https":
   112  		p := func(request *http.Request) (*url.URL, error) {
   113  			return u, nil
   114  		}
   115  		return &HttpProxy{p: p}, nil
   116  	case "socks5", "socks5h":
   117  		s5, err := NewSocks5Proxy(address)
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  		return &HttpProxy{s5: s5}, nil
   122  	}
   123  	return nil, fmt.Errorf("address的scheme不支持: %s", scheme)
   124  }