Bug Summary

File:epan/dissectors/packet-rtsp.c
Warning:line 1568, column 5
Value stored to 'linelen' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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