Coverage Report

Created: 2025-08-04 07:15

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