mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-18 05:05:23 +00:00
introduce timeouts config in types.Options (#5228)
* introduce timeout variants * update instances and add codeexectimeout * fix test * default to 10s * minor * make timeouts pluggable and rename * remove residual code --------- Co-authored-by: Tarun Koyalwar <tarun@projectdiscovery.io>
This commit is contained in:
parent
d4e81fd9e6
commit
f080d614c3
@ -297,7 +297,6 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.BoolVarP(&options.ShowMatchLine, "show-match-line", "sml", false, "show match lines for file templates, works with extractors only"),
|
||||
flagSet.BoolVar(&options.ZTLS, "ztls", false, "use ztls library with autofallback to standard one for tls13 [Deprecated] autofallback to ztls is enabled by default"), //nolint:all
|
||||
flagSet.StringVar(&options.SNI, "sni", "", "tls sni hostname to use (default: input domain name)"),
|
||||
flagSet.DurationVarP(&options.DialerTimeout, "dialer-timeout", "dt", 0, "timeout for network requests."),
|
||||
flagSet.DurationVarP(&options.DialerKeepAlive, "dialer-keep-alive", "dka", 0, "keep-alive duration for network requests."),
|
||||
flagSet.BoolVarP(&options.AllowLocalFileAccess, "allow-local-file-access", "lfa", false, "allows file (payload) access anywhere on the system"),
|
||||
flagSet.BoolVarP(&options.RestrictLocalNetworkAccess, "restrict-local-network-access", "lna", false, "blocks connections to the local / private network"),
|
||||
@ -306,7 +305,6 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.StringVarP(&options.SourceIP, "source-ip", "sip", "", "source ip address to use for network scan"),
|
||||
flagSet.IntVarP(&options.ResponseReadSize, "response-size-read", "rsr", 0, "max response size to read in bytes"),
|
||||
flagSet.IntVarP(&options.ResponseSaveSize, "response-size-save", "rss", unitutils.Mega, "max response size to read in bytes"),
|
||||
flagSet.DurationVarP(&options.ResponseReadTimeout, "response-read-timeout", "rrt", time.Duration(5*time.Second), "response read timeout in seconds"),
|
||||
flagSet.CallbackVar(resetCallback, "reset", "reset removes all nuclei configuration and data files (including nuclei-templates)"),
|
||||
flagSet.BoolVarP(&options.TlsImpersonate, "tls-impersonate", "tlsi", false, "enable experimental client hello (ja3) tls randomization"),
|
||||
flagSet.StringVarP(&options.HttpApiEndpoint, "http-api-endpoint", "hae", "", "experimental http api endpoint"),
|
||||
|
||||
@ -4,11 +4,11 @@ package compiler
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
contextutil "github.com/projectdiscovery/utils/context"
|
||||
"github.com/projectdiscovery/utils/errkit"
|
||||
stringsutil "github.com/projectdiscovery/utils/strings"
|
||||
@ -38,13 +38,13 @@ type ExecuteOptions struct {
|
||||
// Cleanup is extra cleanup function to be called after execution
|
||||
Cleanup func(runtime *goja.Runtime)
|
||||
|
||||
/// Timeout for this script execution
|
||||
Timeout int
|
||||
// Source is original source of the script
|
||||
Source *string
|
||||
|
||||
Context context.Context
|
||||
|
||||
TimeoutVariants *types.Timeouts
|
||||
|
||||
// Manually exported objects
|
||||
exports map[string]interface{}
|
||||
}
|
||||
@ -79,15 +79,6 @@ func (e ExecuteResult) GetSuccess() bool {
|
||||
return val
|
||||
}
|
||||
|
||||
// Execute executes a script with the default options.
|
||||
func (c *Compiler) Execute(code string, args *ExecuteArgs) (ExecuteResult, error) {
|
||||
p, err := WrapScriptNCompile(code, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.ExecuteWithOptions(p, args, &ExecuteOptions{Context: context.Background()})
|
||||
}
|
||||
|
||||
// ExecuteWithOptions executes a script with the provided options.
|
||||
func (c *Compiler) ExecuteWithOptions(program *goja.Program, args *ExecuteArgs, opts *ExecuteOptions) (ExecuteResult, error) {
|
||||
if opts == nil {
|
||||
@ -106,14 +97,9 @@ func (c *Compiler) ExecuteWithOptions(program *goja.Program, args *ExecuteArgs,
|
||||
// merge all args into templatectx
|
||||
args.TemplateCtx = generators.MergeMaps(args.TemplateCtx, args.Args)
|
||||
|
||||
if opts.Timeout <= 0 || opts.Timeout > 180 {
|
||||
// some js scripts can take longer time so allow configuring timeout
|
||||
// from template but keep it within sane limits (180s)
|
||||
opts.Timeout = JsProtocolTimeout
|
||||
}
|
||||
|
||||
// execute with context and timeout
|
||||
ctx, cancel := context.WithTimeoutCause(opts.Context, time.Duration(opts.Timeout)*time.Second, ErrJSExecDeadline)
|
||||
|
||||
ctx, cancel := context.WithTimeoutCause(opts.Context, opts.TimeoutVariants.JsCompilerExecutionTimeout, ErrJSExecDeadline)
|
||||
defer cancel()
|
||||
// execute the script
|
||||
results, err := contextutil.ExecFuncWithTwoReturns(ctx, func() (val goja.Value, err error) {
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/gologger/levels"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
)
|
||||
|
||||
func TestNewCompilerConsoleDebug(t *testing.T) {
|
||||
@ -18,7 +21,14 @@ func TestNewCompilerConsoleDebug(t *testing.T) {
|
||||
})
|
||||
|
||||
compiler := New()
|
||||
_, err := compiler.Execute("console.log('hello world');", NewExecuteArgs())
|
||||
p, err := WrapScriptNCompile("console.log('hello world');", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = compiler.ExecuteWithOptions(p, NewExecuteArgs(), &ExecuteOptions{Context: context.Background(),
|
||||
TimeoutVariants: &types.Timeouts{JsCompilerExecutionTimeout: time.Duration(20) * time.Second}},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -27,17 +37,6 @@ func TestNewCompilerConsoleDebug(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteResultGetSuccess(t *testing.T) {
|
||||
compiler := New()
|
||||
result, err := compiler.Execute("1+1 == 2", NewExecuteArgs())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.GetSuccess() != true {
|
||||
t.Fatalf("expected true, got=%v", result.GetSuccess())
|
||||
}
|
||||
}
|
||||
|
||||
type noopWriter struct {
|
||||
Callback func(data []byte, level levels.Level)
|
||||
}
|
||||
|
||||
@ -7,26 +7,17 @@ import (
|
||||
// jsprotocolInit
|
||||
|
||||
var (
|
||||
// Per Execution Javascript timeout in seconds
|
||||
JsProtocolTimeout = 10
|
||||
PoolingJsVmConcurrency = 100
|
||||
NonPoolingVMConcurrency = 20
|
||||
JsTimeoutMultiplier = 1.5
|
||||
)
|
||||
|
||||
// Init initializes the javascript protocol
|
||||
func Init(opts *types.Options) error {
|
||||
if opts.Timeout < 10 {
|
||||
// keep existing 10s timeout
|
||||
return nil
|
||||
}
|
||||
|
||||
if opts.JsConcurrency < 100 {
|
||||
// 100 is reasonable default
|
||||
opts.JsConcurrency = 100
|
||||
}
|
||||
// we have dialer timeout set to 10s so js needs to be at least
|
||||
// 15s to return the actual error if not it will be a dialer timeout
|
||||
JsProtocolTimeout = int(float64(opts.Timeout) * JsTimeoutMultiplier)
|
||||
PoolingJsVmConcurrency = opts.JsConcurrency
|
||||
PoolingJsVmConcurrency -= NonPoolingVMConcurrency
|
||||
return nil
|
||||
|
||||
@ -37,8 +37,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
pythonEnvRegex = `os\.getenv\(['"]([^'"]+)['"]\)`
|
||||
TimeoutMultiplier = 6 // timeout multiplier for code protocol
|
||||
pythonEnvRegex = `os\.getenv\(['"]([^'"]+)['"]\)`
|
||||
)
|
||||
|
||||
var (
|
||||
@ -179,9 +178,6 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
|
||||
metaSrc.AddVariable(gozerotypes.Variable{Name: name, Value: v})
|
||||
}
|
||||
|
||||
// set timeout using multiplier
|
||||
timeout := TimeoutMultiplier * request.options.Options.Timeout
|
||||
|
||||
if request.PreCondition != "" {
|
||||
if request.options.Options.Debug || request.options.Options.DebugRequests {
|
||||
gologger.Debug().Msgf("[%s] Executing Precondition for Code request\n", request.TemplateID)
|
||||
@ -199,11 +195,11 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
|
||||
|
||||
result, err := request.options.JsCompiler.ExecuteWithOptions(request.preConditionCompiled, args,
|
||||
&compiler.ExecuteOptions{
|
||||
Timeout: timeout,
|
||||
Source: &request.PreCondition,
|
||||
Callback: registerPreConditionFunctions,
|
||||
Cleanup: cleanUpPreConditionFunctions,
|
||||
Context: input.Context(),
|
||||
TimeoutVariants: request.options.Options.GetTimeouts(),
|
||||
Source: &request.PreCondition,
|
||||
Callback: registerPreConditionFunctions,
|
||||
Cleanup: cleanUpPreConditionFunctions,
|
||||
Context: input.Context(),
|
||||
})
|
||||
if err != nil {
|
||||
return errorutil.NewWithTag(request.TemplateID, "could not execute pre-condition: %s", err)
|
||||
@ -218,7 +214,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeoutCause(input.Context(), time.Duration(timeout)*time.Second, ErrCodeExecutionDeadline)
|
||||
ctx, cancel := context.WithTimeoutCause(input.Context(), request.options.Options.GetTimeouts().CodeExecutionTimeout, ErrCodeExecutionDeadline)
|
||||
defer cancel()
|
||||
// Note: we use contextutil despite the fact that gozero accepts context as argument
|
||||
gOutput, err := contextutil.ExecFuncWithTwoReturns(ctx, func() (*gozerotypes.Result, error) {
|
||||
|
||||
@ -34,9 +34,7 @@ func Init(options *types.Options) error {
|
||||
|
||||
lfaAllowed = options.AllowLocalFileAccess
|
||||
opts := fastdialer.DefaultOptions
|
||||
if options.DialerTimeout > 0 {
|
||||
opts.DialerTimeout = options.DialerTimeout
|
||||
}
|
||||
opts.DialerTimeout = options.GetTimeouts().DialTimeout
|
||||
if options.DialerKeepAlive > 0 {
|
||||
opts.DialerKeepAlive = options.DialerKeepAlive
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
|
||||
request.Raw[i] = strings.ReplaceAll(raw, "\n", "\r\n")
|
||||
}
|
||||
}
|
||||
request.rawhttpClient = httpclientpool.GetRawHTTP(options.Options)
|
||||
request.rawhttpClient = httpclientpool.GetRawHTTP(options)
|
||||
}
|
||||
if len(request.Matchers) > 0 || len(request.Extractors) > 0 {
|
||||
compiled := &request.Operators
|
||||
|
||||
@ -17,6 +17,7 @@ import (
|
||||
"golang.org/x/net/publicsuffix"
|
||||
|
||||
"github.com/projectdiscovery/fastdialer/fastdialer/ja3/impersonate"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
@ -31,28 +32,14 @@ var (
|
||||
forceMaxRedirects int
|
||||
normalClient *retryablehttp.Client
|
||||
clientPool *mapsutil.SyncLockMap[string, *retryablehttp.Client]
|
||||
// MaxResponseHeaderTimeout is the timeout for response headers
|
||||
// to be read from the server (this prevents infinite hang started by server if any)
|
||||
// Note: this will be overridden temporarily when using @timeout request annotation
|
||||
MaxResponseHeaderTimeout = time.Duration(10) * time.Second
|
||||
// HttpTimeoutMultiplier is the multiplier for the http timeout
|
||||
HttpTimeoutMultiplier = 3
|
||||
)
|
||||
|
||||
// GetHttpTimeout returns the http timeout for the client
|
||||
func GetHttpTimeout(opts *types.Options) time.Duration {
|
||||
return time.Duration(opts.Timeout*HttpTimeoutMultiplier) * time.Second
|
||||
}
|
||||
|
||||
// Init initializes the clientpool implementation
|
||||
func Init(options *types.Options) error {
|
||||
// Don't create clients if already created in the past.
|
||||
if normalClient != nil {
|
||||
return nil
|
||||
}
|
||||
if options.Timeout > 10 {
|
||||
MaxResponseHeaderTimeout = time.Duration(options.Timeout) * time.Second
|
||||
}
|
||||
if options.ShouldFollowHTTPRedirects() {
|
||||
forceMaxRedirects = options.MaxRedirects
|
||||
}
|
||||
@ -143,7 +130,7 @@ func (c *Configuration) HasStandardOptions() bool {
|
||||
}
|
||||
|
||||
// GetRawHTTP returns the rawhttp request client
|
||||
func GetRawHTTP(options *types.Options) *rawhttp.Client {
|
||||
func GetRawHTTP(options *protocols.ExecutorOptions) *rawhttp.Client {
|
||||
if rawHttpClient == nil {
|
||||
rawHttpOptions := rawhttp.DefaultOptions
|
||||
if types.ProxyURL != "" {
|
||||
@ -153,7 +140,7 @@ func GetRawHTTP(options *types.Options) *rawhttp.Client {
|
||||
} else if protocolstate.Dialer != nil {
|
||||
rawHttpOptions.FastDialer = protocolstate.Dialer
|
||||
}
|
||||
rawHttpOptions.Timeout = GetHttpTimeout(options)
|
||||
rawHttpOptions.Timeout = options.Options.GetTimeouts().HttpTimeout
|
||||
rawHttpClient = rawhttp.NewClient(rawHttpOptions)
|
||||
}
|
||||
return rawHttpClient
|
||||
@ -239,7 +226,7 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
|
||||
}
|
||||
|
||||
// responseHeaderTimeout is max timeout for response headers to be read
|
||||
responseHeaderTimeout := MaxResponseHeaderTimeout
|
||||
responseHeaderTimeout := options.GetTimeouts().HttpResponseHeaderTimeout
|
||||
if configuration.ResponseHeaderTimeout != 0 {
|
||||
responseHeaderTimeout = configuration.ResponseHeaderTimeout
|
||||
}
|
||||
@ -308,7 +295,7 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
|
||||
CheckRedirect: makeCheckRedirectFunc(redirectFlow, maxRedirects),
|
||||
}
|
||||
if !configuration.NoTimeout {
|
||||
httpclient.Timeout = GetHttpTimeout(options)
|
||||
httpclient.Timeout = options.GetTimeouts().HttpTimeout
|
||||
}
|
||||
client := retryablehttp.NewWithHTTPClient(httpclient, retryableHttpOptions)
|
||||
if jar != nil {
|
||||
|
||||
@ -483,7 +483,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
|
||||
request.options.RateLimitTake()
|
||||
|
||||
ctx := request.newContext(input)
|
||||
ctxWithTimeout, cancel := context.WithTimeoutCause(ctx, httpclientpool.GetHttpTimeout(request.options.Options), ErrHttpEngineRequestDeadline)
|
||||
ctxWithTimeout, cancel := context.WithTimeoutCause(ctx, request.options.Options.GetTimeouts().HttpTimeout, ErrHttpEngineRequestDeadline)
|
||||
defer cancel()
|
||||
|
||||
generatedHttpRequest, err := generator.Make(ctxWithTimeout, input, data, payloads, dynamicValue)
|
||||
|
||||
@ -130,6 +130,10 @@ func (r *Request) parseAnnotations(rawRequest string, request *retryablehttp.Req
|
||||
if duration := reTimeoutAnnotation.FindStringSubmatch(rawRequest); len(duration) > 0 {
|
||||
value := strings.TrimSpace(duration[1])
|
||||
if parsed, err := time.ParseDuration(value); err == nil {
|
||||
// to avoid dos via timeout request annotation in http template we set it to maximum of 2 minutes
|
||||
if parsed > 2*time.Minute {
|
||||
parsed = 2 * time.Minute
|
||||
}
|
||||
//nolint:govet // cancelled automatically by withTimeout
|
||||
// global timeout is overridden by annotation by replacing context
|
||||
ctx, overrides.cancelFunc = context.WithTimeoutCause(context.TODO(), parsed, ErrTimeoutAnnotationDeadline)
|
||||
@ -140,7 +144,7 @@ func (r *Request) parseAnnotations(rawRequest string, request *retryablehttp.Req
|
||||
} else {
|
||||
//nolint:govet // cancelled automatically by withTimeout
|
||||
// global timeout is overridden by annotation by replacing context
|
||||
ctx, overrides.cancelFunc = context.WithTimeoutCause(context.TODO(), httpclientpool.GetHttpTimeout(r.options.Options), ErrRequestTimeoutDeadline)
|
||||
ctx, overrides.cancelFunc = context.WithTimeoutCause(context.TODO(), r.options.Options.GetTimeouts().HttpTimeout, ErrRequestTimeoutDeadline)
|
||||
request = request.Clone(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,9 +65,6 @@ type Request struct {
|
||||
// Code contains code to execute for the javascript request.
|
||||
Code string `yaml:"code,omitempty" json:"code,omitempty" jsonschema:"title=code to execute in javascript,description=Executes inline javascript code for the request"`
|
||||
// description: |
|
||||
// Timeout in seconds is optional timeout for each javascript script execution (i.e init, pre-condition, code)
|
||||
Timeout int `yaml:"timeout,omitempty" json:"timeout,omitempty" jsonschema:"title=timeout for javascript execution,description=Timeout in seconds is optional timeout for entire javascript script execution"`
|
||||
// description: |
|
||||
// StopAtFirstMatch stops processing the request at first match.
|
||||
StopAtFirstMatch bool `yaml:"stop-at-first-match,omitempty" json:"stop-at-first-match,omitempty" jsonschema:"title=stop at first match,description=Stop the execution after a match is found"`
|
||||
// description: |
|
||||
@ -153,9 +150,9 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
|
||||
}
|
||||
|
||||
opts := &compiler.ExecuteOptions{
|
||||
Timeout: request.Timeout,
|
||||
Source: &request.Init,
|
||||
Context: context.Background(),
|
||||
TimeoutVariants: request.options.Options.GetTimeouts(),
|
||||
Source: &request.Init,
|
||||
Context: context.Background(),
|
||||
}
|
||||
// register 'export' function to export variables from init code
|
||||
// these are saved in args and are available in pre-condition and request code
|
||||
@ -345,7 +342,10 @@ func (request *Request) ExecuteWithResults(target *contextargs.Context, dynamicV
|
||||
argsCopy.TemplateCtx = templateCtx.GetAll()
|
||||
|
||||
result, err := request.options.JsCompiler.ExecuteWithOptions(request.preConditionCompiled, argsCopy,
|
||||
&compiler.ExecuteOptions{Timeout: request.Timeout, Source: &request.PreCondition, Context: target.Context()})
|
||||
&compiler.ExecuteOptions{
|
||||
TimeoutVariants: requestOptions.Options.GetTimeouts(),
|
||||
Source: &request.PreCondition, Context: target.Context(),
|
||||
})
|
||||
if err != nil {
|
||||
return errorutil.NewWithTag(request.TemplateID, "could not execute pre-condition: %s", err)
|
||||
}
|
||||
@ -500,7 +500,11 @@ func (request *Request) executeRequestWithPayloads(hostPort string, input *conte
|
||||
}
|
||||
|
||||
results, err := request.options.JsCompiler.ExecuteWithOptions(request.scriptCompiled, argsCopy,
|
||||
&compiler.ExecuteOptions{Timeout: request.Timeout, Source: &request.Code, Context: input.Context()})
|
||||
&compiler.ExecuteOptions{
|
||||
TimeoutVariants: requestOptions.Options.GetTimeouts(),
|
||||
Source: &request.Code,
|
||||
Context: input.Context(),
|
||||
})
|
||||
if err != nil {
|
||||
// shouldn't fail even if it returned error instead create a failure event
|
||||
results = compiler.ExecuteResult{"success": false, "error": err.Error()}
|
||||
|
||||
@ -327,7 +327,7 @@ func (request *Request) executeRequestWithPayloads(variables map[string]interfac
|
||||
}
|
||||
|
||||
if input.Read > 0 {
|
||||
buffer, err := ConnReadNWithTimeout(conn, int64(input.Read), request.options.Options.ResponseReadTimeout)
|
||||
buffer, err := ConnReadNWithTimeout(conn, int64(input.Read), request.options.Options.GetTimeouts().TcpReadTimeout)
|
||||
if err != nil {
|
||||
return errorutil.NewWithErr(err).Msgf("could not read response from connection")
|
||||
}
|
||||
@ -377,7 +377,7 @@ func (request *Request) executeRequestWithPayloads(variables map[string]interfac
|
||||
bufferSize = -1
|
||||
}
|
||||
|
||||
final, err := ConnReadNWithTimeout(conn, int64(bufferSize), request.options.Options.ResponseReadTimeout)
|
||||
final, err := ConnReadNWithTimeout(conn, int64(bufferSize), request.options.Options.GetTimeouts().TcpReadTimeout)
|
||||
if err != nil {
|
||||
request.options.Output.Request(request.options.TemplatePath, address, request.Type().String(), err)
|
||||
gologger.Verbose().Msgf("could not read more data from %s: %s", actualAddress, err)
|
||||
|
||||
@ -39,15 +39,15 @@ func setup() {
|
||||
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
|
||||
|
||||
executerOpts = protocols.ExecutorOptions{
|
||||
Output: testutils.NewMockOutputWriter(options.OmitTemplate),
|
||||
Options: options,
|
||||
Progress: progressImpl,
|
||||
ProjectFile: nil,
|
||||
IssuesClient: nil,
|
||||
Browser: nil,
|
||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
||||
Parser: templates.NewParser(),
|
||||
Output: testutils.NewMockOutputWriter(options.OmitTemplate),
|
||||
Options: options,
|
||||
Progress: progressImpl,
|
||||
ProjectFile: nil,
|
||||
IssuesClient: nil,
|
||||
Browser: nil,
|
||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
||||
Parser: templates.NewParser(),
|
||||
}
|
||||
workflowLoader, err := workflow.NewLoader(&executerOpts)
|
||||
if err != nil {
|
||||
|
||||
@ -76,7 +76,6 @@ var DefaultOptions = &types.Options{
|
||||
InteractionsPollDuration: 5,
|
||||
GitHubTemplateRepo: []string{},
|
||||
GitHubToken: "",
|
||||
ResponseReadTimeout: time.Second * 5,
|
||||
}
|
||||
|
||||
// TemplateInfo contains info for a mock executed template.
|
||||
@ -90,17 +89,17 @@ type TemplateInfo struct {
|
||||
func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecutorOptions {
|
||||
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
|
||||
executerOpts := &protocols.ExecutorOptions{
|
||||
TemplateID: info.ID,
|
||||
TemplateInfo: info.Info,
|
||||
TemplatePath: info.Path,
|
||||
Output: NewMockOutputWriter(options.OmitTemplate),
|
||||
Options: options,
|
||||
Progress: progressImpl,
|
||||
ProjectFile: nil,
|
||||
IssuesClient: nil,
|
||||
Browser: nil,
|
||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
||||
TemplateID: info.ID,
|
||||
TemplateInfo: info.Info,
|
||||
TemplatePath: info.Path,
|
||||
Output: NewMockOutputWriter(options.OmitTemplate),
|
||||
Options: options,
|
||||
Progress: progressImpl,
|
||||
ProjectFile: nil,
|
||||
IssuesClient: nil,
|
||||
Browser: nil,
|
||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
||||
}
|
||||
executerOpts.CreateTemplateCtxStore()
|
||||
return executerOpts
|
||||
|
||||
@ -27,15 +27,15 @@ func setup() {
|
||||
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
|
||||
|
||||
executerOpts = protocols.ExecutorOptions{
|
||||
Output: testutils.NewMockOutputWriter(options.OmitTemplate),
|
||||
Options: options,
|
||||
Progress: progressImpl,
|
||||
ProjectFile: nil,
|
||||
IssuesClient: nil,
|
||||
Browser: nil,
|
||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
||||
Parser: templates.NewParser(),
|
||||
Output: testutils.NewMockOutputWriter(options.OmitTemplate),
|
||||
Options: options,
|
||||
Progress: progressImpl,
|
||||
ProjectFile: nil,
|
||||
IssuesClient: nil,
|
||||
Browser: nil,
|
||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
||||
Parser: templates.NewParser(),
|
||||
}
|
||||
workflowLoader, err := workflow.NewLoader(&executerOpts)
|
||||
if err != nil {
|
||||
|
||||
@ -278,8 +278,6 @@ type Options struct {
|
||||
SNI string
|
||||
// InputFileMode specifies the mode of input file (jsonl, burp, openapi, swagger, etc)
|
||||
InputFileMode string
|
||||
// DialerTimeout sets the timeout for network requests.
|
||||
DialerTimeout time.Duration
|
||||
// DialerKeepAlive sets the keep alive duration for network requests.
|
||||
DialerKeepAlive time.Duration
|
||||
// Interface to use for network scan
|
||||
@ -292,8 +290,6 @@ type Options struct {
|
||||
ResponseReadSize int
|
||||
// ResponseSaveSize is the maximum size of response to save
|
||||
ResponseSaveSize int
|
||||
// ResponseReadTimeout is response read timeout in seconds
|
||||
ResponseReadTimeout time.Duration
|
||||
// Health Check
|
||||
HealthCheck bool
|
||||
// Time to wait between each input read operation before closing the stream
|
||||
@ -406,6 +402,79 @@ type Options struct {
|
||||
HttpApiEndpoint string
|
||||
// ListTemplateProfiles lists all available template profiles
|
||||
ListTemplateProfiles bool
|
||||
// timeouts contains various types of timeouts used in nuclei
|
||||
// these timeouts are derived from dial-timeout (-timeout) with known multipliers
|
||||
// This is internally managed and does not need to be set by user by explicitly setting
|
||||
// this overrides the default/derived one
|
||||
timeouts *Timeouts
|
||||
}
|
||||
|
||||
// SetTimeouts sets the timeout variants to use for the executor
|
||||
func (opts *Options) SetTimeouts(t *Timeouts) {
|
||||
opts.timeouts = t
|
||||
}
|
||||
|
||||
// GetTimeouts returns the timeout variants to use for the executor
|
||||
func (eo *Options) GetTimeouts() *Timeouts {
|
||||
if eo.timeouts != nil {
|
||||
// redundant but apply to avoid any potential issues
|
||||
eo.timeouts.ApplyDefaults()
|
||||
return eo.timeouts
|
||||
}
|
||||
// set timeout variant value
|
||||
eo.timeouts = NewTimeoutVariant(eo.Timeout)
|
||||
eo.timeouts.ApplyDefaults()
|
||||
return eo.timeouts
|
||||
}
|
||||
|
||||
// Timeouts is a struct that contains all the timeout variants for nuclei
|
||||
// dialer timeout is used to derive other timeouts
|
||||
type Timeouts struct {
|
||||
// DialTimeout for fastdialer (default 10s)
|
||||
DialTimeout time.Duration
|
||||
// Tcp(Network Protocol) Read From Connection Timeout (default 5s)
|
||||
TcpReadTimeout time.Duration
|
||||
// Http Response Header Timeout (default 10s)
|
||||
// this timeout prevents infinite hangs started by server if any
|
||||
// this is temporarily overridden when using @timeout request annotation
|
||||
HttpResponseHeaderTimeout time.Duration
|
||||
// HttpTimeout for http client (default -> 3 x dial-timeout = 30s)
|
||||
HttpTimeout time.Duration
|
||||
// JsCompilerExec timeout/deadline (default -> 2 x dial-timeout = 20s)
|
||||
JsCompilerExecutionTimeout time.Duration
|
||||
// CodeExecutionTimeout for code execution (default -> 3 x dial-timeout = 30s)
|
||||
CodeExecutionTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewTimeoutVariant creates a new timeout variant with the given dial timeout in seconds
|
||||
func NewTimeoutVariant(dialTimeoutSec int) *Timeouts {
|
||||
tv := &Timeouts{
|
||||
DialTimeout: time.Duration(dialTimeoutSec) * time.Second,
|
||||
}
|
||||
tv.ApplyDefaults()
|
||||
return tv
|
||||
}
|
||||
|
||||
// ApplyDefaults applies default values to timeout variants when missing
|
||||
func (tv *Timeouts) ApplyDefaults() {
|
||||
if tv.DialTimeout == 0 {
|
||||
tv.DialTimeout = 10 * time.Second
|
||||
}
|
||||
if tv.TcpReadTimeout == 0 {
|
||||
tv.TcpReadTimeout = 5 * time.Second
|
||||
}
|
||||
if tv.HttpResponseHeaderTimeout == 0 {
|
||||
tv.HttpResponseHeaderTimeout = 10 * time.Second
|
||||
}
|
||||
if tv.HttpTimeout == 0 {
|
||||
tv.HttpTimeout = 3 * tv.DialTimeout
|
||||
}
|
||||
if tv.JsCompilerExecutionTimeout == 0 {
|
||||
tv.JsCompilerExecutionTimeout = 2 * tv.DialTimeout
|
||||
}
|
||||
if tv.CodeExecutionTimeout == 0 {
|
||||
tv.CodeExecutionTimeout = 3 * tv.DialTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldLoadResume resume file
|
||||
@ -444,7 +513,6 @@ func DefaultOptions() *Options {
|
||||
MaxHostError: 30,
|
||||
ResponseReadSize: 10 * unitutils.Mega,
|
||||
ResponseSaveSize: unitutils.Mega,
|
||||
ResponseReadTimeout: 5 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user