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