package protocol import ( "bytes" "fmt" ) func init() { Register(Server, "\x0a", detectMySQL) } func detectMySQL(dir Direction, data []byte, srcPort, dstPort int) (proto *Protocol, confidence float64) { if len(data) < 7 { return nil, 0 } // The first byte of the handshake packet is the protocol version. // For MySQL, this is 10 (0x0A). if data[0] != 0x0A { return nil, 0 } if srcPort == 3306 { confidence = .1 } // After the protocol version, there is a null-terminated server version string. // We search for the null byte starting from the second byte (index 1). nullIndex := bytes.IndexByte(data[1:], 0x00) // If no null byte is found, it's not a valid banner. if nullIndex == -1 { return nil, 0 } // The position of the null byte is relative to the start of the whole slice. // It's 1 (for the protocol byte) + nullIndex. serverVersionEndPos := 1 + nullIndex // After the null-terminated version string, there must be at least 4 bytes // for the connection ID, plus more data for capabilities, auth, etc. // We'll check for the 4-byte connection ID as a minimum requirement. const connectionIDLength = 4 if len(data) < serverVersionEndPos+1+connectionIDLength { return nil, 0 } var version Version _, _ = fmt.Sscanf(string(data[1:serverVersionEndPos]), "%d.%d.%d-%s", &version.Major, &version.Minor, &version.Patch, &version.Extra) return &Protocol{ Type: TypeMySQL, Version: version, }, confidence + .75 }