Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a mitmMutateRequest hook and add ConnectAction to ProxyCtx #27

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ type ProxyCtx struct {
// call of RespHandler
UserData interface{}
// Will connect a request to a response
Session int64
proxy *ProxyHttpServer
Session int64
proxy *ProxyHttpServer
ConnectAction ConnectActionLiteral
}

type RoundTripper interface {
Expand Down
13 changes: 9 additions & 4 deletions https.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ var (
)

type ConnectAction struct {
Action ConnectActionLiteral
Hijack func(req *http.Request, client net.Conn, ctx *ProxyCtx)
TLSConfig func(host string, ctx *ProxyCtx) (*tls.Config, error)
Action ConnectActionLiteral
Hijack func(req *http.Request, client net.Conn, ctx *ProxyCtx)
TLSConfig func(host string, ctx *ProxyCtx) (*tls.Config, error)
MitmMutateRequest func(req *http.Request, ctx *ProxyCtx)
}

func stripPort(s string) string {
Expand Down Expand Up @@ -114,6 +115,7 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
break
}
}
ctx.ConnectAction = todo.Action
switch todo.Action {
case ConnectAccept:
if !hasPort.MatchString(host) {
Expand Down Expand Up @@ -264,7 +266,7 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
req, err := http.ReadRequest(clientTlsReader)
// Set the RoundTripper on the ProxyCtx within the `HandleConnect` action of goproxy, then
// inject the roundtripper here in order to use a custom round tripper while mitm.
var ctx = &ProxyCtx{Req: req, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy, UserData: ctx.UserData, RoundTripper: ctx.RoundTripper}
var ctx = &ProxyCtx{Req: req, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy, UserData: ctx.UserData, RoundTripper: ctx.RoundTripper, ConnectAction: ctx.ConnectAction}
if err != nil && err != io.EOF {
return
}
Expand All @@ -273,6 +275,9 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
return
}
req.RemoteAddr = r.RemoteAddr // since we're converting the request, need to carry over the original connecting IP as well
if todo.MitmMutateRequest != nil {
todo.MitmMutateRequest(req, ctx)
}
ctx.Logf("req %v", r.Host)

if !httpsRegexp.MatchString(req.URL.String()) {
Expand Down
44 changes: 44 additions & 0 deletions proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,26 @@ func (QueryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, req.Form.Get("result"))
}

type HeadersHandler struct{}

// This handlers returns a body with a string containing all the request headers it received.
func (HeadersHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var sb strings.Builder
for name, values := range req.Header {
for _, value := range values {
sb.WriteString(name)
sb.WriteString(": ")
sb.WriteString(value)
sb.WriteString(";")
}
}
io.WriteString(w, sb.String())
}

func init() {
http.DefaultServeMux.Handle("/bobo", ConstantHanlder("bobo"))
http.DefaultServeMux.Handle("/query", QueryHandler{})
http.DefaultServeMux.Handle("/headers", HeadersHandler{})
}

type ConstantHanlder string
Expand Down Expand Up @@ -436,6 +453,33 @@ func TestSimpleMitm(t *testing.T) {
}
}

func TestMitmMutateRequest(t *testing.T) {
mitmMutateRequest := func(req *http.Request, ctx *goproxy.ProxyCtx) {
// We inject a header in the request
req.Header.Set("Mitm-Header-Inject", "true")
}
mitmConnect := &goproxy.ConnectAction{
Action: goproxy.ConnectMitm,
TLSConfig: goproxy.TLSConfigFromCA(&goproxy.GoproxyCa),
MitmMutateRequest: mitmMutateRequest,
}
var mitm goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
return mitmConnect, host
}

proxy := goproxy.NewProxyHttpServer()
proxy.OnRequest().HandleConnect(mitm)

client, l := oneShotProxy(proxy, t)
defer l.Close()

r := string(getOrFail(https.URL+"/headers", client, t))
if !strings.Contains(r, "Mitm-Header-Inject: true") {
t.Error("Expected response body to contain the MITM injected header. Got instead: ", r)
}

}

func TestConnectHandler(t *testing.T) {
proxy := goproxy.NewProxyHttpServer()
althttps := httptest.NewTLSServer(ConstantHanlder("althttps"))
Expand Down
Loading