1 /* packet-rtsp.c
2 * Routines for RTSP packet disassembly (RFC 2326)
3 *
4 * Jason Lango <jal@netapp.com>
5 * Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 *
13 * References:
14 * RTSP is defined in RFC 2326, https://tools.ietf.org/html/rfc2326
15 * https://www.iana.org/assignments/rsvp-parameters
16 */
17
18 #include "config.h"
19
20 #include <stdio.h> /* for sscanf() */
21
22 #include <epan/packet.h>
23 #include <epan/req_resp_hdrs.h>
24 #include <epan/prefs.h>
25 #include <epan/conversation.h>
26 #include <epan/expert.h>
27 #include <epan/strutil.h>
28 #include <epan/tap-voip.h>
29 #include <epan/stats_tree.h>
30 #include <epan/addr_resolv.h>
31 #include <wsutil/str_util.h>
32 #include <wsutil/strtoi.h>
33
34 #include "packet-rdt.h"
35 #include "packet-rtp.h"
36 #include "packet-rtcp.h"
37 #include "packet-e164.h"
38 #include "packet-rtsp.h"
39
40 void proto_register_rtsp(void);
41
42 static int rtsp_tap = -1;
43 static rtsp_info_value_t *rtsp_stat_info;
44
45 /* http://www.iana.org/assignments/rtsp-parameters/rtsp-parameters.xml */
46
47 const value_string rtsp_status_code_vals[] = {
48 { 100, "Continue" },
49 { 199, "Informational - Others" },
50
51 { 200, "OK"},
52 { 201, "Created"},
53 { 250, "Low on Storage Space"},
54 { 299, "Success - Others"},
55
56 { 300, "Multiple Choices"},
57 { 301, "Moved Permanently"},
58 { 302, "Moved Temporarily"},
59 { 303, "See Other"},
60 { 305, "Use Proxy"},
61 { 399, "Redirection - Others"},
62
63 { 400, "Bad Request"},
64 { 401, "Unauthorized"},
65 { 402, "Payment Required"},
66 { 403, "Forbidden"},
67 { 404, "Not Found"},
68 { 405, "Method Not Allowed"},
69 { 406, "Not Acceptable"},
70 { 407, "Proxy Authentication Required"},
71 { 408, "Request Timeout"},
72 { 410, "Gone"},
73 { 411, "Length Required"},
74 { 412, "Precondition Failed"},
75 { 413, "Request Entity Too Large"},
76 { 414, "Request-URI Too Long"},
77 { 415, "Unsupported Media Type"},
78 { 451, "Invalid Parameter"},
79 { 452, "Illegal Conference Identifier"},
80 { 453, "Not Enough Bandwidth"},
81 { 454, "Session Not Found"},
82 { 455, "Method Not Valid In This State"},
83 { 456, "Header Field Not Valid"},
84 { 457, "Invalid Range"},
85 { 458, "Parameter Is Read-Only"},
86 { 459, "Aggregate Operation Not Allowed"},
87 { 460, "Only Aggregate Operation Allowed"},
88 { 461, "Unsupported Transport"},
89 { 462, "Destination Unreachable"},
90 { 499, "Client Error - Others"},
91
92 { 500, "Internal Server Error"},
93 { 501, "Not Implemented"},
94 { 502, "Bad Gateway"},
95 { 503, "Service Unavailable"},
96 { 504, "Gateway Timeout"},
97 { 505, "RTSP Version not supported"},
98 { 551, "Option Not Support"},
99 { 599, "Server Error - Others"},
100
101 { 0, NULL}
102 };
103
104 static int proto_rtsp = -1;
105
106 static gint ett_rtsp = -1;
107 static gint ett_rtspframe = -1;
108 static gint ett_rtsp_method = -1;
109
110 static int hf_rtsp_request = -1;
111 static int hf_rtsp_response = -1;
112 static int hf_rtsp_content_type = -1;
113 static int hf_rtsp_content_length = -1;
114 static int hf_rtsp_method = -1;
115 static int hf_rtsp_url = -1;
116 static int hf_rtsp_status = -1;
117 static int hf_rtsp_session = -1;
118 static int hf_rtsp_transport = -1;
119 static int hf_rtsp_rdtfeaturelevel = -1;
120 static int hf_rtsp_X_Vig_Msisdn = -1;
121 static int hf_rtsp_magic = -1;
122 static int hf_rtsp_channel = -1;
123 static int hf_rtsp_length = -1;
124 static int hf_rtsp_data = -1;
125
126 static int voip_tap = -1;
127
128 static expert_field ei_rtsp_unknown_transport_type = EI_INIT;
129 static expert_field ei_rtsp_bad_server_port = EI_INIT;
130 static expert_field ei_rtsp_bad_client_port = EI_INIT;
131 static expert_field ei_rtsp_bad_interleaved_channel = EI_INIT;
132 static expert_field ei_rtsp_content_length_invalid = EI_INIT;
133 static expert_field ei_rtsp_rdtfeaturelevel_invalid = EI_INIT;
134 static expert_field ei_rtsp_bad_server_ip_address = EI_INIT;
135 static expert_field ei_rtsp_bad_client_ip_address = EI_INIT;
136
137 static dissector_handle_t rtsp_handle;
138 static dissector_handle_t rtp_handle;
139 static dissector_handle_t rtp_rfc4571_handle;
140 static dissector_handle_t rtcp_handle;
141 static dissector_handle_t rdt_handle;
142 static dissector_table_t media_type_dissector_table;
143 static heur_dissector_list_t heur_subdissector_list;
144
145 static const gchar *st_str_packets = "Total RTSP Packets";
146 static const gchar *st_str_requests = "RTSP Request Packets";
147 static const gchar *st_str_responses = "RTSP Response Packets";
148 static const gchar *st_str_resp_broken = "???: broken";
149 static const gchar *st_str_resp_100 = "1xx: Informational";
150 static const gchar *st_str_resp_200 = "2xx: Success";
151 static const gchar *st_str_resp_300 = "3xx: Redirection";
152 static const gchar *st_str_resp_400 = "4xx: Client Error";
153 static const gchar *st_str_resp_500 = "5xx: Server Error";
154 static const gchar *st_str_other = "Other RTSP Packets";
155
156 static int st_node_packets = -1;
157 static int st_node_requests = -1;
158 static int st_node_responses = -1;
159 static int st_node_resp_broken = -1;
160 static int st_node_resp_100 = -1;
161 static int st_node_resp_200 = -1;
162 static int st_node_resp_300 = -1;
163 static int st_node_resp_400 = -1;
164 static int st_node_resp_500 = -1;
165 static int st_node_other = -1;
166
167 static void
rtsp_stats_tree_init(stats_tree * st)168 rtsp_stats_tree_init(stats_tree* st)
169 {
170 st_node_packets = stats_tree_create_node(st, st_str_packets, 0, STAT_DT_INT, TRUE);
171 st_node_requests = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
172 st_node_responses = stats_tree_create_node(st, st_str_responses, st_node_packets, STAT_DT_INT, TRUE);
173 st_node_resp_broken = stats_tree_create_node(st, st_str_resp_broken, st_node_responses, STAT_DT_INT, TRUE);
174 st_node_resp_100 = stats_tree_create_node(st, st_str_resp_100, st_node_responses, STAT_DT_INT, TRUE);
175 st_node_resp_200 = stats_tree_create_node(st, st_str_resp_200, st_node_responses, STAT_DT_INT, TRUE);
176 st_node_resp_300 = stats_tree_create_node(st, st_str_resp_300, st_node_responses, STAT_DT_INT, TRUE);
177 st_node_resp_400 = stats_tree_create_node(st, st_str_resp_400, st_node_responses, STAT_DT_INT, TRUE);
178 st_node_resp_500 = stats_tree_create_node(st, st_str_resp_500, st_node_responses, STAT_DT_INT, TRUE);
179 st_node_other = stats_tree_create_node(st, st_str_other, st_node_packets, STAT_DT_INT, FALSE);
180 }
181
182 /* RTSP/Packet Counter stats packet function */
183 static tap_packet_status
rtsp_stats_tree_packet(stats_tree * st,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * p)184 rtsp_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p)
185 {
186 const rtsp_info_value_t *v = (const rtsp_info_value_t *)p;
187 guint i = v->response_code;
188 int resp_grp;
189 const gchar *resp_str;
190 static gchar str[64];
191
192 tick_stat_node(st, st_str_packets, 0, FALSE);
193
194 if (i) {
195 tick_stat_node(st, st_str_responses, st_node_packets, FALSE);
196
197 if ( (i<100)||(i>=600) ) {
198 resp_grp = st_node_resp_broken;
199 resp_str = st_str_resp_broken;
200 } else if (i<200) {
201 resp_grp = st_node_resp_100;
202 resp_str = st_str_resp_100;
203 } else if (i<300) {
204 resp_grp = st_node_resp_200;
205 resp_str = st_str_resp_200;
206 } else if (i<400) {
207 resp_grp = st_node_resp_300;
208 resp_str = st_str_resp_300;
209 } else if (i<500) {
210 resp_grp = st_node_resp_400;
211 resp_str = st_str_resp_400;
212 } else {
213 resp_grp = st_node_resp_500;
214 resp_str = st_str_resp_500;
215 }
216
217 tick_stat_node(st, resp_str, st_node_responses, FALSE);
218
219 g_snprintf(str, sizeof(str),"%u %s",i,val_to_str(i,rtsp_status_code_vals, "Unknown (%d)"));
220 tick_stat_node(st, str, resp_grp, FALSE);
221 } else if (v->request_method) {
222 stats_tree_tick_pivot(st,st_node_requests,v->request_method);
223 } else {
224 tick_stat_node(st, st_str_other, st_node_packets, FALSE);
225 }
226
227 return TAP_PACKET_REDRAW;
228 }
229 void proto_reg_handoff_rtsp(void);
230
231 /*
232 * desegmentation of RTSP headers
233 * (when we are over TCP or another protocol providing the desegmentation API)
234 */
235 static gboolean rtsp_desegment_headers = TRUE;
236
237 /*
238 * desegmentation of RTSP bodies
239 * (when we are over TCP or another protocol providing the desegmentation API)
240 * TODO let the user filter on content-type the bodies he wants desegmented
241 */
242 static gboolean rtsp_desegment_body = TRUE;
243
244 /* http://www.iana.org/assignments/port-numbers lists two rtsp ports.
245 * In Addition RTSP uses display port over Wi-Fi Display: 7236.
246 */
247 #define RTSP_TCP_PORT_RANGE "554,8554,7236"
248
249 /*
250 * Takes an array of bytes, assumed to contain a null-terminated
251 * string, as an argument, and returns the length of the string -
252 * i.e., the size of the array, minus 1 for the null terminator.
253 */
254 #define STRLEN_CONST(str) (sizeof (str) - 1)
255
256 #define RTSP_FRAMEHDR ('$')
257
258 typedef struct {
259 dissector_handle_t dissector;
260 } rtsp_interleaved_t;
261
262 #define RTSP_MAX_INTERLEAVED (256)
263
264 /*
265 * Careful about dynamically allocating memory in this structure (say
266 * for dynamically increasing the size of the 'interleaved' array) -
267 * the containing structure is garbage collected and contained
268 * pointers will not be freed.
269 */
270 typedef struct {
271 rtsp_interleaved_t interleaved[RTSP_MAX_INTERLEAVED];
272 } rtsp_conversation_data_t;
273
274 static int
dissect_rtspinterleaved(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree)275 dissect_rtspinterleaved(tvbuff_t *tvb, int offset, packet_info *pinfo,
276 proto_tree *tree)
277 {
278 guint length_remaining;
279 proto_item *ti;
280 proto_tree *rtspframe_tree = NULL;
281 int orig_offset;
282 guint8 rf_chan; /* interleaved channel id */
283 guint16 rf_len; /* packet length */
284 tvbuff_t *next_tvb;
285 conversation_t *conv;
286 rtsp_conversation_data_t *data;
287 dissector_handle_t dissector;
288
289 /*
290 * This will throw an exception if we don't have any data left.
291 * That's what we want. (See "tcp_dissect_pdus()", which is
292 * similar.)
293 */
294 length_remaining = tvb_ensure_captured_length_remaining(tvb, offset);
295
296 /*
297 * Can we do reassembly?
298 */
299 if (rtsp_desegment_headers && pinfo->can_desegment) {
300 /*
301 * Yes - would an RTSP multiplexed header starting at
302 * this offset be split across segment boundaries?
303 */
304 if (length_remaining < 4) {
305 /*
306 * Yes. Tell the TCP dissector where the data for
307 * this message starts in the data it handed us and
308 * that we need "some more data." Don't tell it
309 * exactly how many bytes we need because if/when we
310 * ask for even more (after the header) that will
311 * break reassembly.
312 */
313 pinfo->desegment_offset = offset;
314 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
315 return -1;
316 }
317 }
318
319 /*
320 * Get the "$", channel, and length from the header.
321 */
322 orig_offset = offset;
323 rf_chan = tvb_get_guint8(tvb, offset+1);
324 rf_len = tvb_get_ntohs(tvb, offset+2);
325
326 /*
327 * Can we do reassembly?
328 */
329 if (rtsp_desegment_body && pinfo->can_desegment) {
330 /*
331 * Yes - is the header + encapsulated packet split
332 * across segment boundaries?
333 */
334 if (length_remaining < 4U + rf_len) {
335 /*
336 * Yes. Tell the TCP dissector where the data
337 * for this message starts in the data it handed
338 * us, and how many more bytes we need, and return.
339 */
340 pinfo->desegment_offset = offset;
341 pinfo->desegment_len = 4U + rf_len - length_remaining;
342 return -1;
343 }
344 }
345
346 col_add_fstr(pinfo->cinfo, COL_INFO,
347 "Interleaved channel 0x%02x, %u bytes",
348 rf_chan, rf_len);
349
350 ti = proto_tree_add_protocol_format(tree, proto_rtsp, tvb,
351 offset, 4,
352 "RTSP Interleaved Frame, Channel: 0x%02x, %u bytes",
353 rf_chan, rf_len);
354 rtspframe_tree = proto_item_add_subtree(ti, ett_rtspframe);
355
356 proto_tree_add_item(rtspframe_tree, hf_rtsp_magic, tvb, offset, 1, ENC_BIG_ENDIAN);
357
358 offset += 1;
359
360 proto_tree_add_item(rtspframe_tree, hf_rtsp_channel, tvb, offset, 1, ENC_BIG_ENDIAN);
361
362 offset += 1;
363
364 proto_tree_add_item(rtspframe_tree, hf_rtsp_length, tvb, offset, 2, ENC_BIG_ENDIAN);
365 offset += 2;
366
367 /*
368 * We set the actual length of the tvbuff for the interleaved
369 * stuff to the minimum of what's left in the tvbuff and the
370 * length in the header.
371 *
372 * XXX - what if there's nothing left in the tvbuff?
373 * We'd want a BoundsError exception to be thrown, so
374 * that a Short Frame would be reported.
375 */
376 if (length_remaining > rf_len)
377 length_remaining = rf_len;
378 next_tvb = tvb_new_subset_length_caplen(tvb, offset, length_remaining, rf_len);
379
380 conv = find_conversation_pinfo(pinfo, 0);
381
382 if (conv &&
383 (data = (rtsp_conversation_data_t *)conversation_get_proto_data(conv, proto_rtsp)) &&
384 /* Add the following condition if it is not always true.
385 rf_chan < RTSP_MAX_INTERLEAVED &&
386 */
387 (dissector = data->interleaved[rf_chan].dissector)) {
388 call_dissector(dissector, next_tvb, pinfo, tree);
389 } else {
390 gboolean dissected = FALSE;
391 heur_dtbl_entry_t *hdtbl_entry = NULL;
392
393 dissected = dissector_try_heuristic(heur_subdissector_list,
394 next_tvb, pinfo, tree, &hdtbl_entry, NULL);
395
396 if (!dissected) {
397 proto_tree_add_item(rtspframe_tree, hf_rtsp_data, tvb, offset, rf_len, ENC_NA);
398 }
399 }
400
401 offset += rf_len;
402
403 return offset - orig_offset;
404 }
405
406 static void process_rtsp_request(tvbuff_t *tvb, int offset, const guchar *data,
407 size_t linelen, size_t next_line_offset,
408 proto_tree *tree);
409
410 static void process_rtsp_reply(tvbuff_t *tvb, int offset, const guchar *data,
411 size_t linelen, size_t next_line_offset,
412 proto_tree *tree);
413
414 typedef enum {
415 RTSP_REQUEST,
416 RTSP_REPLY,
417 RTSP_NOT_FIRST_LINE
418 } rtsp_type_t;
419
420 static const char *rtsp_methods[] = {
421 "DESCRIBE",
422 "ANNOUNCE",
423 "GET_PARAMETER",
424 "OPTIONS",
425 "PAUSE",
426 "PLAY",
427 "RECORD",
428 "REDIRECT",
429 "SETUP",
430 "SET_PARAMETER",
431 "TEARDOWN"
432 };
433
434 #define RTSP_NMETHODS array_length(rtsp_methods)
435
436 static gboolean
is_rtsp_request_or_reply(const guchar * line,size_t linelen,rtsp_type_t * type)437 is_rtsp_request_or_reply(const guchar *line, size_t linelen, rtsp_type_t *type)
438 {
439 guint ii;
440 const guchar *token, *next_token;
441 int tokenlen;
442 gchar response_chars[4];
443
444 /* Is this an RTSP reply? */
445 if (linelen >= 5 && g_ascii_strncasecmp("RTSP/", line, 5) == 0) {
446 /*
447 * Yes.
448 */
449 *type = RTSP_REPLY;
450 /* The first token is the version. */
451 tokenlen = get_token_len(line, line+linelen, &token);
452 if (tokenlen != 0) {
453 /* The next token is the status code. */
454 tokenlen = get_token_len(token, line+linelen, &next_token);
455 if (tokenlen >= 3) {
456 memcpy(response_chars, token, 3);
457 response_chars[3] = '\0';
458 ws_strtou32(response_chars, NULL, &rtsp_stat_info->response_code);
459 }
460 }
461 return TRUE;
462 }
463
464 /*
465 * Is this an RTSP request?
466 * Check whether the line begins with one of the RTSP request
467 * methods.
468 */
469 for (ii = 0; ii < RTSP_NMETHODS; ii++) {
470 size_t len = strlen(rtsp_methods[ii]);
471 if (linelen >= len &&
472 g_ascii_strncasecmp(rtsp_methods[ii], line, len) == 0 &&
473 (len == linelen || g_ascii_isspace(line[len])))
474 {
475 *type = RTSP_REQUEST;
476 rtsp_stat_info->request_method =
477 wmem_strndup(wmem_packet_scope(), rtsp_methods[ii], len+1);
478 return TRUE;
479 }
480 }
481
482 /* Wasn't a request or a response */
483 *type = RTSP_NOT_FIRST_LINE;
484 return FALSE;
485 }
486
487 static const char rtsp_content_type[] = "Content-Type:";
488 static const char rtsp_transport[] = "Transport:";
489 static const char rtsp_sps_server_port[] = "server_port=";
490 static const char rtsp_cps_server_port[] = "client_port=";
491 static const char rtsp_sps_dest_addr[] = "dest_addr=";
492 static const char rtsp_cps_src_addr[] = "src_addr=";
493 static const char rtsp_rtp_udp_default[] = "rtp/avp";
494 static const char rtsp_rtp_udp[] = "rtp/avp/udp";
495 static const char rtsp_rtp_tcp[] = "rtp/avp/tcp";
496 static const char rtsp_rdt_feature_level[] = "RDTFeatureLevel";
497 static const char rtsp_real_rdt[] = "x-real-rdt/";
498 static const char rtsp_real_tng[] = "x-pn-tng/"; /* synonym for x-real-rdt */
499 static const char rtsp_inter[] = "interleaved=";
500
501 static void
rtsp_create_conversation(packet_info * pinfo,proto_item * ti,const guchar * line_begin,size_t line_len,gint rdt_feature_level,rtsp_type_t rtsp_type_packet)502 rtsp_create_conversation(packet_info *pinfo, proto_item *ti,
503 const guchar *line_begin, size_t line_len,
504 gint rdt_feature_level,
505 rtsp_type_t rtsp_type_packet)
506 {
507 conversation_t *conv;
508 gchar buf[256];
509 gchar *tmp;
510 gboolean rtp_udp_transport = FALSE;
511 gboolean rtp_tcp_transport = FALSE;
512 gboolean rdt_transport = FALSE;
513 guint c_data_port, c_mon_port;
514 guint s_data_port, s_mon_port;
515 guint ipv4_1, ipv4_2, ipv4_3, ipv4_4;
516 gboolean is_video = FALSE; /* FIX ME - need to indicate video or not */
517 address src_addr;
518 address dst_addr;
519 guint32 ip4_addr;
520
521 if (rtsp_type_packet != RTSP_REPLY) {
522 return;
523 }
524
525 src_addr=pinfo->src;
526 dst_addr=pinfo->dst;
527
528 /* Copy line into buf */
529 if (line_len > sizeof(buf) - 1)
530 {
531 /* Don't overflow the buffer. */
532 line_len = sizeof(buf) - 1;
533 }
534 memcpy(buf, line_begin, line_len);
535 buf[line_len] = '\0';
536
537 /* Get past "Transport:" and spaces */
538 tmp = buf + STRLEN_CONST(rtsp_transport);
539 while (*tmp && g_ascii_isspace(*tmp))
540 tmp++;
541
542 /* Work out which transport type is here */
543 if (g_ascii_strncasecmp(tmp, rtsp_rtp_udp, strlen(rtsp_rtp_udp)) == 0)
544 {
545 rtp_udp_transport = TRUE;
546 }
547 else if (g_ascii_strncasecmp(tmp, rtsp_rtp_tcp, strlen(rtsp_rtp_tcp)) == 0)
548 {
549 rtp_tcp_transport = TRUE;
550 }
551 else if (g_ascii_strncasecmp(tmp, rtsp_rtp_udp_default, strlen(rtsp_rtp_udp_default)) == 0)
552 {
553 rtp_udp_transport = TRUE;
554 }
555 else if (g_ascii_strncasecmp(tmp, rtsp_real_rdt, strlen(rtsp_real_rdt)) == 0 ||
556 g_ascii_strncasecmp(tmp, rtsp_real_tng, strlen(rtsp_real_tng)) == 0)
557 {
558 rdt_transport = TRUE;
559 }
560 else
561 {
562 /* Give up on unknown transport types */
563 expert_add_info(pinfo, ti, &ei_rtsp_unknown_transport_type);
564 return;
565 }
566
567 c_data_port = c_mon_port = 0;
568 s_data_port = s_mon_port = 0;
569
570 /* Look for server port */
571 if ((tmp = strstr(buf, rtsp_sps_server_port))) {
572 tmp += strlen(rtsp_sps_server_port);
573 if (sscanf(tmp, "%u-%u", &s_data_port, &s_mon_port) < 1) {
574 expert_add_info(pinfo, ti, &ei_rtsp_bad_server_port);
575 return;
576 }
577 }
578 else if ((tmp = strstr(buf, rtsp_sps_dest_addr))) {
579 tmp += strlen(rtsp_sps_dest_addr);
580 if (sscanf(tmp, "\":%u\"", &s_data_port) == 1) {
581 /* :9 mean ignore */
582 if (s_data_port == 9) {
583 s_data_port = 0;
584 }
585 }
586 else if (sscanf(tmp, "\"%u.%u.%u.%u:%u\"", &ipv4_1, &ipv4_2, &ipv4_3, &ipv4_4, &s_data_port) == 5) {
587 gchar *tmp2;
588 gchar *tmp3;
589
590 /* Skip leading " */
591 tmp++;
592 tmp2=strstr(tmp,":");
593 tmp3=g_strndup(tmp,tmp2-tmp);
594 if (!str_to_ip(tmp3, &ip4_addr)) {
595 g_free(tmp3);
596 expert_add_info(pinfo, ti, &ei_rtsp_bad_server_ip_address);
597 return;
598 }
599 set_address(&dst_addr, AT_IPv4, 4, &ip4_addr);
600 g_free(tmp3);
601 }
602 else if (sscanf(tmp, "\"%u.%u.%u.%u\"", &ipv4_1, &ipv4_2, &ipv4_3, &ipv4_4) == 4) {
603 gchar *tmp2;
604 gchar *tmp3;
605
606 /* Skip leading " */
607 tmp++;
608 tmp2=strstr(tmp,"\"");
609 tmp3=g_strndup(tmp,tmp2-tmp);
610 if (!str_to_ip(tmp3, &ip4_addr)) {
611 g_free(tmp3);
612 expert_add_info(pinfo, ti, &ei_rtsp_bad_server_ip_address);
613 return;
614 }
615 set_address(&dst_addr, AT_IPv4, 4, &ip4_addr);
616 g_free(tmp3);
617 }
618 else
619 {
620 expert_add_info(pinfo, ti, &ei_rtsp_bad_server_port);
621 return;
622 }
623 }
624
625
626 /* Look for client port */
627 if ((tmp = strstr(buf, rtsp_cps_server_port))) {
628 tmp += strlen(rtsp_cps_server_port);
629 if (sscanf(tmp, "%u-%u", &c_data_port, &c_mon_port) < 1) {
630 expert_add_info(pinfo, ti, &ei_rtsp_bad_client_port);
631 return;
632 }
633 }
634 else if ((tmp = strstr(buf, rtsp_cps_src_addr))) {
635 tmp += strlen(rtsp_cps_src_addr);
636 if (sscanf(tmp, "\"%u.%u.%u.%u:%u\"", &ipv4_1, &ipv4_2, &ipv4_3, &ipv4_4, &c_data_port) == 5) {
637 gchar *tmp2;
638 gchar *tmp3;
639
640 /* Skip leading " */
641 tmp++;
642 tmp2=strstr(tmp,":");
643 tmp3=g_strndup(tmp,tmp2-tmp);
644 if (!str_to_ip(tmp3, &ip4_addr)) {
645 g_free(tmp3);
646 expert_add_info(pinfo, ti, &ei_rtsp_bad_client_ip_address);
647 return;
648 }
649 set_address(&src_addr, AT_IPv4, 4, &ip4_addr);
650 g_free(tmp3);
651 }
652 }
653
654 /* Deal with RTSP TCP-interleaved conversations. */
655 tmp = strstr(buf, rtsp_inter);
656 if (tmp != NULL) {
657 rtsp_conversation_data_t *data;
658 guint s_data_chan, s_mon_chan;
659 int i;
660
661 /* Move tmp to beyond interleaved string */
662 tmp += strlen(rtsp_inter);
663 /* Look for channel number(s) */
664 i = sscanf(tmp, "%u-%u", &s_data_chan, &s_mon_chan);
665 if (i < 1)
666 {
667 expert_add_info(pinfo, ti, &ei_rtsp_bad_interleaved_channel);
668 return;
669 }
670
671 /* At least data channel present, look for conversation (presumably TCP) */
672 conv = find_or_create_conversation(pinfo);
673
674 /* Look for previous data */
675 data = (rtsp_conversation_data_t *)conversation_get_proto_data(conv, proto_rtsp);
676
677 /* Create new data if necessary */
678 if (!data)
679 {
680 data = wmem_new0(wmem_file_scope(), rtsp_conversation_data_t);
681 conversation_add_proto_data(conv, proto_rtsp, data);
682 }
683
684 /* Now set the dissector handle of the interleaved channel
685 according to the transport protocol used */
686 if (rtp_tcp_transport)
687 {
688 if (s_data_chan < RTSP_MAX_INTERLEAVED) {
689 data->interleaved[s_data_chan].dissector =
690 rtp_handle;
691 }
692 if (i > 1 && s_mon_chan < RTSP_MAX_INTERLEAVED) {
693 data->interleaved[s_mon_chan].dissector =
694 rtcp_handle;
695 }
696 }
697 else if (rdt_transport)
698 {
699 if (s_data_chan < RTSP_MAX_INTERLEAVED) {
700 data->interleaved[s_data_chan].dissector =
701 rdt_handle;
702 }
703 }
704 return;
705 }
706 /* Noninterleaved options follow */
707 /*
708 * We only want to match on the destination address, not the
709 * source address, because the server might send back a packet
710 * from an address other than the address to which its client
711 * sent the packet, so we construct a conversation with no
712 * second address.
713 */
714 else if (rtp_udp_transport)
715 {
716 /* RTP only if indicated */
717 if (c_data_port)
718 {
719 rtp_add_address(pinfo, PT_UDP, &dst_addr, c_data_port, s_data_port,
720 "RTSP", pinfo->num, is_video, NULL);
721 }
722 else if (s_data_port)
723 {
724 rtp_add_address(pinfo, PT_UDP, &src_addr, s_data_port, 0,
725 "RTSP", pinfo->num, is_video, NULL);
726 }
727
728 /* RTCP only if indicated */
729 if (c_mon_port)
730 {
731 rtcp_add_address(pinfo, &pinfo->dst, c_mon_port, s_mon_port,
732 "RTSP", pinfo->num);
733 }
734 }
735 else if (rtp_tcp_transport)
736 {
737 /* RTP only if indicated */
738 rtp_add_address(pinfo, PT_TCP, &src_addr, c_data_port, s_data_port,
739 "RTSP", pinfo->num, is_video, NULL);
740 }
741 else if (rdt_transport)
742 {
743 /* Real Data Transport */
744 rdt_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port,
745 "RTSP", rdt_feature_level);
746 }
747 return;
748 }
749
750 static const char rtsp_content_length[] = "Content-Length:";
751
752 static int
rtsp_get_content_length(const guchar * line_begin,size_t line_len)753 rtsp_get_content_length(const guchar *line_begin, size_t line_len)
754 {
755 char buf[256];
756 char *tmp;
757 gint32 content_length;
758 const char *p;
759 const char *up;
760
761 if (line_len > sizeof(buf) - 1) {
762 /*
763 * Don't overflow the buffer.
764 */
765 line_len = sizeof(buf) - 1;
766 }
767 memcpy(buf, line_begin, line_len);
768 buf[line_len] = '\0';
769
770 tmp = buf + STRLEN_CONST(rtsp_content_length);
771 while (*tmp && g_ascii_isspace(*tmp))
772 tmp++;
773 ws_strtoi32(tmp, &p, &content_length);
774 up = p;
775 if (up == tmp || (*up != '\0' && !g_ascii_isspace(*up)))
776 return -1; /* not a valid number */
777 return content_length;
778 }
779
780 static const char rtsp_Session[] = "Session:";
781 static const char rtsp_X_Vig_Msisdn[] = "X-Vig-Msisdn";
782
783 static int
dissect_rtspmessage(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree)784 dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo,
785 proto_tree *tree)
786 {
787 proto_tree *rtsp_tree = NULL;
788 proto_tree *sub_tree = NULL;
789 proto_item *ti_top = NULL;
790 const guchar *line;
791 gint next_offset;
792 const guchar *linep, *lineend;
793 int orig_offset;
794 int first_linelen, linelen;
795 int line_end_offset;
796 int colon_offset;
797 gboolean is_request_or_reply;
798 gboolean body_requires_content_len;
799 gboolean saw_req_resp_or_header;
800 guchar c;
801 rtsp_type_t rtsp_type_packet;
802 rtsp_type_t rtsp_type_line;
803 gboolean is_header;
804 int datalen;
805 int content_length;
806 int reported_datalen;
807 int value_offset;
808 int value_len;
809 e164_info_t e164_info;
810 gint rdt_feature_level = 0;
811 gchar *media_type_str_lower_case = NULL;
812 int semi_colon_offset;
813 int par_end_offset;
814 gchar *frame_label = NULL;
815 gchar *session_id = NULL;
816 voip_packet_info_t *stat_info = NULL;
817
818 rtsp_stat_info = wmem_new(wmem_packet_scope(), rtsp_info_value_t);
819 rtsp_stat_info->framenum = pinfo->num;
820 rtsp_stat_info->response_code = 0;
821 rtsp_stat_info->request_method = NULL;
822 rtsp_stat_info->request_uri = NULL;
823 rtsp_stat_info->rtsp_host = NULL;
824
825 /*
826 * Is this a request or response?
827 *
828 * Note that "tvb_find_line_end()" will return a value that
829 * is not longer than what's in the buffer, so the
830 * "tvb_get_ptr()" call won't throw an exception.
831 */
832 first_linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
833
834 /*
835 * Is the first line a request or response?
836 */
837 line = tvb_get_ptr(tvb, offset, first_linelen);
838 is_request_or_reply = is_rtsp_request_or_reply(line, first_linelen,
839 &rtsp_type_packet);
840 if (is_request_or_reply) {
841 /*
842 * Yes, it's a request or response.
843 * Do header desegmentation if we've been told to,
844 * and do body desegmentation if we've been told to and
845 * we find a Content-Length header.
846 *
847 * RFC 7826, Section 18.17. requires Content-Length and
848 * assumes zero if missing.
849 */
850 if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
851 rtsp_desegment_headers, rtsp_desegment_body, FALSE)) {
852 /*
853 * More data needed for desegmentation.
854 */
855 return -1;
856 }
857 }
858
859 /*
860 * RFC 2326 says that a content length must be specified
861 * in requests that have a body, although section 4.4 speaks
862 * of a server closing the connection indicating the end of
863 * a reply body.
864 *
865 * To support pipelining, we check if line behind blank line
866 * looks like RTSP header. If so, we process rest of packet with
867 * RTSP loop.
868 *
869 * If no, we assume that an absent content length in a request means
870 * that we don't have a body, and that an absent content length
871 * in a reply means that the reply body runs to the end of
872 * the connection. If the first line is neither, we assume
873 * that whatever follows a blank line should be treated as a
874 * body; there's not much else we can do, as we're jumping
875 * into the message in the middle.
876 *
877 * XXX - if there was no Content-Length entity header, we should
878 * accumulate all data until the end of the connection.
879 * That'd require that the TCP dissector call subdissectors
880 * for all frames with FIN, even if they contain no data,
881 * which would require subdissectors to deal intelligently
882 * with empty segments.
883 */
884 if (rtsp_type_packet == RTSP_REQUEST)
885 body_requires_content_len = TRUE;
886 else
887 body_requires_content_len = FALSE;
888
889 line = tvb_get_ptr(tvb, offset, first_linelen);
890 if (is_request_or_reply) {
891 if ( rtsp_type_packet == RTSP_REPLY ) {
892 frame_label = wmem_strdup_printf(wmem_packet_scope(),
893 "Reply: %s", format_text(wmem_packet_scope(), line, first_linelen));
894 }
895 else {
896 frame_label = format_text(wmem_packet_scope(), line, first_linelen);
897 }
898 }
899
900 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTSP");
901 /*
902 * Put the first line from the buffer into the summary
903 * if it's an RTSP request or reply (but leave out the
904 * line terminator).
905 * Otherwise, just call it a continuation.
906 *
907 * Note that "tvb_find_line_end()" will return a value that
908 * is not longer than what's in the buffer, so the
909 * "tvb_get_ptr()" call won't throw an exception.
910 */
911 if (is_request_or_reply)
912 if ( rtsp_type_packet == RTSP_REPLY ) {
913 col_set_str(pinfo->cinfo, COL_INFO, "Reply: ");
914 col_append_str(pinfo->cinfo, COL_INFO,
915 format_text(wmem_packet_scope(), line, first_linelen));
916 }
917 else {
918 col_add_str(pinfo->cinfo, COL_INFO,
919 format_text(wmem_packet_scope(), line, first_linelen));
920 }
921
922 else
923 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
924
925 orig_offset = offset;
926 if (tree) {
927 ti_top = proto_tree_add_item(tree, proto_rtsp, tvb, offset, -1,
928 ENC_NA);
929 rtsp_tree = proto_item_add_subtree(ti_top, ett_rtsp);
930 }
931
932 /*
933 * We haven't yet seen a Content-Length header.
934 */
935 content_length = -1;
936
937 /*
938 * Process the packet data, a line at a time.
939 */
940 saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
941 while (tvb_offset_exists(tvb, offset)) {
942 /*
943 * We haven't yet concluded that this is a header.
944 */
945 is_header = FALSE;
946
947 /*
948 * Find the end of the line.
949 */
950 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
951 if (linelen < 0)
952 return -1;
953 line_end_offset = offset + linelen;
954 /*
955 * colon_offset may be -1
956 */
957 colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
958
959
960 /*
961 * Get a buffer that refers to the line.
962 */
963 line = tvb_get_ptr(tvb, offset, linelen);
964 lineend = line + linelen;
965
966 /*
967 * OK, does it look like an RTSP request or response?
968 */
969 is_request_or_reply = is_rtsp_request_or_reply(line, linelen, &rtsp_type_line);
970 if (is_request_or_reply)
971 goto is_rtsp;
972
973 /*
974 * No. Does it look like a blank line (as would appear
975 * at the end of an RTSP request)?
976 */
977 if (linelen == 0)
978 goto is_rtsp; /* Yes. */
979
980 /*
981 * No. Does it look like a header?
982 */
983 linep = line;
984 while (linep < lineend) {
985 c = *linep++;
986
987 /*
988 * This must be a CHAR, and must not be a CTL, to be part
989 * of a token; that means it must be printable ASCII.
990 *
991 * XXX - what about leading LWS on continuation
992 * lines of a header?
993 */
994 if (!g_ascii_isprint(c))
995 break;
996
997 switch (c) {
998
999 case '(':
1000 case ')':
1001 case '<':
1002 case '>':
1003 case '@':
1004 case ',':
1005 case ';':
1006 case '\\':
1007 case '"':
1008 case '/':
1009 case '[':
1010 case ']':
1011 case '?':
1012 case '=':
1013 case '{':
1014 case '}':
1015 /*
1016 * It's a tspecial, so it's not
1017 * part of a token, so it's not
1018 * a field name for the beginning
1019 * of a header.
1020 */
1021 goto not_rtsp;
1022
1023 case ':':
1024 /*
1025 * This ends the token; we consider
1026 * this to be a header.
1027 */
1028 is_header = TRUE;
1029 goto is_rtsp;
1030
1031 case ' ':
1032 case '\t':
1033 /*
1034 * LWS (RFC-2616, 4.2); continue the previous
1035 * header.
1036 */
1037 goto is_rtsp;
1038 }
1039 }
1040
1041 /*
1042 * We haven't seen the colon, but everything else looks
1043 * OK for a header line.
1044 *
1045 * If we've already seen an RTSP request or response
1046 * line, or a header line, and we're at the end of
1047 * the tvbuff, we assume this is an incomplete header
1048 * line. (We quit this loop after seeing a blank line,
1049 * so if we've seen a request or response line, or a
1050 * header line, this is probably more of the request
1051 * or response we're presumably seeing. There is some
1052 * risk of false positives, but the same applies for
1053 * full request or response lines or header lines,
1054 * although that's less likely.)
1055 *
1056 * We throw an exception in that case, by checking for
1057 * the existence of the next byte after the last one
1058 * in the line. If it exists, "tvb_ensure_bytes_exist()"
1059 * throws no exception, and we fall through to the
1060 * "not RTSP" case. If it doesn't exist,
1061 * "tvb_ensure_bytes_exist()" will throw the appropriate
1062 * exception.
1063 */
1064 if (saw_req_resp_or_header)
1065 tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
1066
1067 not_rtsp:
1068 /*
1069 * We don't consider this part of an RTSP request or
1070 * reply, so we don't display it.
1071 */
1072 break;
1073
1074 is_rtsp:
1075 /*
1076 * Process this line.
1077 */
1078 if (linelen == 0) {
1079 /*
1080 * This is a blank line, which means that
1081 * whatever follows it isn't part of this
1082 * request or reply.
1083 */
1084 proto_tree_add_format_text(rtsp_tree, tvb, offset, next_offset - offset);
1085 offset = next_offset;
1086 break;
1087 }
1088
1089 /*
1090 * Not a blank line - either a request, a reply, or a header
1091 * line.
1092 */
1093 saw_req_resp_or_header = TRUE;
1094 if (rtsp_tree) {
1095
1096 switch (rtsp_type_line)
1097 {
1098 case RTSP_REQUEST:
1099 process_rtsp_request(tvb, offset, line, linelen, next_offset, rtsp_tree);
1100 break;
1101
1102 case RTSP_REPLY:
1103 process_rtsp_reply(tvb, offset, line, linelen, next_offset, rtsp_tree);
1104 break;
1105
1106 case RTSP_NOT_FIRST_LINE:
1107 /* Drop through, it may well be a header line */
1108 break;
1109 }
1110 }
1111
1112 if (is_header)
1113 {
1114 /* We know that colon_offset must be set */
1115
1116 /* Skip whitespace after the colon. */
1117 value_offset = colon_offset + 1;
1118 while ((value_offset < line_end_offset) &&
1119 ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t'))
1120 {
1121 value_offset++;
1122 }
1123 value_len = line_end_offset - value_offset;
1124
1125 /*
1126 * Process some headers specially.
1127 */
1128 #define HDR_MATCHES(header) \
1129 ( (size_t)linelen > STRLEN_CONST(header) && \
1130 g_ascii_strncasecmp(line, (header), STRLEN_CONST(header)) == 0)
1131
1132 if (HDR_MATCHES(rtsp_transport))
1133 {
1134 proto_item *ti;
1135 ti = proto_tree_add_string(rtsp_tree, hf_rtsp_transport, tvb,
1136 offset, linelen,
1137 tvb_format_text(pinfo->pool, tvb, value_offset,
1138 value_len));
1139
1140 /*
1141 * Based on the port numbers specified
1142 * in the Transport: header, set up
1143 * a conversation that will be dissected
1144 * with the appropriate dissector.
1145 */
1146 rtsp_create_conversation(pinfo, ti, line, linelen, rdt_feature_level, rtsp_type_packet);
1147 } else if (HDR_MATCHES(rtsp_content_type))
1148 {
1149 proto_tree_add_string(rtsp_tree, hf_rtsp_content_type,
1150 tvb, offset, linelen,
1151 tvb_format_text(pinfo->pool, tvb, value_offset,
1152 value_len));
1153
1154 offset = offset + (int)STRLEN_CONST(rtsp_content_type);
1155 /* Skip wsp */
1156 offset = tvb_skip_wsp(tvb, offset, value_len);
1157 semi_colon_offset = tvb_find_guint8(tvb, value_offset, value_len, ';');
1158 if ( semi_colon_offset != -1) {
1159 /* m-parameter present */
1160 par_end_offset = tvb_skip_wsp_return(tvb, semi_colon_offset-1);
1161 value_len = par_end_offset - offset;
1162 }
1163
1164 media_type_str_lower_case = ascii_strdown_inplace(
1165 (gchar *)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, value_len, ENC_ASCII));
1166
1167 } else if (HDR_MATCHES(rtsp_content_length))
1168 {
1169 guint32 clength;
1170 gboolean clength_valid;
1171 proto_item* pi;
1172 clength_valid = ws_strtou32(tvb_format_text(pinfo->pool, tvb, value_offset, value_len),
1173 NULL, &clength);
1174 pi = proto_tree_add_uint(rtsp_tree, hf_rtsp_content_length,
1175 tvb, offset, linelen, clength);
1176 if (!clength_valid)
1177 expert_add_info(pinfo, pi, &ei_rtsp_content_length_invalid);
1178
1179 /*
1180 * Only the amount specified by the
1181 * Content-Length: header should be treated
1182 * as payload.
1183 */
1184 content_length = rtsp_get_content_length(line, linelen);
1185
1186 } else if (HDR_MATCHES(rtsp_Session))
1187 {
1188 session_id = tvb_format_text(pinfo->pool, tvb, value_offset, value_len);
1189 /* Put the value into the protocol tree */
1190 proto_tree_add_string(rtsp_tree, hf_rtsp_session, tvb,
1191 offset, linelen,
1192 session_id);
1193
1194 } else if (HDR_MATCHES(rtsp_X_Vig_Msisdn)) {
1195 /*
1196 * Extract the X_Vig_Msisdn string
1197 */
1198 if (colon_offset != -1)
1199 {
1200 proto_item *ti;
1201 /* Put the value into the protocol tree */
1202 ti = proto_tree_add_string(rtsp_tree, hf_rtsp_X_Vig_Msisdn,tvb,
1203 offset, linelen ,
1204 tvb_format_text(pinfo->pool, tvb, value_offset, value_len));
1205 sub_tree = proto_item_add_subtree(ti, ett_rtsp_method);
1206
1207 e164_info.e164_number_type = CALLING_PARTY_NUMBER;
1208 e164_info.nature_of_address = 0;
1209
1210 e164_info.E164_number_str = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset,
1211 value_len, ENC_ASCII);
1212 e164_info.E164_number_length = value_len;
1213 dissect_e164_number(tvb, sub_tree, value_offset,
1214 value_len, e164_info);
1215 }
1216 } else if (HDR_MATCHES(rtsp_rdt_feature_level))
1217 {
1218 gboolean rdt_feature_level_valid;
1219 proto_item* pi;
1220 rdt_feature_level_valid = ws_strtou32(tvb_format_text(pinfo->pool, tvb, value_offset, value_len),
1221 NULL, &rdt_feature_level);
1222 pi = proto_tree_add_uint(rtsp_tree, hf_rtsp_rdtfeaturelevel,
1223 tvb, offset, linelen, rdt_feature_level);
1224 if (!rdt_feature_level_valid)
1225 expert_add_info(pinfo, pi, &ei_rtsp_rdtfeaturelevel_invalid);
1226 }
1227 else
1228 {
1229 /* Default case for headers. Show line as text */
1230 proto_tree_add_format_text(rtsp_tree, tvb, offset, next_offset - offset);
1231 }
1232 }
1233 else if (rtsp_type_line == RTSP_NOT_FIRST_LINE)
1234 {
1235 /* Catch-all for all other lines... Show line as text.
1236 TODO: should these be shown as errors? */
1237 proto_tree_add_format_text(rtsp_tree, tvb, offset, next_offset - offset);
1238 }
1239
1240 offset = next_offset;
1241 }
1242
1243 if (session_id) {
1244 stat_info = wmem_new0(wmem_packet_scope(), voip_packet_info_t);
1245 stat_info->protocol_name = wmem_strdup(wmem_packet_scope(), "RTSP");
1246 stat_info->call_id = session_id;
1247 stat_info->frame_label = frame_label;
1248 stat_info->call_state = VOIP_CALL_SETUP;
1249 stat_info->call_active_state = VOIP_ACTIVE;
1250 stat_info->frame_comment = frame_label;
1251 tap_queue_packet(voip_tap, pinfo, stat_info);
1252 }
1253
1254 /*
1255 * Have now read all of the lines of this message.
1256 *
1257 * If a content length was supplied, the amount of data to be
1258 * processed as RTSP payload is the minimum of the content
1259 * length and the amount of data remaining in the frame.
1260 *
1261 * If no content length was supplied (or if a bad content length
1262 * was supplied), the amount of data to be processed is the amount
1263 * of data remaining in the frame.
1264 */
1265 datalen = tvb_captured_length_remaining(tvb, offset);
1266 reported_datalen = tvb_reported_length_remaining(tvb, offset);
1267 if (content_length != -1) {
1268 /*
1269 * Content length specified; display only that amount
1270 * as payload.
1271 */
1272 if (datalen > content_length)
1273 datalen = content_length;
1274
1275 /*
1276 * XXX - limit the reported length in the tvbuff we'll
1277 * hand to a subdissector to be no greater than the
1278 * content length.
1279 *
1280 * We really need both unreassembled and "how long it'd
1281 * be if it were reassembled" lengths for tvbuffs, so
1282 * that we throw the appropriate exceptions for
1283 * "not enough data captured" (running past the length),
1284 * "packet needed reassembly" (within the length but
1285 * running past the unreassembled length), and
1286 * "packet is malformed" (running past the reassembled
1287 * length).
1288 */
1289 if (reported_datalen > content_length)
1290 reported_datalen = content_length;
1291 } else {
1292 /*
1293 * No content length specified; if this message doesn't
1294 * have a body if no content length is specified, process
1295 * nothing as payload.
1296 */
1297 if (body_requires_content_len)
1298 datalen = 0;
1299 }
1300
1301 if (datalen > 0) {
1302 /*
1303 * There's stuff left over; process it.
1304 */
1305 tvbuff_t *new_tvb;
1306
1307 /*
1308 * Now create a tvbuff for the Content-type stuff and
1309 * dissect it.
1310 *
1311 * The amount of data to be processed that's
1312 * available in the tvbuff is "datalen", which
1313 * is the minimum of the amount of data left in
1314 * the tvbuff and any specified content length.
1315 *
1316 * The amount of data to be processed that's in
1317 * this frame, regardless of whether it was
1318 * captured or not, is "reported_datalen",
1319 * which, if no content length was specified,
1320 * is -1, i.e. "to the end of the frame.
1321 */
1322 new_tvb = tvb_new_subset_length_caplen(tvb, offset, datalen,
1323 reported_datalen);
1324
1325 /*
1326 * Check if next line is RTSP message - pipelining
1327 * If yes, stop processing and start next loop
1328 * If no, process rest of packet with dissectors
1329 */
1330 first_linelen = tvb_find_line_end(new_tvb, 0, -1, &next_offset, FALSE);
1331 line = tvb_get_ptr(new_tvb, 0, first_linelen);
1332 is_request_or_reply = is_rtsp_request_or_reply(line, first_linelen,
1333 &rtsp_type_packet);
1334
1335 if (!is_request_or_reply){
1336 if (media_type_str_lower_case &&
1337 dissector_try_string(media_type_dissector_table,
1338 media_type_str_lower_case,
1339 new_tvb, pinfo, rtsp_tree, NULL)){
1340
1341 } else {
1342 /*
1343 * Fix up the top-level item so that it doesn't
1344 * include the SDP stuff.
1345 */
1346 if (ti_top != NULL)
1347 proto_item_set_len(ti_top, offset);
1348
1349 if (tvb_get_guint8(tvb, offset) == RTSP_FRAMEHDR) {
1350 /*
1351 * This is interleaved stuff; don't
1352 * treat it as raw data - set "datalen"
1353 * to 0, so we won't skip the offset
1354 * past it, which will cause our
1355 * caller to process that stuff itself.
1356 */
1357 datalen = 0;
1358 } else {
1359 proto_tree_add_bytes_format(rtsp_tree, hf_rtsp_data, tvb, offset,
1360 datalen, NULL, "Data (%d bytes)",
1361 reported_datalen);
1362 }
1363 }
1364
1365 /*
1366 * We've processed "datalen" bytes worth of data
1367 * (which may be no data at all); advance the
1368 * offset past whatever data we've processed.
1369 */
1370 offset += datalen;
1371 }
1372 }
1373
1374 tap_queue_packet(rtsp_tap, pinfo, rtsp_stat_info);
1375
1376 return offset - orig_offset;
1377 }
1378
1379 static void
process_rtsp_request(tvbuff_t * tvb,int offset,const guchar * data,size_t linelen,size_t next_line_offset,proto_tree * tree)1380 process_rtsp_request(tvbuff_t *tvb, int offset, const guchar *data,
1381 size_t linelen, size_t next_line_offset, proto_tree *tree)
1382 {
1383 proto_tree *sub_tree;
1384 proto_item *ti;
1385 const guchar *lineend = data + linelen;
1386 guint ii;
1387 const guchar *url;
1388 const guchar *url_start;
1389 guchar *tmp_url;
1390
1391 /* Request Methods */
1392 for (ii = 0; ii < RTSP_NMETHODS; ii++) {
1393 size_t len = strlen(rtsp_methods[ii]);
1394 if (linelen >= len &&
1395 g_ascii_strncasecmp(rtsp_methods[ii], data, len) == 0 &&
1396 (len == linelen || g_ascii_isspace(data[len])))
1397 break;
1398 }
1399 if (ii == RTSP_NMETHODS) {
1400 /*
1401 * We got here because "is_rtsp_request_or_reply()" returned
1402 * RTSP_REQUEST, so we know one of the request methods
1403 * matched, so we "can't get here".
1404 */
1405 DISSECTOR_ASSERT_NOT_REACHED();
1406 }
1407
1408 /* Add a tree for this request */
1409 ti = proto_tree_add_string(tree, hf_rtsp_request, tvb, offset,
1410 (gint) (next_line_offset - offset),
1411 tvb_format_text(wmem_packet_scope(), tvb, offset, (gint) (next_line_offset - offset)));
1412 sub_tree = proto_item_add_subtree(ti, ett_rtsp_method);
1413
1414
1415 /* Add method name to tree */
1416 proto_tree_add_string(sub_tree, hf_rtsp_method, tvb, offset,
1417 (gint) strlen(rtsp_methods[ii]), rtsp_methods[ii]);
1418
1419 /* URL */
1420 url = data;
1421 /* Skip method name again */
1422 while (url < lineend && !g_ascii_isspace(*url))
1423 url++;
1424 /* Skip spaces */
1425 while (url < lineend && g_ascii_isspace(*url))
1426 url++;
1427 /* URL starts here */
1428 url_start = url;
1429 /* Scan to end of URL */
1430 while (url < lineend && !g_ascii_isspace(*url))
1431 url++;
1432 /* Create a URL-sized buffer and copy contents */
1433 tmp_url = wmem_strndup(wmem_packet_scope(), url_start, url - url_start);
1434
1435 /* Add URL to tree */
1436 proto_tree_add_string(sub_tree, hf_rtsp_url, tvb,
1437 offset + (gint) (url_start - data), (gint) (url - url_start), tmp_url);
1438 }
1439
1440 /* Read first line of a reply message */
1441 static void
process_rtsp_reply(tvbuff_t * tvb,int offset,const guchar * data,size_t linelen,size_t next_line_offset,proto_tree * tree)1442 process_rtsp_reply(tvbuff_t *tvb, int offset, const guchar *data,
1443 size_t linelen, size_t next_line_offset, proto_tree *tree)
1444 {
1445 proto_tree *sub_tree;
1446 proto_item *ti;
1447 const guchar *lineend = data + linelen;
1448 const guchar *status = data;
1449 const guchar *status_start;
1450 guint status_i;
1451
1452 /* Add a tree for this request */
1453 ti = proto_tree_add_string(tree, hf_rtsp_response, tvb, offset,
1454 (gint) (next_line_offset - offset),
1455 tvb_format_text(wmem_packet_scope(), tvb, offset, (gint) (next_line_offset - offset)));
1456 sub_tree = proto_item_add_subtree(ti, ett_rtsp_method);
1457
1458
1459 /* status code */
1460
1461 /* Skip protocol/version */
1462 while (status < lineend && !g_ascii_isspace(*status))
1463 status++;
1464 /* Skip spaces */
1465 while (status < lineend && g_ascii_isspace(*status))
1466 status++;
1467
1468 /* Actual code number now */
1469 status_start = status;
1470 status_i = 0;
1471 while (status < lineend && g_ascii_isdigit(*status))
1472 status_i = status_i * 10 + *status++ - '0';
1473
1474 /* Add field to tree */
1475 proto_tree_add_uint(sub_tree, hf_rtsp_status, tvb,
1476 offset + (gint) (status_start - data),
1477 (gint) (status - status_start), status_i);
1478 }
1479
1480 static int
dissect_rtsp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1481 dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1482 {
1483 int offset = 0;
1484 int len;
1485
1486 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1487 /*
1488 * Add separator between multiple messages in column info text
1489 */
1490 if (offset > 0) {
1491 col_set_str(pinfo->cinfo, COL_INFO, ", ");
1492 col_set_fence(pinfo->cinfo, COL_INFO);
1493 }
1494 len = (tvb_get_guint8(tvb, offset) == RTSP_FRAMEHDR)
1495 ? dissect_rtspinterleaved(tvb, offset, pinfo, tree)
1496 : dissect_rtspmessage(tvb, offset, pinfo, tree);
1497 if (len == -1)
1498 break;
1499 offset += len;
1500
1501 /*
1502 * OK, we've set the Protocol and Info columns for the
1503 * first RTSP message; set fence so changes are kept for
1504 * subsequent RTSP messages.
1505 */
1506 col_set_fence(pinfo->cinfo, COL_INFO);
1507 }
1508 return tvb_captured_length(tvb);
1509 }
1510
1511 void
proto_register_rtsp(void)1512 proto_register_rtsp(void)
1513 {
1514 static gint *ett[] = {
1515 &ett_rtspframe,
1516 &ett_rtsp,
1517 &ett_rtsp_method,
1518 };
1519 static hf_register_info hf[] = {
1520 { &hf_rtsp_request,
1521 { "Request", "rtsp.request", FT_STRING, BASE_NONE, NULL, 0,
1522 NULL, HFILL }},
1523 { &hf_rtsp_response,
1524 { "Response", "rtsp.response", FT_STRING, BASE_NONE, NULL, 0,
1525 NULL, HFILL }},
1526 { &hf_rtsp_method,
1527 { "Method", "rtsp.method", FT_STRING, BASE_NONE, NULL, 0,
1528 NULL, HFILL }},
1529 { &hf_rtsp_content_type,
1530 { "Content-type", "rtsp.content-type", FT_STRING, BASE_NONE, NULL, 0,
1531 NULL, HFILL }},
1532 { &hf_rtsp_content_length,
1533 { "Content-length", "rtsp.content-length", FT_UINT32, BASE_DEC, NULL, 0,
1534 NULL, HFILL }},
1535 { &hf_rtsp_url,
1536 { "URL", "rtsp.url", FT_STRING, BASE_NONE, NULL, 0,
1537 NULL, HFILL }},
1538 { &hf_rtsp_status,
1539 { "Status", "rtsp.status", FT_UINT32, BASE_DEC, NULL, 0,
1540 NULL, HFILL }},
1541 { &hf_rtsp_session,
1542 { "Session", "rtsp.session", FT_STRING, BASE_NONE, NULL, 0,
1543 NULL, HFILL }},
1544 { &hf_rtsp_transport,
1545 { "Transport", "rtsp.transport", FT_STRING, BASE_NONE, NULL, 0,
1546 NULL, HFILL }},
1547 { &hf_rtsp_rdtfeaturelevel,
1548 { "RDTFeatureLevel", "rtsp.rdt-feature-level", FT_UINT32, BASE_DEC, NULL, 0,
1549 NULL, HFILL }},
1550 { &hf_rtsp_X_Vig_Msisdn,
1551 { "X-Vig-Msisdn", "rtsp.X_Vig_Msisdn", FT_STRING, BASE_NONE, NULL, 0,
1552 NULL, HFILL }},
1553 { &hf_rtsp_magic,
1554 { "Magic", "rtsp.magic", FT_UINT8, BASE_HEX, NULL, 0x0,
1555 NULL, HFILL }},
1556 { &hf_rtsp_channel,
1557 { "Channel", "rtsp.channel", FT_UINT8, BASE_HEX, NULL, 0x0,
1558 NULL, HFILL }},
1559 { &hf_rtsp_length,
1560 { "Length", "rtsp.length", FT_UINT16, BASE_DEC, NULL, 0x0,
1561 NULL, HFILL }},
1562 { &hf_rtsp_data,
1563 { "Data", "rtsp.data", FT_BYTES, BASE_NONE, NULL, 0x0,
1564 NULL, HFILL }},
1565 };
1566
1567 static ei_register_info ei[] = {
1568 { &ei_rtsp_unknown_transport_type,
1569 { "rtsp.unknown_transport_type", PI_UNDECODED, PI_WARN, "Unknown transport type", EXPFILL }},
1570 { &ei_rtsp_bad_server_port,
1571 { "rtsp.bad_server_port", PI_UNDECODED, PI_WARN, "Bad server_port", EXPFILL }},
1572 { &ei_rtsp_bad_client_port,
1573 { "rtsp.bad_client_port", PI_UNDECODED, PI_WARN, "Bad client port", EXPFILL }},
1574 { &ei_rtsp_bad_interleaved_channel,
1575 { "rtsp.bad_interleaved_channel", PI_UNDECODED, PI_WARN, "Bad interleaved_channel", EXPFILL }},
1576 { &ei_rtsp_content_length_invalid,
1577 { "rtsp.content-length.invalid", PI_MALFORMED, PI_ERROR, "Invalid content length", EXPFILL }},
1578 { &ei_rtsp_rdtfeaturelevel_invalid,
1579 { "rtsp.rdt-feature-level.invalid", PI_MALFORMED, PI_ERROR, "Invalid RDTFeatureLevel", EXPFILL }},
1580 { &ei_rtsp_bad_server_ip_address,
1581 { "rtsp.bad_client_ip_address", PI_MALFORMED, PI_ERROR, "Bad server IP address", EXPFILL }},
1582 { &ei_rtsp_bad_client_ip_address,
1583 { "rtsp.bad_client_ip_address", PI_MALFORMED, PI_ERROR, "Bad client IP address", EXPFILL }}
1584 };
1585
1586 module_t *rtsp_module;
1587 expert_module_t *expert_rtsp;
1588
1589 proto_rtsp = proto_register_protocol("Real Time Streaming Protocol", "RTSP", "rtsp");
1590
1591 proto_register_field_array(proto_rtsp, hf, array_length(hf));
1592 proto_register_subtree_array(ett, array_length(ett));
1593
1594 expert_rtsp = expert_register_protocol(proto_rtsp);
1595 expert_register_field_array(expert_rtsp, ei, array_length(ei));
1596
1597 /* Make this dissector findable by name */
1598 rtsp_handle = register_dissector("rtsp", dissect_rtsp, proto_rtsp);
1599
1600 /* Register our configuration options, particularly our ports */
1601
1602 rtsp_module = prefs_register_protocol(proto_rtsp, NULL);
1603
1604 prefs_register_obsolete_preference(rtsp_module, "tcp.alternate_port");
1605
1606 prefs_register_bool_preference(rtsp_module, "desegment_headers",
1607 "Reassemble RTSP headers spanning multiple TCP segments",
1608 "Whether the RTSP dissector should reassemble headers "
1609 "of a request spanning multiple TCP segments. "
1610 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1611 &rtsp_desegment_headers);
1612 prefs_register_bool_preference(rtsp_module, "desegment_body",
1613 "Trust the \"Content-length:\" header when desegmenting",
1614 "Whether the RTSP dissector should use the "
1615 "\"Content-length:\" value to desegment the body "
1616 "of a request spanning multiple TCP segments",
1617 &rtsp_desegment_body);
1618
1619 /*
1620 * Heuristic dissectors SHOULD register themselves in
1621 * this table using the standard heur_dissector_add()
1622 * function.
1623 */
1624 heur_subdissector_list = register_heur_dissector_list("rtsp", proto_rtsp);
1625
1626 /*
1627 * Register for tapping
1628 */
1629 rtsp_tap = register_tap("rtsp"); /* RTSP statistics tap */
1630 }
1631
1632 void
proto_reg_handoff_rtsp(void)1633 proto_reg_handoff_rtsp(void)
1634 {
1635 rtp_handle = find_dissector_add_dependency("rtp", proto_rtsp);
1636 rtp_rfc4571_handle = find_dissector_add_dependency("rtp.rfc4571", proto_rtsp);
1637 rtcp_handle = find_dissector_add_dependency("rtcp", proto_rtsp);
1638 rdt_handle = find_dissector_add_dependency("rdt", proto_rtsp);
1639 media_type_dissector_table = find_dissector_table("media_type");
1640 voip_tap = find_tap_id("voip");
1641
1642 /* Set our port number for future use */
1643 dissector_add_uint_range_with_preference("tcp.port", RTSP_TCP_PORT_RANGE, rtsp_handle);
1644
1645 /* XXX: Do the following only once ?? */
1646 stats_tree_register("rtsp","rtsp","RTSP/Packet Counter", 0, rtsp_stats_tree_packet, rtsp_stats_tree_init, NULL );
1647
1648 }
1649
1650 /*
1651 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1652 *
1653 * Local variables:
1654 * c-basic-offset: 4
1655 * tab-width: 8
1656 * indent-tabs-mode: space
1657 * End:
1658 *
1659 * vi: set shiftwidth=4 tabstop=8 expandtab:
1660 * :indentSize=4:tabSize=8:noTabs=true:
1661 */
1662