aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols/cassandra.c
diff options
context:
space:
mode:
authorVladimir Gavrilov <105977161+0xA50C1A1@users.noreply.github.com>2023-11-21 18:56:01 +0300
committerGitHub <noreply@github.com>2023-11-21 16:56:01 +0100
commit35abafec4fabcb7ad91973e4e9d3c505589e47ca (patch)
tree993a9571ae7c546e7b1354e5f7256517dee7557b /src/lib/protocols/cassandra.c
parentae6e6d61f0644ebe13adb7ef328ceb123daae818 (diff)
Get rid of Apache Cassandra false positives (#2159)
* Rewrite Apache Cassandra dissector * Replace memcmp with strncmp * Add payload length check * Update Cassandra dissector * Update test results --------- Co-authored-by: 0xA50C1A1 <mage.wizard88@gmail.com>
Diffstat (limited to 'src/lib/protocols/cassandra.c')
-rw-r--r--src/lib/protocols/cassandra.c137
1 files changed, 42 insertions, 95 deletions
diff --git a/src/lib/protocols/cassandra.c b/src/lib/protocols/cassandra.c
index 9a066f26f..effb9d255 100644
--- a/src/lib/protocols/cassandra.c
+++ b/src/lib/protocols/cassandra.c
@@ -1,7 +1,10 @@
/*
* cassandra.c
*
- * Copyright (C) 2021 by Lucas Santos <lfneiva.santos@gmail.com>
+ * Apache Cassandra CQL Binary protocol
+ *
+ * Copyright (C) 2023 - ntop.org
+ * Copyright (C) 2023 - V.G <jacendi@protonmail.com>
*
* This file is part of nDPI, an open source deep packet inspection
* library based on the OpenDPI and PACE technology by ipoque GmbH
@@ -18,92 +21,34 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with nDPI. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
-#include <stdbool.h>
#include "ndpi_protocol_ids.h"
+
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_CASSANDRA
+
#include "ndpi_api.h"
#include "ndpi_private.h"
-#define CASSANDRA_HEADER_LEN 9
-#define CASSANDRA_MAX_BODY_SIZE 268435456 //256MB (256 * 1024^2)
-
-enum cassandra_version
-{
- CASSANDRA_V1_REQUEST = 0x01,
- CASSANDRA_V1_RESPONSE = 0x81,
- CASSANDRA_V2_REQUEST = 0x02,
- CASSANDRA_V2_RESPONSE = 0x82,
- CASSANDRA_V3_REQUEST = 0x03,
- CASSANDRA_V3_RESPONSE = 0x83,
- CASSANDRA_V4_REQUEST = 0x04,
- CASSANDRA_V4_RESPONSE = 0x84
-};
-
-enum cassandra_opcode
-{
- CASSANDRA_ERROR = 0x00,
- CASSANDRA_STARTUP = 0x01,
- CASSANDRA_READY = 0x02,
- CASSANDRA_AUTHENTICATE = 0x03,
- CASSANDRA_OPTIONS = 0x05,
- CASSANDRA_SUPPORTED = 0x06,
- CASSANDRA_QUERY = 0x07,
- CASSANDRA_RESULT = 0x08,
- CASSANDRA_PREPARE = 0x09,
- CASSANDRA_EXECUTE = 0x0A,
- CASSANDRA_REGISTER = 0x0B,
- CASSANDRA_EVENT = 0x0C,
- CASSANDRA_BATCH = 0x0D,
- CASSANDRA_AUTH_CHALLENGE = 0x0E,
- CASSANDRA_AUTH_RESPONSE = 0x0F,
- CASSANDRA_AUTH_SUCCESS = 0x10
-};
-
-static bool ndpi_check_valid_cassandra_version(uint8_t version)
+static inline int ndpi_validate_cassandra_response(u_int8_t response)
{
- switch(version) {
- case CASSANDRA_V1_REQUEST:
- case CASSANDRA_V1_RESPONSE:
- case CASSANDRA_V2_REQUEST:
- case CASSANDRA_V2_RESPONSE:
- case CASSANDRA_V3_REQUEST:
- case CASSANDRA_V3_RESPONSE:
- case CASSANDRA_V4_REQUEST:
- case CASSANDRA_V4_RESPONSE:
- return true;
- }
- return false;
+ return (response >= 0x81 && response <= 0x84) ? 1 : -1;
}
-static bool ndpi_check_valid_cassandra_opcode(uint8_t opcode)
+static inline int ndpi_validate_cassandra_request(u_int8_t request)
{
- switch (opcode) {
- case CASSANDRA_ERROR:
- case CASSANDRA_STARTUP:
- case CASSANDRA_READY:
- case CASSANDRA_AUTHENTICATE:
- case CASSANDRA_OPTIONS:
- case CASSANDRA_SUPPORTED:
- case CASSANDRA_QUERY:
- case CASSANDRA_RESULT:
- case CASSANDRA_PREPARE:
- case CASSANDRA_EXECUTE:
- case CASSANDRA_REGISTER:
- case CASSANDRA_EVENT:
- case CASSANDRA_BATCH:
- case CASSANDRA_AUTH_CHALLENGE:
- case CASSANDRA_AUTH_RESPONSE:
- case CASSANDRA_AUTH_SUCCESS:
- return true;
- }
- return false;
+ return (request >= 0x01 && request <= 0x04) ? 1 : -1;
}
-static bool ndpi_check_valid_cassandra_flags(uint8_t flags)
+static void ndpi_int_cassandra_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
{
- return (flags & 0xF0) == 0;
+ NDPI_LOG_INFO(ndpi_struct, "found Cassandra CQL\n");
+
+ ndpi_set_detected_protocol(ndpi_struct, flow,
+ NDPI_PROTOCOL_CASSANDRA, NDPI_PROTOCOL_UNKNOWN,
+ NDPI_CONFIDENCE_DPI);
}
static void ndpi_search_cassandra(struct ndpi_detection_module_struct *ndpi_struct,
@@ -111,32 +56,34 @@ static void ndpi_search_cassandra(struct ndpi_detection_module_struct *ndpi_stru
{
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
- NDPI_LOG_DBG(ndpi_struct, "search Cassandra\n");
+ NDPI_LOG_DBG(ndpi_struct, "search Cassandra CQL\n");
- if (packet->tcp) {
- if (packet->payload_packet_len >= CASSANDRA_HEADER_LEN &&
- ndpi_check_valid_cassandra_version(get_u_int8_t(packet->payload, 0)) &&
- ndpi_check_valid_cassandra_flags(get_u_int8_t(packet->payload, 1)) &&
- ndpi_check_valid_cassandra_opcode(get_u_int8_t(packet->payload, 4)) &&
- ntohl(get_u_int32_t(packet->payload, 5)) <= CASSANDRA_MAX_BODY_SIZE &&
- ntohl(get_u_int32_t(packet->payload, 5)) >= (uint32_t) (packet->payload_packet_len - CASSANDRA_HEADER_LEN) &&
- flow->h323_valid_packets == 0 /* To avoid clashing with H323 */ &&
- flow->socks4_stage == 0 /* To avoid clashing with SOCKS */) {
- if (flow->packet_counter > 3)
- {
- NDPI_LOG_INFO(ndpi_struct, "found Cassandra\n");
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_CASSANDRA, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
- }
- return;
- }
+ if (packet->payload_packet_len < 9 ||
+ (!ndpi_validate_cassandra_response(packet->payload[0]) ||
+ !ndpi_validate_cassandra_request(packet->payload[0])))
+ {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if (flow->packet_direction_counter[packet->packet_direction] > 2) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ /* Looking for a 'STARTUP' message from the client,
+ * which should always contain the CQL_VERSION string
+ */
+ if (packet->payload_packet_len > 24 &&
+ (packet->payload[4] == 0x01 &&
+ (strncmp((char *)&packet->payload[13], "CQL_VERSION", 11) == 0)))
+ {
+ NDPI_LOG_INFO(ndpi_struct, "found Cassandra CQL\n");
+ ndpi_int_cassandra_add_connection(ndpi_struct, flow);
+ return;
}
-
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
}
-/* ********************************* */
-
-
void init_cassandra_dissector(struct ndpi_detection_module_struct *ndpi_struct,
u_int32_t *id) {