error handling + support offlinehttp in flow templates (#4653)

This commit is contained in:
Tarun Koyalwar 2024-01-17 23:16:57 +05:30 committed by GitHub
parent 44745cb0c9
commit 68b9dd52ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 17 deletions

View File

@ -183,8 +183,9 @@ func (template *Template) compileProtocolRequests(options *protocols.ExecutorOpt
requests = append(requests, template.convertRequestToProtocolsRequest(template.RequestsJavascript)...) requests = append(requests, template.convertRequestToProtocolsRequest(template.RequestsJavascript)...)
} }
} }
template.Executer = tmplexec.NewTemplateExecuter(requests, options) var err error
return nil template.Executer, err = tmplexec.NewTemplateExecuter(requests, options)
return err
} }
// convertRequestToProtocolsRequest is a convenience wrapper to convert // convertRequestToProtocolsRequest is a convenience wrapper to convert
@ -228,8 +229,13 @@ mainLoop:
} }
if len(operatorsList) > 0 { if len(operatorsList) > 0 {
options.Operators = operatorsList options.Operators = operatorsList
template.Executer = tmplexec.NewTemplateExecuter([]protocols.Request{&offlinehttp.Request{}}, options) var err error
return nil template.Executer, err = tmplexec.NewTemplateExecuter([]protocols.Request{&offlinehttp.Request{}}, options)
if err != nil {
// it seems like flow executor cannot be used for offline http matching (ex:http(1) && http(2))
return ErrIncompatibleWithOfflineMatching
}
return err
} }
return ErrIncompatibleWithOfflineMatching return ErrIncompatibleWithOfflineMatching

View File

@ -31,7 +31,7 @@ type TemplateExecuter struct {
var _ protocols.Executer = &TemplateExecuter{} var _ protocols.Executer = &TemplateExecuter{}
// NewTemplateExecuter creates a new request TemplateExecuter for list of requests // NewTemplateExecuter creates a new request TemplateExecuter for list of requests
func NewTemplateExecuter(requests []protocols.Request, options *protocols.ExecutorOptions) *TemplateExecuter { func NewTemplateExecuter(requests []protocols.Request, options *protocols.ExecutorOptions) (*TemplateExecuter, error) {
isMultiProto := false isMultiProto := false
lastProto := "" lastProto := ""
for _, request := range requests { for _, request := range requests {
@ -47,7 +47,11 @@ func NewTemplateExecuter(requests []protocols.Request, options *protocols.Execut
// we use a dummy input here because goal of flow executor at this point is to just check // we use a dummy input here because goal of flow executor at this point is to just check
// syntax and other things are correct before proceeding to actual execution // syntax and other things are correct before proceeding to actual execution
// during execution new instance of flow will be created as it is tightly coupled with lot of executor options // during execution new instance of flow will be created as it is tightly coupled with lot of executor options
e.engine = flow.NewFlowExecutor(requests, scan.NewScanContext(contextargs.NewWithInput("dummy")), options, e.results) var err error
e.engine, err = flow.NewFlowExecutor(requests, scan.NewScanContext(contextargs.NewWithInput("dummy")), options, e.results)
if err != nil {
return nil, fmt.Errorf("could not create flow executor: %s", err)
}
} else { } else {
// Review: // Review:
// multiproto engine is only used if there is more than one protocol in template // multiproto engine is only used if there is more than one protocol in template
@ -58,8 +62,7 @@ func NewTemplateExecuter(requests []protocols.Request, options *protocols.Execut
e.engine = generic.NewGenericEngine(requests, options, e.results) e.engine = generic.NewGenericEngine(requests, options, e.results)
} }
} }
return e, nil
return e
} }
// Compile compiles the execution generators preparing any requests possible. // Compile compiles the execution generators preparing any requests possible.
@ -146,7 +149,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
} }
} }
} }
var err error var errx error
// Note: this is required for flow executor // Note: this is required for flow executor
// flow executer is tightly coupled with lot of executor options // flow executer is tightly coupled with lot of executor options
@ -155,20 +158,24 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
// so in compile step earlier we compile it to validate javascript syntax and other things // so in compile step earlier we compile it to validate javascript syntax and other things
// and while executing we create new instance of flow executor everytime // and while executing we create new instance of flow executor everytime
if e.options.Flow != "" { if e.options.Flow != "" {
flowexec := flow.NewFlowExecutor(e.requests, ctx, e.options, results) flowexec, err := flow.NewFlowExecutor(e.requests, ctx, e.options, results)
if err != nil {
ctx.LogError(err)
return false, fmt.Errorf("could not create flow executor: %s", err)
}
if err := flowexec.Compile(); err != nil { if err := flowexec.Compile(); err != nil {
ctx.LogError(err) ctx.LogError(err)
return false, err return false, err
} }
err = flowexec.ExecuteWithResults(ctx) errx = flowexec.ExecuteWithResults(ctx)
} else { } else {
err = e.engine.ExecuteWithResults(ctx) errx = e.engine.ExecuteWithResults(ctx)
} }
if lastMatcherEvent != nil { if lastMatcherEvent != nil {
writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus) writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus)
} }
return results.Load(), err return results.Load(), errx
} }
// ExecuteWithResults executes the protocol requests and returns results instead of writing them. // ExecuteWithResults executes the protocol requests and returns results instead of writing them.

View File

@ -55,7 +55,7 @@ type FlowExecutor struct {
// NewFlowExecutor creates a new flow executor from a list of requests // NewFlowExecutor creates a new flow executor from a list of requests
// Note: Unlike other engine for every target x template flow needs to be compiled and executed everytime // Note: Unlike other engine for every target x template flow needs to be compiled and executed everytime
// unlike other engines where we compile once and execute multiple times // unlike other engines where we compile once and execute multiple times
func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, options *protocols.ExecutorOptions, results *atomic.Bool) *FlowExecutor { func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, options *protocols.ExecutorOptions, results *atomic.Bool) (*FlowExecutor, error) {
allprotos := make(map[string][]protocols.Request) allprotos := make(map[string][]protocols.Request)
for _, req := range requests { for _, req := range requests {
switch req.Type() { switch req.Type() {
@ -79,9 +79,11 @@ func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, option
allprotos[templateTypes.CodeProtocol.String()] = append(allprotos[templateTypes.CodeProtocol.String()], req) allprotos[templateTypes.CodeProtocol.String()] = append(allprotos[templateTypes.CodeProtocol.String()], req)
case templateTypes.JavascriptProtocol: case templateTypes.JavascriptProtocol:
allprotos[templateTypes.JavascriptProtocol.String()] = append(allprotos[templateTypes.JavascriptProtocol.String()], req) allprotos[templateTypes.JavascriptProtocol.String()] = append(allprotos[templateTypes.JavascriptProtocol.String()], req)
case templateTypes.OfflineHTTPProtocol:
// offlinehttp is run in passive mode but templates are same so instead of using offlinehttp() we use http() in flow
allprotos[templateTypes.HTTPProtocol.String()] = append(allprotos[templateTypes.OfflineHTTPProtocol.String()], req)
default: default:
ctx.LogError(fmt.Errorf("invalid request type %s", req.Type().String())) return nil, fmt.Errorf("invalid request type %s", req.Type().String())
return nil
} }
} }
f := &FlowExecutor{ f := &FlowExecutor{
@ -96,7 +98,7 @@ func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, option
jsVM: protocolstate.NewJSRuntime(), jsVM: protocolstate.NewJSRuntime(),
ctx: ctx, ctx: ctx,
} }
return f return f, nil
} }
// Compile compiles js program and registers all functions // Compile compiles js program and registers all functions