mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 15:55:26 +00:00
per-target rate limit
This commit is contained in:
parent
44eeb5a60b
commit
d075a4e217
2
go.mod
2
go.mod
@ -99,7 +99,7 @@ require (
|
|||||||
github.com/projectdiscovery/mapcidr v1.1.34
|
github.com/projectdiscovery/mapcidr v1.1.34
|
||||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
|
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
|
||||||
github.com/projectdiscovery/networkpolicy v0.1.18
|
github.com/projectdiscovery/networkpolicy v0.1.18
|
||||||
github.com/projectdiscovery/ratelimit v0.0.81
|
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819165347-d56e782c656d
|
||||||
github.com/projectdiscovery/rdap v0.9.0
|
github.com/projectdiscovery/rdap v0.9.0
|
||||||
github.com/projectdiscovery/sarif v0.0.1
|
github.com/projectdiscovery/sarif v0.0.1
|
||||||
github.com/projectdiscovery/tlsx v1.1.9
|
github.com/projectdiscovery/tlsx v1.1.9
|
||||||
|
|||||||
6
go.sum
6
go.sum
@ -805,6 +805,12 @@ github.com/projectdiscovery/networkpolicy v0.1.18 h1:DAeP73SvcuT4evaohNS7BPELw+V
|
|||||||
github.com/projectdiscovery/networkpolicy v0.1.18/go.mod h1:2yWanKsU2oBZ75ch94IsEQy6hByFp+3oTiSyC6ew3TE=
|
github.com/projectdiscovery/networkpolicy v0.1.18/go.mod h1:2yWanKsU2oBZ75ch94IsEQy6hByFp+3oTiSyC6ew3TE=
|
||||||
github.com/projectdiscovery/ratelimit v0.0.81 h1:u6lW+rAhS/UO0amHTYmYLipPK8NEotA9521hdojBtgI=
|
github.com/projectdiscovery/ratelimit v0.0.81 h1:u6lW+rAhS/UO0amHTYmYLipPK8NEotA9521hdojBtgI=
|
||||||
github.com/projectdiscovery/ratelimit v0.0.81/go.mod h1:tK04WXHuC4i6AsFkByInODSNf45gd9sfaMHzmy2bAsA=
|
github.com/projectdiscovery/ratelimit v0.0.81/go.mod h1:tK04WXHuC4i6AsFkByInODSNf45gd9sfaMHzmy2bAsA=
|
||||||
|
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819014026-b6ac32486d12 h1:oS/0Oe6tv7SG2zoFBofwvoB3mfDb5Yk76np4zU0Mcg8=
|
||||||
|
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819014026-b6ac32486d12/go.mod h1:z076BrLkBb5yS7uhHNoCTf8X/BvFSGRxwQ8EzEL9afM=
|
||||||
|
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819164203-5e0837ee74a5 h1:tulP7aVzZsWlXbWo6W78nVFqJ05c6zSS8dsos/cBaSY=
|
||||||
|
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819164203-5e0837ee74a5/go.mod h1:z076BrLkBb5yS7uhHNoCTf8X/BvFSGRxwQ8EzEL9afM=
|
||||||
|
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819165347-d56e782c656d h1:zUptoE5gh4gyJsbcHfNUEKgdoieyAHW2hCfWXZ/Zye4=
|
||||||
|
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819165347-d56e782c656d/go.mod h1:z076BrLkBb5yS7uhHNoCTf8X/BvFSGRxwQ8EzEL9afM=
|
||||||
github.com/projectdiscovery/rawhttp v0.1.90 h1:LOSZ6PUH08tnKmWsIwvwv1Z/4zkiYKYOSZ6n+8RFKtw=
|
github.com/projectdiscovery/rawhttp v0.1.90 h1:LOSZ6PUH08tnKmWsIwvwv1Z/4zkiYKYOSZ6n+8RFKtw=
|
||||||
github.com/projectdiscovery/rawhttp v0.1.90/go.mod h1:VZYAM25UI/wVB3URZ95ZaftgOnsbphxyAw/XnQRRz4Y=
|
github.com/projectdiscovery/rawhttp v0.1.90/go.mod h1:VZYAM25UI/wVB3URZ95ZaftgOnsbphxyAw/XnQRRz4Y=
|
||||||
github.com/projectdiscovery/rdap v0.9.0 h1:wPhHx5pQ2QI+WGhyNb2PjhTl0NtB39Nk7YFZ9cp8ZGA=
|
github.com/projectdiscovery/rdap v0.9.0 h1:wPhHx5pQ2QI+WGhyNb2PjhTl0NtB39Nk7YFZ9cp8ZGA=
|
||||||
|
|||||||
@ -87,7 +87,7 @@ type Runner struct {
|
|||||||
colorizer aurora.Aurora
|
colorizer aurora.Aurora
|
||||||
issuesClient reporting.Client
|
issuesClient reporting.Client
|
||||||
browser *engine.Browser
|
browser *engine.Browser
|
||||||
rateLimiter *ratelimit.Limiter
|
rateLimiter *ratelimit.AutoLimiter
|
||||||
hostErrors hosterrorscache.CacheInterface
|
hostErrors hosterrorscache.CacheInterface
|
||||||
resumeCfg *types.ResumeCfg
|
resumeCfg *types.ResumeCfg
|
||||||
pprofServer *pprofutil.PprofServer
|
pprofServer *pprofutil.PprofServer
|
||||||
@ -384,11 +384,17 @@ func New(options *types.Options) (*Runner, error) {
|
|||||||
if options.RateLimit > 0 && options.RateLimitDuration == 0 {
|
if options.RateLimit > 0 && options.RateLimitDuration == 0 {
|
||||||
options.RateLimitDuration = time.Second
|
options.RateLimitDuration = time.Second
|
||||||
}
|
}
|
||||||
|
var ratelimiter *ratelimit.AutoLimiter
|
||||||
if options.RateLimit == 0 && options.RateLimitDuration == 0 {
|
if options.RateLimit == 0 && options.RateLimitDuration == 0 {
|
||||||
runner.rateLimiter = ratelimit.NewUnlimited(context.Background())
|
ratelimiter = ratelimit.NewAutoLimiter(context.Background(), ratelimit.WithUnlimited())
|
||||||
} else {
|
} else {
|
||||||
runner.rateLimiter = ratelimit.New(context.Background(), uint(options.RateLimit), options.RateLimitDuration)
|
ratelimiter = ratelimit.NewAutoLimiter(
|
||||||
|
context.Background(),
|
||||||
|
ratelimit.WithMaxCount(uint(options.RateLimit)),
|
||||||
|
ratelimit.WithDuration(options.RateLimitDuration),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
runner.rateLimiter = ratelimiter
|
||||||
|
|
||||||
if tmpDir, err := os.MkdirTemp("", "nuclei-tmp-*"); err == nil {
|
if tmpDir, err := os.MkdirTemp("", "nuclei-tmp-*"); err == nil {
|
||||||
runner.tmpDir = tmpDir
|
runner.tmpDir = tmpDir
|
||||||
|
|||||||
@ -50,7 +50,7 @@ type NucleiExecutorOptions struct {
|
|||||||
Progress progress.Progress
|
Progress progress.Progress
|
||||||
Catalog catalog.Catalog
|
Catalog catalog.Catalog
|
||||||
IssuesClient reporting.Client
|
IssuesClient reporting.Client
|
||||||
RateLimiter *ratelimit.Limiter
|
RateLimiter *ratelimit.AutoLimiter
|
||||||
Interactsh *interactsh.Client
|
Interactsh *interactsh.Client
|
||||||
ProjectFile *projectfile.ProjectFile
|
ProjectFile *projectfile.ProjectFile
|
||||||
Browser *browserEngine.Browser
|
Browser *browserEngine.Browser
|
||||||
|
|||||||
@ -151,7 +151,7 @@ func (request *Request) execute(input *contextargs.Context, domain string, metad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
request.options.RateLimitTake()
|
request.options.RateLimitTake(input)
|
||||||
|
|
||||||
// Send the request to the target servers
|
// Send the request to the target servers
|
||||||
response, err := dnsClient.Do(compiledRequest)
|
response, err := dnsClient.Do(compiledRequest)
|
||||||
|
|||||||
@ -291,7 +291,7 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// putting ratelimiter here prevents any unnecessary waiting if any
|
// putting ratelimiter here prevents any unnecessary waiting if any
|
||||||
request.options.RateLimitTake()
|
request.options.RateLimitTake(input)
|
||||||
|
|
||||||
// after ratelimit take, check if we need to stop
|
// after ratelimit take, check if we need to stop
|
||||||
if spmHandler.FoundFirstMatch() || request.isUnresponsiveAddress(updatedInput) || spmHandler.Cancelled() {
|
if spmHandler.FoundFirstMatch() || request.isUnresponsiveAddress(updatedInput) || spmHandler.Cancelled() {
|
||||||
@ -470,7 +470,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
|
|||||||
executeFunc := func(data string, payloads, dynamicValue map[string]interface{}) (bool, error) {
|
executeFunc := func(data string, payloads, dynamicValue map[string]interface{}) (bool, error) {
|
||||||
hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
|
hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
|
||||||
|
|
||||||
request.options.RateLimitTake()
|
request.options.RateLimitTake(input)
|
||||||
|
|
||||||
ctx := request.newContext(input)
|
ctx := request.newContext(input)
|
||||||
ctxWithTimeout, cancel := context.WithTimeoutCause(ctx, request.options.Options.GetTimeouts().HttpTimeout, ErrHttpEngineRequestDeadline)
|
ctxWithTimeout, cancel := context.WithTimeoutCause(ctx, request.options.Options.GetTimeouts().HttpTimeout, ErrHttpEngineRequestDeadline)
|
||||||
|
|||||||
@ -181,7 +181,7 @@ func (request *Request) executeGeneratedFuzzingRequest(gr fuzz.GeneratedRequest,
|
|||||||
if request.options.HostErrorsCache != nil && request.options.HostErrorsCache.Check(request.options.ProtocolType.String(), input) {
|
if request.options.HostErrorsCache != nil && request.options.HostErrorsCache.Check(request.options.ProtocolType.String(), input) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
request.options.RateLimitTake()
|
request.options.RateLimitTake(input)
|
||||||
req := &generatedRequest{
|
req := &generatedRequest{
|
||||||
request: gr.Request,
|
request: gr.Request,
|
||||||
dynamicValues: gr.DynamicValues,
|
dynamicValues: gr.DynamicValues,
|
||||||
|
|||||||
@ -78,7 +78,7 @@ type ExecutorOptions struct {
|
|||||||
// Progress is a progress client for scan reporting
|
// Progress is a progress client for scan reporting
|
||||||
Progress progress.Progress
|
Progress progress.Progress
|
||||||
// RateLimiter is a rate-limiter for limiting sent number of requests.
|
// RateLimiter is a rate-limiter for limiting sent number of requests.
|
||||||
RateLimiter *ratelimit.Limiter
|
RateLimiter *ratelimit.AutoLimiter
|
||||||
// Catalog is a template catalog implementation for nuclei
|
// Catalog is a template catalog implementation for nuclei
|
||||||
Catalog catalog.Catalog
|
Catalog catalog.Catalog
|
||||||
// ProjectFile is the project file for nuclei
|
// ProjectFile is the project file for nuclei
|
||||||
@ -143,7 +143,7 @@ type ExecutorOptions struct {
|
|||||||
// todo: centralizing components is not feasible with current clogged architecture
|
// todo: centralizing components is not feasible with current clogged architecture
|
||||||
// a possible approach could be an internal event bus with pub-subs? This would be less invasive than
|
// a possible approach could be an internal event bus with pub-subs? This would be less invasive than
|
||||||
// reworking dep injection from scratch
|
// reworking dep injection from scratch
|
||||||
func (e *ExecutorOptions) RateLimitTake() {
|
func (e *ExecutorOptions) RateLimitTake(ctx *contextargs.Context) {
|
||||||
// The code below can race and there isn't a great way to fix this without adding an idempotent
|
// The code below can race and there isn't a great way to fix this without adding an idempotent
|
||||||
// function to the rate limiter implementation. For now, stick with whatever rate is already set.
|
// function to the rate limiter implementation. For now, stick with whatever rate is already set.
|
||||||
/*
|
/*
|
||||||
@ -152,8 +152,11 @@ func (e *ExecutorOptions) RateLimitTake() {
|
|||||||
e.RateLimiter.SetDuration(e.Options.RateLimitDuration)
|
e.RateLimiter.SetDuration(e.Options.RateLimitDuration)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if e.RateLimiter != nil {
|
if hostErrorCache, ok := e.HostErrorsCache.(*hosterrorscache.Cache); ok {
|
||||||
e.RateLimiter.Take()
|
key := hostErrorCache.GetKeyFromContext(ctx, nil)
|
||||||
|
if e.RateLimiter != nil {
|
||||||
|
e.RateLimiter.Take(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -88,6 +88,11 @@ type TemplateInfo struct {
|
|||||||
// NewMockExecuterOptions creates a new mock executeroptions struct
|
// NewMockExecuterOptions creates a new mock executeroptions struct
|
||||||
func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecutorOptions {
|
func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecutorOptions {
|
||||||
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
|
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
|
||||||
|
rateLimiter := ratelimit.NewAutoLimiter(
|
||||||
|
context.Background(),
|
||||||
|
ratelimit.WithMaxCount(uint(options.RateLimit)),
|
||||||
|
ratelimit.WithDuration(time.Second),
|
||||||
|
)
|
||||||
executerOpts := &protocols.ExecutorOptions{
|
executerOpts := &protocols.ExecutorOptions{
|
||||||
TemplateID: info.ID,
|
TemplateID: info.ID,
|
||||||
TemplateInfo: info.Info,
|
TemplateInfo: info.Info,
|
||||||
@ -99,7 +104,7 @@ func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protoco
|
|||||||
IssuesClient: nil,
|
IssuesClient: nil,
|
||||||
Browser: nil,
|
Browser: nil,
|
||||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
RateLimiter: rateLimiter,
|
||||||
}
|
}
|
||||||
executerOpts.CreateTemplateCtxStore()
|
executerOpts.CreateTemplateCtxStore()
|
||||||
return executerOpts
|
return executerOpts
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user