From f35a07050ec81e9d0a388d280971d1cd5d6ee00c Mon Sep 17 00:00:00 2001 From: M09Ic Date: Wed, 7 Feb 2024 01:29:05 +0800 Subject: [PATCH] support http/socks5 proxy --- go.mod | 2 ++ go.sum | 2 ++ internal/checkpool.go | 13 +++++--- internal/option.go | 2 ++ internal/pool.go | 19 +++++++---- internal/runner.go | 2 ++ pkg/config.go | 1 + pkg/ihttp/client.go | 76 +++++++++++++++++++++++++++++++++---------- 8 files changed, 89 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 1b7e26f..59399c0 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/jessevdk/go-flags v1.5.0 github.com/panjf2000/ants/v2 v2.7.0 github.com/valyala/fasthttp v1.43.0 + golang.org/x/net v0.0.0-20220906165146-f3363e06e74c golang.org/x/time v0.3.0 sigs.k8s.io/yaml v1.4.0 ) @@ -31,4 +32,5 @@ require ( github.com/twmb/murmur3 v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect golang.org/x/sys v0.2.0 // indirect + golang.org/x/text v0.3.7 // indirect ) diff --git a/go.sum b/go.sum index 87f317f..55e5baa 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,7 @@ golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -106,6 +107,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/checkpool.go b/internal/checkpool.go index 9042951..e3d52c4 100644 --- a/internal/checkpool.go +++ b/internal/checkpool.go @@ -20,10 +20,15 @@ import ( func NewCheckPool(ctx context.Context, config *pkg.Config) (*CheckPool, error) { pctx, cancel := context.WithCancel(ctx) pool := &CheckPool{ - Config: config, - ctx: pctx, - cancel: cancel, - client: ihttp.NewClient(config.Thread, config.Timeout, config.ClientType), + Config: config, + ctx: pctx, + cancel: cancel, + client: ihttp.NewClient(&ihttp.ClientConfig{ + Thread: config.Thread, + Type: config.ClientType, + Timeout: time.Duration(config.Timeout) * time.Second, + ProxyAddr: config.ProxyAddr, + }), wg: sync.WaitGroup{}, additionCh: make(chan *Unit, 100), closeCh: make(chan struct{}), diff --git a/internal/option.go b/internal/option.go index e01647a..089c0fe 100644 --- a/internal/option.go +++ b/internal/option.go @@ -84,6 +84,7 @@ type RequestOptions struct { Cookie []string `long:"cookie" description:"Strings, custom cookie"` ReadAll bool `long:"read-all" description:"Bool, read all response body"` MaxBodyLength int `long:"max-length" default:"100" description:"Int, max response body length (kb), default 100k, e.g. -max-length 1000"` + Proxy string `long:"proxy" default:"" description:"String, proxy address, e.g.: --proxy socks5://127.0.0.1:1080"` } type PluginOptions struct { @@ -168,6 +169,7 @@ func (opt *Option) PrepareRunner() (*Runner, error) { RandomUserAgent: opt.RandomUserAgent, Random: opt.Random, Index: opt.Index, + Proxy: opt.Proxy, } // log and bar diff --git a/internal/pool.go b/internal/pool.go index ae9c13d..21c9789 100644 --- a/internal/pool.go +++ b/internal/pool.go @@ -41,13 +41,18 @@ func NewPool(ctx context.Context, config *pkg.Config) (*Pool, error) { } pctx, cancel := context.WithCancel(ctx) pool := &Pool{ - Config: config, - base: u.Scheme + "://" + u.Host, - isDir: strings.HasSuffix(u.Path, "/"), - url: u, - ctx: pctx, - cancel: cancel, - client: ihttp.NewClient(config.Thread, config.Timeout, config.ClientType), + Config: config, + base: u.Scheme + "://" + u.Host, + isDir: strings.HasSuffix(u.Path, "/"), + url: u, + ctx: pctx, + cancel: cancel, + client: ihttp.NewClient(&ihttp.ClientConfig{ + Thread: config.Thread, + Type: config.ClientType, + Timeout: time.Duration(config.Timeout) * time.Second, + ProxyAddr: config.ProxyAddr, + }), baselines: make(map[int]*pkg.Baseline), urls: make(map[string]struct{}), scopeurls: make(map[string]struct{}), diff --git a/internal/runner.go b/internal/runner.go index ffa5dfc..5c8b5f6 100644 --- a/internal/runner.go +++ b/internal/runner.go @@ -84,6 +84,7 @@ type Runner struct { RandomUserAgent bool Random string Index string + Proxy string } func (r *Runner) PrepareConfig() *pkg.Config { @@ -114,6 +115,7 @@ func (r *Runner) PrepareConfig() *pkg.Config { RandomUserAgent: r.RandomUserAgent, Random: r.Random, Index: r.Index, + ProxyAddr: r.Proxy, } if config.ClientType == ihttp.Auto { diff --git a/pkg/config.go b/pkg/config.go index 0f34592..2aa0f14 100644 --- a/pkg/config.go +++ b/pkg/config.go @@ -21,6 +21,7 @@ var ModMap = map[string]SprayMod{ type Config struct { BaseURL string + ProxyAddr string Thread int Wordlist []string Timeout int diff --git a/pkg/ihttp/client.go b/pkg/ihttp/client.go index 6d46e57..3580d8e 100644 --- a/pkg/ihttp/client.go +++ b/pkg/ihttp/client.go @@ -4,9 +4,14 @@ import ( "context" "crypto/tls" "fmt" + "github.com/chainreactors/logs" "github.com/valyala/fasthttp" + "github.com/valyala/fasthttp/fasthttpproxy" + "golang.org/x/net/proxy" "net" "net/http" + "net/url" + "strings" "time" ) @@ -20,20 +25,17 @@ const ( STANDARD ) -func NewClient(thread int, timeout int, clientType int) *Client { - if clientType == FAST { - dialfunc := func(addr string) (net.Conn, error) { - return fasthttp.DialTimeout(addr, time.Duration(timeout)*time.Second) - } +func NewClient(config *ClientConfig) *Client { + if config.Type == FAST { return &Client{ fastClient: &fasthttp.Client{ TLSConfig: &tls.Config{ Renegotiation: tls.RenegotiateOnceAsClient, InsecureSkipVerify: true, }, - Dial: dialfunc, - MaxConnsPerHost: thread * 3 / 2, - MaxIdleConnDuration: time.Duration(timeout) * time.Second, + Dial: customDialFunc(config.ProxyAddr, config.Timeout), + MaxConnsPerHost: config.Thread * 3 / 2, + MaxIdleConnDuration: config.Timeout, //MaxConnWaitTimeout: time.Duration(timeout) * time.Second, //ReadTimeout: time.Duration(timeout) * time.Second, //WriteTimeout: time.Duration(timeout) * time.Second, @@ -43,8 +45,7 @@ func NewClient(thread int, timeout int, clientType int) *Client { DisablePathNormalizing: true, DisableHeaderNamesNormalizing: true, }, - timeout: time.Duration(timeout) * time.Second, - clientType: clientType, + Config: config, } } else { return &Client{ @@ -56,26 +57,34 @@ func NewClient(thread int, timeout int, clientType int) *Client { Renegotiation: tls.RenegotiateOnceAsClient, InsecureSkipVerify: true, }, - MaxConnsPerHost: thread * 3 / 2, - IdleConnTimeout: time.Duration(timeout) * time.Second, + MaxConnsPerHost: config.Thread * 3 / 2, + IdleConnTimeout: config.Timeout, ReadBufferSize: 16384, // 16k + Proxy: func(_ *http.Request) (*url.URL, error) { + return url.Parse(config.ProxyAddr) + }, }, - Timeout: time.Second * time.Duration(timeout), + Timeout: config.Timeout, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, }, - timeout: time.Duration(timeout) * time.Second, - clientType: clientType, + Config: config, } } } +type ClientConfig struct { + Type int + Timeout time.Duration + Thread int + ProxyAddr string +} + type Client struct { fastClient *fasthttp.Client standardClient *http.Client - clientType int - timeout time.Duration + Config *ClientConfig } func (c *Client) TransToCheck() { @@ -107,3 +116,36 @@ func (c *Client) Do(ctx context.Context, req *Request) (*Response, error) { return nil, fmt.Errorf("not found client") } } + +func customDialFunc(proxyAddr string, timeout time.Duration) fasthttp.DialFunc { + u, err := url.Parse(proxyAddr) + if err != nil { + logs.Log.Error(err.Error()) + return nil + } + if strings.ToLower(u.Scheme) == "socks5" { + + return func(addr string) (net.Conn, error) { + dialer, err := proxy.SOCKS5("tcp", u.Host, nil, proxy.Direct) + if err != nil { + return nil, err + } + + // Set up a connection with a timeout + conn, err := dialer.Dial("tcp", addr) + if err != nil { + return nil, err + } + + // Set deadlines for the connection + deadline := time.Now().Add(timeout) + if err := conn.SetDeadline(deadline); err != nil { + conn.Close() + return nil, err + } + return conn, nil + } + } else { + return fasthttpproxy.FasthttpHTTPDialerTimeout(proxyAddr, timeout) + } +}