TLS explorer: report the true negotiated version (supported_versions / QUIC), not the compat record version; capture QUIC server port
This commit is contained in:
@@ -482,23 +482,42 @@ func (e *Engine) TLS(ctx context.Context, id string, limit int) ([]TLSRecord, []
|
|||||||
limit = 5000
|
limit = 5000
|
||||||
}
|
}
|
||||||
// ClientHello: SNI, ALPN, offered; ServerHello: negotiated version + cipher.
|
// ClientHello: SNI, ALPN, offered; ServerHello: negotiated version + cipher.
|
||||||
chFields := []string{"ip.src", "ipv6.src", "ip.dst", "ipv6.dst", "tcp.dstport", "tcp.srcport", "tcp.stream", "tls.handshake.type", "tls.handshake.extensions_server_name", "tls.handshake.version", "tls.record.version", "tls.handshake.ciphersuite", "tls.handshake.extensions_alpn_str"}
|
// The true negotiated version for TLS 1.3 is in the supported_versions
|
||||||
|
// extension of the ServerHello; the record/handshake version stays 0x0303
|
||||||
|
// for middlebox compatibility, so reading only those would mislabel 1.3 as 1.2.
|
||||||
|
chFields := []string{"ip.src", "ipv6.src", "ip.dst", "ipv6.dst", "tcp.dstport", "udp.dstport", "tcp.srcport", "tcp.stream", "tls.handshake.type", "tls.handshake.extensions_server_name", "tls.handshake.version", "tls.record.version", "tls.handshake.ciphersuite", "tls.handshake.extensions_alpn_str", "tls.handshake.extensions.supported_version"}
|
||||||
|
// c offsets: 0=num,1=time, then 2+index into chFields.
|
||||||
|
const (
|
||||||
|
cType = 10
|
||||||
|
cSNI = 11
|
||||||
|
cHV = 12
|
||||||
|
cRV = 13
|
||||||
|
cCS = 14
|
||||||
|
cALPN = 15
|
||||||
|
cSV = 16
|
||||||
|
)
|
||||||
rowsF, err := e.extractFields(ctx, id, "tls.handshake.type==1 || tls.handshake.type==2", chFields, limit)
|
rowsF, err := e.extractFields(ctx, id, "tls.handshake.type==1 || tls.handshake.type==2", chFields, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
need := 2 + len(chFields)
|
||||||
// Index ServerHello (type 2) by stream to join onto the ClientHello.
|
// Index ServerHello (type 2) by stream to join onto the ClientHello.
|
||||||
type sh struct{ version, cipher string }
|
type sh struct{ version, cipher string }
|
||||||
byStream := map[string]sh{}
|
byStream := map[string]sh{}
|
||||||
for _, c := range rowsF {
|
for _, c := range rowsF {
|
||||||
if len(c) < 2+len(chFields) || c[9] != "2" {
|
if len(c) < need || c[cType] != "2" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
byStream[c[8]] = sh{version: firstNonEmpty(c[11], c[12]), cipher: c[13]}
|
// supported_version in a ServerHello may be a list; take the last (chosen).
|
||||||
|
sv := c[cSV]
|
||||||
|
if i := strings.LastIndex(sv, ","); i >= 0 {
|
||||||
|
sv = sv[i+1:]
|
||||||
|
}
|
||||||
|
byStream[c[9]] = sh{version: firstNonEmpty(sv, firstNonEmpty(c[cHV], c[cRV])), cipher: c[cCS]}
|
||||||
}
|
}
|
||||||
recs := []TLSRecord{}
|
recs := []TLSRecord{}
|
||||||
for _, c := range rowsF {
|
for _, c := range rowsF {
|
||||||
if len(c) < 2+len(chFields) || c[9] != "1" {
|
if len(c) < need || c[cType] != "1" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r := TLSRecord{}
|
r := TLSRecord{}
|
||||||
@@ -506,10 +525,10 @@ func (e *Engine) TLS(ctx context.Context, id string, limit int) ([]TLSRecord, []
|
|||||||
r.Time, _ = strconv.ParseFloat(c[1], 64)
|
r.Time, _ = strconv.ParseFloat(c[1], 64)
|
||||||
r.Client = firstNonEmpty(c[2], c[3])
|
r.Client = firstNonEmpty(c[2], c[3])
|
||||||
r.Server = firstNonEmpty(c[4], c[5])
|
r.Server = firstNonEmpty(c[4], c[5])
|
||||||
r.ServerPort, _ = strconv.Atoi(c[6])
|
r.ServerPort, _ = strconv.Atoi(firstNonEmpty(c[6], c[7])) // tcp or udp (QUIC)
|
||||||
r.SNI = c[10]
|
r.SNI = c[cSNI]
|
||||||
r.ALPN = c[14]
|
r.ALPN = c[cALPN]
|
||||||
if st := c[8]; st != "" {
|
if st := c[9]; st != "" {
|
||||||
if v, err := strconv.Atoi(st); err == nil {
|
if v, err := strconv.Atoi(st); err == nil {
|
||||||
r.Stream = &v
|
r.Stream = &v
|
||||||
}
|
}
|
||||||
@@ -519,7 +538,12 @@ func (e *Engine) TLS(ctx context.Context, id string, limit int) ([]TLSRecord, []
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if r.Version == "" {
|
if r.Version == "" {
|
||||||
r.Version = tlsVersion(firstNonEmpty(c[11], c[12]))
|
if c[7] != "" { // over UDP: QUIC, which mandates TLS 1.3
|
||||||
|
r.Version = "TLS 1.3 (QUIC)"
|
||||||
|
} else {
|
||||||
|
// No ServerHello captured: report what the client offered, not a guess.
|
||||||
|
r.Version = tlsVersion(firstNonEmpty(c[cHV], c[cRV])) + " (offered)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
recs = append(recs, r)
|
recs = append(recs, r)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user