I fixed the 400 Server Error issue and add a request checking before inject *Proxy-Authorization *header in order to alter only GET or CONNECT requests: https://github.com/hbollon/IGopher/blob/proxy/internal/proxy/pipe.go But now I'm getting this error after curl request: *OpenSSL SSL_read: error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version, errno 0*
Maybe my approach is completely crazy or wrong but I feel can succeed lmao Le mercredi 17 mars 2021 à 16:00:22 UTC+1, Hugo Bollon a écrit : > Yeah, I'm not very comfortable with networking so it's possible I'm not > using the right terms... > > I want to be able to allow my users to use, with Selenium (and therefore > Chrome), a proxy with authentication. The problem is that I cannot send the > proxy credentials to the Chrome instance or interact with the proxy > connection alert box. > > So basically, what I want to do, is a localhost proxy managed by my > program which will receive all Chrome CONNECT requests, inject the > Proxy-Authorization header to authenticate requests and send them back to > the user remote proxy. > > I managed to get something with a TCP tunnel, I relied on the source code > of io.Copy source code. > I managed to intercept the request from the incoming net.Conn, decode the > http request from the tcp packet, add the Proxy-Authorization at the end, > re-encode the packet and finally write it to the outgoing net.Conn (to the > remote proxy ) > But I'm getting a 400 Server Error on the remote proxy side... > > You can check all of that here: > https://github.com/hbollon/IGopher/tree/proxy/internal/proxy > (It's WIP stuff, so it's not cleaned or optimized yet. I just pushed it so > you could check it out) > > Hope I am clear enough ... > Anyways, thanks for your help! :) > > Le mercredi 17 mars 2021 à 09:30:22 UTC+1, vlad...@varank.in a écrit : > >> I think I didn't get what you're building right. Now, it looks like, >> instead of implementing a custom RR's director, you need to configure its >> Transport [1], which will be aware of your auth proxy in the middle. Have a >> look at net/http.Transport.Proxy field [2] for that. >> >> [1]: https://pkg.go.dev/net/http/httputil?utm_source=godoc#ReverseProxy >> [2]: https://pkg.go.dev/net/http?utm_source=godoc#Transport >> >> On Tuesday, March 16, 2021 at 11:17:49 AM UTC+1 hugo....@gmail.com wrote: >> >>> Thank you for your advice that I applied. >>> But now I have a *407 Proxy Authentication Required* error, while the >>> header is added to the request... >>> Here is the output: >>> >>> INFO[0019] Pre-Edited request: &{Method:CONNECT URL://google.com:443 >>> Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 >>> Header:map[Proxy-Connection:[Keep-Alive] User-Agent:[curl/7.68.0]] >>> Body:<nil> GetBody:<nil> ContentLength:0 TransferEncoding:[] Close:false >>> Host:google.com:443 Form:map[] PostForm:map[] MultipartForm:<nil> >>> Trailer:map[] RemoteAddr:127.0.0.1:45382 RequestURI:google.com:443 >>> TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc000814240} function=func1 >>> line=60 >>> >>> INFO[0019] Edited Request: &{Method:CONNECT URL: >>> http://51.178.xx.xx:3128/ Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 >>> Header:map[Proxy-Authorization:[Basic <auth>] Proxy-Connection:[Keep-Alive] >>> User-Agent:[curl/7.68.0]] Body:<nil> GetBody:<nil> ContentLength:0 >>> TransferEncoding:[] Close:false Host:google.com:443 Form:map[] >>> PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: >>> 127.0.0.1:45382 RequestURI:google.com:443 TLS:<nil> Cancel:<nil> >>> Response:<nil> ctx:0xc000814240} function=func1 line=69 >>> >>> INFO[0019] Scheme: http, Host: 51.178.xx.xx:3128, Port: 3128 >>> function=func1 line=70 >>> >>> INFO[0019] Response: &{Status:407 Proxy Authentication Required >>> StatusCode:407 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 >>> Header:map[Content-Language:[en] Content-Length:[3520] >>> Content-Type:[text/html;charset=utf-8] Date:[Tue, 16 Mar 2021 10:03:44 GMT] >>> Mime-Version:[1.0] Server:[squid/3.5.27] Vary:[Accept-Language] Via:[1.1 >>> vps799016 (squid/3.5.27)] X-Cache:[MISS from vps799xxx] >>> X-Cache-Lookup:[NONE from vps799xxx:3128] >>> X-Squid-Error:[ERR_CACHE_ACCESS_DENIED 0]] Body:0xc0004de180 >>> ContentLength:3520 TransferEncoding:[] Close:false Uncompressed:false >>> Trailer:map[] Request:0xc0005ee100 TLS:<nil>} function=PrintResponse >>> line=33 >>> >>> >>> PS: Is it possible on Google Groups to format code snippets? Markdown >>> not seems to be supported >>> >>> Le mardi 16 mars 2021 à 09:04:31 UTC+1, vlad...@varank.in a écrit : >>> >>>> Hey there, >>>> >>>> Seems the issue hides in the chunk, where you overwrite reverse proxy's >>>> "Director" method, which NewSingleHostReverseProxy creates internally. >>>> Since your own director doesn't set the client request's Schema and Host, >>>> you have to either do that manually or make sure you call the original >>>> director. >>>> >>>> Try doing the following: >>>> >>>> proxyDirector := proxy.Director // ← keep the original director >>>> d := func(req *http.Request) { >>>> logrus.Infof("Pre-Edited request: %+v\n", req) >>>> >>>> proxyDirector(req) // ← call the original director to make sure >>>> the request will go through the proxy >>>> >>>> // Inject proxy authentication headers to outgoing request into >>>> new Header >>>> basicAuth := "Basic " + >>>> base64.StdEncoding.EncodeToString([]byte(remoteServerAuth)) >>>> req.Header.Set("Proxy-Authorization", basicAuth) >>>> logrus.Infof("Edited Request: %+v\n", req) >>>> logrus.Infof("Scheme: %s, Host: %s, Port: %s\n", >>>> req.URL.Scheme, req.URL.Host, req.URL.Port()) >>>> } >>>> proxy.Director = d >>>> >>>> Also, have a look at the implementation of NewSingleHostReverseProxy >>>> https://go.googlesource.com/go/+/go1.16/src/net/http/httputil/reverseproxy.go#142 >>>> >>>> Cheers, >>>> V. >>>> >>>> On Monday, March 15, 2021 at 11:37:51 PM UTC+1 hugo....@gmail.com >>>> wrote: >>>> >>>>> Hi! >>>>> I'm actually building an automation tool based on Selenium with Go >>>>> called IGopher and I have had a few requests to implement native proxy >>>>> support. >>>>> However, I am facing an issue with those with authentication... >>>>> I can't send the proxy credentials to Chrome and without them it asks >>>>> through an alert box for authentication that I can hardly interact with >>>>> through Selenium (I'm not even sure it's possible in headless mode) . >>>>> >>>>> So I thought of an intermediary proxy system hosted locally by my >>>>> program which will add the *Proxy-Authorization* header and transfer >>>>> the request to the remote proxy: >>>>> >>>>> [image: IGopher_proxies.jpg] >>>>> >>>>> Something like this: proxy-login-automator >>>>> <https://github.com/sjitech/proxy-login-automator> >>>>> >>>>> I'm not very familiar with proxies to be honest, but I tried this >>>>> approach using *NewSingleHostReverseProxy*: >>>>> ```go >>>>> var ( >>>>> localServerHost string >>>>> remoteServerHost string >>>>> remoteServerAuth string >>>>> ) >>>>> >>>>> // ProxyConfig store all remote proxy configuration >>>>> type ProxyConfig struct { >>>>> IP string `yaml:"ip"` >>>>> Port int `yaml:"port"` >>>>> Username string `yaml:"username"` >>>>> Password string `yaml:"password"` >>>>> Enabled bool `yaml:"activated"` >>>>> } >>>>> >>>>> func PrintResponse(r *http.Response) error { >>>>> logrus.Infof("Response: %+v\n", r) >>>>> return nil >>>>> } >>>>> >>>>> // LaunchForwardingProxy launch forward server used to inject proxy >>>>> authentication header >>>>> // into outgoing requests >>>>> func LaunchForwardingProxy(localPort uint16, remoteProxy ProxyConfig) >>>>> error { >>>>> localServerHost = fmt.Sprintf("localhost:%d", localPort) >>>>> remoteServerHost = fmt.Sprintf( >>>>> "http://%s:%d", >>>>> remoteProxy.IP, >>>>> remoteProxy.Port, >>>>> ) >>>>> remoteServerAuth = fmt.Sprintf( >>>>> "%s:%s", >>>>> remoteProxy.Username, >>>>> remoteProxy.Password, >>>>> ) >>>>> >>>>> remote, err := url.Parse(remoteServerHost) >>>>> if err != nil { >>>>> panic(err) >>>>> } >>>>> >>>>> proxy := httputil.NewSingleHostReverseProxy(remote) >>>>> d := func(req *http.Request) { >>>>> logrus.Infof("Pre-Edited request: %+v\n", req) >>>>> // Inject proxy authentication headers to outgoing request into new >>>>> Header >>>>> basicAuth := "Basic " + >>>>> base64.StdEncoding.EncodeToString([]byte(remoteServerAuth)) >>>>> req.Header.Set("Proxy-Authorization", basicAuth) >>>>> logrus.Infof("Edited Request: %+v\n", req) >>>>> logrus.Infof("Scheme: %s, Host: %s, Port: %s\n", req.URL.Scheme, >>>>> req.URL.Host, req.URL.Port()) >>>>> } >>>>> proxy.Director = d >>>>> proxy.ModifyResponse = PrintResponse >>>>> http.ListenAndServe(localServerHost, proxy) >>>>> >>>>> return nil >>>>> } >>>>> ``` >>>>> >>>>> With this code snippet, I'm able to intercept the request and update >>>>> the header. >>>>> However, resending the CONNECT request fails with the following output: >>>>> >>>>> ``` >>>>> INFO[0028] Pre-Edited request: &{Method:CONNECT URL://google.com:443 >>>>> Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 >>>>> Header:map[Proxy-Connection:[Keep-Alive] User-Agent:[curl/7.68.0]] >>>>> Body:<nil> GetBody:<nil> ContentLength:0 TransferEncoding:[] Close:false >>>>> Host:google.com:443 Form:map[] PostForm:map[] MultipartForm:<nil> >>>>> Trailer:map[] RemoteAddr:127.0.0.1:35610 RequestURI:google.com:443 >>>>> TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc000164300} function=func1 >>>>> line=59 >>>>> >>>>> INFO[0028] Edited Request: &{Method:CONNECT URL://google.com:443 >>>>> Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 >>>>> Header:map[Proxy-Authorization:[Basic <auth>] >>>>> Proxy-Connection:[Keep-Alive] >>>>> User-Agent:[curl/7.68.0]] Body:<nil> GetBody:<nil> ContentLength:0 >>>>> TransferEncoding:[] Close:false Host:google.com:443 Form:map[] >>>>> PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: >>>>> 127.0.0.1:35610 RequestURI:google.com:443 TLS:<nil> Cancel:<nil> >>>>> Response:<nil> ctx:0xc000164300} function=func1 line=63 >>>>> >>>>> INFO[0028] Scheme: , Host: google.com:443, Port: 443 >>>>> function=func1 line=64 >>>>> >>>>> *2021/03/15 21:35:11 http: proxy error: unsupported protocol scheme ""* >>>>> ``` >>>>> >>>>> What am I doing wrong? Is there a way to send a CONNECT request >>>>> without scheme in Go? >>>>> Maybe I'm doing something wrong or my approach to this problem is >>>>> wrong. Are there better methods to achieve my goals? >>>>> >>>>> If you have an idea to complete what I did or any other method, please >>>>> let me know! :) >>>>> >>>>> You can find all IGopher sources here: GitHub repository >>>>> <https://github.com/hbollon/IGopher> (Proxy stuff excluded) >>>>> >>>> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/49857947-71be-4e6a-8ed5-f12aa9d99ad0n%40googlegroups.com.