-
Notifications
You must be signed in to change notification settings - Fork 61
Description
I've got a feature request I'd love to share. I'm using cloudflared and encountered this problem
# cloudflared update
2025-02-15T06:22:36Z ERR update failed to apply error="Get \"https://github.com/cloudflare/cloudflared/releases/download/2025.2.0/cloudflared-linux-arm64\": read tcp x.x.x.x:43954->140.82.116.4:443: read: connection reset by peer"
failed to update cloudflared: Get "https://github.com/cloudflare/cloudflared/releases/download/2025.2.0/cloudflared-linux-arm64": read tcp x.x.x.x:43954->140.82.116.4:443: read: connection reset by peer
This is caused by the SNI blocking in our region.
When I discovered this repository, I noticed that it primarily focuses on enhancing the TLS stack with intriguing new features, mostly derived from RFC specifications.
I'm especially excited about this because I know a simple yet effective method to bypass certain SNI blocking techniques — though not mentioned in the RFCs. The approach is straightforward and interesting enough that I'd like to demonstrate it directly through a draft PR #189.
I understand that this repository values easy synchronization with the upstream. However, since my proposed changes are minimal and this specific code has remained stable for years (from Go 1.19 through 1.24, as far as I know), I was hoping that we could discuss this design together.
Specifically, in my current proposal, when creating a specialized HTTP TLS client, you could make a client like
import (
"context"
"crypto/tls"
"io"
"net"
"net/http"
"os"
"time"
)
var defaultDialer = net.Dialer{
Timeout: time.Minute,
}
var DefaultClient = http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
if defaultDialer.Timeout != 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, defaultDialer.Timeout)
defer cancel()
}
if !defaultDialer.Deadline.IsZero() {
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(ctx, defaultDialer.Deadline)
defer cancel()
}
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
// The host it looked up must be correct.
addrs, err := net.DefaultResolver.LookupHost(ctx, host)
if err != nil {
return nil, err
}
var conn net.Conn
var tlsConn *tls.Conn
for _, a := range addrs {
conn, err = defaultDialer.DialContext(ctx, network, net.JoinHostPort(a, port))
if err != nil {
continue
}
// MAINLY THIS PART ⬇
tlsConn = tls.Client(conn, &tls.Config{
ServerName: host,
})
tlsConn.SetFirstHandshakeRecordMaxPayloadSize(4) // the proposed feature
err = tlsConn.HandshakeContext(ctx)
if err == nil {
break
}
_ = tlsConn.Close()
// MAINLY THIS PART ⬆
tlsConn = nil
conn, err = defaultDialer.DialContext(ctx, network, net.JoinHostPort(a, port))
if err != nil {
continue
}
tlsConn = tls.Client(conn, &tls.Config{
ServerName: host,
})
err = tlsConn.HandshakeContext(ctx)
if err == nil {
break
}
_ = tlsConn.Close()
tlsConn = nil
}
return tlsConn, err
},
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
Then I compiled it using the edited go and download that file again
func main() {
resp, err := DefaultClient.Get("https://github.com/cloudflare/cloudflared/releases/download/2025.2.0/cloudflared-linux-arm64")
if err != nil {
panic(err)
}
defer resp.Body.Close()
f, err := os.Create("cloudflared-linux-arm64")
if err != nil {
panic(err)
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
}
At this time it works well.