Skip to content

Commit

Permalink
Reworked the STUN plugin
Browse files Browse the repository at this point in the history
Added support for WhatsApp Voice vs WhatsApp (chat, no voice)
  • Loading branch information
lucaderi committed Jun 4, 2015
1 parent a31b0a3 commit 4ce9dec
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 197 deletions.
3 changes: 3 additions & 0 deletions example/ndpiReader.c
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,9 @@ static unsigned int packet_processing(u_int16_t thread_id,
|| ((proto == IPPROTO_TCP) && (flow->packets > 10))) {
flow->detection_completed = 1;

if((flow->detected_protocol == NDPI_PROTOCOL_UNKNOWN) && (ndpi_flow->num_stun_udp_pkts > 0))
ndpi_int_add_connection(ndpi_thread_info[thread_id].ndpi_struct, ndpi_flow, NDPI_PROTOCOL_STUN, NDPI_REAL_PROTOCOL);

snprintf(flow->host_server_name, sizeof(flow->host_server_name), "%s", flow->ndpi_flow->host_server_name);

if((proto == IPPROTO_TCP) && (flow->detected_protocol != NDPI_PROTOCOL_DNS)) {
Expand Down
5 changes: 3 additions & 2 deletions src/include/ndpi_protocol_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
#define NDPI_PROTOCOL_VHUA 184
#define NDPI_PROTOCOL_TELEGRAM 185 /* Gianluca Costa <g.costa@xplico.org> */
#define NDPI_PROTOCOL_QUIC 188 /* Andrea Buscarinu <andrea.buscarinu@gmail.com> - Michele Campus <michelecampus5@gmail.com> */
#define NDPI_PROTOCOL_WHATSAPP_VOICE 189


#define NDPI_CONTENT_AVI 39
Expand Down Expand Up @@ -236,8 +237,8 @@
#define NDPI_SERVICE_YAHOO NDPI_PROTOCOL_YAHOO /* Tomasz Bujlow <tomasz@skatnet.dk> */
#define NDPI_SERVICE_PANDORA 187

/* UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE (NDPI_PROTOCOL_QUIC) */
#define NDPI_LAST_IMPLEMENTED_PROTOCOL 188
/* UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE (NDPI_PROTOCOL_WHATSAPP_VOICE) */
#define NDPI_LAST_IMPLEMENTED_PROTOCOL 189

#define NDPI_MAX_SUPPORTED_PROTOCOLS (NDPI_LAST_IMPLEMENTED_PROTOCOL + 1)
#define NDPI_MAX_NUM_CUSTOM_PROTOCOLS (NDPI_NUM_BITS-NDPI_LAST_IMPLEMENTED_PROTOCOL)
Expand Down
11 changes: 1 addition & 10 deletions src/include/ndpi_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,16 +747,7 @@ typedef struct ndpi_flow_struct {
/* protocols which have marked a connection as this connection cannot be protocol XXX, multiple u_int64_t */
NDPI_PROTOCOL_BITMASK excluded_protocol_bitmask;

#if 0
#ifdef NDPI_PROTOCOL_RTP
u_int32_t rtp_ssid[2];
u_int16_t rtp_seqnum[2]; /* current highest sequence number (only goes forwards, is not decreased by retransmissions) */
/* tcp and udp */
u_int8_t rtp_payload_type[2];
u_int32_t rtp_stage1:2; //0-3
u_int32_t rtp_stage2:2;
#endif
#endif
u_int8_t num_stun_udp_pkts;

#ifdef NDPI_PROTOCOL_REDIS
u_int8_t redis_s2d_first_char, redis_d2s_first_char;
Expand Down
11 changes: 8 additions & 3 deletions src/lib/ndpi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp
ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_STUN,
no_master, custom_master, "STUN",
ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */);
ndpi_build_default_ports(ports_b, 3478, 0, 0, 0, 0) /* UDP */);
ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_IP_IPSEC,
no_master,
no_master, "IPsec",
Expand Down Expand Up @@ -1209,6 +1209,11 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp
no_master, "PcAnywhere",
ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */);
ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHATSAPP_VOICE,
no_master,
no_master, "WhatsApp Voice",
ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */);

