1 /*
2 * jabber.c
3 *
4 * Copyright (C) 2009-11 - ipoque GmbH
5 * Copyright (C) 2011-21 - ntop.org
6 *
7 * This file is part of nDPI, an open source deep packet inspection
8 * library based on the OpenDPI and PACE technology by ipoque GmbH
9 *
10 * nDPI is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * nDPI is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with nDPI. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25 #include "ndpi_protocol_ids.h"
26
27 #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_JABBER
28
29 #include "ndpi_api.h"
30
31 struct jabber_string {
32 char *string;
33 u_int ndpi_protocol;
34 };
35
36 static struct jabber_string jabber_strings[] = {
37 { "='im.truphone.com'", NDPI_PROTOCOL_TRUPHONE },
38 { "=\"im.truphone.com\"", NDPI_PROTOCOL_TRUPHONE },
39 { NULL, 0 }
40 };
41
ndpi_int_jabber_add_connection(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow,u_int32_t protocol)42 static void ndpi_int_jabber_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
43 struct ndpi_flow_struct *flow,
44 u_int32_t protocol)
45 {
46 ndpi_set_detected_protocol(ndpi_struct, flow, protocol, NDPI_PROTOCOL_UNKNOWN);
47 }
48
check_content_type_and_change_protocol(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow,u_int16_t x)49 static void check_content_type_and_change_protocol(struct ndpi_detection_module_struct *ndpi_struct,
50 struct ndpi_flow_struct *flow, u_int16_t x)
51 {
52 struct ndpi_packet_struct *packet = &flow->packet;
53 int i, left = packet->payload_packet_len-x;
54
55 if(left <= 0) return;
56
57 for(i=0; jabber_strings[i].string != NULL; i++) {
58 if(ndpi_strnstr((const char*)&packet->payload[x], jabber_strings[i].string, left) != NULL) {
59 ndpi_int_jabber_add_connection(ndpi_struct, flow, jabber_strings[i].ndpi_protocol);
60 return;
61 }
62 }
63 }
64
ndpi_search_jabber_tcp(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow)65 void ndpi_search_jabber_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
66 {
67 struct ndpi_packet_struct *packet = &flow->packet;
68 struct ndpi_id_struct *src = flow->src;
69 struct ndpi_id_struct *dst = flow->dst;
70 u_int16_t x;
71
72 NDPI_LOG_DBG(ndpi_struct, "search JABBER\n");
73
74 if (flow->packet_counter > 5) {
75 NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
76 return;
77 }
78
79 /* search for jabber file transfer */
80 /* this part is working asymmetrically */
81 if (packet->tcp != NULL && packet->tcp->syn != 0 && packet->payload_packet_len == 0) {
82 NDPI_LOG_DBG2(ndpi_struct, "check jabber syn\n");
83 if (src != NULL && src->jabber_file_transfer_port[0] != 0) {
84 NDPI_LOG_DBG2(ndpi_struct, "src jabber ft port set, ports are: %u, %u\n",
85 ntohs(src->jabber_file_transfer_port[0]),
86 ntohs(src->jabber_file_transfer_port[1]));
87 if (((u_int32_t)
88 (packet->current_time_ms - src->jabber_stun_or_ft_ts)) >= ndpi_struct->jabber_file_transfer_timeout) {
89 NDPI_LOG_DBG2(ndpi_struct, "JABBER src stun timeout %u %u\n",
90 src->jabber_stun_or_ft_ts, packet->current_time_ms);
91 src->jabber_file_transfer_port[0] = 0;
92 src->jabber_file_transfer_port[1] = 0;
93 } else if (src->jabber_file_transfer_port[0] == packet->tcp->dest
94 || src->jabber_file_transfer_port[0] == packet->tcp->source
95 || src->jabber_file_transfer_port[1] == packet->tcp->dest
96 || src->jabber_file_transfer_port[1] == packet->tcp->source) {
97 NDPI_LOG_INFO(ndpi_struct, "found jabber file transfer\n");
98
99 ndpi_int_jabber_add_connection(ndpi_struct, flow,
100 NDPI_PROTOCOL_JABBER);
101 }
102 }
103 if (dst != NULL && dst->jabber_file_transfer_port[0] != 0) {
104 NDPI_LOG_DBG2(ndpi_struct, "dst jabber ft port set, ports are: %u, %u\n",
105 ntohs(dst->jabber_file_transfer_port[0]),
106 ntohs(dst->jabber_file_transfer_port[1]));
107 if (((u_int32_t)
108 (packet->current_time_ms - dst->jabber_stun_or_ft_ts)) >= ndpi_struct->jabber_file_transfer_timeout) {
109 NDPI_LOG_DBG2(ndpi_struct, "JABBER dst stun timeout %u %u\n",
110 dst->jabber_stun_or_ft_ts, packet->current_time_ms);
111 dst->jabber_file_transfer_port[0] = 0;
112 dst->jabber_file_transfer_port[1] = 0;
113 } else if (dst->jabber_file_transfer_port[0] == packet->tcp->dest
114 || dst->jabber_file_transfer_port[0] == packet->tcp->source
115 || dst->jabber_file_transfer_port[1] == packet->tcp->dest
116 || dst->jabber_file_transfer_port[1] == packet->tcp->source) {
117 NDPI_LOG_INFO(ndpi_struct, "found jabber file transfer\n");
118
119 ndpi_int_jabber_add_connection(ndpi_struct, flow,
120 NDPI_PROTOCOL_JABBER);
121 }
122 }
123 return;
124 }
125
126 if (packet->tcp != 0 && packet->payload_packet_len == 0) {
127 return;
128 }
129
130
131 /* this part parses a packet and searches for port=. it works asymmetrically. */
132 if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_JABBER) {
133 u_int16_t lastlen;
134 u_int16_t j_port = 0;
135 /* check for google jabber voip connections ... */
136 /* need big packet */
137 if (packet->payload_packet_len < 100) {
138 NDPI_LOG_DBG2(ndpi_struct, "packet too small, return\n");
139 return;
140 }
141 /* need message to or type for file-transfer */
142 if (memcmp(packet->payload, "<iq from=\"", 10) == 0 || memcmp(packet->payload, "<iq from=\'", 10) == 0) {
143 NDPI_LOG_DBG2(ndpi_struct, "JABBER <iq from=\"\n");
144 lastlen = packet->payload_packet_len - 11;
145 for (x = 10; x < lastlen; x++) {
146 if (packet->payload[x] == 'p') {
147 if (memcmp(&packet->payload[x], "port=", 5) == 0) {
148 NDPI_LOG_DBG2(ndpi_struct, "port=\n");
149 if (src != NULL) {
150 src->jabber_stun_or_ft_ts = packet->current_time_ms;
151 }
152
153 if (dst != NULL) {
154 dst->jabber_stun_or_ft_ts = packet->current_time_ms;
155 }
156 x += 6;
157 j_port = ntohs_ndpi_bytestream_to_number(&packet->payload[x], packet->payload_packet_len, &x);
158 NDPI_LOG_DBG2(ndpi_struct, "JABBER port : %u\n", ntohs(j_port));
159 if (src != NULL) {
160 if (src->jabber_file_transfer_port[0] == 0 || src->jabber_file_transfer_port[0] == j_port) {
161 NDPI_LOG_DBG2(ndpi_struct, "src->jabber_file_transfer_port[0] = j_port = %u;\n",
162 ntohs(j_port));
163 src->jabber_file_transfer_port[0] = j_port;
164 } else {
165 NDPI_LOG_DBG2(ndpi_struct, "src->jabber_file_transfer_port[1] = j_port = %u;\n",
166 ntohs(j_port));
167 src->jabber_file_transfer_port[1] = j_port;
168 }
169 }
170 if (dst != NULL) {
171 if (dst->jabber_file_transfer_port[0] == 0 || dst->jabber_file_transfer_port[0] == j_port) {
172 NDPI_LOG_DBG2(ndpi_struct, "dst->jabber_file_transfer_port[0] = j_port = %u;\n",
173 ntohs(j_port));
174 dst->jabber_file_transfer_port[0] = j_port;
175 } else {
176 NDPI_LOG_DBG2(ndpi_struct, "dst->jabber_file_transfer_port[1] = j_port = %u;\n",
177 ntohs(j_port));
178 dst->jabber_file_transfer_port[1] = j_port;
179 }
180 }
181 }
182
183
184 }
185 }
186
187 } else if (memcmp(packet->payload, "<iq to=\"", 8) == 0 || memcmp(packet->payload, "<iq to=\'", 8) == 0
188 || memcmp(packet->payload, "<iq type=", 9) == 0) {
189 NDPI_LOG_DBG2(ndpi_struct, "JABBER <iq to=\"/type=\"\n");
190 lastlen = packet->payload_packet_len - 21;
191 for (x = 8; x < lastlen; x++) {
192 /* invalid character */
193 if (packet->payload[x] < 32 || packet->payload[x] > 127) {
194 return;
195 }
196 if (packet->payload[x] == '@') {
197 NDPI_LOG_DBG2(ndpi_struct, "JABBER @\n");
198 break;
199 }
200 }
201 if (x >= lastlen) {
202 return;
203 }
204
205 lastlen = packet->payload_packet_len - 10;
206 for (; x < lastlen; x++) {
207 if (packet->payload[x] == 'p') {
208 if (memcmp(&packet->payload[x], "port=", 5) == 0) {
209 NDPI_LOG_DBG2(ndpi_struct, "port=\n");
210 if (src != NULL) {
211 src->jabber_stun_or_ft_ts = packet->current_time_ms;
212 }
213
214 if (dst != NULL) {
215 dst->jabber_stun_or_ft_ts = packet->current_time_ms;
216 }
217
218 x += 6;
219 j_port = ntohs_ndpi_bytestream_to_number(&packet->payload[x], packet->payload_packet_len, &x);
220 NDPI_LOG_DBG2(ndpi_struct, "JABBER port : %u\n", ntohs(j_port));
221
222 if (src != NULL && src->jabber_voice_stun_used_ports < JABBER_MAX_STUN_PORTS - 1) {
223 if (packet->payload[5] == 'o') {
224 src->jabber_voice_stun_port[src->jabber_voice_stun_used_ports++]
225 = j_port;
226 } else {
227 if (src->jabber_file_transfer_port[0] == 0
228 || src->jabber_file_transfer_port[0] == j_port) {
229 NDPI_LOG_DBG2(ndpi_struct, "src->jabber_file_transfer_port[0] = j_port = %u;\n",
230 ntohs(j_port));
231 src->jabber_file_transfer_port[0] = j_port;
232 } else {
233 NDPI_LOG_DBG2(ndpi_struct, "src->jabber_file_transfer_port[1] = j_port = %u;\n",
234 ntohs(j_port));
235 src->jabber_file_transfer_port[1] = j_port;
236 }
237 }
238 }
239
240 if (dst != NULL && dst->jabber_voice_stun_used_ports < JABBER_MAX_STUN_PORTS - 1) {
241 if (packet->payload[5] == 'o') {
242 dst->jabber_voice_stun_port[dst->jabber_voice_stun_used_ports++]
243 = j_port;
244 } else {
245 if (dst->jabber_file_transfer_port[0] == 0
246 || dst->jabber_file_transfer_port[0] == j_port) {
247 NDPI_LOG_DBG2(ndpi_struct, "dst->jabber_file_transfer_port[0] = j_port = %u;\n",
248 ntohs(j_port));
249 dst->jabber_file_transfer_port[0] = j_port;
250 } else {
251 NDPI_LOG_DBG2(ndpi_struct, "dst->jabber_file_transfer_port[1] = j_port = %u;\n",
252 ntohs(j_port));
253 dst->jabber_file_transfer_port[1] = j_port;
254 }
255 }
256 }
257 return;
258 }
259 }
260 }
261 }
262 return;
263 }
264
265
266 /* search for jabber here */
267 /* this part is working asymmetrically */
268 if ((packet->payload_packet_len > 13 && memcmp(packet->payload, "<?xml version=", 14) == 0)
269 || (packet->payload_packet_len >= NDPI_STATICSTRING_LEN("<stream:stream ")
270 && memcmp(packet->payload, "<stream:stream ", NDPI_STATICSTRING_LEN("<stream:stream ")) == 0)) {
271 int start = packet->payload_packet_len-13;
272
273 if(ndpi_strnstr((const char *)&packet->payload[13], "xmlns:stream='http://etherx.jabber.org/streams'", start)
274 || ndpi_strnstr((const char *)&packet->payload[13], "xmlns:stream=\"http://etherx.jabber.org/streams\"", start)) {
275
276 /* Protocol family */
277 ndpi_int_jabber_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_JABBER);
278
279 /* search for subprotocols */
280 check_content_type_and_change_protocol(ndpi_struct, flow, 13);
281 return;
282 }
283 }
284
285 if (flow->packet_counter < 3) {
286 NDPI_LOG_DBG2(ndpi_struct, "packet_counter: %u\n", flow->packet_counter);
287 return;
288 }
289
290 NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
291
292 ndpi_exclude_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TRUPHONE,
293 __FILE__,__FUNCTION__,__LINE__);
294 }
295
296
init_jabber_dissector(struct ndpi_detection_module_struct * ndpi_struct,u_int32_t * id,NDPI_PROTOCOL_BITMASK * detection_bitmask)297 void init_jabber_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
298 {
299 ndpi_set_bitmask_protocol_detection("Jabber", ndpi_struct, detection_bitmask, *id,
300 NDPI_PROTOCOL_JABBER,
301 ndpi_search_jabber_tcp,
302 NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITHOUT_RETRANSMISSION,
303 SAVE_DETECTION_BITMASK_AS_UNKNOWN,
304 ADD_TO_DETECTION_BITMASK);
305
306 *id += 1;
307 }
308
309