goproxy
goproxy copied to clipboard
is there any way to change upstream proxy each request
i have try this below but not worked:
proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (request *http.Request, response *http.Response) {
proxy.Tr = &http.Transport{Proxy: func(request *http.Request) (url *url.URL, e error) {
ip := GetNewProxy()
fmt.Println("======New ip:", ip)
return url.Parse(ip)
}}
return req, nil
})
You can set a transport per request IIRC
You can set a transport per request IIRC
Hey there, do you have an example for this? I've been banging my head against my keyboard trying to figure it out and can't seem to find a way to assign a transport to a specific request. I can attach it to the server, but with concurrent connections that seems like it's asking for trouble.
Thanks!
You could write a Custom Transport: https://github.com/elazarl/goproxy/blob/aa519ddbe484d5dddfd1a4056f90aa2b6cbc99cf/proxy.go#L28
With a custom proxy function which parses a different proxy IP each time an HTTP request is executed
You can use ProxyCtx.RoundTripper
for this:
proxy.OnRequest().DoFunc(func (req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
ctx.RoundTripper = goproxy.RoundTripperFunc(func (req *http.Request, ctx *goproxy.ProxyCtx) (*http.Response, error) {
// create transport and RoundTrip here
})
return req, nil
})
Beware that this will work for HTTP connections but not for HTTPS!
To make this work for HTTPS, you'll need to create a custom ConnectDial
implementation. I'm currently working on this in a private project.
@axelrindle can you share what you do in your project? needed that feature! Thank you.
@chekun Have a look at this file: https://github.com/axelrindle/proxyguy/blob/main/server/server.go
This is currently at a very early stage of implementation.
@axelrindle Thank you.
FYI, ConnectDialWithReq
function solved my problem.
@axelrindle Thank you.
FYI,
ConnectDialWithReq
function solved my problem.
Could you please provide an example for how you used ConnectDialWithReq
? I'm also stuck on this.
Here you go @rosahaj
proxyServer.ConnectDialWithReq = func(req *http.Request, network, addr string) (net.Conn, error) {
if strings.Contains(req.URL.Path, "somethingyouwant") {
return proxyServer.NewConnectDialToProxyWithHandler("http://proxy1.com", func(req *http.Request) {
})(network, addr)
} else {
return proxyServer.NewConnectDialToProxyWithHandler("http://proxy2.com", func(req *http.Request) {})(network, addr)
}
}
Here you go @rosahaj
proxyServer.ConnectDialWithReq = func(req *http.Request, network, addr string) (net.Conn, error) { if strings.Contains(req.URL.Path, "somethingyouwant") { return proxyServer.NewConnectDialToProxyWithHandler("http://proxy1.com", func(req *http.Request) { })(network, addr) } else { return proxyServer.NewConnectDialToProxyWithHandler("http://proxy2.com", func(req *http.Request) {})(network, addr) } }
Thanks for sharing your example. Unfortunately I still can't get it to work, seemingly ConnectDialWithReq
simply isn't called:
package main
import (
"log"
"net"
"net/http"
"net/url"
"regexp"
"github.com/elazarl/goproxy"
)
func main() {
proxyServer := goproxy.NewProxyHttpServer()
secondProxyServer := goproxy.NewProxyHttpServer()
secondProxyServer.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
println("Second proxy received request")
return req, nil
})
go http.ListenAndServe(":8090", secondProxyServer)
proxyServer.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
HandleConnect(goproxy.AlwaysMitm)
proxyServer.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
println("Tr.Proxy was called")
return url.Parse("http://localhost:8090/")
}
proxyServer.ConnectDialWithReq = func(req *http.Request, network, addr string) (net.Conn, error) {
println("ConnectDialWithReq was called")
return proxyServer.NewConnectDialToProxyWithHandler("http://localhost:8090/", func(req *http.Request) {})(network, addr)
}
log.Fatal(http.ListenAndServe(":8080", proxyServer))
}
Only Tr.Proxy was called
gets printed. Requests are never passed to the second proxy.
Edit:
Leaving out this line:
proxyServer.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
HandleConnect(goproxy.AlwaysMitm)
results in ConnectDialWithReq
being called, but req.URL
is nil and the second proxy still isn't used.
@rosahaj Since you turn on Mitm
, you don't need ConnectDialWithReq anymore ,just put your logic in proxyServer.Tr.Proxy
proxyServer.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
println("Tr.Proxy was called")
if (some condition) {
return url.Parse("http://localhost:8290/")
}
return url.Parse("http://localhost:8090/")
}
@chekun Unfortunately setting Tr.Proxy
doesn't ensure the request goes through the returned proxy URL:
package main
import (
"fmt"
"log"
"net/http"
"net/url"
"regexp"
"strings"
"github.com/elazarl/goproxy"
)
func logOnNewConnection(proxyName string) {
fmt.Printf("New connection on proxy: %s", proxyName)
}
func main() {
entryProxyServer := goproxy.NewProxyHttpServer()
firstChoiceProxyServer := goproxy.NewProxyHttpServer()
secondChoiceProxyServer := goproxy.NewProxyHttpServer()
firstChoiceProxyServer.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
logOnNewConnection("First choice")
return req, nil
})
secondChoiceProxyServer.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
logOnNewConnection("First choice")
return req, nil
})
go http.ListenAndServe(":8081", firstChoiceProxyServer)
go http.ListenAndServe(":8082", secondChoiceProxyServer)
// Enable MITM
entryProxyServer.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
HandleConnect(goproxy.AlwaysMitm)
entryProxyServer.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
println("Tr.Proxy was called")
if strings.Contains(req.URL.Path, "somethingyouwant") {
println("Proxying to first choice")
return url.Parse("http://localhost:8081/")
} else {
println("Proxying to second choice")
return url.Parse("http://localhost:8082/")
}
}
log.Fatal(http.ListenAndServe(":8080", entryProxyServer))
}
Output:
Tr.Proxy was called
Proxying to first choice
The only way I was able to get it to work at all is by implementing a custom RoundTripper, but this defeats the benefits of using goproxy
in the first place.
I'm not sure, in my case it all works fine.