mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-16 02:12:22 +08:00
Add JA3 parser to TLS sniffer
This commit is contained in:
parent
f5c5570bec
commit
a9dcb2d092
|
@ -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
|
||||
|
||||
|
|
|
@ -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
1
go.mod
|
@ -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
2
go.sum
|
@ -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=
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user