shadow1ng/fscan · error
unexpected opcode: %d
Error message
unexpected opcode: %d
What it means
Guard in doCassandraAuth: after sending the SASL PLAIN auth token, the next CQL frame carried neither the AUTH_SUCCESS nor the ERROR opcode expected at this point in the handshake. An unexpected protocol opcode means the server response does not match the CQL conversation state.
Source
Thrown at plugins/services/cassandra.go:145
}
// SASL PLAIN: \x00username\x00password
saslToken := []byte("\x00" + cred.Username + "\x00" + cred.Password)
if err := cqlSend(conn, cqlOpAuthRsp, saslToken); err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}
}
opcode, body, err = cqlRecv(conn)
if err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}
}
// AUTH_SUCCESS → 认证成功
// ERROR → 认证失败
if opcode == cqlOpError {
return &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf("authentication failed: %s", string(body))}
}
if opcode != cqlOpAuthOk && opcode != cqlOpReady {
return &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf("unexpected opcode: %d", opcode)}
}
}
// Step 4: 发送测试查询
queryBody := cqlLongString("SELECT cluster_name FROM system.local")
// 添加 consistency level (ONE=1)
queryBody = append(queryBody, 0x00, 0x01) // flags=0, consistency=ONE
if err := cqlSend(conn, cqlOpQuery, queryBody); err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}
}
opcode, body, err = cqlRecv(conn)
if err != nil {
state.IncrementTCPFailedPacketCount()
return &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}
}
if err := validateCQLQueryResponse(opcode, body); err != nil {
return &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: err}View on GitHub (pinned to 95cc12e753)
Solutions
- Note the opcode value in the error and compare with the Cassandra native protocol spec to identify the reply type.
- Confirm the target really is a Cassandra node and no TCP proxy is rewriting the stream.
- Try pinning a different CQL protocol version so framing/opcode negotiation matches the server.
Defensive patterns
Strategy: retry
Try / catch
res := doCassandraAuth(conn, cred, state)
if !res.Success && strings.HasPrefix(res.Error.Error(), "unexpected opcode") {
conn.Close()
conn = dial(...) // fresh connection resyncs framing
} Prevention
- Confirm the target IP:port is a Cassandra native-transport endpoint, not a proxy or another service.
- Pin a mutually supported CQL protocol version.
- Always reconnect (never keep reading) after an unclassifiable frame to avoid desync.
When it happens
Trigger: doCassandraAuth reads the post-SASL response; opcode is not cqlOpAuthOk, cqlOpReady, or cqlOpError — e.g. a protocol violation or an intermediary answering with an unexpected frame.
Common situations: Target is not really Cassandra (a proxy/load balancer speaking something else); protocol version mismatch causing garbled framing; server extension or fork deviating from the native protocol v3/v4 spec.
Related errors
- unexpected query opcode: %d
- cassandra error: %s
- cassandra frame too large: %d
- cassandra query failed: %s
- Unsupport FastPathPDU type 0x%x
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/9928da084103a38c.
Report an issue: GitHub.