2 * RTPproxy command protocol dissector
3 * Copyright 2013, Peter Lemenkov <lemenkov@gmail.com>
5 * This dissector tries to dissect rtpproxy control protocol. Please visit this
6 * link for brief details on the command format:
8 * http://www.rtpproxy.org/wiki/RTPproxy/Protocol
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1999 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
21 #include <epan/packet.h>
22 #include <epan/prefs.h>
23 #include <epan/conversation.h>
24 #include <epan/expert.h>
25 #include <epan/rtp_pt.h>
26 #include <epan/addr_resolv.h>
28 /* For setting up RTP/RTCP dissectors based on the RTPproxy's answers */
29 #include "packet-rtp.h"
30 #include "packet-rtcp.h"
32 void proto_register_rtpproxy(void);
34 static int proto_rtpproxy = -1;
36 static int hf_rtpproxy_cookie = -1;
37 static int hf_rtpproxy_error = -1;
38 static int hf_rtpproxy_status = -1;
39 static int hf_rtpproxy_ok = -1;
40 static int hf_rtpproxy_ipv4 = -1;
41 static int hf_rtpproxy_ipv6 = -1;
42 static int hf_rtpproxy_port = -1;
43 static int hf_rtpproxy_lf = -1;
44 static int hf_rtpproxy_request = -1;
45 static int hf_rtpproxy_command = -1;
46 static int hf_rtpproxy_command_parameters = -1;
47 static int hf_rtpproxy_command_parameter = -1;
48 static int hf_rtpproxy_command_parameter_codec = -1;
49 static int hf_rtpproxy_command_parameter_local_ipv4 = -1;
50 static int hf_rtpproxy_command_parameter_remote_ipv4 = -1;
51 static int hf_rtpproxy_command_parameter_repacketize = -1;
52 static int hf_rtpproxy_command_parameter_dtmf = -1;
53 /* static int hf_rtpproxy_command_parameter_cmap = -1; TODO */
54 static int hf_rtpproxy_command_parameter_proto = -1;
55 static int hf_rtpproxy_command_parameter_transcode = -1;
56 static int hf_rtpproxy_command_parameter_acc = -1;
57 static int hf_rtpproxy_callid = -1;
58 static int hf_rtpproxy_copy_target = -1;
59 static int hf_rtpproxy_playback_filename = -1;
60 static int hf_rtpproxy_playback_codec = -1;
61 static int hf_rtpproxy_notify = -1;
62 static int hf_rtpproxy_notify_ipv4 = -1;
63 static int hf_rtpproxy_notify_ipv6 = -1;
64 static int hf_rtpproxy_notify_port = -1;
65 static int hf_rtpproxy_notify_tag = -1;
66 static int hf_rtpproxy_tag = -1;
67 static int hf_rtpproxy_mediaid = -1;
68 static int hf_rtpproxy_reply = -1;
69 static int hf_rtpproxy_version_request = -1;
70 static int hf_rtpproxy_version_supported = -1;
71 static int hf_rtpproxy_ng_bencode = -1;
74 static expert_field ei_rtpproxy_timeout = EI_INIT;
75 static expert_field ei_rtpproxy_notify_no_ip = EI_INIT;
76 static expert_field ei_rtpproxy_bad_ipv4 = EI_INIT;
77 static expert_field ei_rtpproxy_bad_ipv6 = EI_INIT;
79 /* Request/response tracking */
80 static int hf_rtpproxy_request_in = -1;
81 static int hf_rtpproxy_response_in = -1;
82 static int hf_rtpproxy_response_time = -1;
84 typedef struct _rtpproxy_info {
91 static dissector_handle_t rtcp_handle;
92 static dissector_handle_t rtp_events_handle;
93 static dissector_handle_t rtp_handle;
94 static dissector_handle_t bencode_handle;
96 typedef struct _rtpproxy_conv_info {
98 } rtpproxy_conv_info_t;
101 static const string_string versiontypenames[] = {
102 { "20040107", "Basic RTP proxy functionality" },
103 { "20050322", "Support for multiple RTP streams and MOH" },
104 { "20060704", "Support for extra parameter in the V command" },
105 { "20071116", "Support for RTP re-packetization" },
106 { "20071218", "Support for forking (copying) RTP stream" },
107 { "20080403", "Support for RTP statistics querying" },
108 { "20081102", "Support for setting codecs in the update/lookup command" },
109 { "20081224", "Support for session timeout notifications" },
110 { "20090810", "Support for automatic bridging" },
111 { "20140323", "Support for tracking/reporting load" },
112 { "20140617", "Support for anchoring session connect time" },
113 { "20141004", "Support for extendable performance counters" },
114 { "20150330", "Support for allocating a new port (\"Un\"/\"Ln\" commands)" },
118 static const value_string commandtypenames[] = {
119 { 'V', "Handshake/Ping" },
120 { 'v', "Handshake/Ping" },
121 { 'U', "Offer/Update" },
122 { 'u', "Offer/Update" },
123 { 'L', "Answer/Lookup" },
124 { 'l', "Answer/Lookup" },
125 { 'I', "Information"},
126 { 'i', "Information"},
127 { 'X', "Close all active sessions"},
128 { 'x', "Close all active sessions"},
129 { 'D', "Delete an active session (Bye/Cancel/Error)"},
130 { 'd', "Delete an active session (Bye/Cancel/Error)"},
131 { 'P', "Start playback (music-on-hold)"},
132 { 'p', "Start playback (music-on-hold)"},
133 { 'S', "Stop playback (music-on-hold)"},
134 { 's', "Stop playback (music-on-hold)"},
135 { 'R', "Start recording"},
136 { 'r', "Start recording"},
137 { 'C', "Copy stream"},
138 { 'c', "Copy stream"},
139 { 'Q', "Query info about a session"},
140 { 'q', "Query info about a session"},
144 static const value_string paramtypenames[] = {
145 /* Official command parameters */
146 {'4', "Remote address is IPv4"},
147 {'6', "Remote address is IPv6"},
148 {'a', "Asymmetric stream"},
149 {'A', "Asymmetric stream"},
150 {'b', "Brief stats"},
151 {'B', "Brief stats"},
154 {'e', "External network (non RFC 1918)"},
155 {'E', "External network (non RFC 1918)"},
156 {'i', "Internal network (RFC 1918)"},
157 {'I', "Internal network (RFC 1918)"},
158 {'l', "Local address / Load average"},
159 {'L', "Local address / Load average"},
160 {'n', "request New port"},
161 {'N', "request New port"},
162 {'r', "Remote address"},
163 {'R', "Remote address"},
164 {'s', "Symmetric stream / Single file"},
165 {'S', "Symmetric stream / Single file"},
166 {'w', "Weak connection (allows roaming)"},
167 {'W', "Weak connection (allows roaming)"},
168 {'z', "repacketiZe"},
169 {'Z', "repacketiZe"},
170 /* Unofficial command parameters / expensions */
171 {'d', "DTMF payload ID (unofficial extension)"},
172 {'D', "DTMF payload ID (unofficial extension)"},
173 {'m', "codec Mapping (unofficial extension)"},
174 {'M', "codec Mapping (unofficial extension)"},
175 {'p', "Protocol type (unofficial extension)"},
176 {'P', "Protocol type (unofficial extension)"},
177 {'t', "Transcode to (unofficial extension)"},
178 {'T', "Transcode to (unofficial extension)"},
179 {'u', "accoUnting (unofficial extension)"},
180 {'U', "accoUnting (unofficial extension)"},
184 static const value_string prototypenames[] = {
185 { '0', "UDP (default)"},
190 static const value_string acctypenames[] = {
192 { '1', "Interim update"},
197 static const value_string oktypenames[] = {
199 { '1', "Version Supported"},
203 static const string_string errortypenames[] = {
204 { "E0", "Syntax error: unknown command (CMDUNKN)" },
205 { "E1", "Syntax error: wrond number of arguments (PARSE_NARGS)" },
206 { "E2", "Syntax error: unknown modifiers (PARSE_MODS)" },
212 { "E10", "PARSE_10" },
213 { "E11", "PARSE_11" },
214 { "E12", "PARSE_12" },
215 { "E13", "PARSE_13" },
216 { "E14", "PARSE_14" },
217 { "E15", "PARSE_15" },
218 { "E16", "PARSE_16" },
219 { "E17", "PARSE_6" },
220 { "E18", "PARSE_7" },
221 { "E25", "Software error: return string too big (RTOOBIG_1)" },
222 { "E31", "INVLARG_1" },
223 { "E32", "INVLARG_2" },
224 { "E33", "INVLARG_3" },
225 { "E34", "INVLARG_4" },
226 { "E35", "INVLARG_5" },
227 { "E50", "SESUNKN" },
228 { "E60", "PLRFAIL" },
229 { "E65", "CPYFAIL" },
230 { "E68", "STSFAIL" },
231 { "E71", "Software error: can't create listener (LSTFAIL_1)" },
232 { "E72", "Software error: can't create listener (LSTFAIL_2)" },
233 { "E81", "Out of memory (NOMEM_1)" },
234 { "E82", "Out of memory (NOMEM_2)" },
235 { "E83", "Out of memory (NOMEM_3)" },
236 { "E84", "Out of memory (NOMEM_4)" },
237 { "E85", "Out of memory (NOMEM_5)" },
238 { "E86", "Out of memory (NOMEM_6)" },
239 { "E87", "Out of memory (NOMEM_7)" },
240 { "E88", "Out of memory (NOMEM_8)" },
241 { "E99", "Software error: proxy is in the deorbiting-burn mode, new session rejected (SLOWSHTDN)" },
245 static gint ett_rtpproxy = -1;
247 static gint ett_rtpproxy_request = -1;
248 static gint ett_rtpproxy_command = -1;
249 static gint ett_rtpproxy_command_parameters = -1;
250 static gint ett_rtpproxy_command_parameters_codecs = -1;
251 static gint ett_rtpproxy_command_parameters_local = -1;
252 static gint ett_rtpproxy_command_parameters_remote = -1;
253 static gint ett_rtpproxy_command_parameters_repacketize = -1;
254 static gint ett_rtpproxy_command_parameters_dtmf = -1;
255 static gint ett_rtpproxy_command_parameters_cmap = -1;
256 static gint ett_rtpproxy_command_parameters_proto = -1;
257 static gint ett_rtpproxy_command_parameters_transcode = -1;
258 static gint ett_rtpproxy_command_parameters_acc = -1;
259 static gint ett_rtpproxy_tag = -1;
260 static gint ett_rtpproxy_notify = -1;
262 static gint ett_rtpproxy_reply = -1;
264 static gint ett_rtpproxy_ng_bencode = -1;
267 #define RTPPROXY_PORT 22222 /* Not IANA registered */
268 static gboolean rtpproxy_establish_conversation = TRUE;
269 /* See - https://www.opensips.org/html/docs/modules/1.10.x/rtpproxy.html#id293555 */
270 /* See - http://www.kamailio.org/docs/modules/4.3.x/modules/rtpproxy.html#idp15794952 */
271 static guint rtpproxy_timeout = 1000;
272 static nstime_t rtpproxy_timeout_ns = NSTIME_INIT_ZERO;
274 void proto_reg_handoff_rtpproxy(void);
277 rtpproxy_add_tag(proto_tree *rtpproxy_tree, tvbuff_t *tvb, guint begin, guint realsize)
279 proto_item *ti = NULL;
280 proto_tree *another_tree = NULL;
284 new_offset = tvb_find_guint8(tvb, begin, -1, ' ');
286 end = realsize; /* No more parameters */
290 /* SER/OpenSER/OpenSIPS/Kamailio adds Media-ID right after the Tag
291 * separated by a semicolon
293 new_offset = tvb_find_guint8(tvb, begin, end, ';');
294 if(new_offset == -1){
295 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, end - begin, ENC_ASCII | ENC_NA);
296 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
297 ti = proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, 0, ENC_ASCII | ENC_NA);
298 proto_item_append_text(ti, "<skipped>");
299 proto_item_set_generated(ti);
302 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, new_offset - begin, ENC_ASCII | ENC_NA);
303 if ((guint)new_offset == begin){
304 proto_item_append_text(ti, "<skipped>"); /* A very first Offer/Update command */
305 proto_item_set_generated(ti);
307 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
308 proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, end - (new_offset+1), ENC_ASCII | ENC_NA);
310 return (end == realsize ? -1 : (gint)end);
314 rtpproxy_add_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint realsize)
317 proto_tree *another_tree = NULL;
319 guint new_offset = 0;
322 gchar** codecs = NULL;
324 guint8* rawstr = NULL;
325 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
327 /* Extract the entire parameters line. */
328 /* Something like "t4p1iic8,0,2,4,18,96,97,98,100,101" */
329 rawstr = tvb_get_string_enc(wmem_packet_scope(), tvb, begin, realsize, ENC_ASCII);
331 while(offset < realsize){
332 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameter, tvb, begin + offset, 1, ENC_ASCII | ENC_NA);
333 offset++; /* Skip 1-byte parameter's type */
334 switch (g_ascii_tolower(tvb_get_guint8(tvb, begin+offset-1)))
336 /* Official long parameters */
338 new_offset = (gint)strspn(rawstr+offset, "0123456789,");
339 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_codecs);
340 codecs = wmem_strsplit(wmem_packet_scope(), tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ",", 0);
343 /* We assume strings < 2^32-1 bytes long. :-) */
344 codec_len = (guint)strlen(codecs[i]);
345 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_codec, tvb, begin+offset, codec_len,
346 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, codec_len, ENC_ASCII), NULL, 10));
347 proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(tvb,begin+offset,codec_len),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
350 offset++; /* skip comma */
355 /* That's another one protocol shortcoming - the same parameter used twice. */
356 /* https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#createupdatelookup-session */
357 /* https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#get-information */
358 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
360 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_local);
361 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
362 proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_local_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
364 proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
365 offset += new_offset;
369 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
370 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_remote);
371 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
372 proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_remote_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
374 proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
375 offset += new_offset;
378 new_offset = (gint)strspn(rawstr+offset, "0123456789");
379 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_repacketize);
380 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_repacketize, tvb, begin+offset, new_offset,
381 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
382 offset += new_offset;
384 /* Unofficial long parameters */
386 new_offset = (gint)strspn(rawstr+offset, "0123456789");
387 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_dtmf);
388 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_dtmf, tvb, begin+offset, new_offset,
389 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
390 if(rtpproxy_establish_conversation){
391 pt = (guint)strtoul(tvb_format_text(tvb,begin+offset,new_offset),NULL,10);
392 dissector_add_uint("rtp.pt", pt, rtp_events_handle);
394 offset += new_offset;
397 new_offset = (gint)strspn(rawstr+offset, "0123456789=,");
399 offset += new_offset;
402 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_proto);
403 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_proto, tvb, begin+offset, 1, ENC_ASCII | ENC_NA);
407 new_offset = (gint)strspn(rawstr+offset, "0123456789");
408 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_transcode);
409 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_transcode, tvb, begin+offset, new_offset,
410 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
411 proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(tvb,begin+offset, new_offset),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
412 offset += new_offset;
415 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_acc);
416 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_acc, tvb, begin+offset, 1, ENC_ASCII | ENC_NA);
425 static rtpproxy_info_t *
426 rtpproxy_add_tid(gboolean is_request, tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, rtpproxy_conv_info_t *rtpproxy_conv, const guint8* cookie)
428 rtpproxy_info_t *rtpproxy_info;
431 if (!PINFO_FD_VISITED(pinfo)) {
433 rtpproxy_info = wmem_new0(wmem_file_scope(), rtpproxy_info_t);
434 rtpproxy_info->req_frame = pinfo->num;
435 rtpproxy_info->req_time = pinfo->abs_ts;
436 wmem_tree_insert_string(rtpproxy_conv->trans, cookie, rtpproxy_info, 0);
438 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
440 rtpproxy_info->resp_frame = pinfo->num;
444 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
445 if (rtpproxy_info && (is_request ? rtpproxy_info->resp_frame : rtpproxy_info->req_frame)) {
448 pi = proto_tree_add_uint(rtpproxy_tree, is_request ? hf_rtpproxy_response_in : hf_rtpproxy_request_in, tvb, 0, 0, is_request ? rtpproxy_info->resp_frame : rtpproxy_info->req_frame);
449 proto_item_set_generated(pi);
451 /* If not a request (so it's a reply) then calculate response time */
453 nstime_delta(&ns, &pinfo->abs_ts, &rtpproxy_info->req_time);
454 pi = proto_tree_add_time(rtpproxy_tree, hf_rtpproxy_response_time, tvb, 0, 0, &ns);
455 proto_item_set_generated(pi);
456 if (nstime_cmp(&rtpproxy_timeout_ns, &ns) < 0)
457 expert_add_info_format(pinfo, rtpproxy_tree, &ei_rtpproxy_timeout, "Response timeout %.3f seconds", nstime_to_sec(&ns));
461 /* Could be NULL so we should check it before dereferencing */
462 return rtpproxy_info;
466 rtpproxy_add_notify_addr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint end)
470 gboolean ipv6 = FALSE;
471 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
474 /* Check for at least one colon */
475 offset = tvb_find_guint8(tvb, begin, end, ':');
477 /* Find if it's the latest colon (not in case of a IPv6) */
478 while((tmp = tvb_find_guint8(tvb, offset+1, end, ':')) != -1){
482 /* We have ip:port */
484 if(str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, offset - begin, ENC_ASCII), ipaddr))
485 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, offset - begin, (const ws_in6_addr*)ipaddr);
487 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, begin, offset - begin);
490 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, offset - begin, ENC_ASCII), ipaddr))
491 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, offset - begin, ipaddr[0]);
493 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin, offset - begin);
495 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, offset+1, end - (offset+1),
496 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset+1, end - (offset+1), ENC_ASCII), NULL, 10));
499 /* Only port is supplied - take IPv4/IPv6 from ip.src/ipv6.src respectively */
500 expert_add_info(pinfo, rtpproxy_tree, &ei_rtpproxy_notify_no_ip);
501 if (pinfo->src.type == AT_IPv4)
502 ti = proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, 0, *(const guint32*)(pinfo->src.data));
504 ti = proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, 0, (const ws_in6_addr *)(pinfo->src.data));
505 proto_item_set_generated(ti);
506 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, begin, end - begin,
507 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, end - begin, ENC_ASCII), NULL, 10));
512 dissect_rtpproxy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
514 gboolean has_lf = FALSE;
521 const guint8* tmpstr;
524 proto_tree *rtpproxy_tree;
525 conversation_t *conversation;
526 rtpproxy_conv_info_t *rtpproxy_conv;
527 const guint8* cookie = NULL;
528 /* For RT(C)P setup */
531 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
532 rtpproxy_info_t *rtpproxy_info = NULL;
535 /* If it does not start with a printable character it's not RTPProxy */
536 if(!g_ascii_isprint(tvb_get_guint8(tvb, 0)))
540 offset = tvb_find_guint8(tvb, offset, -1, ' ');
544 /* We believe it's likely a RTPproxy / RTPproxy-ng protocol */
545 /* Note: we no longer distinct between packets with or w/o LF - it turned
546 * out to be useless */
547 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy");
549 /* Clear out stuff in the info column - we'll set it later */
550 col_clear(pinfo->cinfo, COL_INFO);
552 ti = proto_tree_add_item(tree, proto_rtpproxy, tvb, 0, -1, ENC_NA);
553 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy);
555 proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_cookie, tvb, 0, offset, ENC_ASCII | ENC_NA, wmem_packet_scope(), &cookie);
557 /* Skip whitespace */
558 offset = tvb_skip_wsp(tvb, offset+1, -1);
560 /* Calculate size to prevent recalculation in the future */
561 realsize = tvb_reported_length(tvb);
563 /* Don't count trailing zeroes (inserted by some SIP-servers sometimes) */
564 while (tvb_get_guint8(tvb, realsize - 1) == 0){
568 /* Check for LF (required for TCP connection, optional for UDP) */
569 if (tvb_get_guint8(tvb, realsize - 1) == '\n'){
570 /* Don't count trailing LF */
575 /* Try to create conversation */
576 conversation = find_or_create_conversation(pinfo);
577 rtpproxy_conv = (rtpproxy_conv_info_t *)conversation_get_proto_data(conversation, proto_rtpproxy);
578 if (!rtpproxy_conv) {
579 rtpproxy_conv = wmem_new(wmem_file_scope(), rtpproxy_conv_info_t);
580 rtpproxy_conv->trans = wmem_tree_new(wmem_file_scope());
581 conversation_add_proto_data(conversation, proto_rtpproxy, rtpproxy_conv);
584 /* Get payload string */
585 rawstr = tvb_format_text(tvb, offset, realsize - offset);
587 /* Extract command */
588 tmp = g_ascii_tolower(tvb_get_guint8(tvb, offset));
592 /* A specific case - long info answer */
593 /* %COOKIE% sessions created %NUM0% active sessions: %NUM1% */
594 /* FIXME https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#information */
595 rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
596 if ('e' == tvb_get_guint8(tvb, offset+1)){
597 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
598 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
600 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
601 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_status, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
610 tmp2 = tvb_get_guint8(tvb, offset+1);
611 if(('1' <= tmp2) && (tmp2 <= '9') && (tvb_get_guint8(tvb, offset+2) == ':')){
612 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy-ng");
613 col_add_fstr(pinfo->cinfo, COL_INFO, "RTPproxy-ng: %s", rawstr);
614 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ng_bencode, tvb, offset, -1, ENC_ASCII | ENC_NA);
615 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_ng_bencode);
616 subtvb = tvb_new_subset_remaining(tvb, offset);
617 call_dissector(bencode_handle, subtvb, pinfo, rtpproxy_tree);
626 rtpproxy_info = rtpproxy_add_tid(TRUE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
627 col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s", rawstr);
628 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_request, tvb, offset, -1, ENC_NA);
629 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_request);
631 /* A specific case - version request:
632 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#get-list-of-veatures
634 * In this case a command size must be bigger or equal to a "VF YYYYMMDD" string size.
635 * It's bigger if there is more than one space inserted between "VF" and "YYYYMMDD" tokens.
637 if ((tmp == 'v') && (offset + (gint)strlen("VF YYYYMMDD") <= realsize)){
638 /* Skip whitespace between "VF" and "YYYYMMDD" tokens */
639 new_offset = tvb_skip_wsp(tvb, offset + ((guint)strlen("VF") + 1), -1);
640 ti = proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_version_request, tvb, new_offset, (gint)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA, wmem_packet_scope(), &tmpstr);
641 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, versiontypenames, "Unknown"));
645 /* All other commands */
646 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command, tvb, offset, 1, ENC_ASCII | ENC_NA);
648 /* A specific case - handshake/ping */
650 break; /* No more parameters */
652 /* A specific case - close all calls */
654 break; /* No more parameters */
656 /* Extract parameters */
657 /* Parameters should be right after the command and before EOL (in case of Info command) or before whitespace */
658 new_offset = (tmp == 'i' ? (realsize - 1 > offset ? offset + (gint)strlen("Ib") : offset + (gint)strlen("I")) : tvb_find_guint8(tvb, offset, -1, ' '));
660 if (new_offset != offset + 1){
661 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_command);
662 ti2 = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameters, tvb, offset+1, new_offset - (offset+1), ENC_ASCII | ENC_NA);
663 rtpproxy_add_parameter(tvb, pinfo, proto_item_add_subtree(ti2, ett_rtpproxy_command_parameters), offset+1, new_offset - (offset+1));
664 rtpproxy_tree = proto_item_get_parent(ti);
667 /* A specific case - query information */
669 break; /* No more parameters */
671 /* Skip whitespace */
672 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
674 /* Extract Call-ID */
675 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
676 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
677 if(rtpproxy_info && !rtpproxy_info->callid)
678 rtpproxy_info->callid = tvb_get_string_enc(wmem_file_scope(), tvb, offset, new_offset - offset, ENC_ASCII);
679 /* Skip whitespace */
680 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
682 /* Extract IP and Port in case of Offer/Answer */
683 if ((tmp == 'u') || (tmp == 'l')){
685 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
686 if (tvb_find_guint8(tvb, offset, new_offset - offset, ':') == -1){
687 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
688 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, new_offset - offset, ipaddr[0]);
690 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, new_offset - offset);
693 if(str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
694 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, new_offset - offset, (const ws_in6_addr *)ipaddr);
696 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, new_offset - offset);
698 /* Skip whitespace */
699 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
702 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
703 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset,
704 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
705 /* Skip whitespace */
706 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
709 /* Extract Copy target */
711 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
712 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_copy_target, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
713 /* Skip whitespace */
714 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
717 /* Extract Playback file and codecs */
719 /* Extract filename */
720 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
721 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_playback_filename, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
722 /* Skip whitespace */
723 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
726 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
727 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_playback_codec, tvb, offset, new_offset - offset,
728 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
729 /* Skip whitespace */
730 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
733 /* Extract first tag */
734 new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
736 break; /* No more parameters */
737 /* Skip whitespace */
738 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
740 /* Extract second tag */
741 new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
743 break; /* No more parameters */
744 /* Skip whitespace */
745 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
747 /* Extract Notification address */
749 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
750 proto_item_set_text(ti, "Notify");
751 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_notify);
753 /* Check for NotifyTag parameter (separated by space) */
754 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
755 if(new_offset == -1){
756 /* NotifyTag wasn't found (we should re-use Call-ID instead) */
757 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, realsize);
758 break; /* No more parameters */
761 /* NotifyTag was found */
762 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, new_offset);
763 /* Skip whitespace */
764 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
766 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_tag, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
780 rtpproxy_info = rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
782 col_add_fstr(pinfo->cinfo, COL_INFO, "Error reply: %s", rawstr);
784 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
786 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
787 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
789 if(rtpproxy_info && rtpproxy_info->callid){
790 ti = proto_tree_add_string(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, 0, rtpproxy_info->callid);
791 proto_item_set_generated(ti);
795 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
796 tmpstr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII);
797 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_error, tvb, offset, (gint)strlen(tmpstr), ENC_ASCII | ENC_NA);
798 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, errortypenames, "Unknown"));
802 /* Check for a single '0' or '1' character followed by the end-of-line.
803 * These both are positive replies - either a 'positive reply' or a 'version ack'.
805 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#positive-reply
806 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#version-reply
808 if (((tmp == '0') || (tmp == '1')) && (realsize == offset + (gint)strlen("X"))){
809 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ok, tvb, offset, 1, ENC_ASCII | ENC_NA);
813 /* Check for the VERSION_NUMBER string reply:
814 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#version-reply
816 * If a total size equals to a current offset + size of "YYYYMMDD" string
817 * then it's a version reply.
819 if (realsize == offset + (gint)strlen("YYYYMMDD")){
820 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_version_supported, tvb, offset, (guint32)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA);
825 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
826 /* Convert port to unsigned 16-bit number */
827 port = (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10);
828 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset, port);
829 /* Skip whitespace */
830 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
833 memset(&addr, 0, sizeof(address));
835 /* Try rtpengine bogus extension first. It appends 4 or
836 * 6 depending on type of the IP. See
837 * https://github.com/sipwise/rtpengine/blob/eea3256/daemon/call_interfaces.c#L74
838 * for further details */
839 tmp = tvb_find_guint8(tvb, offset, -1, ' ');
840 if(tmp == (guint)(-1)){
841 /* No extension - operate normally */
842 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
848 if (tvb_find_guint8(tvb, offset, -1, ':') == -1){
849 if (str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII), ipaddr)){
852 addr.data = wmem_memdup(wmem_packet_scope(), ipaddr, 4);
853 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, tmp, ipaddr[0]);
856 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, tmp);
859 if (str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII), ipaddr)){
862 addr.data = wmem_memdup(wmem_packet_scope(), ipaddr, 16);
863 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, tmp, (const ws_in6_addr *)ipaddr);
866 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, tmp);
869 if(rtpproxy_establish_conversation){
871 /* FIXME tell if isn't a video stream, and setup codec mapping */
873 rtp_add_address(pinfo, PT_UDP, &addr, port, 0, "RTPproxy", pinfo->num, 0, NULL);
877 rtcp_add_address(pinfo, &addr, port+1, 0, "RTPproxy", pinfo->num);
884 /* TODO add an expert warning about packets w/o LF sent over TCP */
886 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_lf, tvb, realsize, 1, ENC_NA);
888 return tvb_captured_length(tvb);
892 proto_register_rtpproxy(void)
894 module_t *rtpproxy_module;
895 expert_module_t* expert_rtpproxy_module;
897 static hf_register_info hf[] = {
912 &hf_rtpproxy_version_request,
925 &hf_rtpproxy_version_supported,
928 "rtpproxy.version_supported",
1007 FT_UINT16, /* 0 - 65535 */
1016 &hf_rtpproxy_request,
1029 &hf_rtpproxy_command,
1035 VALS(commandtypenames),
1042 &hf_rtpproxy_command_parameters,
1044 "Command parameters",
1045 "rtpproxy.command_parameters",
1055 &hf_rtpproxy_command_parameter,
1058 "rtpproxy.command_parameter",
1061 VALS(paramtypenames),
1068 &hf_rtpproxy_command_parameter_codec,
1071 "rtpproxy.command_parameter_codec",
1072 FT_UINT8, /* 0 - 127 */
1081 &hf_rtpproxy_command_parameter_local_ipv4,
1083 "Local IPv4 address",
1084 "rtpproxy.command_parameter_local_ipv4",
1085 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1094 &hf_rtpproxy_command_parameter_remote_ipv4,
1096 "Remote IPv4 address",
1097 "rtpproxy.command_parameter_remote_ipv4",
1098 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1107 &hf_rtpproxy_command_parameter_repacketize,
1110 "rtpproxy.command_parameter_repacketize",
1111 FT_UINT16, /* 0 - 1000 milliseconds */
1120 &hf_rtpproxy_command_parameter_dtmf,
1123 "rtpproxy.command_parameter_dtmf",
1124 FT_UINT8, /* 0 - 127 */
1133 &hf_rtpproxy_command_parameter_proto,
1135 "RTP tramsission protocol",
1136 "rtpproxy.command_parameter_proto",
1139 VALS(prototypenames),
1146 &hf_rtpproxy_command_parameter_transcode,
1149 "rtpproxy.command_parameter_transcode",
1150 FT_UINT8, /* 0 - 127 */
1159 &hf_rtpproxy_command_parameter_acc,
1162 "rtpproxy.command_parameter_acc",
1172 &hf_rtpproxy_copy_target,
1175 "rtpproxy.copy_target",
1176 FT_STRING, /* Filename or UDP address, e.g. /var/tmp/fileXXXX.yyy or IP:Port */
1185 &hf_rtpproxy_playback_filename,
1187 "Playback filename",
1188 "rtpproxy.playback_filename",
1198 &hf_rtpproxy_playback_codec,
1201 "rtpproxy.playback_codec",
1202 FT_UINT8, /* 0 - 127 */
1211 &hf_rtpproxy_callid,
1224 &hf_rtpproxy_notify,
1250 &hf_rtpproxy_mediaid,
1263 &hf_rtpproxy_notify_ipv4,
1265 "Notification IPv4",
1266 "rtpproxy.notify_ipv4",
1276 &hf_rtpproxy_notify_ipv6,
1278 "Notification IPv6",
1279 "rtpproxy.notify_ipv6",
1289 &hf_rtpproxy_notify_port,
1291 "Notification Port",
1292 "rtpproxy.notify_port",
1302 &hf_rtpproxy_notify_tag,
1305 "rtpproxy.notify_tag",
1341 &hf_rtpproxy_request_in,
1344 "rtpproxy.request_in",
1355 &hf_rtpproxy_response_in,
1358 "rtpproxy.response_in",
1368 &hf_rtpproxy_response_time,
1371 "rtpproxy.response_time",
1376 "The time between the Request and the Reply",
1381 &hf_rtpproxy_ng_bencode,
1383 "RTPproxy-ng bencode packet",
1384 "rtpproxy.ng.bencode",
1389 "Serialized structure of integers, dictionaries, strings and lists.",
1395 static ei_register_info ei[] = {
1396 { &ei_rtpproxy_timeout,
1397 { "rtpproxy.response_timeout", PI_RESPONSE_CODE, PI_WARN,
1398 "TIMEOUT", EXPFILL }},
1399 { &ei_rtpproxy_notify_no_ip,
1400 { "rtpproxy.notify_no_ip", PI_RESPONSE_CODE, PI_COMMENT,
1401 "No notification IP address provided. Using ip.src or ipv6.src as a value.", EXPFILL }},
1402 { &ei_rtpproxy_bad_ipv4,
1403 { "rtpproxy.bad_ipv4", PI_MALFORMED, PI_ERROR,
1404 "Bad IPv4", EXPFILL }},
1405 { &ei_rtpproxy_bad_ipv6,
1406 { "rtpproxy.bad_ipv6", PI_MALFORMED, PI_ERROR,
1407 "Bad IPv6", EXPFILL }},
1410 /* Setup protocol subtree array */
1411 static gint *ett[] = {
1413 &ett_rtpproxy_request,
1414 &ett_rtpproxy_command,
1415 &ett_rtpproxy_command_parameters,
1416 &ett_rtpproxy_command_parameters_codecs,
1417 &ett_rtpproxy_command_parameters_local,
1418 &ett_rtpproxy_command_parameters_remote,
1419 &ett_rtpproxy_command_parameters_repacketize,
1420 &ett_rtpproxy_command_parameters_dtmf,
1421 &ett_rtpproxy_command_parameters_cmap,
1422 &ett_rtpproxy_command_parameters_proto,
1423 &ett_rtpproxy_command_parameters_transcode,
1424 &ett_rtpproxy_command_parameters_acc,
1426 &ett_rtpproxy_notify,
1427 &ett_rtpproxy_reply,
1428 &ett_rtpproxy_ng_bencode
1431 proto_rtpproxy = proto_register_protocol ("Sippy RTPproxy Protocol", "RTPproxy", "rtpproxy");
1433 proto_register_field_array(proto_rtpproxy, hf, array_length(hf));
1434 proto_register_subtree_array(ett, array_length(ett));
1436 expert_rtpproxy_module = expert_register_protocol(proto_rtpproxy);
1437 expert_register_field_array(expert_rtpproxy_module, ei, array_length(ei));
1439 rtpproxy_module = prefs_register_protocol(proto_rtpproxy, proto_reg_handoff_rtpproxy);
1441 prefs_register_bool_preference(rtpproxy_module, "establish_conversation",
1442 "Establish Media Conversation",
1443 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
1444 "upon port numbers found in RTPproxy answers",
1445 &rtpproxy_establish_conversation);
1447 prefs_register_uint_preference(rtpproxy_module, "reply.timeout",
1448 "RTPproxy reply timeout", /* Title */
1449 "Maximum timeout value in waiting for reply from RTPProxy (in milliseconds).", /* Descr */
1455 proto_reg_handoff_rtpproxy(void)
1457 static gboolean rtpproxy_initialized = FALSE;
1459 dissector_handle_t rtpproxy_tcp_handle, rtpproxy_udp_handle;
1461 if(!rtpproxy_initialized){
1462 rtpproxy_tcp_handle = create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1463 rtpproxy_udp_handle = create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1465 /* Register TCP port for dissection */
1466 dissector_add_uint_with_preference("tcp.port", RTPPROXY_PORT, rtpproxy_tcp_handle);
1467 dissector_add_uint_with_preference("udp.port", RTPPROXY_PORT, rtpproxy_udp_handle);
1468 rtpproxy_initialized = TRUE;
1471 rtcp_handle = find_dissector_add_dependency("rtcp", proto_rtpproxy);
1472 rtp_events_handle = find_dissector_add_dependency("rtpevent", proto_rtpproxy);
1473 rtp_handle = find_dissector_add_dependency("rtp", proto_rtpproxy);
1474 bencode_handle = find_dissector_add_dependency("bencode", proto_rtpproxy);
1476 /* Calculate nstime_t struct for the timeout from the rtpproxy_timeout value in milliseconds */
1477 rtpproxy_timeout_ns.secs = (rtpproxy_timeout - rtpproxy_timeout % 1000) / 1000;
1478 rtpproxy_timeout_ns.nsecs = (rtpproxy_timeout % 1000) * 1000;
1482 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1487 * indent-tabs-mode: nil
1490 * vi: set shiftwidth=4 tabstop=8 expandtab:
1491 * :indentSize=4:tabSize=8:noTabs=true: