mirror of
				https://github.com/chainreactors/spray.git
				synced 2025-11-04 09:58:03 +00:00 
			
		
		
		
	现在同时支持http.net与fasthttp两个库, 适用不同的场景
This commit is contained in:
		
							parent
							
								
									029a83faa8
								
							
						
					
					
						commit
						9582a32586
					
				@ -2,46 +2,48 @@ package internal
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"github.com/chainreactors/parsers"
 | 
						"github.com/chainreactors/parsers"
 | 
				
			||||||
	"github.com/chainreactors/spray/pkg"
 | 
						"github.com/chainreactors/spray/pkg"
 | 
				
			||||||
	"github.com/valyala/fasthttp"
 | 
						"github.com/chainreactors/spray/pkg/ihttp"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewBaseline(u *fasthttp.URI, resp *fasthttp.Response) *baseline {
 | 
					func NewBaseline(u, host string, resp *ihttp.Response) *baseline {
 | 
				
			||||||
	bl := &baseline{
 | 
						bl := &baseline{
 | 
				
			||||||
		Url:       u,
 | 
							//Url:       u,
 | 
				
			||||||
		UrlString: u.String(),
 | 
							UrlString: u,
 | 
				
			||||||
 | 
							Host:      host,
 | 
				
			||||||
		Status:    resp.StatusCode(),
 | 
							Status:    resp.StatusCode(),
 | 
				
			||||||
		IsValid:   true,
 | 
							IsValid:   true,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bl.Body = resp.Body()
 | 
						bl.Body = resp.Body()
 | 
				
			||||||
	bl.BodyLength = resp.Header.ContentLength()
 | 
						bl.BodyLength = resp.ContentLength()
 | 
				
			||||||
	bl.Header = resp.Header.Header()
 | 
						bl.Header = resp.Header()
 | 
				
			||||||
	bl.HeaderLength = resp.Header.Len()
 | 
						bl.HeaderLength = len(bl.Header)
 | 
				
			||||||
	bl.RedirectURL = string(resp.Header.Peek("Location"))
 | 
						bl.RedirectURL = resp.GetHeader("Location")
 | 
				
			||||||
	bl.Raw = append(bl.Header, bl.Body...)
 | 
						bl.Raw = append(bl.Header, bl.Body...)
 | 
				
			||||||
	return bl
 | 
						return bl
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewInvalidBaseline(u *fasthttp.URI, resp *fasthttp.Response) *baseline {
 | 
					func NewInvalidBaseline(u, host string, resp *ihttp.Response) *baseline {
 | 
				
			||||||
	bl := &baseline{
 | 
						bl := &baseline{
 | 
				
			||||||
		Url:       u,
 | 
							//Url:       u,
 | 
				
			||||||
		UrlString: u.String(),
 | 
							UrlString: u,
 | 
				
			||||||
 | 
							Host:      host,
 | 
				
			||||||
		Status:    resp.StatusCode(),
 | 
							Status:    resp.StatusCode(),
 | 
				
			||||||
		IsValid:   false,
 | 
							IsValid:   false,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bl.RedirectURL = string(resp.Header.Peek("Location"))
 | 
						bl.RedirectURL = string(resp.GetHeader("Location"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return bl
 | 
						return bl
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type baseline struct {
 | 
					type baseline struct {
 | 
				
			||||||
	Url          *fasthttp.URI  `json:"-"`
 | 
						UrlString    string         `json:"url"`
 | 
				
			||||||
	UrlString    string         `json:"url_string"`
 | 
						Host         string         `json:"host"`
 | 
				
			||||||
	Body         []byte         `json:"-"`
 | 
						Body         []byte         `json:"-"`
 | 
				
			||||||
	BodyLength   int            `json:"body_length"`
 | 
						BodyLength   int            `json:"body_length"`
 | 
				
			||||||
	Header       []byte         `json:"-"`
 | 
						Header       []byte         `json:"-"`
 | 
				
			||||||
@ -51,6 +53,7 @@ type baseline struct {
 | 
				
			|||||||
	Status       int            `json:"status"`
 | 
						Status       int            `json:"status"`
 | 
				
			||||||
	IsDynamicUrl bool           `json:"is_dynamic_url"` // 判断是否存在动态的url
 | 
						IsDynamicUrl bool           `json:"is_dynamic_url"` // 判断是否存在动态的url
 | 
				
			||||||
	Spended      int            `json:"spended"`        // 耗时, 毫秒
 | 
						Spended      int            `json:"spended"`        // 耗时, 毫秒
 | 
				
			||||||
 | 
						Title        string         `json:"title"`
 | 
				
			||||||
	Frameworks   pkg.Frameworks `json:"frameworks"`
 | 
						Frameworks   pkg.Frameworks `json:"frameworks"`
 | 
				
			||||||
	Extracteds   pkg.Extracteds `json:"extracts"`
 | 
						Extracteds   pkg.Extracteds `json:"extracts"`
 | 
				
			||||||
	Err          error          `json:"-"`
 | 
						Err          error          `json:"-"`
 | 
				
			||||||
@ -61,6 +64,7 @@ type baseline struct {
 | 
				
			|||||||
// Collect 深度收集信息
 | 
					// Collect 深度收集信息
 | 
				
			||||||
func (bl *baseline) Collect() {
 | 
					func (bl *baseline) Collect() {
 | 
				
			||||||
	bl.Hashes = parsers.NewHashes(bl.Raw)
 | 
						bl.Hashes = parsers.NewHashes(bl.Raw)
 | 
				
			||||||
 | 
						bl.Title = parsers.MatchTitle(string(bl.Body))
 | 
				
			||||||
	// todo extract
 | 
						// todo extract
 | 
				
			||||||
	bl.Extracteds = pkg.Extractors.Extract(string(bl.Raw))
 | 
						bl.Extracteds = pkg.Extractors.Extract(string(bl.Raw))
 | 
				
			||||||
	// todo 指纹识别
 | 
						// todo 指纹识别
 | 
				
			||||||
@ -95,11 +99,21 @@ func (bl *baseline) String() string {
 | 
				
			|||||||
	var line strings.Builder
 | 
						var line strings.Builder
 | 
				
			||||||
	//line.WriteString("[+] ")
 | 
						//line.WriteString("[+] ")
 | 
				
			||||||
	line.WriteString(bl.UrlString)
 | 
						line.WriteString(bl.UrlString)
 | 
				
			||||||
	line.WriteString(fmt.Sprintf(" - %d - %d ", bl.Status, bl.BodyLength))
 | 
						line.WriteString(" (" + bl.Host + ")")
 | 
				
			||||||
 | 
						line.WriteString(" - ")
 | 
				
			||||||
 | 
						line.WriteString(strconv.Itoa(bl.Status))
 | 
				
			||||||
 | 
						line.WriteString(" - ")
 | 
				
			||||||
 | 
						line.WriteString(strconv.Itoa(bl.BodyLength))
 | 
				
			||||||
	if bl.RedirectURL != "" {
 | 
						if bl.RedirectURL != "" {
 | 
				
			||||||
		line.WriteString("-> ")
 | 
							line.WriteString(" -> ")
 | 
				
			||||||
		line.WriteString(bl.RedirectURL)
 | 
							line.WriteString(bl.RedirectURL)
 | 
				
			||||||
 | 
							line.WriteString(" ")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						line.WriteString(" [" + bl.Title + "]")
 | 
				
			||||||
 | 
						if bl.Hashes != nil {
 | 
				
			||||||
 | 
							line.WriteString(" [" + bl.Hashes.BodyMd5 + "]")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	line.WriteString(bl.Frameworks.ToString())
 | 
						line.WriteString(bl.Frameworks.ToString())
 | 
				
			||||||
	//line.WriteString(bl.Extracteds)
 | 
						//line.WriteString(bl.Extracteds)
 | 
				
			||||||
	//line.WriteString("\n")
 | 
						//line.WriteString("\n")
 | 
				
			||||||
 | 
				
			|||||||
@ -4,9 +4,11 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"github.com/chainreactors/logs"
 | 
						"github.com/chainreactors/logs"
 | 
				
			||||||
	"github.com/chainreactors/spray/pkg"
 | 
						"github.com/chainreactors/spray/pkg"
 | 
				
			||||||
 | 
						"github.com/chainreactors/spray/pkg/ihttp"
 | 
				
			||||||
	"github.com/chainreactors/words"
 | 
						"github.com/chainreactors/words"
 | 
				
			||||||
	"github.com/panjf2000/ants/v2"
 | 
						"github.com/panjf2000/ants/v2"
 | 
				
			||||||
	"github.com/valyala/fasthttp"
 | 
						"github.com/valyala/fasthttp"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -25,7 +27,7 @@ func NewPool(ctx context.Context, config *pkg.Config, outputCh chan *baseline) (
 | 
				
			|||||||
		Config:      config,
 | 
							Config:      config,
 | 
				
			||||||
		ctx:         pctx,
 | 
							ctx:         pctx,
 | 
				
			||||||
		cancel:      cancel,
 | 
							cancel:      cancel,
 | 
				
			||||||
		client:      pkg.NewClient(config.Thread, 2),
 | 
							client:      ihttp.NewClient(config.Thread, 2, config.ClientType),
 | 
				
			||||||
		worder:      words.NewWorder(config.Wordlist),
 | 
							worder:      words.NewWorder(config.Wordlist),
 | 
				
			||||||
		outputCh:    outputCh,
 | 
							outputCh:    outputCh,
 | 
				
			||||||
		tempCh:      make(chan *baseline, config.Thread),
 | 
							tempCh:      make(chan *baseline, config.Thread),
 | 
				
			||||||
@ -37,13 +39,32 @@ func NewPool(ctx context.Context, config *pkg.Config, outputCh chan *baseline) (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch config.Mod {
 | 
						switch config.Mod {
 | 
				
			||||||
	case pkg.PathSpray:
 | 
						case pkg.PathSpray:
 | 
				
			||||||
		pool.genReq = func(s string) (*fasthttp.Request, error) {
 | 
							pool.genReq = func(s string) (*ihttp.Request, error) {
 | 
				
			||||||
			return pool.buildPathRequest(s)
 | 
								return pool.buildPathRequest(s)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							pool.check = func() {
 | 
				
			||||||
 | 
								pool.wg.Add(1)
 | 
				
			||||||
 | 
								_ = pool.pool.Invoke(newUnit(pkg.RandPath(), CheckSource))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if pool.failedCount > breakThreshold {
 | 
				
			||||||
 | 
									// 当报错次数超过上限是, 结束任务
 | 
				
			||||||
 | 
									pool.cancel()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	case pkg.HostSpray:
 | 
						case pkg.HostSpray:
 | 
				
			||||||
		pool.genReq = func(s string) (*fasthttp.Request, error) {
 | 
							pool.genReq = func(s string) (*ihttp.Request, error) {
 | 
				
			||||||
			return pool.buildHostRequest(s)
 | 
								return pool.buildHostRequest(s)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pool.check = func() {
 | 
				
			||||||
 | 
								pool.wg.Add(1)
 | 
				
			||||||
 | 
								_ = pool.pool.Invoke(newUnit(pkg.RandHost(), CheckSource))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if pool.failedCount > breakThreshold {
 | 
				
			||||||
 | 
									// 当报错次数超过上限是, 结束任务
 | 
				
			||||||
 | 
									pool.cancel()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p, _ := ants.NewPoolWithFunc(config.Thread, func(i interface{}) {
 | 
						p, _ := ants.NewPoolWithFunc(config.Thread, func(i interface{}) {
 | 
				
			||||||
@ -56,8 +77,11 @@ func NewPool(ctx context.Context, config *pkg.Config, outputCh chan *baseline) (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		var bl *baseline
 | 
							var bl *baseline
 | 
				
			||||||
		resp, reqerr := pool.client.Do(pctx, req)
 | 
							resp, reqerr := pool.client.Do(pctx, req)
 | 
				
			||||||
		defer fasthttp.ReleaseResponse(resp)
 | 
							if pool.ClientType == ihttp.FAST {
 | 
				
			||||||
		defer fasthttp.ReleaseRequest(req)
 | 
								defer fasthttp.ReleaseResponse(resp.FastResponse)
 | 
				
			||||||
 | 
								defer fasthttp.ReleaseRequest(req.FastRequest)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if reqerr != nil && reqerr != fasthttp.ErrBodyTooLarge {
 | 
							if reqerr != nil && reqerr != fasthttp.ErrBodyTooLarge {
 | 
				
			||||||
			pool.failedCount++
 | 
								pool.failedCount++
 | 
				
			||||||
			bl = &baseline{UrlString: pool.BaseURL + unit.path, Err: reqerr}
 | 
								bl = &baseline{UrlString: pool.BaseURL + unit.path, Err: reqerr}
 | 
				
			||||||
@ -65,9 +89,9 @@ func NewPool(ctx context.Context, config *pkg.Config, outputCh chan *baseline) (
 | 
				
			|||||||
			pool.failedCount = 0
 | 
								pool.failedCount = 0
 | 
				
			||||||
			if err = pool.PreCompare(resp); err == nil || unit.source == CheckSource {
 | 
								if err = pool.PreCompare(resp); err == nil || unit.source == CheckSource {
 | 
				
			||||||
				// 通过预对比跳过一些无用数据, 减少性能消耗
 | 
									// 通过预对比跳过一些无用数据, 减少性能消耗
 | 
				
			||||||
				bl = NewBaseline(req.URI(), resp)
 | 
									bl = NewBaseline(req.URI(), req.Host(), resp)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				bl = NewInvalidBaseline(req.URI(), resp)
 | 
									bl = NewInvalidBaseline(req.URI(), req.Host(), resp)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			bl.Err = reqerr
 | 
								bl.Err = reqerr
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -108,7 +132,7 @@ func NewPool(ctx context.Context, config *pkg.Config, outputCh chan *baseline) (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type Pool struct {
 | 
					type Pool struct {
 | 
				
			||||||
	*pkg.Config
 | 
						*pkg.Config
 | 
				
			||||||
	client *pkg.Client
 | 
						client *ihttp.Client
 | 
				
			||||||
	pool   *ants.PoolWithFunc
 | 
						pool   *ants.PoolWithFunc
 | 
				
			||||||
	bar    *pkg.Bar
 | 
						bar    *pkg.Bar
 | 
				
			||||||
	ctx    context.Context
 | 
						ctx    context.Context
 | 
				
			||||||
@ -122,22 +146,13 @@ type Pool struct {
 | 
				
			|||||||
	checkPeriod int
 | 
						checkPeriod int
 | 
				
			||||||
	errPeriod   int
 | 
						errPeriod   int
 | 
				
			||||||
	analyzeDone bool
 | 
						analyzeDone bool
 | 
				
			||||||
	genReq      func(s string) (*fasthttp.Request, error)
 | 
						genReq      func(s string) (*ihttp.Request, error)
 | 
				
			||||||
 | 
						check       func()
 | 
				
			||||||
	worder      *words.Worder
 | 
						worder      *words.Worder
 | 
				
			||||||
	wg          sync.WaitGroup
 | 
						wg          sync.WaitGroup
 | 
				
			||||||
	initwg      sync.WaitGroup // 初始化用, 之后改成锁
 | 
						initwg      sync.WaitGroup // 初始化用, 之后改成锁
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *Pool) check() {
 | 
					 | 
				
			||||||
	p.wg.Add(1)
 | 
					 | 
				
			||||||
	_ = p.pool.Invoke(newUnit(pkg.RandPath(), CheckSource))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if p.failedCount > breakThreshold {
 | 
					 | 
				
			||||||
		// 当报错次数超过上限是, 结束任务
 | 
					 | 
				
			||||||
		p.cancel()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (p *Pool) Init() error {
 | 
					func (p *Pool) Init() error {
 | 
				
			||||||
	p.initwg.Add(1)
 | 
						p.initwg.Add(1)
 | 
				
			||||||
	p.check()
 | 
						p.check()
 | 
				
			||||||
@ -189,12 +204,12 @@ Loop:
 | 
				
			|||||||
	p.Close()
 | 
						p.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *Pool) PreCompare(resp *fasthttp.Response) error {
 | 
					func (p *Pool) PreCompare(resp *ihttp.Response) error {
 | 
				
			||||||
	if !CheckStatusCode(resp.StatusCode()) {
 | 
						if !CheckStatusCode(resp.StatusCode()) {
 | 
				
			||||||
		return ErrBadStatus
 | 
							return ErrBadStatus
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if CheckRedirect != nil && !CheckRedirect(string(resp.Header.Peek("Location"))) {
 | 
						if CheckRedirect != nil && !CheckRedirect(string(resp.GetHeader("Location"))) {
 | 
				
			||||||
		return ErrRedirect
 | 
							return ErrRedirect
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -238,15 +253,26 @@ func (p *Pool) Close() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *Pool) buildPathRequest(path string) (*fasthttp.Request, error) {
 | 
					func (p *Pool) buildPathRequest(path string) (*ihttp.Request, error) {
 | 
				
			||||||
	req := fasthttp.AcquireRequest()
 | 
						if p.Config.ClientType == ihttp.FAST {
 | 
				
			||||||
	req.SetRequestURI(p.BaseURL + path)
 | 
							req := fasthttp.AcquireRequest()
 | 
				
			||||||
	return req, nil
 | 
							req.SetRequestURI(p.BaseURL + path)
 | 
				
			||||||
 | 
							return &ihttp.Request{FastRequest: req}, nil
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							req, err := http.NewRequest("GET", p.BaseURL+path, nil)
 | 
				
			||||||
 | 
							return &ihttp.Request{StandardRequest: req}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *Pool) buildHostRequest(host string) (*fasthttp.Request, error) {
 | 
					func (p *Pool) buildHostRequest(host string) (*ihttp.Request, error) {
 | 
				
			||||||
	req := fasthttp.AcquireRequest()
 | 
						if p.Config.ClientType == ihttp.FAST {
 | 
				
			||||||
	req.SetRequestURI(p.BaseURL)
 | 
							req := fasthttp.AcquireRequest()
 | 
				
			||||||
	req.SetHost(host)
 | 
							req.SetRequestURI(p.BaseURL)
 | 
				
			||||||
	return req, nil
 | 
							req.SetHost(host)
 | 
				
			||||||
 | 
							return &ihttp.Request{FastRequest: req}, nil
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							req, err := http.NewRequest("GET", p.BaseURL, nil)
 | 
				
			||||||
 | 
							req.Host = host
 | 
				
			||||||
 | 
							return &ihttp.Request{StandardRequest: req}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,9 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/chainreactors/logs"
 | 
						"github.com/chainreactors/logs"
 | 
				
			||||||
	"github.com/chainreactors/spray/pkg"
 | 
						"github.com/chainreactors/spray/pkg"
 | 
				
			||||||
 | 
						"github.com/chainreactors/spray/pkg/ihttp"
 | 
				
			||||||
	"github.com/gosuri/uiprogress"
 | 
						"github.com/gosuri/uiprogress"
 | 
				
			||||||
 | 
						"github.com/panjf2000/ants/v2"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@ -27,8 +29,9 @@ type Runner struct {
 | 
				
			|||||||
	Offset     int         `long:"offset"`
 | 
						Offset     int         `long:"offset"`
 | 
				
			||||||
	Limit      int         `long:"limit"`
 | 
						Limit      int         `long:"limit"`
 | 
				
			||||||
	Threads    int         `short:"t" long:"thread" default:"20"`
 | 
						Threads    int         `short:"t" long:"thread" default:"20"`
 | 
				
			||||||
	PoolSize   int         `short:"p" long:"pool"`
 | 
						PoolSize   int         `short:"p" long:"pool" default:"5"`
 | 
				
			||||||
	Pools      map[string]*Pool
 | 
						Pools      *ants.PoolWithFunc
 | 
				
			||||||
 | 
						poolwg     sync.WaitGroup
 | 
				
			||||||
	Deadline   int    `long:"deadline" default:"600"` // todo 总的超时时间,适配云函数的deadline
 | 
						Deadline   int    `long:"deadline" default:"600"` // todo 总的超时时间,适配云函数的deadline
 | 
				
			||||||
	Debug      bool   `long:"debug"`
 | 
						Debug      bool   `long:"debug"`
 | 
				
			||||||
	Quiet      bool   `short:"q" long:"quiet"`
 | 
						Quiet      bool   `short:"q" long:"quiet"`
 | 
				
			||||||
@ -108,46 +111,52 @@ func (r *Runner) Prepare() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r.OutputCh = make(chan *baseline, 100)
 | 
						r.OutputCh = make(chan *baseline, 100)
 | 
				
			||||||
	r.Pools = make(map[string]*Pool)
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r.Pools, err = ants.NewPoolWithFunc(r.PoolSize, func(i interface{}) {
 | 
				
			||||||
 | 
							u := i.(string)
 | 
				
			||||||
 | 
							config := &pkg.Config{
 | 
				
			||||||
 | 
								BaseURL:      u,
 | 
				
			||||||
 | 
								Wordlist:     r.Wordlist,
 | 
				
			||||||
 | 
								Thread:       r.Threads,
 | 
				
			||||||
 | 
								Timeout:      2,
 | 
				
			||||||
 | 
								Headers:      r.Headers,
 | 
				
			||||||
 | 
								Mod:          pkg.ModMap[r.Mod],
 | 
				
			||||||
 | 
								DeadlineTime: r.Deadline,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if config.Mod == pkg.PathSpray {
 | 
				
			||||||
 | 
								config.ClientType = ihttp.FAST
 | 
				
			||||||
 | 
							} else if config.Mod == pkg.HostSpray {
 | 
				
			||||||
 | 
								config.ClientType = ihttp.STANDARD
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pool, err := NewPool(ctx, config, r.OutputCh)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logs.Log.Error(err.Error())
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pool.bar = pkg.NewBar(u, len(r.Wordlist), r.Progress)
 | 
				
			||||||
 | 
							err = pool.Init()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logs.Log.Error(err.Error())
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// todo pool 总超时时间
 | 
				
			||||||
 | 
							pool.Run(ctx)
 | 
				
			||||||
 | 
							r.poolwg.Done()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
	go r.Outputting()
 | 
						go r.Outputting()
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *Runner) Run() {
 | 
					func (r *Runner) Run() {
 | 
				
			||||||
	// todo pool 结束与并发控制
 | 
						// todo pool 结束与并发控制
 | 
				
			||||||
	ctx := context.Background()
 | 
					 | 
				
			||||||
	var wg sync.WaitGroup
 | 
					 | 
				
			||||||
	for _, u := range r.URLList {
 | 
						for _, u := range r.URLList {
 | 
				
			||||||
		wg.Add(1)
 | 
							r.poolwg.Add(1)
 | 
				
			||||||
		u := u
 | 
							r.Pools.Invoke(u)
 | 
				
			||||||
		go func() {
 | 
					 | 
				
			||||||
			config := &pkg.Config{
 | 
					 | 
				
			||||||
				BaseURL:      u,
 | 
					 | 
				
			||||||
				Wordlist:     r.Wordlist,
 | 
					 | 
				
			||||||
				Thread:       r.Threads,
 | 
					 | 
				
			||||||
				Timeout:      2,
 | 
					 | 
				
			||||||
				Headers:      r.Headers,
 | 
					 | 
				
			||||||
				Mod:          pkg.ModMap[r.Mod],
 | 
					 | 
				
			||||||
				DeadlineTime: r.Deadline,
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			pool, err := NewPool(ctx, config, r.OutputCh)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				logs.Log.Error(err.Error())
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			pool.bar = pkg.NewBar(u, len(r.Wordlist), r.Progress)
 | 
					 | 
				
			||||||
			err = pool.Init()
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				logs.Log.Error(err.Error())
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			r.Pools[u] = pool
 | 
					 | 
				
			||||||
			// todo pool 总超时时间
 | 
					 | 
				
			||||||
			pool.Run(ctx)
 | 
					 | 
				
			||||||
			wg.Done()
 | 
					 | 
				
			||||||
		}()
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wg.Wait()
 | 
						r.poolwg.Wait()
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		if len(r.OutputCh) == 0 {
 | 
							if len(r.OutputCh) == 0 {
 | 
				
			||||||
			close(r.OutputCh)
 | 
								close(r.OutputCh)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,67 +0,0 @@
 | 
				
			|||||||
package pkg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"context"
 | 
					 | 
				
			||||||
	"crypto/tls"
 | 
					 | 
				
			||||||
	"github.com/valyala/fasthttp"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	DefaultMaxBodySize = 1024 * 100 // 100k
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewClient(thread int, timeout int) *Client {
 | 
					 | 
				
			||||||
	c := &Client{
 | 
					 | 
				
			||||||
		client: &fasthttp.Client{
 | 
					 | 
				
			||||||
			TLSConfig: &tls.Config{
 | 
					 | 
				
			||||||
				Renegotiation:      tls.RenegotiateOnceAsClient,
 | 
					 | 
				
			||||||
				InsecureSkipVerify: true,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			//ReadBufferSize:      20480,
 | 
					 | 
				
			||||||
			MaxConnsPerHost:     thread * 2,
 | 
					 | 
				
			||||||
			MaxIdleConnDuration: time.Duration(timeout) * time.Second,
 | 
					 | 
				
			||||||
			MaxConnWaitTimeout:  time.Duration(timeout) * time.Second,
 | 
					 | 
				
			||||||
			ReadTimeout:         time.Duration(timeout) * time.Second,
 | 
					 | 
				
			||||||
			WriteTimeout:        time.Duration(timeout) * time.Second,
 | 
					 | 
				
			||||||
			MaxResponseBodySize: DefaultMaxBodySize,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		timeout: time.Duration(timeout) * time.Second,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	//c := &Client{
 | 
					 | 
				
			||||||
	//	client: &http.Client{
 | 
					 | 
				
			||||||
	//		Transport:     tr,
 | 
					 | 
				
			||||||
	//		Timeout:       time.Second * time.Duration(timeout),
 | 
					 | 
				
			||||||
	//		CheckRedirect: checkRedirect,
 | 
					 | 
				
			||||||
	//	},
 | 
					 | 
				
			||||||
	//}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//c.Method = method
 | 
					 | 
				
			||||||
	//c.Headers = Opt.Headers
 | 
					 | 
				
			||||||
	//c.Mod = Opt.Mod
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return c
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Client struct {
 | 
					 | 
				
			||||||
	client  *fasthttp.Client
 | 
					 | 
				
			||||||
	timeout time.Duration
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Client) Do(ctx context.Context, req *fasthttp.Request) (*fasthttp.Response, error) {
 | 
					 | 
				
			||||||
	//if req.Header == nil {
 | 
					 | 
				
			||||||
	//	req.Header = c.Headers
 | 
					 | 
				
			||||||
	//}
 | 
					 | 
				
			||||||
	resp := fasthttp.AcquireResponse()
 | 
					 | 
				
			||||||
	return resp, c.client.Do(req, resp)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var MaxRedirects = 0
 | 
					 | 
				
			||||||
var checkRedirect = func(req *http.Request, via []*http.Request) error {
 | 
					 | 
				
			||||||
	if len(via) > MaxRedirects {
 | 
					 | 
				
			||||||
		return http.ErrUseLastResponse
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -29,4 +29,5 @@ type Config struct {
 | 
				
			|||||||
	Headers      http.Header
 | 
						Headers      http.Header
 | 
				
			||||||
	DeadlineTime int
 | 
						DeadlineTime int
 | 
				
			||||||
	EnableFuzzy  bool
 | 
						EnableFuzzy  bool
 | 
				
			||||||
 | 
						ClientType   int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										94
									
								
								pkg/ihttp/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								pkg/ihttp/client.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					package ihttp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"crypto/tls"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/valyala/fasthttp"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						DefaultMaxBodySize = 1024 * 100 // 100k
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						FAST = iota
 | 
				
			||||||
 | 
						STANDARD
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewClient(thread int, timeout int, clientType int) *Client {
 | 
				
			||||||
 | 
						if clientType == FAST {
 | 
				
			||||||
 | 
							return &Client{
 | 
				
			||||||
 | 
								fastClient: &fasthttp.Client{
 | 
				
			||||||
 | 
									TLSConfig: &tls.Config{
 | 
				
			||||||
 | 
										Renegotiation:      tls.RenegotiateOnceAsClient,
 | 
				
			||||||
 | 
										InsecureSkipVerify: true,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									//ReadBufferSize:      20480,
 | 
				
			||||||
 | 
									MaxConnsPerHost:     thread * 2,
 | 
				
			||||||
 | 
									MaxIdleConnDuration: time.Duration(timeout) * time.Second,
 | 
				
			||||||
 | 
									MaxConnWaitTimeout:  time.Duration(timeout) * time.Second,
 | 
				
			||||||
 | 
									ReadTimeout:         time.Duration(timeout) * time.Second,
 | 
				
			||||||
 | 
									WriteTimeout:        time.Duration(timeout) * time.Second,
 | 
				
			||||||
 | 
									MaxResponseBodySize: DefaultMaxBodySize,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								timeout: time.Duration(timeout) * time.Second,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return &Client{
 | 
				
			||||||
 | 
								standardClient: &http.Client{
 | 
				
			||||||
 | 
									Transport: &http.Transport{
 | 
				
			||||||
 | 
										//Proxy: Proxy,
 | 
				
			||||||
 | 
										//TLSHandshakeTimeout : delay * time.Second,
 | 
				
			||||||
 | 
										TLSClientConfig: &tls.Config{
 | 
				
			||||||
 | 
											Renegotiation:      tls.RenegotiateOnceAsClient,
 | 
				
			||||||
 | 
											InsecureSkipVerify: true,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										MaxConnsPerHost: thread,
 | 
				
			||||||
 | 
										IdleConnTimeout: time.Duration(timeout) * time.Second,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Timeout:       time.Second * time.Duration(timeout),
 | 
				
			||||||
 | 
									CheckRedirect: checkRedirect,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								timeout: time.Duration(timeout) * time.Second,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Client struct {
 | 
				
			||||||
 | 
						fastClient     *fasthttp.Client
 | 
				
			||||||
 | 
						standardClient *http.Client
 | 
				
			||||||
 | 
						timeout        time.Duration
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) FastDo(ctx context.Context, req *fasthttp.Request) (*fasthttp.Response, error) {
 | 
				
			||||||
 | 
						resp := fasthttp.AcquireResponse()
 | 
				
			||||||
 | 
						return resp, c.fastClient.Do(req, resp)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) StandardDo(ctx context.Context, req *http.Request) (*http.Response, error) {
 | 
				
			||||||
 | 
						return c.standardClient.Do(req)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) Do(ctx context.Context, req *Request) (*Response, error) {
 | 
				
			||||||
 | 
						if c.fastClient != nil {
 | 
				
			||||||
 | 
							resp, err := c.FastDo(ctx, req.FastRequest)
 | 
				
			||||||
 | 
							return &Response{FastResponse: resp}, err
 | 
				
			||||||
 | 
						} else if c.standardClient != nil {
 | 
				
			||||||
 | 
							resp, err := c.StandardDo(ctx, req.StandardRequest)
 | 
				
			||||||
 | 
							return &Response{StandardResponse: resp}, err
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("not found client")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var MaxRedirects = 0
 | 
				
			||||||
 | 
					var checkRedirect = func(req *http.Request, via []*http.Request) error {
 | 
				
			||||||
 | 
						if len(via) > MaxRedirects {
 | 
				
			||||||
 | 
							return http.ErrUseLastResponse
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								pkg/ihttp/request.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								pkg/ihttp/request.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					package ihttp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/valyala/fasthttp"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Request struct {
 | 
				
			||||||
 | 
						StandardRequest *http.Request
 | 
				
			||||||
 | 
						FastRequest     *fasthttp.Request
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Request) URI() string {
 | 
				
			||||||
 | 
						if r.FastRequest != nil {
 | 
				
			||||||
 | 
							return r.FastRequest.URI().String()
 | 
				
			||||||
 | 
						} else if r.StandardRequest != nil {
 | 
				
			||||||
 | 
							return r.StandardRequest.URL.String()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Request) Host() string {
 | 
				
			||||||
 | 
						if r.FastRequest != nil {
 | 
				
			||||||
 | 
							return string(r.FastRequest.Host())
 | 
				
			||||||
 | 
						} else if r.StandardRequest != nil {
 | 
				
			||||||
 | 
							return r.StandardRequest.Host
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										83
									
								
								pkg/ihttp/response.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								pkg/ihttp/response.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					package ihttp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"github.com/chainreactors/logs"
 | 
				
			||||||
 | 
						"github.com/valyala/fasthttp"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Response struct {
 | 
				
			||||||
 | 
						StandardResponse *http.Response
 | 
				
			||||||
 | 
						FastResponse     *fasthttp.Response
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Response) StatusCode() int {
 | 
				
			||||||
 | 
						if r.FastResponse != nil {
 | 
				
			||||||
 | 
							return r.FastResponse.StatusCode()
 | 
				
			||||||
 | 
						} else if r.StandardResponse != nil {
 | 
				
			||||||
 | 
							return r.StandardResponse.StatusCode
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Response) Body() []byte {
 | 
				
			||||||
 | 
						if r.FastResponse != nil {
 | 
				
			||||||
 | 
							return r.FastResponse.Body()
 | 
				
			||||||
 | 
						} else if r.StandardResponse != nil {
 | 
				
			||||||
 | 
							body := make([]byte, 20480)
 | 
				
			||||||
 | 
							if r.StandardResponse.ContentLength > 0 {
 | 
				
			||||||
 | 
								n, err := io.ReadFull(r.StandardResponse.Body, body)
 | 
				
			||||||
 | 
								_ = r.StandardResponse.Body.Close()
 | 
				
			||||||
 | 
								if err == nil {
 | 
				
			||||||
 | 
									return body
 | 
				
			||||||
 | 
								} else if err == io.ErrUnexpectedEOF {
 | 
				
			||||||
 | 
									return body[:n]
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									logs.Log.Error("readfull failed" + err.Error())
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Response) ContentLength() int {
 | 
				
			||||||
 | 
						if r.FastResponse != nil {
 | 
				
			||||||
 | 
							return r.FastResponse.Header.ContentLength()
 | 
				
			||||||
 | 
						} else if r.StandardResponse != nil {
 | 
				
			||||||
 | 
							return int(r.StandardResponse.ContentLength)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Response) Header() []byte {
 | 
				
			||||||
 | 
						if r.FastResponse != nil {
 | 
				
			||||||
 | 
							return r.FastResponse.Header.Header()
 | 
				
			||||||
 | 
						} else if r.StandardResponse != nil {
 | 
				
			||||||
 | 
							var header bytes.Buffer
 | 
				
			||||||
 | 
							for k, v := range r.StandardResponse.Header {
 | 
				
			||||||
 | 
								for _, i := range v {
 | 
				
			||||||
 | 
									header.WriteString(k + ": " + i + "\r\n")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return header.Bytes()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Response) GetHeader(key string) string {
 | 
				
			||||||
 | 
						if r.FastResponse != nil {
 | 
				
			||||||
 | 
							return string(r.FastResponse.Header.Peek(key))
 | 
				
			||||||
 | 
						} else if r.StandardResponse != nil {
 | 
				
			||||||
 | 
							return r.StandardResponse.Header.Get(key)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								pkg/utils.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								pkg/utils.go
									
									
									
									
									
								
							@ -56,3 +56,23 @@ func RandPath() string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return *(*string)(unsafe.Pointer(&b))
 | 
						return *(*string)(unsafe.Pointer(&b))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func RandHost() string {
 | 
				
			||||||
 | 
						n := 8
 | 
				
			||||||
 | 
						b := make([]byte, n)
 | 
				
			||||||
 | 
						// A rand.Int63() generates 63 random bits, enough for letterIdMax letters!
 | 
				
			||||||
 | 
						for i, cache, remain := n-1, src.Int63(), letterIdMax; i >= 1; {
 | 
				
			||||||
 | 
							if remain == 0 {
 | 
				
			||||||
 | 
								cache, remain = src.Int63(), letterIdMax
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if idx := int(cache & letterIdMask); idx < len(letters) {
 | 
				
			||||||
 | 
								b[i] = letters[idx]
 | 
				
			||||||
 | 
								i--
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							cache >>= letterIdBits
 | 
				
			||||||
 | 
							remain--
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b[5] = byte(0x2e)
 | 
				
			||||||
 | 
						return *(*string)(unsafe.Pointer(&b))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user