diff options
Diffstat (limited to 'src/lib/protocols/soulseek.c')
-rw-r--r-- | src/lib/protocols/soulseek.c | 286 |
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 |