This commit is contained in:
gospider
2025-01-03 09:51:55 +08:00
parent 8182106fd4
commit 34a416a1b0
7 changed files with 88 additions and 105 deletions

View File

@@ -8,7 +8,6 @@ import (
"iter"
"net"
"net/http"
"net/url"
"sync"
"sync/atomic"
"time"
@@ -110,7 +109,7 @@ type connecotr struct {
Conn Conn
c net.Conn
proxys []*url.URL
proxys []Address
}
func (obj *connecotr) withCancel(forceCtx context.Context, safeCtx context.Context) {

89
dial.go
View File

@@ -146,7 +146,7 @@ func (obj *Dialer) ProxyDialContext(ctx context.Context, ctxData *RequestOption,
return obj.dialContext(ctx, ctxData, network, addr, true)
}
func (obj *Dialer) DialProxyContext(ctx context.Context, ctxData *RequestOption, network string, proxyTlsConfig *tls.Config, proxyUrls ...*url.URL) (net.Conn, error) {
func (obj *Dialer) DialProxyContext(ctx context.Context, ctxData *RequestOption, network string, proxyTlsConfig *tls.Config, proxyUrls ...Address) (net.Conn, error) {
proxyLen := len(proxyUrls)
if proxyLen < 2 {
return nil, errors.New("proxyUrls is nil")
@@ -166,41 +166,35 @@ func (obj *Dialer) DialProxyContext(ctx context.Context, ctxData *RequestOption,
}
return conn, err
}
func getProxyAddr(proxyUrl *url.URL) (addr string, err error) {
if proxyUrl.Port() == "" {
switch proxyUrl.Scheme {
case "http":
addr = net.JoinHostPort(proxyUrl.Hostname(), "80")
case "https":
addr = net.JoinHostPort(proxyUrl.Hostname(), "443")
case "socks5":
addr = net.JoinHostPort(proxyUrl.Hostname(), "1080")
default:
return "", errors.New("not support scheme")
}
} else {
addr = net.JoinHostPort(proxyUrl.Hostname(), proxyUrl.Port())
}
return
}
func (obj *Dialer) dialProxyContext(ctx context.Context, ctxData *RequestOption, network string, proxyUrl *url.URL) (net.Conn, error) {
if proxyUrl == nil {
return nil, errors.New("proxyUrl is nil")
}
// func getProxyAddr(proxyUrl *url.URL) (addr string, err error) {
// if proxyUrl.Port() == "" {
// switch proxyUrl.Scheme {
// case "http":
// addr = net.JoinHostPort(proxyUrl.Hostname(), "80")
// case "https":
// addr = net.JoinHostPort(proxyUrl.Hostname(), "443")
// case "socks5":
// addr = net.JoinHostPort(proxyUrl.Hostname(), "1080")
// default:
// return "", errors.New("not support scheme")
// }
// } else {
// addr = net.JoinHostPort(proxyUrl.Hostname(), proxyUrl.Port())
// }
// return
// }
func (obj *Dialer) dialProxyContext(ctx context.Context, ctxData *RequestOption, network string, proxyUrl Address) (net.Conn, error) {
if ctxData == nil {
ctxData = &RequestOption{}
}
addr, err := GetAddressWithUrl(proxyUrl)
if err != nil {
return nil, err
}
return obj.ProxyDialContext(ctx, ctxData, network, addr)
return obj.ProxyDialContext(ctx, ctxData, network, proxyUrl)
}
func (obj *Dialer) verifyProxyToRemote(ctx context.Context, option *RequestOption, conn net.Conn, proxyTlsConfig *tls.Config, proxyUrl *url.URL, remoteUrl *url.URL) (net.Conn, error) {
func (obj *Dialer) verifyProxyToRemote(ctx context.Context, option *RequestOption, conn net.Conn, proxyTlsConfig *tls.Config, proxyAddress Address, remoteAddress Address) (net.Conn, error) {
var err error
if proxyUrl.Scheme == "https" {
if conn, err = obj.addTls(ctx, conn, proxyUrl.Host, true, proxyTlsConfig); err != nil {
if proxyAddress.Scheme == "https" {
if conn, err = obj.addTls(ctx, conn, proxyAddress.Host, true, proxyTlsConfig); err != nil {
return conn, err
}
if option.Logger != nil {
@@ -208,39 +202,31 @@ func (obj *Dialer) verifyProxyToRemote(ctx context.Context, option *RequestOptio
Id: option.requestId,
Time: time.Now(),
Type: LogType_ProxyTLSHandshake,
Msg: proxyUrl.String(),
Msg: proxyAddress.String(),
})
}
}
done := make(chan struct{})
go func() {
switch proxyUrl.Scheme {
switch proxyAddress.Scheme {
case "http", "https":
err = obj.clientVerifyHttps(ctx, conn, proxyUrl, remoteUrl)
err = obj.clientVerifyHttps(ctx, conn, proxyAddress, remoteAddress)
if option.Logger != nil {
option.Logger(Log{
Id: option.requestId,
Time: time.Now(),
Type: LogType_ProxyConnectRemote,
Msg: remoteUrl.String(),
Msg: remoteAddress.String(),
})
}
case "socks5":
var proxyAddress Address
var remoteAddress Address
if proxyAddress, err = GetAddressWithUrl(proxyUrl); err != nil {
return
}
if remoteAddress, err = GetAddressWithUrl(remoteUrl); err != nil {
return
}
err = obj.verifyTCPSocks5(conn, proxyAddress, remoteAddress)
if option.Logger != nil {
option.Logger(Log{
Id: option.requestId,
Time: time.Now(),
Type: LogType_ProxyTCPConnect,
Msg: remoteUrl.String(),
Msg: remoteAddress.String(),
})
}
}
@@ -495,25 +481,18 @@ func (obj *Dialer) Socks5UdpProxy(ctx context.Context, ctxData *RequestOption, p
return
}
}
func (obj *Dialer) clientVerifyHttps(ctx context.Context, conn net.Conn, proxyUrl *url.URL, remoteUrl *url.URL) (err error) {
func (obj *Dialer) clientVerifyHttps(ctx context.Context, conn net.Conn, proxyAddress Address, remoteAddress Address) (err error) {
hdr := make(http.Header)
hdr.Set("User-Agent", tools.UserAgent)
if proxyUrl.User != nil {
if password, ok := proxyUrl.User.Password(); ok {
hdr.Set("Proxy-Authorization", "Basic "+tools.Base64Encode(proxyUrl.User.Username()+":"+password))
}
if proxyAddress.User != "" && proxyAddress.Password != "" {
hdr.Set("Proxy-Authorization", "Basic "+tools.Base64Encode(proxyAddress.User+":"+proxyAddress.Password))
}
addr, err := getProxyAddr(remoteUrl)
connectReq, err := NewRequestWithContext(ctx, http.MethodConnect, &url.URL{Opaque: remoteAddress.String()}, nil)
if err != nil {
return err
}
connectReq, err := NewRequestWithContext(ctx, http.MethodConnect, &url.URL{Opaque: addr}, nil)
if err != nil {
return err
}
connectReq.Header = hdr
connectReq.Host = remoteUrl.Host
connectReq.Host = remoteAddress.Host
if err = connectReq.Write(conn); err != nil {
return err
}

View File

@@ -339,7 +339,7 @@ func (obj *Response) IsNewConn() bool {
}
// conn proxy
func (obj *Response) Proxys() []*url.URL {
func (obj *Response) Proxys() []Address {
if obj.rawConn != nil {
return obj.rawConn.Proxys()
}

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"io"
"net"
"net/url"
"time"
"net/http"
@@ -91,25 +90,20 @@ func (obj *roundTripper) newConnecotr() *connecotr {
return conne
}
func (obj *roundTripper) http3Dial(ctx context.Context, option *RequestOption, proxyUrl *url.URL, remtoeAddress Address) (udpConn net.PacketConn, err error) {
if proxyUrl != nil {
if proxyUrl.Scheme != "socks5" {
func (obj *roundTripper) http3Dial(ctx context.Context, option *RequestOption, proxyAddress Address, remtoeAddress Address) (udpConn net.PacketConn, err error) {
if !proxyAddress.Nil() {
if proxyAddress.Scheme != "socks5" {
err = errors.New("http3 only socks5 proxy supported")
return
}
var proxyAddress Address
proxyAddress, err = GetAddressWithUrl(proxyUrl)
if err != nil {
return nil, err
}
udpConn, err = obj.dialer.Socks5UdpProxy(ctx, option, proxyAddress, remtoeAddress)
} else {
udpConn, err = net.ListenUDP("udp", nil)
}
return
}
func (obj *roundTripper) ghttp3Dial(ctx context.Context, option *RequestOption, proxyUrl *url.URL, remoteAddress Address) (conn *connecotr, err error) {
udpConn, err := obj.http3Dial(ctx, option, proxyUrl, remoteAddress)
func (obj *roundTripper) ghttp3Dial(ctx context.Context, option *RequestOption, proxyAddress Address, remoteAddress Address) (conn *connecotr, err error) {
udpConn, err := obj.http3Dial(ctx, option, proxyAddress, remoteAddress)
if err != nil {
return nil, err
}
@@ -130,8 +124,8 @@ func (obj *roundTripper) ghttp3Dial(ctx context.Context, option *RequestOption,
return
}
func (obj *roundTripper) uhttp3Dial(ctx context.Context, option *RequestOption, proxyUrl *url.URL, remoteAddress Address) (conn *connecotr, err error) {
udpConn, err := obj.http3Dial(ctx, option, proxyUrl, remoteAddress)
func (obj *roundTripper) uhttp3Dial(ctx context.Context, option *RequestOption, proxyAddress Address, remoteAddress Address) (conn *connecotr, err error) {
udpConn, err := obj.http3Dial(ctx, option, proxyAddress, remoteAddress)
if err != nil {
return nil, err
}
@@ -157,15 +151,15 @@ func (obj *roundTripper) dial(option *RequestOption, req *http.Request) (conn *c
if err != nil {
return nil, err
}
remoteAddress, err := GetAddressWithUrl(req.URL)
if err != nil {
return nil, err
}
if option.H3 {
var proxyUrl *url.URL
var proxyUrl Address
if len(proxys) > 0 {
proxyUrl = proxys[0]
}
remoteAddress, err := GetAddressWithUrl(req.URL)
if err != nil {
return nil, err
}
if option.Ja3Spec.IsSet() {
return obj.uhttp3Dial(req.Context(), option, proxyUrl, remoteAddress)
} else {
@@ -174,7 +168,7 @@ func (obj *roundTripper) dial(option *RequestOption, req *http.Request) (conn *c
}
var netConn net.Conn
if len(proxys) > 0 {
netConn, err = obj.dialer.DialProxyContext(req.Context(), option, "tcp", option.TlsConfig.Clone(), append(proxys, cloneUrl(req.URL))...)
netConn, err = obj.dialer.DialProxyContext(req.Context(), option, "tcp", option.TlsConfig.Clone(), append(proxys, remoteAddress)...)
} else {
var remoteAddress Address
remoteAddress, err = GetAddressWithUrl(req.URL)
@@ -249,18 +243,26 @@ func (obj *roundTripper) dialAddTls(option *RequestOption, req *http.Request, ne
}
}
}
func (obj *roundTripper) initProxys(option *RequestOption, req *http.Request) ([]*url.URL, error) {
var proxys []*url.URL
func (obj *roundTripper) initProxys(option *RequestOption, req *http.Request) ([]Address, error) {
var proxys []Address
if option.DisProxy {
return nil, nil
}
if option.proxy != nil {
proxys = []*url.URL{cloneUrl(option.proxy)}
proxyAddress, err := GetAddressWithUrl(option.proxy)
if err != nil {
return nil, err
}
proxys = []Address{proxyAddress}
}
if len(proxys) == 0 && len(option.proxys) > 0 {
proxys = make([]*url.URL, len(option.proxys))
proxys = make([]Address, len(option.proxys))
for i, proxy := range option.proxys {
proxys[i] = cloneUrl(proxy)
proxyAddress, err := GetAddressWithUrl(proxy)
if err != nil {
return nil, err
}
proxys[i] = proxyAddress
}
}
if len(proxys) == 0 && option.GetProxy != nil {
@@ -273,7 +275,11 @@ func (obj *roundTripper) initProxys(option *RequestOption, req *http.Request) ([
if err != nil {
return proxys, err
}
proxys = []*url.URL{proxy}
proxyAddress, err := GetAddressWithUrl(proxy)
if err != nil {
return nil, err
}
proxys = []Address{proxyAddress}
}
}
if len(proxys) == 0 && option.GetProxys != nil {
@@ -282,13 +288,17 @@ func (obj *roundTripper) initProxys(option *RequestOption, req *http.Request) ([
return proxys, err
}
if l := len(proxyStrs); l > 0 {
proxys = make([]*url.URL, l)
proxys = make([]Address, l)
for i, proxyStr := range proxyStrs {
proxy, err := gtls.VerifyProxy(proxyStr)
if err != nil {
return proxys, err
}
proxys[i] = proxy
proxyAddress, err := GetAddressWithUrl(proxy)
if err != nil {
return nil, err
}
proxys[i] = proxyAddress
}
}
}

9
rw.go
View File

@@ -4,7 +4,6 @@ import (
"errors"
"io"
"net"
"net/url"
)
type readWriteCloser struct {
@@ -22,13 +21,7 @@ func (obj *readWriteCloser) Read(p []byte) (n int, err error) {
}
return i, err
}
func (obj *readWriteCloser) Proxys() []*url.URL {
if l := len(obj.conn.proxys); l > 0 {
proxys := make([]*url.URL, l)
for i, proxy := range obj.conn.proxys {
proxys[i] = cloneUrl(proxy)
}
}
func (obj *readWriteCloser) Proxys() []Address {
return obj.conn.proxys
}

View File

@@ -81,6 +81,7 @@ type Address struct {
IP net.IP
Port int
NetWork string
Scheme string
}
func (a Address) String() string {
@@ -93,6 +94,9 @@ func (a Address) String() string {
func (a Address) Network() string {
return a.NetWork
}
func (a Address) Nil() bool {
return a.IP == nil && a.Name == ""
}
func ReadUdpAddr(r io.Reader) (Address, error) {
UdpAddress := Address{}

View File

@@ -57,32 +57,30 @@ func GetAddressWithUrl(uurl *url.URL) (addr Address, err error) {
if uurl == nil {
return Address{}, errors.New("url is nil")
}
var port int
addr = Address{
Name: uurl.Hostname(),
Host: uurl.Host,
}
portStr := uurl.Port()
addr.Scheme = uurl.Scheme
if portStr == "" {
switch uurl.Scheme {
case "http":
port = 80
addr.Port = 80
case "https":
port = 443
addr.Port = 443
case "socks5":
port = 1080
addr.Port = 1080
default:
return Address{}, errors.New("unknown scheme")
}
} else {
port, err = strconv.Atoi(portStr)
addr.Port, err = strconv.Atoi(portStr)
if err != nil {
return Address{}, err
}
}
ip, _ := gtls.ParseHost(uurl.Hostname())
addr = Address{
Name: uurl.Hostname(),
Host: uurl.Host,
IP: ip,
Port: port,
}
addr.IP, _ = gtls.ParseHost(uurl.Hostname())
if uurl.User != nil {
addr.User = uurl.User.Username()
addr.Password, _ = uurl.User.Password()