diff --git a/cmd/probe/main.go b/cmd/probe/main.go
@@ -11,7 +11,7 @@ import (
"net"
"net/http"
- utls "github.com/refraction-networking/utls"
+ utls "github.com/bogdanfinn/utls"
"golang.org/x/net/http2"
)
@@ -19,11 +19,28 @@ var presets = []struct {
name string
id utls.ClientHelloID
}{
+ // Chrome
{"HelloChrome_120", utls.HelloChrome_120},
{"HelloChrome_120_PQ", utls.HelloChrome_120_PQ},
+ {"HelloChrome_131", utls.HelloChrome_131},
+ {"HelloChrome_133", utls.HelloChrome_133},
+ // Firefox
{"HelloFirefox_120", utls.HelloFirefox_120},
+ // Safari / iOS
+ {"HelloSafari_15_6_1", utls.HelloSafari_15_6_1},
{"HelloSafari_16_0", utls.HelloSafari_16_0},
+ {"HelloIOS_15_5", utls.HelloIOS_15_5},
+ {"HelloIOS_15_6", utls.HelloIOS_15_6},
+ {"HelloIOS_16_0", utls.HelloIOS_16_0},
+ // Edge
+ {"HelloEdge_85", utls.HelloEdge_85},
{"HelloEdge_106", utls.HelloEdge_106},
+ // Opera
+ {"HelloOpera_89", utls.HelloOpera_89},
+ {"HelloOpera_90", utls.HelloOpera_90},
+ {"HelloOpera_91", utls.HelloOpera_91},
+ // Android
+ {"HelloAndroid_11_OkHttp", utls.HelloAndroid_11_OkHttp},
}
func dialUTLS(ctx context.Context, id utls.ClientHelloID) (*utls.UConn, error) {
@@ -31,7 +48,7 @@ func dialUTLS(ctx context.Context, id utls.ClientHelloID) (*utls.UConn, error) {
if err != nil {
return nil, err
}
- uconn := utls.UClient(tcpConn, &utls.Config{ServerName: "tlsinfo.me"}, id)
+ uconn := utls.UClient(tcpConn, &utls.Config{ServerName: "tlsinfo.me"}, id, false, false, false)
if err := uconn.Handshake(); err != nil {
tcpConn.Close()
return nil, err
diff --git a/cmd/root.go b/cmd/root.go
@@ -24,7 +24,7 @@ var SKID_ASCII_ART = `
-------- ⠀⠀⢸⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⣙⢿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀
⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠻⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀
djnn.sh⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⢹⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀
- ⠀v0.0.1 ⠀⠀⢠⣿⣿⣿⣿⡟⠹⠿⠟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀
+ ⠀v0.0.3 ⠀⠀⢠⣿⣿⣿⣿⡟⠹⠿⠟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡿⠋⡬⢿⣿⣷⣤⣤⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⡇⢸⡇⢸⣿⣿⣿⠟⠁⢀⣬⢽⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣧⣈⣛⣿⣿⣿⡇⠀⠀⣾⠁⢀⢻⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀
diff --git a/fingerprint/fingerprint.go b/fingerprint/fingerprint.go
@@ -2,7 +2,7 @@
// outbound connection fingerprints (TLS ClientHello, TCP socket options, etc.).
package fingerprint
-import utls "github.com/refraction-networking/utls"
+import utls "github.com/bogdanfinn/utls"
// Applier is the base interface for all fingerprint types.
type Applier interface {
diff --git a/fingerprint/tls.go b/fingerprint/tls.go
@@ -3,24 +3,22 @@ package fingerprint
import (
"fmt"
- utls "github.com/refraction-networking/utls"
+ utls "github.com/bogdanfinn/utls"
)
// Table maps known JA4-TLS fingerprint hashes to utls ClientHelloID presets.
-// JA4 hashes are computed from real traffic captures; verify against current
-// browser versions when adding new entries.
-// Table maps JA4-TLS hashes to utls ClientHelloID presets.
//
// Hashes are measured empirically against tlsinfo.me using cmd/probe — they
// reflect what the utls preset actually emits, not captures from real browsers.
// Re-run cmd/probe after upgrading the utls dependency to verify they still match.
//
-// Note: HelloChrome_120_PQ produces the same JA4 as HelloChrome_120 because the
-// post-quantum key share (X25519MLKEM768) falls in a key_share extension entry
-// that JA4 does not distinguish. Use HelloChrome_120_PQ directly in dialTarget
-// if you specifically need the PQ key exchange behaviour.
+// Note: JA4 does not distinguish key_share entries, so Chrome_120, Chrome_120_PQ,
+// and Chrome_131 all produce the same hash. Use the preset directly in dialTarget
+// if you need a specific variant (e.g. HelloChrome_120_PQ for PQ key exchange).
+// Similarly, Safari_15_6_1, Safari_16_0, and all iOS variants share one hash.
var Table = map[string]utls.ClientHelloID{
- "t13d1516h2_8daaf6152771_02713d6af862": utls.HelloChrome_120,
+ "t13d1516h2_8daaf6152771_02713d6af862": utls.HelloChrome_131,
+ "t13d1516h2_8daaf6152771_d8a2da3f94cd": utls.HelloChrome_133,
"t13d1715h2_5b57614c22b0_5c2c66f702b0": utls.HelloFirefox_120,
"t13d2014h2_a09f3c656075_14788d8d241b": utls.HelloSafari_16_0,
"t13d1516h2_8daaf6152771_e5627efa2ab1": utls.HelloEdge_106,
diff --git a/fingerprint/tls_test.go b/fingerprint/tls_test.go
@@ -4,19 +4,19 @@ import (
"strings"
"testing"
+ utls "github.com/bogdanfinn/utls"
"github.com/djnnvx/mic/fingerprint"
- utls "github.com/refraction-networking/utls"
)
-const knownJA4 = "t13d1516h2_8daaf6152771_b0da82dd1658"
+const knownJA4 = "t13d1516h2_8daaf6152771_02713d6af862"
func TestLookup_Known(t *testing.T) {
id, ok := fingerprint.Lookup(knownJA4)
if !ok {
t.Fatalf("Lookup(%q) returned false; expected true", knownJA4)
}
- if id != utls.HelloChrome_120 {
- t.Errorf("Lookup(%q) = %v; want HelloChrome_120", knownJA4, id)
+ if id.Str() != utls.HelloChrome_131.Str() {
+ t.Errorf("Lookup(%q) = %v; want HelloChrome_131", knownJA4, id)
}
}
diff --git a/go.mod b/go.mod
@@ -3,18 +3,18 @@ module github.com/djnnvx/mic
go 1.24.4
require (
+ github.com/bogdanfinn/utls v1.7.7-barnius
github.com/pelletier/go-toml/v2 v2.2.4
- github.com/refraction-networking/utls v1.8.0
github.com/spf13/cobra v1.9.1
+ golang.org/x/net v0.38.0
)
require (
- github.com/andybalholm/brotli v1.0.6 // indirect
+ github.com/andybalholm/brotli v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/klauspost/compress v1.17.4 // indirect
+ github.com/klauspost/compress v1.17.11 // indirect
github.com/spf13/pflag v1.0.6 // indirect
golang.org/x/crypto v0.36.0 // indirect
- golang.org/x/net v0.38.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
)
diff --git a/go.sum b/go.sum
@@ -1,19 +1,21 @@
-github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
-github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
+github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
+github.com/bogdanfinn/utls v1.7.7-barnius h1:OuJ497cc7F3yKNVHRsYPQdGggmk5x6+V5ZlrCR7fOLU=
+github.com/bogdanfinn/utls v1.7.7-barnius/go.mod h1:aAK1VZQlpKZClF1WEQeq6kyclbkPq4hz6xTbB5xSlmg=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
-github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
+github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
-github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
-github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
+github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
diff --git a/proxy/proxy.go b/proxy/proxy.go
@@ -8,8 +8,8 @@ import (
"strings"
"sync"
+ utls "github.com/bogdanfinn/utls"
"github.com/djnnvx/mic/fingerprint"
- utls "github.com/refraction-networking/utls"
)
type Proxy struct {
@@ -56,7 +56,7 @@ func (p *Proxy) dialTarget(host string) (*utls.UConn, error) {
cfg.RootCAs = p.CAPool
}
- uconn := utls.UClient(tcpConn, cfg, helloID)
+ uconn := utls.UClient(tcpConn, cfg, helloID, false, false, false)
if err := uconn.Handshake(); err != nil {
uconn.Close()
return nil, err
diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go
@@ -77,7 +77,7 @@ func TestDialTarget_HandshakeSucceeds(t *testing.T) {
io.Copy(io.Discard, conn)
}()
- fp, err := fingerprint.NewTLS("t13d1516h2_8daaf6152771_b0da82dd1658")
+ fp, err := fingerprint.NewTLS("t13d1516h2_8daaf6152771_02713d6af862")
if err != nil {
t.Fatalf("fingerprint.NewTLS: %v", err)
}
diff --git a/test/client/main.go b/test/client/main.go
@@ -7,7 +7,7 @@ import (
"net/http"
"strings"
- utls "github.com/refraction-networking/utls"
+ utls "github.com/bogdanfinn/utls"
)
func main() {
@@ -42,7 +42,7 @@ func main() {
// 4. Create a uTLS client from the proxied connection.
// We'll use the Chrome 116 fingerprint for the client.
utlsConfig := &utls.Config{ServerName: strings.Split(targetAddr, ":")[0]}
- uclient := utls.UClient(proxyConn, utlsConfig, utls.HelloRandomized)
+ uclient := utls.UClient(proxyConn, utlsConfig, utls.HelloRandomized, false, false, false)
// 5. Perform the TLS handshake and get the handshake state.
if err := uclient.Handshake(); err != nil {
| | | | | | | | | |