Refactoring
Refactored Protocol.Name -> Protocol.Type; added Encapsulation field Refactored TLS parsing; added support for ALPN
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
|
||||
"git.maze.io/go/dpi"
|
||||
@@ -11,12 +14,18 @@ func init() {
|
||||
}
|
||||
|
||||
func registerTLS() {
|
||||
Register(Both, "\x16\x03\x00", detectTLS) // SSLv3
|
||||
Register(Both, "\x16\x03\x01", detectTLS) // TLSv1.0
|
||||
Register(Both, "\x16\x03\x02", detectTLS) // TLSv1.1
|
||||
Register(Both, "\x16\x03\x03", detectTLS) // TLSv1.2
|
||||
Register(Both, "\x16\x03\x00", detectTLS) // SSL 3.0
|
||||
Register(Both, "\x16\x03\x01", detectTLS) // TLS 1.0
|
||||
Register(Both, "\x16\x03\x02", detectTLS) // TLS 1.1
|
||||
Register(Both, "\x16\x03\x03", detectTLS) // TLS 1.2
|
||||
}
|
||||
|
||||
const (
|
||||
tlsRecordTypeHandshake uint8 = 22
|
||||
tlsTypeClientHello uint8 = 1
|
||||
tlsTypeServerHello uint8 = 2
|
||||
)
|
||||
|
||||
func detectTLS(dir Direction, data []byte, _, _ int) (proto *Protocol, confidence float64) {
|
||||
stream := cryptobyte.String(data)
|
||||
|
||||
@@ -44,27 +53,53 @@ func detectTLS(dir Direction, data []byte, _, _ int) (proto *Protocol, confidenc
|
||||
// Initial confidence
|
||||
confidence = 0.5
|
||||
|
||||
// Detected SSL/TLS version
|
||||
var version dpi.TLSVersion
|
||||
// Detected SSL/TLS tlsVersion
|
||||
var tlsVersion dpi.TLSVersion
|
||||
|
||||
// Attempt to decode the full TLS Client Hello handshake
|
||||
if version == 0 {
|
||||
if hello, err := dpi.DecodeTLSClientHelloHandshake(data); err == nil {
|
||||
version = hello.Version
|
||||
confidence += .45
|
||||
}
|
||||
}
|
||||
if tlsVersion == 0 {
|
||||
if record, err := dpi.DecodeTLSRecord(data); err == nil && record.Type == tlsRecordTypeHandshake && len(record.Data) > 1 {
|
||||
tlsVersion = record.Version
|
||||
confidence += .15
|
||||
|
||||
// Attempt to decode the full TLS Server Hello handshake
|
||||
if version == 0 {
|
||||
if hello, err := dpi.DecodeTLSServerHello(data); err == nil {
|
||||
version = hello.Version
|
||||
confidence += .45
|
||||
switch record.Data[0] {
|
||||
case tlsTypeClientHello: // TLS ClientHello
|
||||
if hello, err := dpi.DecodeTLSClientHello(record.Data); err == nil {
|
||||
tlsVersion = hello.Version
|
||||
confidence += .3
|
||||
|
||||
slices.SortStableFunc(hello.ALPNProtocols, func(a, b string) int {
|
||||
return strings.Compare(b, a)
|
||||
})
|
||||
|
||||
for _, id := range hello.ALPNProtocols {
|
||||
if proto = ALPNProtocol[id]; proto != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case tlsTypeServerHello: // TLS ServerHello
|
||||
if hello, err := dpi.DecodeTLSServerHello(record.Data); err == nil {
|
||||
tlsVersion = hello.Version
|
||||
confidence += .3
|
||||
|
||||
slices.SortStableFunc(hello.ALPNProtocols, func(a, b string) int {
|
||||
return strings.Compare(b, a)
|
||||
})
|
||||
|
||||
for _, id := range hello.ALPNProtocols {
|
||||
if proto = ALPNProtocol[id]; proto != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to decode at least the handshake protocol and version.
|
||||
if version == 0 && !Strict {
|
||||
if tlsVersion == 0 && !Strict {
|
||||
var handshakeType uint8
|
||||
if stream.ReadUint8(&handshakeType) && (handshakeType == 1 || handshakeType == 2) {
|
||||
var (
|
||||
@@ -72,33 +107,68 @@ func detectTLS(dir Direction, data []byte, _, _ int) (proto *Protocol, confidenc
|
||||
versionWord uint16
|
||||
)
|
||||
if stream.ReadUint24(&length) && stream.ReadUint16(&versionWord) {
|
||||
version = dpi.TLSVersion(versionWord)
|
||||
tlsVersion = dpi.TLSVersion(versionWord)
|
||||
confidence += .25
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to the version in the TLS record header, this is less accurate
|
||||
if version == 0 && !Strict {
|
||||
version = dpi.TLSVersion(header.Version)
|
||||
if tlsVersion == 0 && !Strict {
|
||||
tlsVersion = dpi.TLSVersion(header.Version)
|
||||
}
|
||||
|
||||
// We're "multi protocol", in that SSL is its own protocol
|
||||
if version == dpi.VersionSSL30 {
|
||||
if tlsVersion == dpi.VersionSSL30 {
|
||||
return &Protocol{
|
||||
Name: ProtocolSSL,
|
||||
Type: TypeSSL,
|
||||
Version: Version{Major: 3, Minor: 0, Patch: -1},
|
||||
}, confidence
|
||||
} else if version >= dpi.VersionTLS10 && version <= dpi.VersionTLS13 {
|
||||
} else if tlsVersion >= dpi.VersionTLS10 && tlsVersion <= dpi.VersionTLS13 {
|
||||
return &Protocol{
|
||||
Name: ProtocolTLS,
|
||||
Version: Version{Major: 1, Minor: int(uint8(version) - 1), Patch: -1},
|
||||
Type: TypeTLS,
|
||||
Version: Version{Major: 1, Minor: int(uint8(tlsVersion) - 1), Patch: -1},
|
||||
}, confidence
|
||||
} else if version >= dpi.VersionTLS13Draft && version <= dpi.VersionTLS13Draft23 {
|
||||
} else if tlsVersion >= dpi.VersionTLS13Draft && tlsVersion <= dpi.VersionTLS13Draft23 {
|
||||
return &Protocol{
|
||||
Name: ProtocolTLS,
|
||||
Type: TypeTLS,
|
||||
Version: Version{Major: 1, Minor: 3, Patch: -1},
|
||||
}, confidence
|
||||
}
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
// ALPNProtocol is a map of TLS Application-Layer Protocol Negotiation (ALPN) Protocol identifier to [Protocol].
|
||||
//
|
||||
// See https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids\
|
||||
var ALPNProtocol = map[string]*Protocol{
|
||||
"acme-tls/1": {Type: TypeACME, Encapsulation: TypeTLS, Version: Version{Major: 1}}, // ACME-TLS/1
|
||||
"co": {Type: TypeCoAP, Encapsulation: TypeTLS}, // CoAP (over DTLS)
|
||||
"coap": {Type: TypeCoAP, Encapsulation: TypeTLS}, // CoAP (over TLS)
|
||||
"c-webrtc": {Type: TypeWebRTC, Encapsulation: TypeTLS}, // Confidential WebRTC Media and Data
|
||||
"dot": {Type: TypeDNS, Encapsulation: TypeTLS}, // DNS-over-TLS
|
||||
"ftp": {Type: TypeFTP, Encapsulation: TypeTLS}, // FTP
|
||||
"http/0.9": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 0, Minor: 9, Patch: -1}}, // HTTP/0.9
|
||||
"http/1.0": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 0, Patch: -1}}, // HTTP/1.0
|
||||
"http/1.1": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 1, Patch: -1}}, // HTTP/1.1
|
||||
"h2": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 2, Minor: -1, Patch: -1}}, // HTTP/2 (over TLS)
|
||||
"h2c": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 2, Minor: -1, Patch: -1}}, // HTTP/2 (over TCP)
|
||||
"h3": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 3, Minor: -1, Patch: -1}}, // HTTP/3
|
||||
"irc": {Type: TypeIRC, Encapsulation: TypeTLS}, // IRC
|
||||
"imap": {Type: TypeIMAP, Encapsulation: TypeTLS}, // IMAP
|
||||
"managesieve": {Type: TypeManageSieve, Encapsulation: TypeTLS}, // ManageSieve
|
||||
"mqtt": {Type: TypeMQTT, Encapsulation: TypeTLS}, // MQTT
|
||||
"nntp": {Type: TypeNNTP, Encapsulation: TypeTLS}, // NNTP (reading)
|
||||
"nnsp": {Type: TypeNNTP, Encapsulation: TypeTLS}, // NNTP (transit)
|
||||
"postgresql": {Type: TypePostgreSQL, Encapsulation: TypeTLS}, // PostgreSQL
|
||||
"pop3": {Type: TypePOP3, Encapsulation: TypeTLS}, // POP3
|
||||
"radius/1.0": {Type: TypeRADIUS, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 0, Patch: -1}}, // RADIUS/1.0
|
||||
"radius/1.1": {Type: TypeRADIUS, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 1, Patch: -1}}, // RADIUS/1.1
|
||||
"smb": {Type: TypeSMB, Encapsulation: TypeTLS, Version: Version{Major: 2, Minor: -1, Patch: -1}}, // SMB2
|
||||
"stun.nat-discovery": {Type: TypeSTUN, Encapsulation: TypeTLS}, // NAT discovery using Session Traversal Utilities for NAT (STUN)
|
||||
"stun.turn": {Type: TypeSTUN, Encapsulation: TypeTLS}, // Traversal Using Relays around NAT (TURN)
|
||||
"sunrpc": {Type: TypeSunRPC, Encapsulation: TypeTLS}, // SunRPC
|
||||
"webrtc": {Type: TypeWebRTC, Encapsulation: TypeTLS}, // WebRTC Media and Data
|
||||
"xmpp-client": {Type: TypeXMPP, Encapsulation: TypeTLS}, // XMPP jabber:client namespace
|
||||
"xmpp-server": {Type: TypeXMPP, Encapsulation: TypeTLS}, // XMPP jabber:server namespace
|
||||
}
|
||||
|
Reference in New Issue
Block a user