aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols/soulseek.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/protocols/soulseek.c')
-rw-r--r--src/lib/protocols/soulseek.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/lib/protocols/soulseek.c b/src/lib/protocols/soulseek.c
new file mode 100644
index 000000000..061acfa51
--- /dev/null
+++ b/src/lib/protocols/soulseek.c
@@ -0,0 +1,286 @@
+/*
+ * soulseek.c
+ *
+ * Copyright (C) 2009-2011 by ipoque GmbH
+ * Copyright (C) 2011-15 - 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_protocols.h"
+
+#ifdef NDPI_PROTOCOL_SOULSEEK
+
+static void ndpi_int_soulseek_add_connection(struct ndpi_detection_module_struct
+ *ndpi_struct, struct ndpi_flow_struct *flow)
+{
+
+ struct ndpi_packet_struct *packet = &flow->packet;
+ struct ndpi_id_struct *src = flow->src;
+ struct ndpi_id_struct *dst = flow->dst;
+
+ ndpi_int_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SOULSEEK, NDPI_REAL_PROTOCOL);
+
+ if (src != NULL) {
+ src->soulseek_last_safe_access_time = packet->tick_timestamp;
+ }
+ if (dst != NULL) {
+ dst->soulseek_last_safe_access_time = packet->tick_timestamp;
+ }
+
+ return;
+}
+
+void ndpi_search_soulseek_tcp(struct ndpi_detection_module_struct
+ *ndpi_struct, struct ndpi_flow_struct *flow)
+{
+ struct ndpi_packet_struct *packet = &flow->packet;
+
+ struct ndpi_id_struct *src = flow->src;
+ struct ndpi_id_struct *dst = flow->dst;
+
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "Soulseek: search soulseec tcp \n");
+
+
+ if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SOULSEEK) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "packet marked as Soulseek\n");
+ if (src != NULL)
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG,
+ " SRC bitmask: %u, packet tick %llu , last safe access timestamp: %llu\n",
+ NDPI_COMPARE_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, NDPI_PROTOCOL_SOULSEEK)
+ != 0 ? 1 : 0, (u_int64_t) packet->tick_timestamp, (u_int64_t) src->soulseek_last_safe_access_time);
+ if (dst != NULL)
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG,
+ " DST bitmask: %u, packet tick %llu , last safe ts: %llu\n",
+ NDPI_COMPARE_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, NDPI_PROTOCOL_SOULSEEK)
+ != 0 ? 1 : 0, (u_int64_t) packet->tick_timestamp, (u_int64_t) dst->soulseek_last_safe_access_time);
+
+ if (packet->payload_packet_len == 431) {
+ if (dst != NULL) {
+ dst->soulseek_last_safe_access_time = packet->tick_timestamp;
+ }
+ return;
+ }
+ if (packet->payload_packet_len == 12 && get_l32(packet->payload, 4) == 0x02) {
+ if (src != NULL) {
+ src->soulseek_last_safe_access_time = packet->tick_timestamp;
+ if (packet->tcp != NULL && src->soulseek_listen_port == 0) {
+ src->soulseek_listen_port = get_l32(packet->payload, 8);
+ return;
+ }
+ }
+ }
+
+ if (src != NULL && ((u_int32_t)
+ (packet->tick_timestamp -
+ src->soulseek_last_safe_access_time) <
+ ndpi_struct->soulseek_connection_ip_tick_timeout)) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG,
+ "Soulseek: SRC update last safe access time and SKIP_FOR_TIME \n");
+ src->soulseek_last_safe_access_time = packet->tick_timestamp;
+ }
+
+ if (dst != NULL && ((u_int32_t)
+ (packet->tick_timestamp -
+ dst->soulseek_last_safe_access_time) <
+ ndpi_struct->soulseek_connection_ip_tick_timeout)) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG,
+ "Soulseek: DST update last safe access time and SKIP_FOR_TIME \n");
+ dst->soulseek_last_safe_access_time = packet->tick_timestamp;
+ }
+ }
+
+
+ if (dst != NULL && dst->soulseek_listen_port != 0 && dst->soulseek_listen_port == ntohs(packet->tcp->dest)
+ && ((u_int32_t)
+ (packet->tick_timestamp - dst->soulseek_last_safe_access_time) <
+ ndpi_struct->soulseek_connection_ip_tick_timeout)) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG,
+ "Soulseek: Plain detection on Port : %u packet_tick_timestamp: %u soulseeek_last_safe_access_time: %u soulseek_connection_ip_ticktimeout: %u\n",
+ dst->soulseek_listen_port, packet->tick_timestamp,
+ dst->soulseek_last_safe_access_time, ndpi_struct->soulseek_connection_ip_tick_timeout);
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+
+ if (flow->l4.tcp.soulseek_stage == 0) {
+
+ u_int32_t index = 0;
+
+ if (packet->payload_packet_len >= 12 && packet->payload_packet_len < 300 && get_l32(packet->payload, 4) == 1) {
+ while (!get_u_int16_t(packet->payload, index + 2)
+ && (index + get_l32(packet->payload, index)) < packet->payload_packet_len - 4) {
+ if (get_l32(packet->payload, index) < 8) /*Minimum soulsek login msg is 8B */
+ break;
+
+ if (index + get_l32(packet->payload, index) + 4 <= index) {
+ /* avoid overflow */
+ break;
+ }
+
+ index += get_l32(packet->payload, index) + 4;
+ }
+ if (index + get_l32(packet->payload, index) ==
+ packet->payload_packet_len - 4 && !get_u_int16_t(packet->payload, 10)) {
+ /*This structure seems to be soulseek proto */
+ index = get_l32(packet->payload, 8) + 12; // end of "user name"
+ if ((index + 4) <= packet->payload_packet_len && !get_u_int16_t(packet->payload, index + 2)) // for passwd len
+ {
+ index += get_l32(packet->payload, index) + 4; //end of "Passwd"
+ if ((index + 4 + 4) <= packet->payload_packet_len && !get_u_int16_t(packet->payload, index + 6)) // to read version,hashlen
+ {
+ index += get_l32(packet->payload, index + 4) + 8; // enf of "hash value"
+ if (index == get_l32(packet->payload, 0)) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK,
+ ndpi_struct, NDPI_LOG_DEBUG, "Soulseek Login Detected\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ }
+ }
+ }
+ }
+ if (packet->payload_packet_len > 8
+ && packet->payload_packet_len < 200 && get_l32(packet->payload, 0) == packet->payload_packet_len - 4) {
+ //Server Messages:
+ const u_int32_t msgcode = get_l32(packet->payload, 4);
+
+ if (msgcode == 0x7d) {
+ flow->l4.tcp.soulseek_stage = 1 + packet->packet_direction;
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "Soulseek Messages Search\n");
+ return;
+ } else if (msgcode == 0x02 && packet->payload_packet_len == 12) {
+ const u_int32_t soulseek_listen_port = get_l32(packet->payload, 8);
+
+ if (src != NULL) {
+ src->soulseek_last_safe_access_time = packet->tick_timestamp;
+
+ if (packet->tcp != NULL && src->soulseek_listen_port == 0) {
+ src->soulseek_listen_port = soulseek_listen_port;
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct,
+ NDPI_LOG_DEBUG, "\n Listen Port Saved : %u", src->soulseek_listen_port);
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ }
+
+ }
+ //Peer Messages : Peer Init Message Detection
+ if (get_l32(packet->payload, 0) == packet->payload_packet_len - 4) {
+ const u_int32_t typelen = get_l32(packet->payload, packet->payload_packet_len - 9);
+ const u_int8_t type = packet->payload[packet->payload_packet_len - 5];
+ const u_int32_t namelen = get_l32(packet->payload, 5);
+ if (packet->payload[4] == 0x01 && typelen == 1
+ && namelen <= packet->payload_packet_len
+ && (4 + 1 + 4 + namelen + 4 + 1 + 4) ==
+ packet->payload_packet_len && (type == 'F' || type == 'P' || type == 'D')) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "soulseek detected\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "1\n");
+ }
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "3\n");
+ //Peer Message : Pierce Firewall
+ if (packet->payload_packet_len == 9 && get_l32(packet->payload, 0) == 5
+ && packet->payload[4] <= 0x10 && get_u_int32_t(packet->payload, 5) != 0x00000000) {
+ flow->l4.tcp.soulseek_stage = 1 + packet->packet_direction;
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_TRACE, "Soulseek Size 9 Pierce Firewall\n");
+ return;
+ }
+
+ }
+
+ if (packet->payload_packet_len > 25 && packet->payload[4] == 0x01 && !get_u_int16_t(packet->payload, 7)
+ && !get_u_int16_t(packet->payload, 2)) {
+ const u_int32_t usrlen = get_l32(packet->payload, 5);
+
+ if (usrlen <= packet->payload_packet_len - 4 + 1 + 4 + 4 + 1 + 4) {
+ const u_int32_t typelen = get_l32(packet->payload, 4 + 1 + 4 + usrlen);
+ const u_int8_t type = packet->payload[4 + 1 + 4 + usrlen + 4];
+ if (typelen == 1 && (type == 'F' || type == 'P' || type == 'D')) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct,
+ NDPI_LOG_DEBUG, "soulseek detected Pattern command(D|P|F).\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ }
+ }
+
+ } else if (flow->l4.tcp.soulseek_stage == 2 - packet->packet_direction) {
+ if (packet->payload_packet_len > 8) {
+ if ((packet->payload[0] || packet->payload[1]) && get_l32(packet->payload, 4) == 9) {
+ /* 9 is search result */
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "soulseek detected Second Pkt\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ if (get_l32(packet->payload, 0) == packet->payload_packet_len - 4) {
+ const u_int32_t msgcode = get_l32(packet->payload, 4);
+ if (msgcode == 0x03 && packet->payload_packet_len >= 12) //Server Message : Get Peer Address
+ {
+ const u_int32_t usrlen = get_l32(packet->payload, 8);
+ if (usrlen <= packet->payload_packet_len && 4 + 4 + 4 + usrlen == packet->payload_packet_len) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct,
+ NDPI_LOG_DEBUG, "Soulseek Request Get Peer Address Detected\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ }
+ }
+ }
+
+ if (packet->payload_packet_len == 8 && get_l32(packet->payload, 4) == 0x00000004) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "soulseek detected\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+
+ if (packet->payload_packet_len == 4
+ && get_u_int16_t(packet->payload, 2) == 0x00 && get_u_int16_t(packet->payload, 0) != 0x00) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "soulseek detected\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ } else if (packet->payload_packet_len == 4) {
+ flow->l4.tcp.soulseek_stage = 3;
+ return;
+ }
+ } else if (flow->l4.tcp.soulseek_stage == 1 + packet->packet_direction) {
+ if (packet->payload_packet_len > 8) {
+ if (packet->payload[4] == 0x03 && get_l32(packet->payload, 5) == 0x00000031) {
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct,
+ NDPI_LOG_DEBUG, "soulseek detected Second Pkt with SIGNATURE :: 0x0331000000 \n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ }
+ }
+ if (flow->l4.tcp.soulseek_stage == 3 && packet->payload_packet_len == 8 && !get_u_int32_t(packet->payload, 4)) {
+
+ NDPI_LOG(NDPI_PROTOCOL_SOULSEEK, ndpi_struct, NDPI_LOG_DEBUG, "soulseek detected bcz of 8B pkt\n");
+ ndpi_int_soulseek_add_connection(ndpi_struct, flow);
+ return;
+ }
+ if (flow->l4.tcp.soulseek_stage && flow->packet_counter < 11) {
+ } else {
+ NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_SOULSEEK);
+ }
+}
+
+#endif