fix https can use https_proxy env

addon-dailer
lqqyt2423 2 years ago
parent a7b41a4887
commit b70d2bc9cc

@ -1,11 +1,16 @@
package proxy package proxy
import ( import (
"bufio"
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"errors"
"net" "net"
"net/http" "net/http"
"net/url"
"strings"
"time"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -138,13 +143,24 @@ func (connCtx *ConnContext) initHttpServerConn() {
connCtx.ServerConn = serverConn connCtx.ServerConn = serverConn
} }
func (connCtx *ConnContext) initServerTcpConn() error { func (connCtx *ConnContext) initServerTcpConn(req *http.Request) error {
log.Debugln("in initServerTcpConn") log.Debugln("in initServerTcpConn")
ServerConn := newServerConn() ServerConn := newServerConn()
connCtx.ServerConn = ServerConn connCtx.ServerConn = ServerConn
ServerConn.Address = connCtx.pipeConn.host ServerConn.Address = connCtx.pipeConn.host
plainConn, err := (&net.Dialer{}).DialContext(context.Background(), "tcp", ServerConn.Address) // test is use proxy
clientReq := &http.Request{URL: &url.URL{Scheme: "https", Host: ServerConn.Address}}
proxyUrl, err := http.ProxyFromEnvironment(clientReq)
if err != nil {
return err
}
var plainConn net.Conn
if proxyUrl != nil {
plainConn, err = getProxyConn(proxyUrl, ServerConn.Address)
} else {
plainConn, err = (&net.Dialer{}).DialContext(context.Background(), "tcp", ServerConn.Address)
}
if err != nil { if err != nil {
return err return err
} }
@ -161,13 +177,63 @@ func (connCtx *ConnContext) initServerTcpConn() error {
return nil return nil
} }
// connect proxy when set https_proxy env
// ref: http/transport.go dialConn func
func getProxyConn(proxyUrl *url.URL, address string) (net.Conn, error) {
conn, err := (&net.Dialer{}).DialContext(context.Background(), "tcp", proxyUrl.Host)
if err != nil {
return nil, err
}
connectReq := &http.Request{
Method: "CONNECT",
URL: &url.URL{Opaque: address},
Host: address,
}
connectCtx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails
var resp *http.Response
// Write the CONNECT request & read the response.
go func() {
defer close(didReadResponse)
err = connectReq.Write(conn)
if err != nil {
return
}
// Okay to use and discard buffered reader here, because
// TLS server will not speak until spoken to.
br := bufio.NewReader(conn)
resp, err = http.ReadResponse(br, connectReq)
}()
select {
case <-connectCtx.Done():
conn.Close()
<-didReadResponse
return nil, connectCtx.Err()
case <-didReadResponse:
// resp or err now set
}
if err != nil {
conn.Close()
return nil, err
}
if resp.StatusCode != 200 {
_, text, ok := strings.Cut(resp.Status, " ")
conn.Close()
if !ok {
return nil, errors.New("unknown status code")
}
return nil, errors.New(text)
}
return conn, nil
}
func (connCtx *ConnContext) initHttpsServerConn() { func (connCtx *ConnContext) initHttpsServerConn() {
if !connCtx.ClientConn.Tls { if !connCtx.ClientConn.Tls {
return return
} }
connCtx.ServerConn.client = &http.Client{ connCtx.ServerConn.client = &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
<-connCtx.ServerConn.tlsHandshaked <-connCtx.ServerConn.tlsHandshaked
return connCtx.ServerConn.tlsConn, connCtx.ServerConn.tlsHandshakeErr return connCtx.ServerConn.tlsConn, connCtx.ServerConn.tlsHandshakeErr

@ -140,7 +140,7 @@ func (m *middle) close() error {
func (m *middle) dial(req *http.Request) (net.Conn, error) { func (m *middle) dial(req *http.Request) (net.Conn, error) {
pipeClientConn, pipeServerConn := newPipes(req) pipeClientConn, pipeServerConn := newPipes(req)
err := pipeServerConn.connContext.initServerTcpConn() err := pipeServerConn.connContext.initServerTcpConn(req)
if err != nil { if err != nil {
pipeClientConn.Close() pipeClientConn.Close()
pipeServerConn.Close() pipeServerConn.Close()

Loading…
Cancel
Save