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