Skip to content

Commit

Permalink
Match Multiple DSLs (#205)
Browse files Browse the repository at this point in the history
* Support multiple request and response matching DSLs

* Multiple request & response replacements

* Fix mitmrelay

* small refactor

Co-authored-by: Mzack9999 <mzack9999@protonmail.com>
  • Loading branch information
wdahlenburg and Mzack9999 authored Jan 6, 2023
1 parent c2b4527 commit 07bf1d3
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 92 deletions.
4 changes: 2 additions & 2 deletions cmd/mitmrelay/mitmrelay.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ func main() {
}
proxyOpts.Protocol = options.Protocol
proxyOpts.HTTPProxy = options.HTTPProxy
proxyOpts.RequestMatchReplaceDSL = options.RequestMatchReplaceDSL
proxyOpts.ResponseMatchReplaceDSL = options.ResponseMatchReplaceDSL
proxyOpts.RequestMatchReplaceDSL = []string{options.RequestMatchReplaceDSL}
proxyOpts.ResponseMatchReplaceDSL = []string{options.ResponseMatchReplaceDSL}

if options.Timeout >= 0 {
proxyOpts.Timeout = time.Duration(options.Timeout) * time.Second
Expand Down
16 changes: 8 additions & 8 deletions internal/runner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ type Options struct {
DNSMapping string // DNSMapping contains user provided hosts
DNSFallbackResolver string // Listen DNS Ip and port (ip:port)
NoColor bool // No Color
RequestDSL string // Request Filter DSL
RequestMatchReplaceDSL string // Request Match-Replace DSL
ResponseDSL string // Response Filter DSL
ResponseMatchReplaceDSL string // Request Match-Replace DSL
RequestDSL goflags.StringSlice // Request Filter DSL
RequestMatchReplaceDSL goflags.StringSlice // Request Match-Replace DSL
ResponseDSL goflags.StringSlice // Response Filter DSL
ResponseMatchReplaceDSL goflags.StringSlice // Request Match-Replace DSL
UpstreamHTTPProxies goflags.StringSlice // Upstream HTTP comma separated Proxies (e.g. http://proxyip:proxyport)
UpstreamSocks5Proxies goflags.StringSlice // Upstream SOCKS5 comma separated Proxies (e.g. socks5://proxyip:proxyport)
UpstreamProxyRequestsNumber int // Number of requests before switching upstream proxy
Expand Down Expand Up @@ -61,10 +61,10 @@ func ParseOptions() *Options {
)

createGroup(flagSet, "filter", "Filter",
flagSet.StringVarP(&options.RequestDSL, "request-dsl", "req-fd", "", "Request Filter DSL"),
flagSet.StringVarP(&options.ResponseDSL, "response-dsl", "resp-fd", "", "Response Filter DSL"),
flagSet.StringVarP(&options.RequestMatchReplaceDSL, "request-match-replace-dsl", "req-mrd", "", "Request Match-Replace DSL"),
flagSet.StringVarP(&options.ResponseMatchReplaceDSL, "response-match-replace-dsl", "resp-mrd", "", "Response Match-Replace DSL"),
flagSet.StringSliceVarP(&options.RequestDSL, "request-dsl", "req-fd", nil, "Request Filter DSL", goflags.StringSliceOptions),
flagSet.StringSliceVarP(&options.ResponseDSL, "response-dsl", "resp-fd", nil, "Response Filter DSL", goflags.StringSliceOptions),
flagSet.StringSliceVarP(&options.RequestMatchReplaceDSL, "request-match-replace-dsl", "req-mrd", nil, "Request Match-Replace DSL", goflags.StringSliceOptions),
flagSet.StringSliceVarP(&options.ResponseMatchReplaceDSL, "response-match-replace-dsl", "resp-mrd", nil, "Response Match-Replace DSL", goflags.StringSliceOptions),
)

createGroup(flagSet, "network", "Network",
Expand Down
41 changes: 14 additions & 27 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,35 +47,22 @@ func NewRunner(options *Options) (*Runner, error) {
return &Runner{options: options, proxy: proxy}, nil
}

// Run polling and notification
func (r *Runner) Run() error {
if r.options.RequestDSL != "" {
_, err := govaluate.NewEvaluableExpressionWithFunctions(r.options.RequestDSL, dsl.DefaultHelperFunctions)
if err != nil {
printDslCompileError(err)
return err
}
}
if r.options.ResponseDSL != "" {
_, err := govaluate.NewEvaluableExpressionWithFunctions(r.options.ResponseDSL, dsl.DefaultHelperFunctions)
if err != nil {
printDslCompileError(err)
return err
}
}
if r.options.RequestMatchReplaceDSL != "" {
_, err := govaluate.NewEvaluableExpressionWithFunctions(r.options.RequestMatchReplaceDSL, dsl.DefaultHelperFunctions)
if err != nil {
printDslCompileError(err)
return err
func (r *Runner) validateExpressions(expressionsGroups ...[]string) error {
for _, expressionsGroup := range expressionsGroups {
for _, expression := range expressionsGroup {
if _, err := govaluate.NewEvaluableExpressionWithFunctions(expression, dsl.DefaultHelperFunctions); err != nil {
printDslCompileError(err)
return err
}
}
}
if r.options.ResponseMatchReplaceDSL != "" {
_, err := govaluate.NewEvaluableExpressionWithFunctions(r.options.ResponseMatchReplaceDSL, dsl.DefaultHelperFunctions)
if err != nil {
printDslCompileError(err)
return err
}
return nil
}

// Run polling and notification
func (r *Runner) Run() error {
if err := r.validateExpressions(r.options.RequestDSL, r.options.ResponseDSL, r.options.RequestMatchReplaceDSL, r.options.ResponseMatchReplaceDSL); err != nil {
return err
}

// configuration summary
Expand Down
107 changes: 60 additions & 47 deletions proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ type Options struct {
ListenAddrHTTP string
ListenAddrSocks5 string
OutputDirectory string
RequestDSL string
ResponseDSL string
RequestDSL []string
ResponseDSL []string
UpstreamHTTPProxies []string
UpstreamSock5Proxies []string
ListenDNSAddr string
DNSMapping string
DNSFallbackResolver string
RequestMatchReplaceDSL string
ResponseMatchReplaceDSL string
RequestMatchReplaceDSL []string
ResponseMatchReplaceDSL []string
OnConnectHTTPCallback OnConnectFunc
OnConnectHTTPSCallback OnConnectFunc
OnRequestCallback OnRequestFunc
Expand Down Expand Up @@ -91,20 +91,22 @@ func (p *Proxy) OnRequest(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Reque
}

// check dsl
if p.options.RequestDSL != "" {
m, _ := util.HTTPRequesToMap(req)
v, err := dsl.EvalExpr(p.options.RequestDSL, m)
if err != nil {
gologger.Warning().Msgf("Could not evaluate request dsl: %s\n", err)
for _, expr := range p.options.RequestDSL {
if !userdata.Match {
m, _ := util.HTTPRequesToMap(req)
v, err := dsl.EvalExpr(expr, m)
if err != nil {
gologger.Warning().Msgf("Could not evaluate request dsl: %s\n", err)
}
userdata.Match = err == nil && v.(bool)
}
userdata.Match = err == nil && v.(bool)
}

id := xid.New().String()
userdata.ID = id

// perform match and replace
if p.options.RequestMatchReplaceDSL != "" {
if len(p.options.RequestMatchReplaceDSL) != 0 {
_ = p.MatchReplaceRequest(req)
}

Expand All @@ -117,17 +119,19 @@ func (p *Proxy) OnRequest(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Reque
func (p *Proxy) OnResponse(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
userdata := ctx.UserData.(types.UserData)
userdata.HasResponse = true
if p.options.ResponseDSL != "" && !userdata.Match {
m, _ := util.HTTPResponseToMap(resp)
v, err := dsl.EvalExpr(p.options.ResponseDSL, m)
if err != nil {
gologger.Warning().Msgf("Could not evaluate response dsl: %s\n", err)
for _, expr := range p.options.ResponseDSL {
if !userdata.Match {
m, _ := util.HTTPResponseToMap(resp)
v, err := dsl.EvalExpr(expr, m)
if err != nil {
gologger.Warning().Msgf("Could not evaluate response dsl: %s\n", err)
}
userdata.Match = err == nil && v.(bool)
}
userdata.Match = err == nil && v.(bool)
}

// perform match and replace
if p.options.ResponseMatchReplaceDSL != "" {
if len(p.options.ResponseMatchReplaceDSL) != 0 {
_ = p.MatchReplaceResponse(resp)
}

Expand Down Expand Up @@ -157,26 +161,30 @@ func (p *Proxy) MatchReplaceRequest(req *http.Request) error {
// lazy mode - ninja level - elaborate
m := make(map[string]interface{})
m["request"] = string(reqdump)
if v, err := dsl.EvalExpr(p.options.RequestMatchReplaceDSL, m); err != nil {
return err
} else {
reqbuffer := fmt.Sprint(v)
// lazy mode - epic level - rebuild
bf := bufio.NewReader(strings.NewReader(reqbuffer))
requestNew, err := http.ReadRequest(bf)
for _, expr := range p.options.RequestMatchReplaceDSL {
v, err := dsl.EvalExpr(expr, m)
if err != nil {
return err
}
// closes old body to allow memory reuse
req.Body.Close()

// override original properties
req.Method = requestNew.Method
req.Header = requestNew.Header
req.Body = requestNew.Body
req.URL = requestNew.URL
return nil
m["request"] = fmt.Sprint(v)
}

reqbuffer := fmt.Sprint(m["request"])
// lazy mode - epic level - rebuild
bf := bufio.NewReader(strings.NewReader(reqbuffer))
requestNew, err := http.ReadRequest(bf)
if err != nil {
return err
}
// closes old body to allow memory reuse
req.Body.Close()

// override original properties
req.Method = requestNew.Method
req.Header = requestNew.Header
req.Body = requestNew.Body
req.URL = requestNew.URL
return nil
}

// MatchReplaceRequest strings or regex
Expand All @@ -193,24 +201,29 @@ func (p *Proxy) MatchReplaceResponse(resp *http.Response) error {
// lazy mode - ninja level - elaborate
m := make(map[string]interface{})
m["response"] = string(respdump)
if v, err := dsl.EvalExpr(p.options.ResponseMatchReplaceDSL, m); err != nil {
return err
} else {
respbuffer := fmt.Sprint(v)
// lazy mode - epic level - rebuild
bf := bufio.NewReader(strings.NewReader(respbuffer))
responseNew, err := http.ReadResponse(bf, nil)
for _, expr := range p.options.ResponseMatchReplaceDSL {
v, err := dsl.EvalExpr(expr, m)

if err != nil {
return err
}
m["response"] = fmt.Sprint(v)
}

// closes old body to allow memory reuse
resp.Body.Close()
resp.Header = responseNew.Header
resp.Body = responseNew.Body
resp.ContentLength = responseNew.ContentLength
return nil
respbuffer := fmt.Sprint(m["response"])
// lazy mode - epic level - rebuild
bf := bufio.NewReader(strings.NewReader(respbuffer))
responseNew, err := http.ReadResponse(bf, nil)
if err != nil {
return err
}

// closes old body to allow memory reuse
resp.Body.Close()
resp.Header = responseNew.Header
resp.Body = responseNew.Body
resp.ContentLength = responseNew.ContentLength
return nil
}

func (p *Proxy) Run() error {
Expand Down
16 changes: 8 additions & 8 deletions socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ type SocketConn struct {
Verbosity types.Verbosity
OutputHex bool
Timeout time.Duration
RequestMatchReplaceDSL string
ResponseMatchReplaceDSL string
RequestMatchReplaceDSL []string
ResponseMatchReplaceDSL []string
OnRequest func([]byte) []byte
OnResponse func([]byte) []byte
}
Expand All @@ -54,8 +54,8 @@ type SocketProxyOptions struct {
Verbosity types.Verbosity
OutputHex bool
Timeout time.Duration
RequestMatchReplaceDSL string
ResponseMatchReplaceDSL string
RequestMatchReplaceDSL []string
ResponseMatchReplaceDSL []string
OnRequest func([]byte) []byte
OnResponse func([]byte) []byte
}
Expand Down Expand Up @@ -222,10 +222,10 @@ func (p *SocketConn) pipe(src, dst io.ReadWriter) {
// Client => Proxy => Destination
if islocal {
// DSL
if p.RequestMatchReplaceDSL != "" {
for _, expr := range p.RequestMatchReplaceDSL {
args := make(map[string]interface{})
args["data"] = b
newB, err := dsl.EvalExpr(p.RequestMatchReplaceDSL, args)
newB, err := dsl.EvalExpr(expr, args)
// In case of error use the original value
if err != nil {
log.Printf("%s\n", err)
Expand All @@ -241,10 +241,10 @@ func (p *SocketConn) pipe(src, dst io.ReadWriter) {
}
} else { // Destination => Proxy => Client
// DSL
if p.ResponseMatchReplaceDSL != "" {
for _, expr := range p.ResponseMatchReplaceDSL {
args := make(map[string]interface{})
args["data"] = b
newB, err := dsl.EvalExpr(p.ResponseMatchReplaceDSL, args)
newB, err := dsl.EvalExpr(expr, args)
// In case of error use the original value
if err != nil {
log.Printf("%s\n", err)
Expand Down

0 comments on commit 07bf1d3

Please sign in to comment.