This commit is contained in:
gospider
2025-02-13 14:54:00 +08:00
parent 99f9906eb2
commit f57ab9b73c
8 changed files with 31 additions and 38 deletions

View File

@@ -4,7 +4,6 @@ import (
"bufio"
"context"
"errors"
"github.com/gospider007/tools"
"io"
"iter"
"net"
@@ -12,6 +11,8 @@ import (
"sync"
"sync/atomic"
"time"
"github.com/gospider007/tools"
)
var maxRetryCount = 10

30
dial.go
View File

@@ -13,7 +13,6 @@ import (
"time"
"github.com/gospider007/gtls"
"github.com/gospider007/ja3"
"github.com/gospider007/tools"
utls "github.com/refraction-networking/utls"
)
@@ -37,9 +36,7 @@ type dialer interface {
// 自定义dialer
type Dialer struct {
dnsIpData sync.Map
specClient *ja3.Client
// dialer dialer
dnsIpData sync.Map
}
type myDialer struct {
dialer *net.Dialer
@@ -156,18 +153,18 @@ func (obj *Dialer) DialProxyContext(ctx *Response, network string, proxyTlsConfi
return packCon, conn, err
}
}
packCon, conn, err = obj.verifyProxyToRemote(ctx, conn, proxyTlsConfig, oneProxy, remoteUrl, index == proxyLen-2)
packCon, conn, err = obj.verifyProxyToRemote(ctx, conn, proxyTlsConfig, oneProxy, remoteUrl, index == proxyLen-2, true)
}
return packCon, conn, err
}
func (obj *Dialer) dialProxyContext(ctx *Response, network string, proxyUrl Address) (net.Conn, error) {
return obj.ProxyDialContext(ctx, network, proxyUrl)
}
func (obj *Dialer) verifyProxyToRemote(ctx *Response, conn net.Conn, proxyTlsConfig *tls.Config, proxyAddress Address, remoteAddress Address, isLast bool) (net.PacketConn, net.Conn, error) {
func (obj *Dialer) verifyProxyToRemote(ctx *Response, conn net.Conn, proxyTlsConfig *tls.Config, proxyAddress Address, remoteAddress Address, isLast bool, forceHttp1 bool) (net.PacketConn, net.Conn, error) {
var err error
var packCon net.PacketConn
if proxyAddress.Scheme == "https" {
if conn, err = obj.addTls(ctx.Context(), conn, proxyAddress.Host, true, proxyTlsConfig); err != nil {
if conn, err = obj.addTls(ctx.Context(), conn, proxyAddress.Host, proxyTlsConfig, forceHttp1); err != nil {
return packCon, conn, err
}
if ctx.option.Logger != nil {
@@ -193,7 +190,7 @@ func (obj *Dialer) verifyProxyToRemote(ctx *Response, conn net.Conn, proxyTlsCon
})
}
case "socks5":
if isLast && ctx.option.H3 {
if isLast && ctx.option.ForceHttp3 {
packCon, err = obj.verifyUDPSocks5(ctx.Context(), conn, proxyAddress, remoteAddress)
} else {
err = obj.verifyTCPSocks5(conn, proxyAddress, remoteAddress)
@@ -381,24 +378,19 @@ func (obj *Dialer) lookupIPAddr(ips []net.IPAddr, addrType gtls.AddrType) (net.I
}
return nil, errors.New("dns parse host error")
}
func (obj *Dialer) addTls(ctx context.Context, conn net.Conn, host string, h2 bool, tlsConfig *tls.Config) (*tls.Conn, error) {
func (obj *Dialer) addTls(ctx context.Context, conn net.Conn, host string, tlsConfig *tls.Config, forceHttp1 bool) (*tls.Conn, error) {
var tlsConn *tls.Conn
tlsConfig.ServerName = gtls.GetServerName(host)
if h2 {
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
} else {
if forceHttp1 {
tlsConfig.NextProtos = []string{"http/1.1"}
} else {
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
}
tlsConn = tls.Client(conn, tlsConfig)
return tlsConn, tlsConn.HandshakeContext(ctx)
}
func (obj *Dialer) addJa3Tls(ctx context.Context, conn net.Conn, host string, h2 bool, spec utls.ClientHelloSpec, tlsConfig *utls.Config) (*utls.UConn, error) {
if h2 {
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
} else {
tlsConfig.NextProtos = []string{"http/1.1"}
}
return obj.specClient.Client(ctx, conn, spec, h2, tlsConfig, gtls.GetServerName(host))
func (obj *Dialer) addJa3Tls(ctx context.Context, conn net.Conn, host string, spec utls.ClientHelloSpec, tlsConfig *utls.Config, forceHttp1 bool) (*utls.UConn, error) {
return specClient.Client(ctx, conn, spec, tlsConfig, gtls.GetServerName(host), forceHttp1)
}
func (obj *Dialer) Socks5TcpProxy(ctx *Response, proxyAddr Address, remoteAddr Address) (conn net.Conn, err error) {
if conn, err = obj.DialContext(ctx, "tcp", proxyAddr); err != nil {

View File

@@ -64,7 +64,7 @@ type ClientOption struct {
Timeout time.Duration //request timeout
ResponseHeaderTimeout time.Duration //ResponseHeaderTimeout ,default:300
TlsHandshakeTimeout time.Duration //tls timeout,default:15
H3 bool //开启http3
ForceHttp3 bool //force use http3 send requests
ForceHttp1 bool //force use http1 send requests
DisCookie bool //disable cookies
DisDecode bool //disable auto decode

View File

@@ -55,17 +55,17 @@ type roundTripper struct {
dialer *Dialer
}
var specClient = ja3.NewClient()
func newRoundTripper(preCtx context.Context) *roundTripper {
if preCtx == nil {
preCtx = context.TODO()
}
ctx, cnl := context.WithCancel(preCtx)
return &roundTripper{
ctx: ctx,
cnl: cnl,
dialer: &Dialer{
specClient: ja3.NewClient(),
},
ctx: ctx,
cnl: cnl,
dialer: new(Dialer),
connPools: newConnPools(),
}
}
@@ -176,7 +176,7 @@ func (obj *roundTripper) dial(ctx *Response) (conn *connecotr, err error) {
if err != nil {
return nil, err
}
if ctx.option.H3 {
if ctx.option.ForceHttp3 {
if ctx.option.USpec != nil {
spec, err := ja3.CreateUSpec(ctx.option.USpec)
if err != nil {
@@ -258,14 +258,14 @@ func (obj *roundTripper) dialAddTls(option *RequestOption, req *http.Request, ne
return nil, false, err
}
if len(spec.Extensions) > 0 {
if tlsConn, err := obj.dialer.addJa3Tls(ctx, netConn, getHost(req), !option.ForceHttp1, spec, option.UtlsConfig.Clone()); err != nil {
if tlsConn, err := obj.dialer.addJa3Tls(ctx, netConn, getHost(req), spec, option.UtlsConfig.Clone(), option.ForceHttp1); err != nil {
return tlsConn, false, tools.WrapError(err, "add ja3 tls error")
} else {
return tlsConn, tlsConn.ConnectionState().NegotiatedProtocol == "h2", nil
}
}
}
if tlsConn, err := obj.dialer.addTls(ctx, netConn, getHost(req), !option.ForceHttp1, option.TlsConfig.Clone()); err != nil {
if tlsConn, err := obj.dialer.addTls(ctx, netConn, getHost(req), option.TlsConfig.Clone(), option.ForceHttp1); err != nil {
return tlsConn, false, tools.WrapError(err, "add tls error")
} else {
return tlsConn, tlsConn.ConnectionState().NegotiatedProtocol == "h2", nil

View File

@@ -11,8 +11,8 @@ import (
func TestHttp3(t *testing.T) {
resp, err := requests.Get(context.TODO(), "https://cloudflare-quic.com/", requests.RequestOption{
ClientOption: requests.ClientOption{
H3: true,
Spec: true,
ForceHttp3: true,
Spec: true,
},
},
)
@@ -31,8 +31,8 @@ func TestHttp3(t *testing.T) {
func TestHttp32(t *testing.T) {
resp, err := requests.Get(context.TODO(), "https://cloudflare-quic.com/", requests.RequestOption{
ClientOption: requests.ClientOption{
USpec: true,
H3: true,
USpec: true,
ForceHttp3: true,
},
},
)

View File

@@ -12,7 +12,7 @@ func TestHttp3(t *testing.T) {
resp, err := requests.Get(context.TODO(), "https://cloudflare-quic.com/", requests.RequestOption{
ClientOption: requests.ClientOption{
H3: true,
// H3: true,
},
},
)

View File

@@ -28,7 +28,7 @@ func client() {
resp, err := requests.Post(nil, "https://"+remoteHost, requests.RequestOption{
ClientOption: requests.ClientOption{
H3: true,
ForceHttp3: true,
Logger: func(l requests.Log) {
log.Print(l)
},
@@ -51,7 +51,7 @@ func client2() {
resp, err := requests.Post(nil, "https://"+remoteHost, requests.RequestOption{
ClientOption: requests.ClientOption{
H3: true,
ForceHttp3: true,
Logger: func(l requests.Log) {
log.Print(l)
},
@@ -130,7 +130,7 @@ func TestHttp3Proxy2(t *testing.T) {
resp, err := requests.Get(context.TODO(), "https://cloudflare-quic.com/", requests.RequestOption{
ClientOption: requests.ClientOption{
H3: true,
ForceHttp3: true,
// Logger: func(l requests.Log) {
// log.Print(l)
// },

View File

@@ -49,7 +49,7 @@ func TestSession2(t *testing.T) {
func TestSession3(t *testing.T) {
session, _ := requests.NewClient(nil)
for i := 0; i < 2; i++ {
resp, err := session.Get(nil, "https://cloudflare-quic.com/", requests.RequestOption{ClientOption: requests.ClientOption{H3: true}})
resp, err := session.Get(nil, "https://cloudflare-quic.com/", requests.RequestOption{ClientOption: requests.ClientOption{ForceHttp3: true}})
if err != nil {
t.Error(err)
}