aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/protocols')
-rw-r--r--src/lib/protocols/coap.c2
-rw-r--r--src/lib/protocols/thrift.c269
2 files changed, 271 insertions, 0 deletions
diff --git a/src/lib/protocols/coap.c b/src/lib/protocols/coap.c
index 6d0f68d46..8935aa22a 100644
--- a/src/lib/protocols/coap.c
+++ b/src/lib/protocols/coap.c
@@ -39,6 +39,8 @@ struct ndpi_coap_hdr
u_int8_t version:2, type:2, tkl:4;
#elif defined(__LITTLE_ENDIAN__)
u_int8_t tkl:4, type:2, version:2;
+#else
+#error "Missing endian macro definitions."
#endif
u_int8_t code;
u_int16_t message_id; //if needed, remember to convert in host number
diff --git a/src/lib/protocols/thrift.c b/src/lib/protocols/thrift.c
new file mode 100644
index 000000000..344795523
--- /dev/null
+++ b/src/lib/protocols/thrift.c
@@ -0,0 +1,269 @@
+/*
+ * thrift.c
+ *
+ * Copyright (C) 2023 - ntop.org
+ *
+ * This file is part of nDPI, an open source deep packet inspection
+ * library based on the OpenDPI and PACE technology by ipoque GmbH
+ *
+ * nDPI is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nDPI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * 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 "ndpi_protocol_ids.h"
+
+#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_APACHE_THRIFT
+
+#include "ndpi_api.h"
+
+#include <stdint.h>
+
+// References: https://thrift.apache.org AND https://github.com/apache/thrift
+// Not Implemented (sub)protocols: TJSONProtocol, TSimpleJSONProtocol and TDebugProtocol
+
+// TBinaryProtocol
+PACK_ON
+struct thrift_strict_hdr {
+ uint8_t protocol_id;
+ uint8_t version;
+ uint8_t unused_byte_pad;
+ uint8_t message_type;
+ uint32_t method_length;
+ char method[0];
+} PACK_OFF;
+
+// TCompactProtocol
+PACK_ON
+struct thrift_compact_hdr {
+ uint8_t protocol_id;
+#if defined(__BIG_ENDIAN__)
+ uint8_t message_type : 3;
+ uint8_t version : 5;
+#elif defined(__LITTLE_ENDIAN__)
+ uint8_t version : 5;
+ uint8_t message_type : 3;
+#else
+#error "Missing endian macro definitions."
+#endif
+ uint8_t sequence_id[3];
+ uint8_t method_length;
+ char method[0];
+} PACK_OFF;
+
+enum thrift_message_type {
+ TMT_INVALID_TMESSAGE_TYPE = 0,
+ TMT_CALL = 1,
+ TMT_REPLY = 2,
+ TMT_EXCEPTION = 3,
+ TMT_ONEWAY = 4,
+ TMT_TYPE_MAX
+};
+
+static void ndpi_int_thrift_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ uint16_t master_protocol)
+{
+ switch (master_protocol)
+ {
+ case NDPI_PROTOCOL_UNKNOWN:
+ NDPI_LOG_DBG(ndpi_struct, "found Apache Thrift TCP/UDP\n");
+ break;
+ case NDPI_PROTOCOL_HTTP:
+ NDPI_LOG_DBG(ndpi_struct, "found Apache Thrift HTTP\n");
+ break;
+ default:
+ NDPI_LOG_DBG(ndpi_struct, "found Apache Thrift\n");
+ break;
+ }
+
+ ndpi_set_detected_protocol(ndpi_struct, flow,
+ NDPI_PROTOCOL_APACHE_THRIFT, master_protocol,
+ NDPI_CONFIDENCE_DPI);
+}
+
+static int thrift_validate_method(char const * const method, size_t method_length)
+{
+ const union {
+ uint8_t const * const ptr;
+ char const * const str;
+ } m = { .str = method };
+
+ return ndpi_is_printable_buffer(m.ptr, method_length);
+}
+
+static int thrift_validate_version(uint8_t version)
+{
+ return version <= 0x01;
+}
+
+static int thrift_validate_type(uint8_t message_type)
+{
+ return message_type < TMT_TYPE_MAX;
+}
+
+static void thrift_set_method(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ char const * const method, size_t method_length)
+{
+ if (thrift_validate_method(method, method_length) == 0) {
+ ndpi_set_risk(ndpi_struct, flow, NDPI_INVALID_CHARACTERS, "Invalid method name");
+ flow->protos.thrift.method[0] = '\0';
+ } else {
+ strncpy(flow->protos.thrift.method, method, method_length);
+ }
+}
+
+static void thrift_set_type(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ uint8_t message_type)
+{
+ if (message_type == TMT_INVALID_TMESSAGE_TYPE) {
+ ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid message type");
+ }
+ flow->protos.thrift.message_type = message_type;
+
+ if (message_type == TMT_EXCEPTION) {
+ ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, "Apache Thrift Exception");
+ }
+}
+
+static void ndpi_dissect_strict_hdr(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ struct thrift_strict_hdr const * const strict_hdr)
+{
+ struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
+ const size_t method_length = ntohl(strict_hdr->method_length);
+
+ if (packet->tcp == NULL) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if (packet->payload_packet_len < sizeof(*strict_hdr) + method_length) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if (thrift_validate_version(strict_hdr->version) == 0) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if (thrift_validate_type(strict_hdr->message_type) == 0) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ ndpi_int_thrift_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNKNOWN);
+
+ thrift_set_method(ndpi_struct, flow, strict_hdr->method, method_length);
+ thrift_set_type(ndpi_struct, flow, strict_hdr->message_type);
+}
+
+static void ndpi_dissect_compact_hdr(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ struct thrift_compact_hdr const * const compact_hdr)
+{
+ struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
+
+ if (packet->udp == NULL) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if (packet->payload_packet_len < sizeof(*compact_hdr) + compact_hdr->method_length) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if (thrift_validate_version(compact_hdr->version) == 0) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if (thrift_validate_type(compact_hdr->message_type) == 0) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ ndpi_int_thrift_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNKNOWN);
+
+ thrift_set_method(ndpi_struct, flow, compact_hdr->method, compact_hdr->method_length);
+ thrift_set_type(ndpi_struct, flow, compact_hdr->message_type);
+}
+
+static void ndpi_search_thrift_tcp_udp(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
+
+ NDPI_LOG_DBG(ndpi_struct, "search Apache Thrift\n");
+
+ if (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_HTTP ||
+ flow->detected_protocol_stack[1] == NDPI_PROTOCOL_HTTP)
+ {
+ /* Check Thrift over HTTP */
+ if (packet->content_line.ptr != NULL)
+ {
+ if ((LINE_ENDS(packet->content_line, "application/vnd.apache.thrift.binary") != 0) ||
+ (LINE_ENDS(packet->content_line, "application/vnd.apache.thrift.compact") != 0) ||
+ (LINE_ENDS(packet->content_line, "application/vnd.apache.thrift.json") != 0))
+ {
+ NDPI_LOG_INFO(ndpi_struct, "found Apache Thrift over HTTP\n");
+ ndpi_int_thrift_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HTTP);
+ return;
+ }
+ }
+ } else if (packet->payload_packet_len >= sizeof(struct thrift_compact_hdr)) {
+ const union {
+ uint8_t const * const raw_ptr;
+ struct thrift_strict_hdr const * const strict_hdr;
+ struct thrift_compact_hdr const * const compact_hdr;
+ } thrift_data = { .raw_ptr = &packet->payload[0] };
+
+ if (thrift_data.raw_ptr[0] == 0x80)
+ {
+ /* Strict Binary Protocol */
+ if (packet->payload_packet_len < sizeof(*thrift_data.strict_hdr))
+ {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ ndpi_dissect_strict_hdr(ndpi_struct, flow, thrift_data.strict_hdr);
+ return;
+ } else if (thrift_data.raw_ptr[0] == 0x82) {
+ /* Compact Protocol */
+ ndpi_dissect_compact_hdr(ndpi_struct, flow, thrift_data.compact_hdr);
+ return;
+ } else {
+ /* Probably not Apache Thrift. */
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+ }
+
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+}
+
+void init_apache_thrift_dissector(struct ndpi_detection_module_struct *ndpi_struct, uint32_t *id)
+{
+ ndpi_set_bitmask_protocol_detection("Thrift", ndpi_struct, *id,
+ NDPI_PROTOCOL_APACHE_THRIFT,
+ ndpi_search_thrift_tcp_udp,
+ NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
+ SAVE_DETECTION_BITMASK_AS_UNKNOWN,
+ ADD_TO_DETECTION_BITMASK);
+ *id += 1;
+}