elazarl / goproxy

An HTTP proxy library for Go
BSD 3-Clause "New" or "Revised" License
5.88k stars 1.07k forks source link

curl to proxy to https fails #294

Closed cedricve closed 6 years ago

cedricve commented 6 years ago

Hey,

I'm really excited to your library, and I want to use it in the @kerberosio project. I'm facing a couple of difficulties. This is my setup:

C++ code which is using CURL to send a POST request to the proxy server. (CURLOPT_PROXY)

        curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION,1);//Set automaticallly redirection
        curl_easy_setopt(curlHandle, CURLOPT_MAXREDIRS,1);//Set max redirection times
        curl_easy_setopt(curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);//Set http version 1.1fer
        curl_easy_setopt(curlHandle, CURLOPT_HEADER, true);//Set header true
        curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, httpHeaders);//Set headers
        curl_easy_setopt(curlHandle, CURLOPT_URL, url.c_str());//Set URL
        curl_easy_setopt(curlHandle, CURLOPT_PROXY, "http://localhost:8080");
        curl_easy_setopt(curlHandle, CURLOPT_TRANSFER_ENCODING, 1L);
        curl_easy_setopt(curlHandle, CURLOPT_CUSTOMREQUEST, "PUT");
        curl_easy_setopt(curlHandle, CURLOPT_UPLOAD, 1L);
        curl_easy_setopt(curlHandle, CURLOPT_READDATA, fd);
        curl_easy_setopt(curlHandle, CURLOPT_NOSIGNAL, 1L);
        curl_easy_setopt(curlHandle, CURLOPT_READFUNCTION, reader);
        curl_easy_setopt(curlHandle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
        curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, write);
        curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &output);

I'm running the Proxy server like you've proposed the example eavesdropping.

package main

import (
    "bufio"
    "flag"
    "log"
    "net"
    "net/http"
    "regexp"
    "crypto/tls"
    "crypto/x509"

    "github.com/elazarl/goproxy"
)

func orPanic(err error) {
    if err != nil {
        panic(err)
    }
}

var caCert = []byte(`-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIJAKe/ZGdfcHdPMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxGTAXBgNVBAMMEGRlbW8gZm9yIGdvcHJveHkwHhcNMTYw
OTI3MTQzNzQ3WhcNMTkwOTI3MTQzNzQ3WjBgMQswCQYDVQQGEwJBVTETMBEGA1UE
CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
MRkwFwYDVQQDDBBkZW1vIGZvciBnb3Byb3h5MIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA2+W48YZoch72zj0a+ZlyFVY2q2MWmqsEY9f/u53fAeTxvPE6
1/DnqsydnA3FnGvxw9Dz0oZO6xG+PZvp+lhN07NZbuXK1nie8IpxCa342axpu4C0
69lZwxikpGyJO4IL5ywp/qfb5a2DxPTAyQOQ8ROAaydoEmktRp25yicnQ2yeZW//
1SIQxt7gRxQIGmuOQ/Gqr/XN/z2cZdbGJVRUvQXk7N6NhQiCX1zlmp1hzUW9jwC+
JEKKF1XVpQbc94Bo5supxhkKJ70CREPy8TH9mAUcQUZQRohnPvvt/lKneYAGhjHK
vhpajwlbMMSocVXFvY7o/IqIE/+ZUeQTs1SUwQIDAQABo1AwTjAdBgNVHQ4EFgQU
GnlWcIbfsWJW7GId+6xZIK8YlFEwHwYDVR0jBBgwFoAUGnlWcIbfsWJW7GId+6xZ
IK8YlFEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoFUjSD15rKlY
xudzyVlr6n0fRNhITkiZMX3JlFOvtHNYif8RfK4TH/oHNBTmle69AgixjMgy8GGd
H90prytGQ5zCs1tKcCFsN5gRSgdAkc2PpRFOK6u8HwOITV5lV7sjucsddXJcOJbQ
4fyVe47V9TTxI+A7lRnUP2HYTR1Bd0R/IgRAH57d1ZHs7omHIuQ+Ea8ph2ppXMnP
DXVOlZ9zfczSnPnQoomqULOU9Fq2ycyi8Y/ROtAHP6O7wCFbYHXhxojdaHSdhkcd
troTflFMD2/4O6MtBKbHxSmEG6H0FBYz5xUZhZq7WUH24V3xYsfge29/lOCd5/Xf
A+j0RJc/lQ==
-----END CERTIFICATE-----`)

var caKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2+W48YZoch72zj0a+ZlyFVY2q2MWmqsEY9f/u53fAeTxvPE6
1/DnqsydnA3FnGvxw9Dz0oZO6xG+PZvp+lhN07NZbuXK1nie8IpxCa342axpu4C0
69lZwxikpGyJO4IL5ywp/qfb5a2DxPTAyQOQ8ROAaydoEmktRp25yicnQ2yeZW//
1SIQxt7gRxQIGmuOQ/Gqr/XN/z2cZdbGJVRUvQXk7N6NhQiCX1zlmp1hzUW9jwC+
JEKKF1XVpQbc94Bo5supxhkKJ70CREPy8TH9mAUcQUZQRohnPvvt/lKneYAGhjHK
vhpajwlbMMSocVXFvY7o/IqIE/+ZUeQTs1SUwQIDAQABAoIBAHK94ww8W0G5QIWL
Qwkc9XeGvg4eLUxVknva2Ll4fkZJxY4WveKx9OCd1lv4n7WoacYIwUGIDaQBZShW
s/eKnkmqGy+PvpC87gqL4sHvQpuqqJ1LYpxylLEFqduWOuGPUVC2Lc+QnWCycsCS
CgqZzsbMq0S+kkKRGSvw32JJneZCzqLgLNssQNVk+Gm6SI3s4jJsGPesjhnvoPaa
xZK14uFpltaA05GSTDaQeZJFEdnnb3f/eNPc2xMEfi0S2ZlJ6Q92WJEOepAetDlR
cRFi004bNyTb4Bphg8s4+9Cti5is199aFkGCRDWxeqEnc6aMY3Ezu9Qg3uttLVUd
uy830GUCgYEA7qS0X+9UH1R02L3aoANyADVbFt2ZpUwQGauw9WM92pH52xeHAw1S
ohus6FI3OC8xQq2CN525tGLUbFDZnNZ3YQHqFsfgevfnTs1//gbKXomitev0oFKh
VT+WYS4lkgYtPlXzhdGuk32q99T/wIocAguvCUY3PiA7yBz93ReyausCgYEA6+P8
bugMqT8qjoiz1q/YCfxsw9bAGWjlVqme2xmp256AKtxvCf1BPsToAaJU3nFi3vkw
ICLxUWAYoMBODJ3YnbOsIZOavdXZwYHv54JqwqFealC3DG0Du6fZYZdiY8pK+E6m
3fiYzP1WoVK5tU4bH8ibuIQvpcI8j7Gy0cV6/AMCgYBHl7fZNAZro72uLD7DVGVF
9LvP/0kR0uDdoqli5JPw12w6szM40i1hHqZfyBJy042WsFDpeHL2z9Nkb1jpeVm1
C4r7rJkGqwqElJf6UHUzqVzb8N6hnkhyN7JYkyyIQzwdgFGfaslRzBiXYxoa3BQM
9Q5c3OjDxY3JuhDa3DoVYwKBgDNqrWJLSD832oHZAEIicBe1IswJKjQfriWWsV6W
mHSbdtpg0/88aZVR/DQm+xLFakSp0jifBTS0momngRu06Dtvp2xmLQuF6oIIXY97
2ON1owvPbibSOEcWDgb8pWCU/oRjOHIXts6vxctCKeKAFN93raGphm0+Ck9T72NU
BTubAoGBAMEhI/Wy9wAETuXwN84AhmPdQsyCyp37YKt2ZKaqu37x9v2iL8JTbPEz
pdBzkA2Gc0Wdb6ekIzRrTsJQl+c/0m9byFHsRsxXW2HnezfOFX1H4qAmF6KWP0ub
M8aIn6Rab4sNPSrvKGrU6rFpv/6M33eegzldVnV9ku6uPJI1fFTC
-----END RSA PRIVATE KEY-----`)

func main() {
    proxy := goproxy.NewProxyHttpServer()
    goproxyCa, _ := tls.X509KeyPair(caCert, caKey)
    goproxyCa.Leaf, _ = x509.ParseCertificate(goproxyCa.Certificate[0])
    goproxy.GoproxyCa = goproxyCa
    goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
    goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
    goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
    goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}

    proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*baidu.com$"))).
        HandleConnect(goproxy.AlwaysReject)
    proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
        HandleConnect(goproxy.AlwaysMitm)
    // enable curl -p for all hosts on port 80
    proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*:80$"))).
        HijackConnect(func(req *http.Request, client net.Conn, ctx *goproxy.ProxyCtx) {
        defer func() {
            if e := recover(); e != nil {
                ctx.Logf("error connecting to remote: %v", e)
                client.Write([]byte("HTTP/1.1 500 Cannot reach destination\r\n\r\n"))
            }
            client.Close()
        }()
        clientBuf := bufio.NewReadWriter(bufio.NewReader(client), bufio.NewWriter(client))
        remote, err := net.Dial("tcp", req.URL.Host)
        orPanic(err)
        remoteBuf := bufio.NewReadWriter(bufio.NewReader(remote), bufio.NewWriter(remote))
        for {
            req, err := http.ReadRequest(clientBuf.Reader)
            orPanic(err)
            orPanic(req.Write(remoteBuf))
            orPanic(remoteBuf.Flush())
            resp, err := http.ReadResponse(remoteBuf.Reader, req)
            orPanic(err)
            orPanic(resp.Write(clientBuf.Writer))
            orPanic(clientBuf.Flush())
        }
    })
    verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
    addr := flag.String("addr", ":8080", "proxy listen address")
    flag.Parse()
    proxy.Verbose = *verbose
    log.Fatal(http.ListenAndServe(*addr, proxy))
}

When running the client programming, the proxy is reached, but is throwing an error when trying to forward it to the aws S3 api.

2018/06/25 20:21:43 [004] INFO: Running 4 CONNECT handlers
2018/06/25 20:21:43 [004] INFO: on 0th handler: &{2 <nil> 0x1258190} kerberosaccept.s3.amazonaws.com:443
2018/06/25 20:21:43 [004] INFO: Assuming CONNECT is TLS, mitm proxying it
2018/06/25 20:21:43 [004] INFO: signing for kerberosaccept.s3.amazonaws.com
2018/06/25 20:21:43 [004] WARN: Cannot handshake client kerberosaccept.s3.amazonaws.com:443 remote error: tls: unknown certificate
cedricve commented 6 years ago

Hmm got it resolved by removing all proxy.OnRequest lines

chekun commented 7 months ago

@cedricve can you share how do you resolve this exactly?