1 /*
2  * skype.c
3  *
4  * Copyright (C) 2017-21 - ntop.org
5  *
6  * nDPI is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * nDPI is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with nDPI.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 #include "ndpi_protocol_ids.h"
21 
22 #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SKYPE_TEAMS
23 
24 #include "ndpi_api.h"
25 
is_port(u_int16_t a,u_int16_t b,u_int16_t c)26 static int is_port(u_int16_t a, u_int16_t b, u_int16_t c) {
27   return(((a == c) || (b == c)) ? 1 : 0);
28 }
29 
ndpi_check_skype_udp_again(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow)30 static int ndpi_check_skype_udp_again(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
31   struct ndpi_packet_struct *packet = &flow->packet;
32   u_int32_t payload_len = packet->payload_packet_len;
33 
34   const uint8_t id_flags_iv_crc_len = 11;
35   const uint8_t crc_len = sizeof(flow->l4.udp.skype_crc);
36   const uint8_t crc_offset = id_flags_iv_crc_len - crc_len;
37 
38   if (flow->packet_counter > 2)
39   {
40     /*
41      * Process only one packet after the initial packet received.
42      * This is required to prevent fals-positives with other protocols e.g. dnscrypt.
43      */
44     return 0;
45   }
46 
47   if ((payload_len >= id_flags_iv_crc_len) && (packet->payload[2] == 0x02 /* Payload flag */ )) {
48     u_int8_t detected = 1;
49 
50     /* Check if both packets have the same CRC */
51     for (int i = 0; i < crc_len && detected; i++) {
52       if (packet->payload[crc_offset + i] != flow->l4.udp.skype_crc[i])
53         detected = 0;
54     }
55 
56     if (detected) {
57       ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_TEAMS, NDPI_PROTOCOL_UNKNOWN);
58       flow->extra_packets_func = NULL;
59 
60       /* Stop checking extra packets */
61       return 0;
62     }
63   }
64 
65   /* Check more packets */
66   return 1;
67 }
68 
ndpi_check_skype(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow)69 static void ndpi_check_skype(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
70   struct ndpi_packet_struct *packet = &flow->packet;
71   // const u_int8_t *packet_payload = packet->payload;
72   u_int32_t payload_len = packet->payload_packet_len;
73 
74   /* No need to do ntohl() with 0xFFFFFFFF */
75   if(packet->iph && (packet->iph->daddr == 0xFFFFFFFF /* 255.255.255.255 */)) {
76     NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
77     return;
78   }
79 
80   if(flow->host_server_name[0] != '\0')
81     return;
82 
83   // UDP check
84   if(packet->udp != NULL) {
85     flow->l4.udp.skype_packet_id++;
86 
87     if(flow->l4.udp.skype_packet_id < 5) {
88       u_int16_t sport = ntohs(packet->udp->source);
89       u_int16_t dport = ntohs(packet->udp->dest);
90 
91       /* skype-to-skype */
92       if(is_port(sport, dport, 1119) /* It can be confused with battle.net */
93 	 || is_port(sport, dport, 80) /* No HTTP-like protocols UDP/80 */
94 	 ) {
95 	;
96       } else {
97 	/* Too many false positives */
98 	if(((payload_len == 3) && ((packet->payload[2] & 0x0F)== 0x0d))
99 	   ||
100 	   ((payload_len >= 16)
101 	    && (((packet->payload[0] & 0xC0) >> 6) == 0x02 /* RTPv2 */
102 		|| (((packet->payload[0] & 0xF0) >> 4) == 0 /* Zoom */)
103 		|| (((packet->payload[0] & 0xF0) >> 4) == 0x07 /* Skype */)
104 		)
105 	    && (packet->payload[0] != 0x30) /* Avoid invalid SNMP detection */
106 	    && (packet->payload[0] != 0x00) /* Avoid invalid CAPWAP detection */
107 	    && (packet->payload[2] == 0x02))) {
108 
109 	  if(is_port(sport, dport, 8801)) {
110 	    ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_ZOOM, NDPI_PROTOCOL_UNKNOWN);
111 	  } else if (payload_len >= 16 && packet->payload[0] != 0x01) /* Avoid invalid Cisco HSRP detection / RADIUS */ {
112 	    ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE_TEAMS);
113 	  }
114 	}
115 
116         if (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) {
117           const uint8_t id_flags_iv_crc_len = 11;
118           const uint8_t crc_len = sizeof(flow->l4.udp.skype_crc);
119           const uint8_t crc_offset = id_flags_iv_crc_len - crc_len;
120 
121           if ((payload_len >= id_flags_iv_crc_len)
122 	      && (packet->payload[2] == 0x02 /* Payload flag */ )
123 	      && (payload_len >= (crc_offset+crc_len))
124 	      && (!flow->extra_packets_func)) {
125             flow->check_extra_packets = 1;
126             flow->max_extra_packets_to_check = 5;
127             flow->extra_packets_func = ndpi_check_skype_udp_again;
128 
129             memcpy(flow->l4.udp.skype_crc, &packet->payload[crc_offset], crc_len);
130             return;
131           }
132         }
133 
134       }
135 
136       // return;
137     }
138 
139     NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
140     return;
141     // TCP check
142   } else if((packet->tcp != NULL)
143 	    /* As the TCP skype heuristic is weak, we need to make sure no other protocols overlap */
144 	    && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN)
145 	    && (flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN)) {
146     flow->l4.tcp.skype_packet_id++;
147 
148     if(flow->l4.tcp.skype_packet_id < 3) {
149       ; /* Too early */
150     } else if((flow->l4.tcp.skype_packet_id == 3)
151 	      /* We have seen the 3-way handshake */
152 	      && flow->l4.tcp.seen_syn
153 	      && flow->l4.tcp.seen_syn_ack
154 	      && flow->l4.tcp.seen_ack) {
155       /* Disabled this logic as it's too weak and leads to false positives */
156 #if 0
157       if((payload_len == 8) || (payload_len == 3) || (payload_len == 17)) {
158 	// printf("[SKYPE] payload_len=%u\n", payload_len);
159 	/* printf("[SKYPE] %u/%u\n", ntohs(packet->tcp->source), ntohs(packet->tcp->dest)); */
160 
161 	NDPI_LOG_INFO(ndpi_struct, "found skype\n");
162 	  ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_TEAMS_CALL, NDPI_PROTOCOL_SKYPE_TEAMS);
163       } else {
164 	// printf("NO [SKYPE] payload_len=%u\n", payload_len);
165       }
166 
167       /* printf("[SKYPE] [id: %u][len: %d]\n", flow->l4.tcp.skype_packet_id, payload_len);  */
168 #endif
169     } else {
170       NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
171     }
172 
173     return;
174   }
175 }
176 
ndpi_search_skype(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow)177 void ndpi_search_skype(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
178 {
179   struct ndpi_packet_struct *packet = &flow->packet;
180 
181   NDPI_LOG_DBG(ndpi_struct, "search skype\n");
182 
183   /* skip marked packets */
184   if(packet->detected_protocol_stack[0] != NDPI_PROTOCOL_SKYPE_TEAMS)
185     ndpi_check_skype(ndpi_struct, flow);
186 }
187 
188 
init_skype_dissector(struct ndpi_detection_module_struct * ndpi_struct,u_int32_t * id,NDPI_PROTOCOL_BITMASK * detection_bitmask)189 void init_skype_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
190 {
191   ndpi_set_bitmask_protocol_detection("Skype", ndpi_struct, detection_bitmask, *id,
192 				      NDPI_PROTOCOL_SKYPE_TEAMS,
193 				      ndpi_search_skype,
194 				      NDPI_SELECTION_BITMASK_PROTOCOL_TCP_OR_UDP_WITH_PAYLOAD,
195 				      SAVE_DETECTION_BITMASK_AS_UNKNOWN,
196 				      ADD_TO_DETECTION_BITMASK);
197 
198   *id += 1;
199 }
200