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