/*Search for BitTorrent commands*/ static void ndpi_int_search_bittorrent_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; if (packet->payload_packet_len == 0) { return; } if (flow->bittorrent_stage == 0 && packet->payload_packet_len != 0) { /* exclude stage 0 detection from next run */ flow->bittorrent_stage = 1; if (ndpi_int_search_bittorrent_tcp_zero(ndpi_struct, flow) != 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_DEBUG, "stage 0 has detected something, returning\n"); return; } NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_DEBUG, "stage 0 has no direct detection, fall through\n"); } return; }
static void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; if (packet->detected_protocol_stack[0] != NDPI_PROTOCOL_BITTORRENT) { /* check for tcp retransmission here */ if ((packet->tcp != NULL) && (packet->tcp_retransmission == 0 || packet->num_retried_bytes)) { ndpi_int_search_bittorrent_tcp(ndpi_struct, flow); } else if(packet->udp != NULL) { flow->bittorrent_stage++; if(flow->bittorrent_stage < 10) { if(packet->payload_packet_len > 19 /* min size */) { char *begin; if(ndpi_strnstr(packet->payload, ":target20:", packet->payload_packet_len) || ndpi_strnstr(packet->payload, ":find_node1:", packet->payload_packet_len) || ndpi_strnstr(packet->payload, "d1:ad2:id20:", packet->payload_packet_len)) { bittorrent_found: NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_REAL_PROTOCOL); return; } else if((begin = memchr(packet->payload, 'B', packet->payload_packet_len-19)) != NULL) { long offset = (u_long)begin - (u_long)packet->payload; if((packet->payload_packet_len-19) > offset) { if(memcmp(begin, "BitTorrent protocol", 19) == 0) { goto bittorrent_found; } } } } return; } NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_BITTORRENT); } } }
static u_int8_t ndpi_int_search_bittorrent_tcp_zero(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; u_int16_t a = 0; if (packet->payload_packet_len == 1 && packet->payload[0] == 0x13) { /* reset stage back to 0 so we will see the next packet here too */ flow->bittorrent_stage = 0; return 0; } if (flow->packet_counter == 2 && packet->payload_packet_len > 20) { if (memcmp(&packet->payload[0], "BitTorrent protocol", 19) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_REAL_PROTOCOL); return 1; } } if (packet->payload_packet_len > 20) { /* test for match 0x13+"BitTorrent protocol" */ if (packet->payload[0] == 0x13) { if (memcmp(&packet->payload[1], "BitTorrent protocol", 19) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_REAL_PROTOCOL); return 1; } } } if (packet->payload_packet_len > 23 && memcmp(packet->payload, "GET /webseed?info_hash=", 23) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: plain webseed BitTorrent protocol detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } /* seen Azureus as server for webseed, possibly other servers existing, to implement */ /* is Server: hypertracker Bittorrent? */ /* no asymmetric detection possible for answer of pattern "GET /data?fid=". */ if (packet->payload_packet_len > 60 && memcmp(packet->payload, "GET /data?fid=", 14) == 0 && memcmp(&packet->payload[54], "&size=", 6) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: plain Bitcomet persistent seed protocol detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } if (packet->payload_packet_len > 90 && (memcmp(packet->payload, "GET ", 4) == 0 || memcmp(packet->payload, "POST ", 5) == 0)) { const u_int8_t *ptr = &packet->payload[4]; u_int16_t len = packet->payload_packet_len - 4; a = 0; /* parse complete get packet here into line structure elements */ ndpi_parse_packet_line_info(ndpi_struct, flow); /* answer to this pattern is HTTP....Server: hypertracker */ if (packet->user_agent_line.ptr != NULL && ((packet->user_agent_line.len > 8 && memcmp(packet->user_agent_line.ptr, "Azureus ", 8) == 0) || (packet->user_agent_line.len >= 10 && memcmp(packet->user_agent_line.ptr, "BitTorrent", 10) == 0) || (packet->user_agent_line.len >= 11 && memcmp(packet->user_agent_line.ptr, "BTWebClient", 11) == 0))) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "Azureus /Bittorrent user agent line detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } if (packet->user_agent_line.ptr != NULL && (packet->user_agent_line.len >= 9 && memcmp(packet->user_agent_line.ptr, "Shareaza ", 9) == 0) && (packet->parsed_lines > 8 && packet->line[8].ptr != 0 && packet->line[8].len >= 9 && memcmp(packet->line[8].ptr, "X-Queue: ", 9) == 0)) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "Bittorrent Shareaza detected.\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } /* this is a self built client, not possible to catch asymmetrically */ if ((packet->parsed_lines == 10 || (packet->parsed_lines == 11 && packet->line[11].len == 0)) && packet->user_agent_line.ptr != NULL && packet->user_agent_line.len > 12 && ndpi_mem_cmp(packet->user_agent_line.ptr, "Mozilla/4.0 ", 12) == 0 && packet->host_line.ptr != NULL && packet->host_line.len >= 7 && packet->line[2].ptr != NULL && packet->line[2].len > 14 && ndpi_mem_cmp(packet->line[2].ptr, "Keep-Alive: 300", 15) == 0 && packet->line[3].ptr != NULL && packet->line[3].len > 21 && ndpi_mem_cmp(packet->line[3].ptr, "Connection: Keep-alive", 22) == 0 && packet->line[4].ptr != NULL && packet->line[4].len > 10 && (ndpi_mem_cmp(packet->line[4].ptr, "Accpet: */*", 11) == 0 || ndpi_mem_cmp(packet->line[4].ptr, "Accept: */*", 11) == 0) && packet->line[5].ptr != NULL && packet->line[5].len > 12 && ndpi_mem_cmp(packet->line[5].ptr, "Range: bytes=", 13) == 0 && packet->line[7].ptr != NULL && packet->line[7].len > 15 && ndpi_mem_cmp(packet->line[7].ptr, "Pragma: no-cache", 16) == 0 && packet->line[8].ptr != NULL && packet->line[8].len > 22 && ndpi_mem_cmp(packet->line[8].ptr, "Cache-Control: no-cache", 23) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "Bitcomet LTS detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_UNSAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } /* FlashGet pattern */ if (packet->parsed_lines == 8 && packet->user_agent_line.ptr != NULL && packet->user_agent_line.len > (sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1) && memcmp(packet->user_agent_line.ptr, "Mozilla/4.0 (compatible; MSIE 6.0;", sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1) == 0 && packet->host_line.ptr != NULL && packet->host_line.len >= 7 && packet->line[2].ptr != NULL && packet->line[2].len == 11 && memcmp(packet->line[2].ptr, "Accept: */*", 11) == 0 && packet->line[3].ptr != NULL && packet->line[3].len >= (sizeof("Referer: ") - 1) && ndpi_mem_cmp(packet->line[3].ptr, "Referer: ", sizeof("Referer: ") - 1) == 0 && packet->line[5].ptr != NULL && packet->line[5].len > 13 && ndpi_mem_cmp(packet->line[5].ptr, "Range: bytes=", 13) == 0 && packet->line[6].ptr != NULL && packet->line[6].len > 21 && ndpi_mem_cmp(packet->line[6].ptr, "Connection: Keep-Alive", 22) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "FlashGet detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_UNSAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } if (packet->parsed_lines == 7 && packet->user_agent_line.ptr != NULL && packet->user_agent_line.len > (sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1) && memcmp(packet->user_agent_line.ptr, "Mozilla/4.0 (compatible; MSIE 6.0;", sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1) == 0 && packet->host_line.ptr != NULL && packet->host_line.len >= 7 && packet->line[2].ptr != NULL && packet->line[2].len == 11 && memcmp(packet->line[2].ptr, "Accept: */*", 11) == 0 && packet->line[3].ptr != NULL && packet->line[3].len >= (sizeof("Referer: ") - 1) && ndpi_mem_cmp(packet->line[3].ptr, "Referer: ", sizeof("Referer: ") - 1) == 0 && packet->line[5].ptr != NULL && packet->line[5].len > 21 && ndpi_mem_cmp(packet->line[5].ptr, "Connection: Keep-Alive", 22) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "FlashGet detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_UNSAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } /* answer to this pattern is not possible to implement asymmetrically */ while (1) { if (len < 50 || ptr[0] == 0x0d) { goto ndpi_end_bt_tracker_check; } if (memcmp(ptr, "info_hash=", 10) == 0) { break; } len--; ptr++; } NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, " BT stat: tracker info hash found\n"); /* len is > 50, so save operation here */ len -= 10; ptr += 10; /* parse bt hash */ for (a = 0; a < 20; a++) { if (len < 3) { goto ndpi_end_bt_tracker_check; } if (*ptr == '%') { u_int8_t x1 = 0xFF; u_int8_t x2 = 0xFF; if (ptr[1] >= '0' && ptr[1] <= '9') { x1 = ptr[1] - '0'; } if (ptr[1] >= 'a' && ptr[1] <= 'f') { x1 = 10 + ptr[1] - 'a'; } if (ptr[1] >= 'A' && ptr[1] <= 'F') { x1 = 10 + ptr[1] - 'A'; } if (ptr[2] >= '0' && ptr[2] <= '9') { x2 = ptr[2] - '0'; } if (ptr[2] >= 'a' && ptr[2] <= 'f') { x2 = 10 + ptr[2] - 'a'; } if (ptr[2] >= 'A' && ptr[2] <= 'F') { x2 = 10 + ptr[2] - 'A'; } if (x1 == 0xFF || x2 == 0xFF) { goto ndpi_end_bt_tracker_check; } ptr += 3; len -= 3; } else if (*ptr >= 32 && *ptr < 127) { ptr++; len--; } else { goto ndpi_end_bt_tracker_check; } } NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, " BT stat: tracker info hash parsed\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } ndpi_end_bt_tracker_check: if (packet->payload_packet_len == 80) { /* Warez 80 Bytes Packet * +----------------+---------------+-----------------+-----------------+ * |20 BytesPattern | 32 Bytes Value| 12 BytesPattern | 16 Bytes Data | * +----------------+---------------+-----------------+-----------------+ * 20 BytesPattern : 4c 00 00 00 ff ff ff ff 57 00 00 00 00 00 00 00 20 00 00 00 * 12 BytesPattern : 28 23 00 00 01 00 00 00 10 00 00 00 * */ static const char pattern_20_bytes[20] = { 0x4c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00 }; static const char pattern_12_bytes[12] = { 0x28, 0x23, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 }; /* did not see this pattern anywhere */ if ((memcmp(&packet->payload[0], pattern_20_bytes, 20) == 0) && (memcmp(&packet->payload[52], pattern_12_bytes, 12) == 0)) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: Warez - Plain BitTorrent protocol detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_REAL_PROTOCOL); return 1; } } else if (packet->payload_packet_len > 50) { if (memcmp(packet->payload, "GET", 3) == 0) { ndpi_parse_packet_line_info(ndpi_struct, flow); /* haven't fount this pattern anywhere */ if (packet->host_line.ptr != NULL && packet->host_line.len >= 9 && memcmp(packet->host_line.ptr, "ip2p.com:", 9) == 0) { NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: Warez - Plain BitTorrent protocol detected due to Host: ip2p.com: pattern\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION, NDPI_CORRELATED_PROTOCOL); return 1; } } } return 0; }
void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; /* This is broadcast */ if(packet->iph && ((packet->iph->saddr == 0xFFFFFFFF) || (packet->iph->daddr == 0xFFFFFFFF))) return; if (packet->detected_protocol_stack[0] != NDPI_PROTOCOL_BITTORRENT) { /* check for tcp retransmission here */ if ((packet->tcp != NULL) && (packet->tcp_retransmission == 0 || packet->num_retried_bytes)) { ndpi_int_search_bittorrent_tcp(ndpi_struct, flow); } else if(packet->udp != NULL) { /* Check for uTP http://www.bittorrent.org/beps/bep_0029.html wireshark/epan/dissectors/packet-bt-utp.c */ if(packet->payload_packet_len >= 23 /* min header size */) { /* Check if this is protocol v0 */ u_int8_t v0_extension = packet->payload[17]; u_int8_t v0_flags = packet->payload[18]; /* Check if this is protocol v1 */ u_int8_t v1_version = packet->payload[0]; u_int8_t v1_extension = packet->payload[1]; if(((v1_version & 0x0f) == 1) && ((v1_version >> 4) < 6 /* ST_NUM_STATES */) && (v1_extension < 3 /* EXT_NUM_EXT */)) { goto bittorrent_found; } else if((v0_flags < 6 /* ST_NUM_STATES */) && (v0_extension < 3 /* EXT_NUM_EXT */)) { u_int32_t ts, // ts_usec, now = (u_int32_t)time(NULL); ts = ntohl(*((u_int32_t*)&(packet->payload[4]))); // ts_usec = ntohl(*((u_int32_t*)&(packet->payload[8]))); if((ts < (now+86400)) && (ts > (now-86400))) { goto bittorrent_found; } } } flow->bittorrent_stage++; if(flow->bittorrent_stage < 10) { if(packet->payload_packet_len > 19 /* min size */) { char *begin; if(ndpi_strnstr(packet->payload, ":target20:", packet->payload_packet_len) || ndpi_strnstr(packet->payload, ":find_node1:", packet->payload_packet_len) || ndpi_strnstr(packet->payload, "d1:ad2:id20:", packet->payload_packet_len)) { bittorrent_found: NDPI_LOG_BITTORRENT(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n"); ndpi_add_connection_as_bittorrent(ndpi_struct, flow, NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION, NDPI_REAL_PROTOCOL); return; } else if((begin = memchr(packet->payload, 'B', packet->payload_packet_len-19)) != NULL) { long offset = (u_long)begin - (u_long)packet->payload; if((packet->payload_packet_len-19) > offset) { if(memcmp(begin, "BitTorrent protocol", 19) == 0) { goto bittorrent_found; } } } } return; } NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_BITTORRENT); }