Coverage Report

Created: 2026-09-28 06:52

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