aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/ndpiReader.c17
-rw-r--r--src/include/ndpi_typedefs.h4
-rw-r--r--src/lib/protocols/bittorrent.c123
-rw-r--r--tests/pcap/bittorrent.pcapbin0 -> 310536 bytes
-rw-r--r--tests/result/bittorrent.pcap.out26
5 files changed, 111 insertions, 59 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index b75672192..3cea58938 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -197,7 +197,8 @@ typedef struct ndpi_flow {
// result only, not used for flow identification
ndpi_protocol detected_protocol;
- char host_server_name[256];
+ char host_server_name[192];
+ char bittorent_hash[41];
struct {
char client_certificate[48], server_certificate[48];
@@ -528,6 +529,7 @@ static void printFlow(u_int16_t thread_id, struct ndpi_flow *flow) {
if(flow->host_server_name[0] != '\0') fprintf(out, "[Host: %s]", flow->host_server_name);
if(flow->ssl.client_certificate[0] != '\0') fprintf(out, "[SSL client: %s]", flow->ssl.client_certificate);
if(flow->ssl.server_certificate[0] != '\0') fprintf(out, "[SSL server: %s]", flow->ssl.server_certificate);
+ if(flow->bittorent_hash[0] != '\0') fprintf(out, "[BT Hash: %s]", flow->bittorent_hash);
fprintf(out, "\n");
} else {
@@ -1066,11 +1068,22 @@ static unsigned int packet_processing(u_int16_t thread_id,
snprintf(flow->host_server_name, sizeof(flow->host_server_name), "%s", flow->ndpi_flow->host_server_name);
+ if(flow->detected_protocol.protocol == NDPI_PROTOCOL_BITTORRENT) {
+ int i, j, n = 0;
+
+ for(i=0, j = 0; i<20; i++) {
+ sprintf(&flow->bittorent_hash[j], "%02x", flow->ndpi_flow->bittorent_hash[i]);
+ j += 2, n += flow->ndpi_flow->bittorent_hash[i];
+ }
+
+ if(n == 0) flow->bittorent_hash[0] = '\0';
+ }
+
if((proto == IPPROTO_TCP) && (flow->detected_protocol.protocol != NDPI_PROTOCOL_DNS)) {
snprintf(flow->ssl.client_certificate, sizeof(flow->ssl.client_certificate), "%s", flow->ndpi_flow->protos.ssl.client_certificate);
snprintf(flow->ssl.server_certificate, sizeof(flow->ssl.server_certificate), "%s", flow->ndpi_flow->protos.ssl.server_certificate);
}
-
+
free_ndpi_flow(flow);
if(verbose > 1) {
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index c4f4fdf73..33fe5430c 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -887,11 +887,13 @@ struct ndpi_flow_struct {
*/
struct ndpi_id_struct *server_id;
/* HTTP host or DNS query */
- u_char host_server_name[256];
+ u_char host_server_name[192];
/* Via HTTP User-Agent */
u_char detected_os[32];
/* Via HTTP X-Forwarded-For */
u_char nat_ip[24];
+ /* Bittorrent hash */
+ u_char bittorent_hash[20];
/*
This structure below will not not stay inside the protos
diff --git a/src/lib/protocols/bittorrent.c b/src/lib/protocols/bittorrent.c
index 99420b85e..fd8ab20c0 100644
--- a/src/lib/protocols/bittorrent.c
+++ b/src/lib/protocols/bittorrent.c
@@ -31,9 +31,24 @@
#define NDPI_PROTOCOL_PLAIN_DETECTION 0
#define NDPI_PROTOCOL_WEBSEED_DETECTION 2
static void ndpi_add_connection_as_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow,
+ int bt_offset,
const u_int8_t save_detection, const u_int8_t encrypted_connection/* , */
/* ndpi_protocol_type_t protocol_type */)
{
+ const char *bt_hash = NULL; /* 20 bytes long */
+ const char *peer_id = NULL; /* 20 bytes long */
+
+ if(bt_offset == -1) {
+ const char *bt_magic = ndpi_strnstr((const char *)flow->packet.payload,
+ "BitTorrent protocol", flow->packet.payload_packet_len);
+
+ if(bt_magic)
+ bt_hash = &bt_magic[19], peer_id = &bt_magic[39];
+ } else
+ bt_hash = &flow->packet.payload[28], peer_id = &flow->packet.payload[48];
+
+ if(bt_hash) memcpy(flow->bittorent_hash, bt_hash, 20);
+
ndpi_int_change_protocol(ndpi_struct, flow, NDPI_PROTOCOL_BITTORRENT, NDPI_PROTOCOL_UNKNOWN);
}
@@ -43,17 +58,17 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
struct ndpi_packet_struct *packet = &flow->packet;
u_int16_t a = 0;
- if (packet->payload_packet_len == 1 && packet->payload[0] == 0x13) {
+ 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) {
+ if(flow->packet_counter == 2 && packet->payload_packet_len > 20) {
+ if(memcmp(&packet->payload[0], "BitTorrent protocol", 19) == 0) {
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT,
ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, 19,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION/* , */
/* NDPI_REAL_PROTOCOL */);
return 1;
@@ -61,13 +76,12 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
}
- if (packet->payload_packet_len > 20) {
+ 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(NDPI_PROTOCOL_BITTORRENT,
- ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ if(packet->payload[0] == 0x13) {
+ if(memcmp(&packet->payload[1], "BitTorrent protocol", 19) == 0) {
+ NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n");
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, 20,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION/* , */
/* NDPI_REAL_PROTOCOL */);
return 1;
@@ -75,10 +89,10 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
}
}
- if (packet->payload_packet_len > 23 && memcmp(packet->payload, "GET /webseed?info_hash=", 23) == 0) {
+ if(packet->payload_packet_len > 23 && memcmp(packet->payload, "GET /webseed?info_hash=", 23) == 0) {
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct,
NDPI_LOG_TRACE, "BT: plain webseed BitTorrent protocol detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION/* , */
/* NDPI_CORRELATED_PROTOCOL */);
return 1;
@@ -86,18 +100,18 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
/* 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
+ if(packet->payload_packet_len > 60
&& memcmp(packet->payload, "GET /data?fid=", 14) == 0 && memcmp(&packet->payload[54], "&size=", 6) == 0) {
NDPI_LOG(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_add_connection_as_bittorrent(ndpi_struct, flow, -1,
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
+ 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;
@@ -107,32 +121,32 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
/* 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
+ 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(NDPI_PROTOCOL_BITTORRENT, ndpi_struct,
NDPI_LOG_TRACE, "Azureus /Bittorrent user agent line detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION/* , */
/* NDPI_CORRELATED_PROTOCOL */);
return 1;
}
- if (packet->user_agent_line.ptr != NULL
+ 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(NDPI_PROTOCOL_BITTORRENT, ndpi_struct,
NDPI_LOG_TRACE, "Bittorrent Shareaza detected.\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
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))
+ 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
&& memcmp(packet->user_agent_line.ptr, "Mozilla/4.0 ",
@@ -160,15 +174,14 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
&& packet->line[8].len > 22 && memcmp(packet->line[8].ptr, "Cache-Control: no-cache", 23) == 0) {
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "Bitcomet LTS detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_UNSAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION/* , */
/* NDPI_CORRELATED_PROTOCOL */);
return 1;
-
}
/* FlashGet pattern */
- if (packet->parsed_lines == 8
+ 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;",
@@ -187,13 +200,13 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
&& packet->line[6].len > 21 && memcmp(packet->line[6].ptr, "Connection: Keep-Alive", 22) == 0) {
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "FlashGet detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_UNSAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION/* , */
/* NDPI_CORRELATED_PROTOCOL */);
return 1;
-
}
- if (packet->parsed_lines == 7
+
+ 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;",
@@ -209,19 +222,18 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
&& packet->line[5].len > 21 && memcmp(packet->line[5].ptr, "Connection: Keep-Alive", 22) == 0) {
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_TRACE, "FlashGet detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
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) {
+ if(len < 50 || ptr[0] == 0x0d) {
goto ndpi_end_bt_tracker_check;
}
- if (memcmp(ptr, "info_hash=", 10) == 0) {
+ if(memcmp(ptr, "info_hash=", 10) == 0) {
break;
}
len--;
@@ -237,40 +249,40 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
/* parse bt hash */
for (a = 0; a < 20; a++) {
- if (len < 3) {
+ if(len < 3) {
goto ndpi_end_bt_tracker_check;
}
- if (*ptr == '%') {
+ if(*ptr == '%') {
u_int8_t x1 = 0xFF;
u_int8_t x2 = 0xFF;
- if (ptr[1] >= '0' && ptr[1] <= '9') {
+ if(ptr[1] >= '0' && ptr[1] <= '9') {
x1 = ptr[1] - '0';
}
- if (ptr[1] >= 'a' && ptr[1] <= 'f') {
+ if(ptr[1] >= 'a' && ptr[1] <= 'f') {
x1 = 10 + ptr[1] - 'a';
}
- if (ptr[1] >= 'A' && ptr[1] <= 'F') {
+ if(ptr[1] >= 'A' && ptr[1] <= 'F') {
x1 = 10 + ptr[1] - 'A';
}
- if (ptr[2] >= '0' && ptr[2] <= '9') {
+ if(ptr[2] >= '0' && ptr[2] <= '9') {
x2 = ptr[2] - '0';
}
- if (ptr[2] >= 'a' && ptr[2] <= 'f') {
+ if(ptr[2] >= 'a' && ptr[2] <= 'f') {
x2 = 10 + ptr[2] - 'a';
}
- if (ptr[2] >= 'A' && ptr[2] <= 'F') {
+ if(ptr[2] >= 'A' && ptr[2] <= 'F') {
x2 = 10 + ptr[2] - 'A';
}
- if (x1 == 0xFF || x2 == 0xFF) {
+ if(x1 == 0xFF || x2 == 0xFF) {
goto ndpi_end_bt_tracker_check;
}
ptr += 3;
len -= 3;
- } else if (*ptr >= 32 && *ptr < 127) {
+ } else if(*ptr >= 32 && *ptr < 127) {
ptr++;
len--;
} else {
@@ -280,7 +292,7 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct,
NDPI_LOG_TRACE, " BT stat: tracker info hash parsed\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION/* , */
/* NDPI_CORRELATED_PROTOCOL */);
return 1;
@@ -288,7 +300,7 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
ndpi_end_bt_tracker_check:
- if (packet->payload_packet_len == 80) {
+ if(packet->payload_packet_len == 80) {
/* Warez 80 Bytes Packet
* +----------------+---------------+-----------------+-----------------+
* |20 BytesPattern | 32 Bytes Value| 12 BytesPattern | 16 Bytes Data |
@@ -306,28 +318,28 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
};
/* did not see this pattern anywhere */
- if ((memcmp(&packet->payload[0], pattern_20_bytes, 20) == 0)
+ if((memcmp(&packet->payload[0], pattern_20_bytes, 20) == 0)
&& (memcmp(&packet->payload[52], pattern_12_bytes, 12) == 0)) {
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct,
NDPI_LOG_TRACE, "BT: Warez - Plain BitTorrent protocol detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
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) {
+ 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
+ if(packet->host_line.ptr != NULL
&& packet->host_line.len >= 9 && memcmp(packet->host_line.ptr, "ip2p.com:", 9) == 0) {
NDPI_LOG(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_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_WEBSEED_DETECTION/* , */
/* NDPI_CORRELATED_PROTOCOL */);
return 1;
@@ -341,17 +353,16 @@ static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module
/*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) {
+ if(packet->payload_packet_len == 0) {
return;
}
- if (flow->bittorrent_stage == 0 && packet->payload_packet_len != 0) {
+ 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) {
+ if(ndpi_int_search_bittorrent_tcp_zero(ndpi_struct, flow) != 0) {
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT, ndpi_struct, NDPI_LOG_DEBUG,
"stage 0 has detected something, returning\n");
return;
@@ -378,10 +389,10 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st
return;
}
- if (packet->detected_protocol_stack[0] != NDPI_PROTOCOL_BITTORRENT) {
+ if(packet->detected_protocol_stack[0] != NDPI_PROTOCOL_BITTORRENT) {
/* check for tcp retransmission here */
- if ((packet->tcp != NULL)
+ if((packet->tcp != NULL)
&& (packet->tcp_retransmission == 0 || packet->num_retried_bytes)) {
ndpi_int_search_bittorrent_tcp(ndpi_struct, flow);
}
@@ -400,7 +411,7 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st
if(packet->payload_packet_len >= 23 /* min header size */) {
if(strncmp((const char*)packet->payload, bt_search, strlen(bt_search)) == 0) {
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION/* , */
/* NDPI_REAL_PROTOCOL */);
return;
@@ -456,7 +467,7 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st
bittorrent_found:
NDPI_LOG(NDPI_PROTOCOL_BITTORRENT,
ndpi_struct, NDPI_LOG_TRACE, "BT: plain BitTorrent protocol detected\n");
- ndpi_add_connection_as_bittorrent(ndpi_struct, flow,
+ ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1,
NDPI_PROTOCOL_SAFE_DETECTION, NDPI_PROTOCOL_PLAIN_DETECTION/* , */
/* NDPI_REAL_PROTOCOL */);
return;
diff --git a/tests/pcap/bittorrent.pcap b/tests/pcap/bittorrent.pcap
new file mode 100644
index 000000000..68f1ca203
--- /dev/null
+++ b/tests/pcap/bittorrent.pcap
Binary files differ
diff --git a/tests/result/bittorrent.pcap.out b/tests/result/bittorrent.pcap.out
new file mode 100644
index 000000000..415673d20
--- /dev/null
+++ b/tests/result/bittorrent.pcap.out
@@ -0,0 +1,26 @@
+BitTorrent 299 305728 24
+
+ 1 TCP 192.168.1.3:52908 <-> 79.55.129.22:12097 [proto: 37/BitTorrent][1 pkts/134 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 2 TCP 79.53.228.2:14627 <-> 192.168.1.3:52896 [proto: 37/BitTorrent][5 pkts/1180 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 3 TCP 192.168.1.3:52922 <-> 95.237.193.34:11321 [proto: 37/BitTorrent][5 pkts/1205 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 4 TCP 192.168.1.3:52925 <-> 93.65.227.100:19116 [proto: 37/BitTorrent][1 pkts/134 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 5 TCP 192.168.1.3:52907 <-> 82.58.216.115:38305 [proto: 37/BitTorrent][4 pkts/1401 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 6 TCP 192.168.1.3:52897 <-> 151.26.95.30:22673 [proto: 37/BitTorrent][5 pkts/1281 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 7 TCP 192.168.1.3:52911 <-> 151.26.95.30:22673 [proto: 37/BitTorrent][5 pkts/1213 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 8 TCP 192.168.1.3:52921 <-> 95.234.159.16:41205 [proto: 37/BitTorrent][5 pkts/1212 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 9 TCP 192.168.1.3:52894 <-> 120.62.33.241:39332 [proto: 37/BitTorrent][1 pkts/134 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 10 TCP 192.168.1.3:52910 <-> 120.62.33.241:39332 [proto: 37/BitTorrent][1 pkts/134 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 11 TCP 192.168.1.3:52895 <-> 83.216.184.241:51413 [proto: 37/BitTorrent][8 pkts/1558 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 12 TCP 192.168.1.3:52927 <-> 83.216.184.241:51413 [proto: 37/BitTorrent][5 pkts/1378 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 13 TCP 192.168.1.3:52906 <-> 82.57.97.83:53137 [proto: 37/BitTorrent][5 pkts/1205 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 14 TCP 192.168.1.3:52902 <-> 190.103.195.56:46633 [proto: 37/BitTorrent][4 pkts/614 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 15 TCP 192.168.1.3:52914 <-> 190.103.195.56:46633 [proto: 37/BitTorrent][7 pkts/1550 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 16 TCP 192.168.1.3:52893 <-> 79.55.129.22:12097 [proto: 37/BitTorrent][1 pkts/134 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 17 TCP 192.168.1.3:52912 <-> 151.72.255.163:59928 [proto: 37/BitTorrent][4 pkts/612 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 18 TCP 79.53.228.2:14627 <-> 192.168.1.3:52909 [proto: 37/BitTorrent][1 pkts/134 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 19 TCP 192.168.1.3:52903 <-> 198.100.146.9:60163 [proto: 37/BitTorrent][6 pkts/1261 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 20 TCP 192.168.1.3:52915 <-> 198.100.146.9:60163 [proto: 37/BitTorrent][210 pkts/285139 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 21 TCP 192.168.1.3:52926 <-> 93.65.249.100:31336 [proto: 37/BitTorrent][3 pkts/930 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 22 TCP 192.168.1.3:52888 <-> 82.58.216.115:38305 [proto: 37/BitTorrent][2 pkts/758 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 23 TCP 192.168.1.3:52887 <-> 82.57.97.83:53137 [proto: 37/BitTorrent][5 pkts/1201 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]
+ 24 TCP 192.168.1.3:52917 <-> 151.15.48.189:47001 [proto: 37/BitTorrent][5 pkts/1226 bytes][BT Hash: dcfcdccfb9e670ccc3dd40c78c161f2bea243126]