Add JA3 parser to TLS sniffer

This commit is contained in:
世界 2023-01-02 14:09:09 +08:00
parent f5c5570bec
commit a9dcb2d092
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
5 changed files with 33 additions and 12 deletions

View File

@ -25,16 +25,17 @@ type InjectableInbound interface {
}
type InboundContext struct {
Inbound string
InboundType string
IPVersion int
Network string
Source M.Socksaddr
Destination M.Socksaddr
Domain string
Protocol string
User string
Outbound string
Inbound string
InboundType string
IPVersion int
Network string
Source M.Socksaddr
Destination M.Socksaddr
Domain string
Protocol string
User string
Outbound string
JA3Fingerprint string
// cache

View File

@ -1,6 +1,7 @@
package sniff
import (
"bytes"
"context"
"crypto/tls"
"io"
@ -8,18 +9,26 @@ import (
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common/bufio"
"github.com/open-ch/ja3"
)
func TLSClientHello(ctx context.Context, reader io.Reader) (*adapter.InboundContext, error) {
var clientHello *tls.ClientHelloInfo
err := tls.Server(bufio.NewReadOnlyConn(reader), &tls.Config{
var buffer bytes.Buffer
err := tls.Server(bufio.NewReadOnlyConn(io.TeeReader(reader, &buffer)), &tls.Config{
GetConfigForClient: func(argHello *tls.ClientHelloInfo) (*tls.Config, error) {
clientHello = argHello
return nil, nil
},
}).HandshakeContext(ctx)
if clientHello != nil {
return &adapter.InboundContext{Protocol: C.ProtocolTLS, Domain: clientHello.ServerName}, nil
metadata := &adapter.InboundContext{Protocol: C.ProtocolTLS, Domain: clientHello.ServerName}
ja3Result, err := ja3.ComputeJA3FromSegment(buffer.Bytes())
if err == nil {
metadata.JA3Fingerprint = ja3Result.GetJA3Hash()
}
return metadata, nil
}
return nil, err
}

1
go.mod
View File

@ -18,6 +18,7 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mholt/acmez v1.0.4
github.com/miekg/dns v1.1.50
github.com/open-ch/ja3 v1.0.1
github.com/oschwald/maxminddb-golang v1.10.0
github.com/pires/go-proxyproto v0.6.2
github.com/refraction-networking/utls v1.2.0

2
go.sum
View File

@ -125,6 +125,8 @@ github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/open-ch/ja3 v1.0.1 h1:kMqfkgS+cTasMlsQaJ627qlw7kA/qRZVTmF0BtFjOLQ=
github.com/open-ch/ja3 v1.0.1/go.mod h1:lTWgltvZDGQjIa/TjWTzfpCVa/eGP+szng2DWz9mAvk=
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=

View File

@ -545,6 +545,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
if sniffMetadata != nil {
metadata.Protocol = sniffMetadata.Protocol
metadata.Domain = sniffMetadata.Domain
metadata.JA3Fingerprint = sniffMetadata.JA3Fingerprint
if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
metadata.Destination = M.Socksaddr{
Fqdn: metadata.Domain,
@ -556,6 +557,9 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
} else {
r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol)
}
if metadata.JA3Fingerprint != "" {
r.logger.DebugContext(ctx, "sniffed ja3 fingerprint: ", metadata.JA3Fingerprint)
}
}
if !buffer.IsEmpty() {
conn = bufio.NewCachedConn(conn, buffer)
@ -627,6 +631,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
if sniffMetadata != nil {
metadata.Protocol = sniffMetadata.Protocol
metadata.Domain = sniffMetadata.Domain
metadata.JA3Fingerprint = sniffMetadata.JA3Fingerprint
if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
metadata.Destination = M.Socksaddr{
Fqdn: metadata.Domain,
@ -638,6 +643,9 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
} else {
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
}
if metadata.JA3Fingerprint != "" {
r.logger.DebugContext(ctx, "sniffed ja3 fingerprint: ", metadata.JA3Fingerprint)
}
}
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
}