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