From c801e3bbffd59cb03d51d96936019c2e356a2721 Mon Sep 17 00:00:00 2001 From: Tarun Koyalwar Date: Fri, 13 Sep 2024 19:30:21 +0530 Subject: [PATCH] scan error formatting --- pkg/scan/scan_context.go | 27 +++++++++--------------- pkg/tmplexec/exec.go | 43 +++++++++++++++++---------------------- pkg/tmplexec/interface.go | 39 +++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 41 deletions(-) diff --git a/pkg/scan/scan_context.go b/pkg/scan/scan_context.go index 45456ddcac..51b98007a6 100644 --- a/pkg/scan/scan_context.go +++ b/pkg/scan/scan_context.go @@ -8,6 +8,7 @@ import ( "github.com/projectdiscovery/nuclei/v3/pkg/output" "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs" + "github.com/projectdiscovery/utils/errkit" ) type ScanContextOption func(*ScanContext) @@ -30,7 +31,7 @@ type ScanContext struct { OnWarning func(string) // unexported state fields - errors []error + error error warnings []string events []*output.InternalWrappedEvent results []*output.ResultEvent @@ -52,8 +53,8 @@ func (s *ScanContext) Context() context.Context { return s.ctx } -func (s *ScanContext) GenerateErrorMessage() string { - return joinErrors(s.errors) +func (s *ScanContext) GenerateErrorMessage() error { + return s.error } // GenerateResult returns final results slice from all events @@ -94,13 +95,16 @@ func (s *ScanContext) LogError(err error) { if err == nil { return } - if s.OnError != nil { s.OnError(err) } - s.errors = append(s.errors, err) + if s.error == nil { + s.error = err + } else { + s.error = errkit.Append(s.error, err) + } - errorMessage := s.GenerateErrorMessage() + errorMessage := s.GenerateErrorMessage().Error() for _, result := range s.results { result.Error = errorMessage @@ -129,14 +133,3 @@ func (s *ScanContext) LogWarning(format string, args ...any) { } } } - -// joinErrors joins multiple errors and returns a single error string -func joinErrors(errors []error) string { - var errorMessages []string - for _, e := range errors { - if e != nil { - errorMessages = append(errorMessages, e.Error()) - } - } - return strings.Join(errorMessages, "; ") -} diff --git a/pkg/tmplexec/exec.go b/pkg/tmplexec/exec.go index 4ca9badf70..149deaa4d5 100644 --- a/pkg/tmplexec/exec.go +++ b/pkg/tmplexec/exec.go @@ -20,7 +20,6 @@ import ( "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto" - "github.com/projectdiscovery/nuclei/v3/pkg/types/nucleierr" "github.com/projectdiscovery/utils/errkit" ) @@ -207,7 +206,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) { ctx.LogError(errx) if lastMatcherEvent != nil { - lastMatcherEvent.InternalEvent["error"] = tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage())) + lastMatcherEvent.InternalEvent["error"] = getErrorCause(ctx.GenerateErrorMessage()) writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus) } @@ -222,7 +221,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) { Info: e.options.TemplateInfo, Type: e.getTemplateType(), Host: ctx.Input.MetaInput.Input, - Error: tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage())), + Error: getErrorCause(ctx.GenerateErrorMessage()), }, }, OperatorsResult: &operators.Result{ @@ -235,31 +234,27 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) { return executed.Load() || matched.Load(), errx } -// tryParseCause tries to parse the cause of given error +// getErrorCause tries to parse the cause of given error // this is legacy support due to use of errorutil in existing libraries // but this should not be required once all libraries are updated -func tryParseCause(err error) string { - errStr := "" - errX := errkit.FromError(err) - if errX != nil { - var errCause error - - if len(errX.Errors()) > 1 { - errCause = errX.Errors()[0] - } - if errCause == nil { - errCause = errX +func getErrorCause(err error) string { + if err == nil { + return "" + } + errx := errkit.FromError(err) + var cause error + for _, e := range errx.Errors() { + if e != nil && strings.Contains(e.Error(), "context deadline exceeded") { + continue } - - msg := strings.Trim(errCause.Error(), "{} ") - parts := strings.Split(msg, ":") - errCause = errkit.New("%s", parts[len(parts)-1]) - errKind := errkit.GetErrorKind(err, nucleierr.ErrTemplateLogic).String() - errStr = errCause.Error() - errStr = strings.TrimSpace(strings.Replace(errStr, "errKind="+errKind, "", -1)) + cause = e + break } - - return errStr + if cause == nil { + cause = errkit.Append(errkit.New("could not get error cause"), errx) + } + // parseScanError prettifies the error message and removes everything except the cause + return parseScanError(cause.Error()) } // ExecuteWithResults executes the protocol requests and returns results instead of writing them. diff --git a/pkg/tmplexec/interface.go b/pkg/tmplexec/interface.go index 67f9621116..36f139cc57 100644 --- a/pkg/tmplexec/interface.go +++ b/pkg/tmplexec/interface.go @@ -1,10 +1,15 @@ package tmplexec import ( + "errors" + "regexp" + "strings" + "github.com/projectdiscovery/nuclei/v3/pkg/scan" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto" + "github.com/projectdiscovery/utils/errkit" ) var ( @@ -30,3 +35,37 @@ type TemplateEngine interface { // Name returns name of template engine Name() string } + +var ( + // A temporary fix to remove errKind from error message + // this is because errkit is not used everywhere yet + reNoKind = regexp.MustCompile(`([\[][^][]+[\]]|errKind=[^ ]+) `) +) + +// parseScanError parses given scan error and only returning the cause +// instead of inefficient one +func parseScanError(msg string) string { + if msg == "" { + return "" + } + if strings.HasPrefix(msg, "ReadStatusLine:") { + // last index is actual error (from rawhttp) + parts := strings.Split(msg, ":") + msg = strings.TrimSpace(parts[len(parts)-1]) + } + if strings.Contains(msg, "read ") { + // same here + parts := strings.Split(msg, ":") + msg = strings.TrimSpace(parts[len(parts)-1]) + } + e := errkit.FromError(errors.New(msg)) + for _, err := range e.Errors() { + if err != nil && strings.Contains(err.Error(), "context deadline exceeded") { + continue + } + msg = reNoKind.ReplaceAllString(err.Error(), "") + return msg + } + wrapped := errkit.Append(errkit.New("failed to get error cause"), e).Error() + return reNoKind.ReplaceAllString(wrapped, "") +}