Added support for STUN protocol detection

This commit is contained in:
2025-10-10 14:39:31 +02:00
parent 7b5578859e
commit 23bd918b20
2 changed files with 186 additions and 0 deletions

101
protocol/detect_stun.go Normal file
View File

@@ -0,0 +1,101 @@
package protocol
import (
"log"
"golang.org/x/crypto/cryptobyte"
)
func init() {
registerSTUN()
}
func registerSTUN() {
Register(Both, "????\x21\x12\xa4\x42", detectSTUN)
}
func detectSTUN(dir Direction, data []byte, srcPort, dstPort int) (proto *Protocol, confidence float64) {
// All STUN messages comprise a 20-byte header followed by zero or more attributes.
var (
stream = cryptobyte.String(data)
messageType uint16
messageLength uint16
magicCookie uint32
transactionID []byte
)
if !stream.ReadUint16(&messageType) ||
!stream.ReadUint16(&messageLength) ||
!stream.ReadUint32(&magicCookie) ||
!stream.ReadBytes(&transactionID, 12) {
return
}
if len(stream) != int(messageLength) {
confidence -= .2
}
// The most significant 2 bits of every STUN message MUST be zeroes.
if messageType&0b11000000 != 0 {
log.Printf("type %#08b", messageType)
return
}
// The Magic Cookie field MUST contain the fixed value 0x2112A442 in network byte order.
if magicCookie != 0x2112A442 {
log.Printf("cookie %#04x", magicCookie)
return
}
confidence += .5
// Decode the message class & type.
class := (messageType & 0b00000100000000) >> 7
class |= (messageType & 0b00000000010000) >> 4
method := (messageType & 0b11111000000000) >> 2
method |= (messageType & 0b00000011100000) >> 1
method |= (messageType & 0b00000000001111) >> 0
// Validate most common methods.
// TODO(maze): check method arguments to improve accuracy
switch class {
case stunRequest: // request
switch method {
case stunBinding: // binding
confidence += .2
}
case stunSuccesResponse: // success response
switch method {
case stunBinding: // binding
confidence += .2
}
case stunErrorResponse:
switch method {
case stunBinding: // binding error
confidence += .2
}
}
if stunPort[srcPort] || stunPort[dstPort] {
confidence += .2
}
return &Protocol{
Type: TypeSTUN,
}, confidence
}
const (
stunRequest = 0b00
stunSuccesResponse = 0b10
stunErrorResponse = 0b11
stunBinding = 0x0001
)
// IANA has updated the reference from RFC 5389 to RFC 8489 for the
// following ports in the "Service Name and Transport Protocol Port
// Number Registry".
var stunPort = map[int]bool{
3478: true,
5349: true,
}