custom_master[0] = NDPI_PROTOCOL_SSL_NO_CERT, custom_master[1] = NDPI_PROTOCOL_UNKNOWN;
ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_SSL,
Expand Down Expand Up @@ -1524,8 +1529,8 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp
no_master,
no_master,
"H323",
ndpi_build_default_ports(ports_a, 1719, 1720, 3478, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 1719, 1720, 3478, 0, 0) /* UDP */);
ndpi_build_default_ports(ports_a, 1719, 1720, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 1719, 1720, 0, 0, 0) /* UDP */);
ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_OPENVPN,
no_master,
no_master, "OpenVPN",
Expand Down
110 changes: 74 additions & 36 deletions src/lib/protocols/stun.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,51 @@
#ifdef NDPI_PROTOCOL_STUN


static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
{
ndpi_int_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_STUN, NDPI_REAL_PROTOCOL);
}
#define MAX_NUM_STUN_PKTS 6


struct stun_packet_header {
u_int16_t msg_type, msg_len;
u_int32_t cookie;
u_int8_t transaction_id[8];
};

static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
u_int proto,
struct ndpi_flow_struct *flow) {
ndpi_int_add_connection(ndpi_struct, flow, proto, NDPI_REAL_PROTOCOL);
}

typedef enum {
NDPI_IS_STUN,
NDPI_IS_NOT_STUN
} ndpi_int_stun_t;

static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *ndpi_struct,
const u_int8_t * payload, const u_int16_t payload_length)
struct ndpi_flow_struct *flow,
const u_int8_t * payload,
const u_int16_t payload_length,
u_int8_t *is_whatsapp)
{
u_int16_t a;
u_int16_t msg_type, msg_len;
struct stun_packet_header *h = (struct stun_packet_header*)payload;

if(payload_length < sizeof(struct stun_packet_header))
return(NDPI_IS_NOT_STUN);

if((payload_length > 13)
&& (strncmp((const char*)payload, (const char*)"RSP/", 4) == 0)
if((strncmp((const char*)payload, (const char*)"RSP/", 4) == 0)
&& (strncmp((const char*)&payload[7], (const char*)" STUN_", 6) == 0)) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "Found stun.\n");
return NDPI_IS_STUN;
goto udp_stun_found;
}

msg_type = ntohs(h->msg_type) & 0x3EEF, msg_len = ntohs(h->msg_len);

