Null-DRM-Official/apps/proxy/device/utls_dial.go
404errordeveloper 2fa8f2435f Initial commit: Null DRM Official
Capture, decrypt, and restream toolkit with compiled-in app modules
(RTE, TG4, BBC), on-device MITM proxy, streamd control plane, and www.
BBC module.yaml is published (clear streams); other module values stay local.
2026-10-06 00:25:35 +02:00

77 lines
2.1 KiB
Go

package main
import (
"context"
"crypto/tls"
"fmt"
"net"
"strings"
"time"
utls "github.com/refraction-networking/utls"
)
// dialTLSChrome dials addr with a Chrome-like ClientHello so CDNs (Fastly)
// are less likely to HTTP 403 Go's default TLS fingerprint.
// Handshakes as HTTP/1.1 only so net/http can use the returned conn.
func dialTLSChrome(ctx context.Context, dialCtx func(context.Context, string, string) (net.Conn, error), network, addr string) (net.Conn, error) {
host := serverNameFromAddr(addr)
raw, err := dialCtx(ctx, network, addr)
if err != nil {
return nil, err
}
cfg := &utls.Config{
ServerName: host,
InsecureSkipVerify: true,
NextProtos: []string{"http/1.1"},
}
spec, err := utls.UTLSIdToSpec(utls.HelloChrome_120)
if err != nil {
_ = raw.Close()
return dialTLSStd(ctx, dialCtx, network, addr)
}
for i := range spec.Extensions {
if alpn, ok := spec.Extensions[i].(*utls.ALPNExtension); ok {
alpn.AlpnProtocols = []string{"http/1.1"}
}
}
uConn := utls.UClient(raw, cfg, utls.HelloCustom)
if err := uConn.ApplyPreset(&spec); err != nil {
_ = raw.Close()
return nil, fmt.Errorf("utls preset %s: %w", host, err)
}
deadline, ok := ctx.Deadline()
if !ok {
deadline = time.Now().Add(15 * time.Second)
}
_ = raw.SetDeadline(deadline)
if err := uConn.Handshake(); err != nil {
_ = raw.Close()
return nil, fmt.Errorf("utls handshake %s: %w", host, err)
}
_ = raw.SetDeadline(time.Time{})
return uConn, nil
}
func dialTLSStd(ctx context.Context, dialCtx func(context.Context, string, string) (net.Conn, error), network, addr string) (net.Conn, error) {
host := serverNameFromAddr(addr)
raw, err := dialCtx(ctx, network, addr)
if err != nil {
return nil, err
}
cfg := &tls.Config{ServerName: host, InsecureSkipVerify: true, NextProtos: []string{"http/1.1"}}
c := tls.Client(raw, cfg)
if err := c.HandshakeContext(ctx); err != nil {
_ = raw.Close()
return nil, err
}
return c, nil
}
func serverNameFromAddr(addr string) string {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return strings.TrimSpace(addr)
}
return host
}