Refactored Protocol.Name -> Protocol.Type; added Encapsulation field Refactored TLS parsing; added support for ALPN
79 lines
2.2 KiB
Go
79 lines
2.2 KiB
Go
package protocol
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"log"
|
|
)
|
|
|
|
func init() {
|
|
registerPostgreSQL()
|
|
}
|
|
|
|
func registerPostgreSQL() {
|
|
Register(Server, "R\x00???", detectPostgreSQLServer) // Authentication request
|
|
Register(Server, "K\x00???", detectPostgreSQLServer) // BackendKeyData
|
|
Register(Server, "S\x00???", detectPostgreSQLServer) // ParameterStatus
|
|
Register(Server, "Z\x00???", detectPostgreSQLServer) // ReadyForQuery
|
|
Register(Server, "E\x00???", detectPostgreSQLServer) // ErrorResponse
|
|
Register(Server, "N\x00???", detectPostgreSQLServer) // NoticeResponse
|
|
Register(Client, "????\x00\x02\x00\x00", detectPostgreSQLClient) // Startup packet, protocol 2.0
|
|
Register(Client, "????\x00\x03\x00\x00", detectPostgreSQLClient) // Startup packet, protocol 3.0
|
|
}
|
|
|
|
func detectPostgreSQLClient(dir Direction, data []byte, srcPort, dstPort int) (proto *Protocol, confidence float64) {
|
|
// A client startup message needs at least 8 bytes (length + protocol version).
|
|
if len(data) < 8 {
|
|
return nil, 0
|
|
}
|
|
|
|
length := int(binary.BigEndian.Uint32(data[0:]))
|
|
if len(data) != length {
|
|
log.Printf("not postgres %q: %d != %d", data, len(data), length)
|
|
return nil, 0
|
|
}
|
|
|
|
if dstPort == 5432 {
|
|
confidence = .1
|
|
}
|
|
|
|
major := int(binary.BigEndian.Uint16(data[4:]))
|
|
minor := int(binary.BigEndian.Uint16(data[6:]))
|
|
if major == 2 || major == 3 {
|
|
return &Protocol{
|
|
Type: TypePostgreSQL,
|
|
Version: Version{
|
|
Major: major,
|
|
Minor: minor,
|
|
Patch: -1,
|
|
},
|
|
}, confidence + .75
|
|
}
|
|
return nil, 0
|
|
}
|
|
|
|
func detectPostgreSQLServer(dir Direction, data []byte, srcPort, dstPort int) (proto *Protocol, confidence float64) {
|
|
// A server message needs at least 5 bytes (type + length).
|
|
if len(data) < 5 {
|
|
return nil, 0
|
|
}
|
|
|
|
if srcPort == 5432 {
|
|
confidence = .1
|
|
}
|
|
|
|
// All server messages (and subsequent client messages) are tagged with a single-byte type.
|
|
firstByte := data[0]
|
|
switch firstByte {
|
|
case 'R', // Authentication request
|
|
'K', // BackendKeyData
|
|
'S', // ParameterStatus
|
|
'Z', // ReadyForQuery
|
|
'E', // ErrorResponse
|
|
'N': // NoticeResponse
|
|
return &Protocol{Type: TypePostgreSQL}, confidence + .65
|
|
|
|
default:
|
|
return nil, 0
|
|
}
|
|
}
|