if((payload_length == (msg_len+20))
&& ((msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */))
goto udp_stun_found;

#ifdef ORIGINAL_CODE
/*
* token list of message types and attribute types from
* http://wwwbs1.informatik.htw-dresden.de/svortrag/i02/Schoene/stun/stun.html
Expand All @@ -68,7 +88,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
* 0x8003, 0x8004 used by facetime
*/

if (payload_length >= 20 && ntohs(get_u_int16_t(payload, 2)) + 20 == payload_length &&
if(payload_length >= 20 && ntohs(get_u_int16_t(payload, 2)) + 20 == payload_length &&
((payload[0] == 0x00 && (payload[1] >= 0x01 && payload[1] <= 0x04)) ||
(payload[0] == 0x01 &&
((payload[1] >= 0x01 && payload[1] <= 0x04) || (payload[1] >= 0x11 && payload[1] <= 0x15))))) {
Expand All @@ -77,16 +97,16 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
u_int8_t padding = 0;
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "len and type match.\n");

if (payload_length == 20) {
if(payload_length == 20) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n");
return NDPI_IS_STUN;
goto udp_stun_found;
}

a = 20;

while (a < payload_length) {

if (old && payload_length >= a + 4
if(old && payload_length >= a + 4
&&
((payload[a] == 0x00
&& ((payload[a + 1] >= 0x01 && payload[a + 1] <= 0x16) || payload[a + 1] == 0x19
Expand All @@ -103,16 +123,16 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *

a += ((payload[a + 2] << 8) + payload[a + 3] + 4);
mod = a % 4;
if (mod) {
if(mod) {
padding = 4 - mod;
}
if (a == payload_length || (padding && (a + padding) == payload_length)) {
if(a == payload_length || (padding && (a + padding) == payload_length)) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n");
return NDPI_IS_STUN;
goto udp_stun_found;
}

} else if (payload_length >= a + padding + 4
&&
} else if(payload_length >= a + padding + 4
&&
((payload[a + padding] == 0x00
&& ((payload[a + 1 + padding] >= 0x01 && payload[a + 1 + padding] <= 0x16)
|| payload[a + 1 + padding] == 0x19 || payload[a + 1 + padding] == 0x20
Expand All @@ -125,64 +145,82 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
|| payload[a + 1 + padding] == 0x20 || payload[a + 1 + padding] == 0x22
|| payload[a + 1 + padding] == 0x28 || payload[a + 1 + padding] == 0x2a
|| payload[a + 1 + padding] == 0x29 || payload[a + 1 + padding] == 0x50
|| payload[a + 1 + padding] == 0x54 || payload[a + 1 + padding] == 0x55)))) {
|| payload[a + 1 + padding] == 0x54 || payload[a + 1 + padding] == 0x55))
|| ((payload[a + padding] == 0x40) && (payload[a + padding + 1] == 0x00))
)) {
if((payload[a + padding] == 0x40) && (payload[a + padding + 1] == 0x00))
goto udp_stun_found;

NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "New STUN - attribute match.\n");

old = 0;
a += ((payload[a + 2 + padding] << 8) + payload[a + 3 + padding] + 4);
padding = 0;
mod = a % 4;
if (mod) {
if(mod) {
a += 4 - mod;
}
if (a == payload_length) {
if(a == payload_length) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n");
return NDPI_IS_STUN;
goto udp_stun_found;
}
} else {
break;
}
}
}
#endif


return NDPI_IS_NOT_STUN;
if((flow->num_stun_udp_pkts > 0) && ((payload[0] == 0x80) || (payload[0] == 0x81))) {
*is_whatsapp = 1;
return NDPI_IS_STUN; /* This is WhatsApp Voice */
} else
return NDPI_IS_NOT_STUN;

udp_stun_found:
flow->num_stun_udp_pkts++;

return((flow->num_stun_udp_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN);
}

void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &flow->packet;

u_int8_t is_whatsapp = 0;

NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "search stun.\n");


if (packet->tcp) {

if(packet->tcp) {
/* STUN may be encapsulated in TCP packets */

if (packet->payload_packet_len >= 2 + 20 &&
if(packet->payload_packet_len >= 2 + 20 &&
ntohs(get_u_int16_t(packet->payload, 0)) + 2 == packet->payload_packet_len) {

/* TODO there could be several STUN packets in a single TCP packet so maybe the detection could be
* improved by checking only the STUN packet of given length */

if (ndpi_int_check_stun(ndpi_struct, packet->payload + 2, packet->payload_packet_len - 2) ==
NDPI_IS_STUN) {
if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload + 2,
packet->payload_packet_len - 2, &is_whatsapp) == NDPI_IS_STUN) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found TCP stun.\n");
ndpi_int_stun_add_connection(ndpi_struct, flow);
ndpi_int_stun_add_connection(ndpi_struct, NDPI_PROTOCOL_STUN, flow);
return;
}
}
}
if (ndpi_int_check_stun(ndpi_struct, packet->payload, packet->payload_packet_len) == NDPI_IS_STUN) {

if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload,
packet->payload_packet_len, &is_whatsapp) == NDPI_IS_STUN) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found UDP stun.\n");
ndpi_int_stun_add_connection(ndpi_struct, flow);
ndpi_int_stun_add_connection(ndpi_struct,
is_whatsapp ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_STUN, flow);
return;
}

NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "exclude stun.\n");
NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_STUN);
if(flow->num_stun_udp_pkts >= MAX_NUM_STUN_PKTS) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "exclude stun.\n");
NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_STUN);
}
}

#endif
Loading

0 comments on commit 4ce9dec

Please sign in to comment.