1 /* packet-rtpproxy.c
2 * RTPproxy command protocol dissector
3 * Copyright 2013, Peter Lemenkov <lemenkov@gmail.com>
4 *
5 * This dissector tries to dissect rtpproxy control protocol. Please visit this
6 * link for brief details on the command format:
7 *
8 * http://www.rtpproxy.org/wiki/RTPproxy/Protocol
9 *
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1999 Gerald Combs
13 *
14 * SPDX-License-Identifier: GPL-2.0-or-later
15 */
16
17 #include "config.h"
18
19 #include <stdlib.h>
20
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>
27
28 /* For setting up RTP/RTCP dissectors based on the RTPproxy's answers */
29 #include "packet-rtp.h"
30 #include "packet-rtcp.h"
31
32 void proto_register_rtpproxy(void);
33
34 static int proto_rtpproxy = -1;
35
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;
72
73 /* Expert fields */
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;
78
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;
83
84 typedef struct _rtpproxy_info {
85 guint32 req_frame;
86 guint32 resp_frame;
87 nstime_t req_time;
88 gchar* callid;
89 } rtpproxy_info_t;
90
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;
95
96 typedef struct _rtpproxy_conv_info {
97 wmem_tree_t *trans;
98 } rtpproxy_conv_info_t;
99
100
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)" },
115 { 0, NULL }
116 };
117
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"},
141 { 0, NULL }
142 };
143
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"},
152 {'c', "Codecs"},
153 {'C', "Codecs"},
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)"},
181 {0, NULL}
182 };
183
184 static const value_string prototypenames[] = {
185 { '0', "UDP (default)"},
186 { '1', "TCP"},
187 { '2', "SCTP"},
188 { 0, NULL }
189 };
190 static const value_string acctypenames[] = {
191 { '0', "Start"},
192 { '1', "Interim update"},
193 { '2', "Stop"},
194 { 0, NULL }
195 };
196
197 static const value_string oktypenames[] = {
198 { '0', "Ok"},
199 { '1', "Version Supported"},
200 { 0, NULL }
201 };
202
203 static const string_string errortypenames[] = {
204 { "E0", "Syntax error: unknown command (CMDUNKN)" },
205 { "E1", "Syntax error: invalid number of arguments (PARSE_NARGS)" },
206 { "E2", "Syntax error: modifiers are not supported by the command (PARSE_MODS)" },
207 { "E3", "Syntax error: subcommand is not supported (PARSE_SUBC)" },
208 { "E5", "PARSE_1" },
209 { "E6", "PARSE_2" },
210 { "E7", "PARSE_3" },
211 { "E8", "PARSE_4" },
212 { "E9", "PARSE_5" },
213 { "E10", "PARSE_10" },
214 { "E11", "PARSE_11" },
215 { "E12", "PARSE_12" },
216 { "E13", "PARSE_13" },
217 { "E14", "PARSE_14" },
218 { "E15", "PARSE_15" },
219 { "E16", "PARSE_16" },
220 { "E17", "PARSE_6" },
221 { "E18", "PARSE_7" },
222 { "E19", "PARSE_8" },
223 { "E25", "Software error: output buffer overflow (RTOOBIG_1)" },
224 { "E26", "Software error: output buffer overflow (RTOOBIG_2)" },
225 { "E31", "Syntax error: invalid local address (INVLARG_1)" },
226 { "E32", "Syntax error: invalid remote address (INVLARG_2)" },
227 { "E33", "Syntax error: can't find local address for remote address (INVLARG_3)" },
228 { "E34", "Syntax error: invalid local address (INVLARG_4)" },
229 { "E35", "Syntax error: no codecs (INVLARG_5)" },
230 { "E36", "Syntax error: cannot match local address for the session (INVLARG_6)" },
231 { "E50", "Software error: session not found (SESUNKN)" },
232 { "E60", "PLRFAIL" },
233 { "E62", "Software error: unsupported/invalid counter name (QRYFAIL)" },
234 { "E65", "CPYFAIL" },
235 { "E68", "STSFAIL" },
236 { "E71", "Software error: can't create listener (LSTFAIL_1)" },
237 { "E72", "Software error: can't create listener (LSTFAIL_2)" },
238 { "E75", "Software error: must permit notification socket with -n (NSOFF)" },
239 { "E81", "Out of memory (NOMEM_1)" },
240 { "E82", "Out of memory (NOMEM_2)" },
241 { "E83", "Out of memory (NOMEM_3)" },
242 { "E84", "Out of memory (NOMEM_4)" },
243 { "E85", "Out of memory (NOMEM_5)" },
244 { "E86", "Out of memory (NOMEM_6)" },
245 { "E87", "Out of memory (NOMEM_7)" },
246 { "E88", "Out of memory (NOMEM_8)" },
247 { "E89", "Out of memory (NOMEM_9)" },
248 { "E98", "OVERLOAD" },
249 { "E99", "Software error: proxy is in the deorbiting-burn mode, new session rejected (SLOWSHTDN)" },
250 { 0, NULL }
251 };
252
253 static gint ett_rtpproxy = -1;
254
255 static gint ett_rtpproxy_request = -1;
256 static gint ett_rtpproxy_command = -1;
257 static gint ett_rtpproxy_command_parameters = -1;
258 static gint ett_rtpproxy_command_parameters_codecs = -1;
259 static gint ett_rtpproxy_command_parameters_local = -1;
260 static gint ett_rtpproxy_command_parameters_remote = -1;
261 static gint ett_rtpproxy_command_parameters_repacketize = -1;
262 static gint ett_rtpproxy_command_parameters_dtmf = -1;
263 static gint ett_rtpproxy_command_parameters_cmap = -1;
264 static gint ett_rtpproxy_command_parameters_proto = -1;
265 static gint ett_rtpproxy_command_parameters_transcode = -1;
266 static gint ett_rtpproxy_command_parameters_acc = -1;
267 static gint ett_rtpproxy_tag = -1;
268 static gint ett_rtpproxy_notify = -1;
269
270 static gint ett_rtpproxy_reply = -1;
271
272 static gint ett_rtpproxy_ng_bencode = -1;
273
274 /* Default values */
275 #define RTPPROXY_PORT 22222 /* Not IANA registered */
276 static gboolean rtpproxy_establish_conversation = TRUE;
277 /* See - https://www.opensips.org/html/docs/modules/1.10.x/rtpproxy.html#id293555 */
278 /* See - http://www.kamailio.org/docs/modules/4.3.x/modules/rtpproxy.html#idp15794952 */
279 static guint rtpproxy_timeout = 1000;
280 static nstime_t rtpproxy_timeout_ns = NSTIME_INIT_ZERO;
281
282 void proto_reg_handoff_rtpproxy(void);
283
284 static gint
rtpproxy_add_tag(proto_tree * rtpproxy_tree,tvbuff_t * tvb,guint begin,guint realsize)285 rtpproxy_add_tag(proto_tree *rtpproxy_tree, tvbuff_t *tvb, guint begin, guint realsize)
286 {
287 proto_item *ti = NULL;
288 proto_tree *another_tree = NULL;
289 gint new_offset;
290 guint end;
291
292 new_offset = tvb_find_guint8(tvb, begin, -1, ' ');
293 if(new_offset < 0)
294 end = realsize; /* No more parameters */
295 else
296 end = new_offset;
297
298 /* SER/OpenSER/OpenSIPS/Kamailio adds Media-ID right after the Tag
299 * separated by a semicolon
300 */
301 new_offset = tvb_find_guint8(tvb, begin, end, ';');
302 if(new_offset == -1){
303 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, end - begin, ENC_ASCII | ENC_NA);
304 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
305 ti = proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, 0, ENC_ASCII | ENC_NA);
306 proto_item_append_text(ti, "<skipped>");
307 proto_item_set_generated(ti);
308 }
309 else{
310 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, new_offset - begin, ENC_ASCII | ENC_NA);
311 if ((guint)new_offset == begin){
312 proto_item_append_text(ti, "<skipped>"); /* A very first Offer/Update command */
313 proto_item_set_generated(ti);
314 }
315 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
316 proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, end - (new_offset+1), ENC_ASCII | ENC_NA);
317 }
318 return (end == realsize ? -1 : (gint)end);
319 }
320
321 static void
rtpproxy_add_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * rtpproxy_tree,guint begin,guint realsize)322 rtpproxy_add_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint realsize)
323 {
324 proto_item *ti;
325 proto_tree *another_tree = NULL;
326 guint offset = 0;
327 guint new_offset = 0;
328 gint i;
329 guint pt = 0;
330 gchar** codecs = NULL;
331 guint codec_len;
332 guint8* rawstr = NULL;
333 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
334
335 /* Extract the entire parameters line. */
336 /* Something like "t4p1iic8,0,2,4,18,96,97,98,100,101" */
337 rawstr = tvb_get_string_enc(pinfo->pool, tvb, begin, realsize, ENC_ASCII);
338
339 while(offset < realsize){
340 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameter, tvb, begin + offset, 1, ENC_ASCII | ENC_NA);
341 offset++; /* Skip 1-byte parameter's type */
342 switch (g_ascii_tolower(tvb_get_guint8(tvb, begin+offset-1)))
343 {
344 /* Official long parameters */
345 case 'c':
346 new_offset = (gint)strspn(rawstr+offset, "0123456789,");
347 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_codecs);
348 codecs = wmem_strsplit(pinfo->pool, tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), ",", 0);
349 i = 0;
350 while(codecs[i]){
351 /* We assume strings < 2^32-1 bytes long. :-) */
352 codec_len = (guint)strlen(codecs[i]);
353 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_codec, tvb, begin+offset, codec_len,
354 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, codec_len, ENC_ASCII), NULL, 10));
355 proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(pinfo->pool, tvb,begin+offset,codec_len),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
356 offset += codec_len;
357 if(codecs[i+1])
358 offset++; /* skip comma */
359 i++;
360 };
361 break;
362 case 'l':
363 /* That's another one protocol shortcoming - the same parameter used twice. */
364 /* https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#createupdatelookup-session */
365 /* https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#get-information */
366 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
367 if(new_offset){
368 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_local);
369 if(str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
370 proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_local_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
371 else
372 proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
373 offset += new_offset;
374 }
375 break;
376 case 'r':
377 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
378 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_remote);
379 if(str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
380 proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_remote_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
381 else
382 proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
383 offset += new_offset;
384 break;
385 case 'z':
386 new_offset = (gint)strspn(rawstr+offset, "0123456789");
387 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_repacketize);
388 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_repacketize, tvb, begin+offset, new_offset,
389 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
390 offset += new_offset;
391 break;
392 /* Unofficial long parameters */
393 case 'd':
394 new_offset = (gint)strspn(rawstr+offset, "0123456789");
395 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_dtmf);
396 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_dtmf, tvb, begin+offset, new_offset,
397 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
398 if(rtpproxy_establish_conversation){
399 pt = (guint)strtoul(tvb_format_text(pinfo->pool, tvb,begin+offset,new_offset),NULL,10);
400 dissector_add_uint("rtp.pt", pt, rtp_events_handle);
401 }
402 offset += new_offset;
403 break;
404 case 'm':
405 new_offset = (gint)strspn(rawstr+offset, "0123456789=,");
406 /* TODO */
407 offset += new_offset;
408 break;
409 case 'p':
410 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_proto);
411 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_proto, tvb, begin+offset, 1, ENC_ASCII | ENC_NA);
412 offset++;
413 break;
414 case 't':
415 new_offset = (gint)strspn(rawstr+offset, "0123456789");
416 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_transcode);
417 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_transcode, tvb, begin+offset, new_offset,
418 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
419 proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(pinfo->pool, tvb,begin+offset, new_offset),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
420 offset += new_offset;
421 break;
422 case 'u':
423 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_acc);
424 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_acc, tvb, begin+offset, 1, ENC_ASCII | ENC_NA);
425 offset++;
426 break;
427 default:
428 break;
429 }
430 }
431 }
432
433 static rtpproxy_info_t *
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)434 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)
435 {
436 rtpproxy_info_t *rtpproxy_info;
437 proto_item *pi;
438
439 if (!PINFO_FD_VISITED(pinfo)) {
440 if (is_request){
441 rtpproxy_info = wmem_new0(wmem_file_scope(), rtpproxy_info_t);
442 rtpproxy_info->req_frame = pinfo->num;
443 rtpproxy_info->req_time = pinfo->abs_ts;
444 wmem_tree_insert_string(rtpproxy_conv->trans, cookie, rtpproxy_info, 0);
445 } else {
446 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
447 if (rtpproxy_info) {
448 rtpproxy_info->resp_frame = pinfo->num;
449 }
450 }
451 } else {
452 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
453 if (rtpproxy_info && (is_request ? rtpproxy_info->resp_frame : rtpproxy_info->req_frame)) {
454 nstime_t ns;
455
456 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);
457 proto_item_set_generated(pi);
458
459 /* If not a request (so it's a reply) then calculate response time */
460 if (!is_request){
461 nstime_delta(&ns, &pinfo->abs_ts, &rtpproxy_info->req_time);
462 pi = proto_tree_add_time(rtpproxy_tree, hf_rtpproxy_response_time, tvb, 0, 0, &ns);
463 proto_item_set_generated(pi);
464 if (nstime_cmp(&rtpproxy_timeout_ns, &ns) < 0)
465 expert_add_info_format(pinfo, rtpproxy_tree, &ei_rtpproxy_timeout, "Response timeout %.3f seconds", nstime_to_sec(&ns));
466 }
467 }
468 }
469 /* Could be NULL so we should check it before dereferencing */
470 return rtpproxy_info;
471 }
472
473 static void
rtpproxy_add_notify_addr(tvbuff_t * tvb,packet_info * pinfo,proto_tree * rtpproxy_tree,guint begin,guint end)474 rtpproxy_add_notify_addr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint end)
475 {
476 gint offset = 0;
477 gint tmp = 0;
478 gboolean ipv6 = FALSE;
479 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
480
481 /* Check for at least one colon */
482 offset = tvb_find_guint8(tvb, begin, end, ':');
483 if(offset != -1){
484 /* Find if it's the latest colon (not in case of a IPv6) */
485 while((tmp = tvb_find_guint8(tvb, offset+1, end, ':')) != -1){
486 ipv6 = TRUE;
487 offset = tmp;
488 }
489 /* We have ip:port */
490 if(ipv6){
491 if(str_to_ip6((char*)tvb_get_string_enc(pinfo->pool, tvb, begin, offset - begin, ENC_ASCII), ipaddr))
492 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, offset - begin, (const ws_in6_addr*)ipaddr);
493 else
494 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, begin, offset - begin);
495 }
496 else{
497 if(str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, begin, offset - begin, ENC_ASCII), ipaddr))
498 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, offset - begin, ipaddr[0]);
499 else
500 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin, offset - begin);
501 }
502 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, offset+1, end - (offset+1),
503 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, offset+1, end - (offset+1), ENC_ASCII), NULL, 10));
504 }
505 else{
506 proto_item *ti = NULL;
507 /* Only port is supplied - take IPv4/IPv6 from ip.src/ipv6.src respectively */
508 expert_add_info(pinfo, rtpproxy_tree, &ei_rtpproxy_notify_no_ip);
509 if (pinfo->src.type == AT_IPv4) {
510 ti = proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, 0, *(const guint32*)(pinfo->src.data));
511 } else if (pinfo->src.type == AT_IPv6) {
512 ti = proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, 0, (const ws_in6_addr *)(pinfo->src.data));
513 }
514 if (ti) {
515 proto_item_set_generated(ti);
516 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, begin, end - begin,
517 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, begin, end - begin, ENC_ASCII), NULL, 10));
518 }
519 }
520 }
521
522 static int
dissect_rtpproxy(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)523 dissect_rtpproxy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
524 {
525 gboolean has_lf = FALSE;
526 gint offset = 0;
527 gint new_offset = 0;
528 guint tmp;
529 guint tmp2;
530 gint realsize = 0;
531 guint8* rawstr;
532 const guint8* tmpstr;
533 proto_item *ti;
534 proto_item *ti2;
535 proto_tree *rtpproxy_tree;
536 conversation_t *conversation;
537 rtpproxy_conv_info_t *rtpproxy_conv;
538 const guint8* cookie = NULL;
539 /* For RT(C)P setup */
540 address addr;
541 guint16 port;
542 guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
543 rtpproxy_info_t *rtpproxy_info = NULL;
544 tvbuff_t *subtvb;
545
546 /* If it does not start with a printable character it's not RTPProxy */
547 if(!g_ascii_isprint(tvb_get_guint8(tvb, 0)))
548 return 0;
549
550 /* Extract Cookie */
551 offset = tvb_find_guint8(tvb, offset, -1, ' ');
552 if(offset == -1)
553 return 0;
554
555 /* We believe it's likely a RTPproxy / RTPproxy-ng protocol */
556 /* Note: we no longer distinct between packets with or w/o LF - it turned
557 * out to be useless */
558 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy");
559
560 /* Clear out stuff in the info column - we'll set it later */
561 col_clear(pinfo->cinfo, COL_INFO);
562
563 ti = proto_tree_add_item(tree, proto_rtpproxy, tvb, 0, -1, ENC_NA);
564 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy);
565
566 proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_cookie, tvb, 0, offset, ENC_ASCII | ENC_NA, pinfo->pool, &cookie);
567
568 /* Skip whitespace */
569 offset = tvb_skip_wsp(tvb, offset+1, -1);
570
571 /* Calculate size to prevent recalculation in the future */
572 realsize = tvb_reported_length(tvb);
573
574 /* Don't count trailing zeroes (inserted by some SIP-servers sometimes) */
575 while (tvb_get_guint8(tvb, realsize - 1) == 0){
576 realsize -= 1;
577 }
578
579 /* Check for LF (required for TCP connection, optional for UDP) */
580 if (tvb_get_guint8(tvb, realsize - 1) == '\n'){
581 /* Don't count trailing LF */
582 realsize -= 1;
583 has_lf = TRUE;
584 }
585
586 /* Try to create conversation */
587 conversation = find_or_create_conversation(pinfo);
588 rtpproxy_conv = (rtpproxy_conv_info_t *)conversation_get_proto_data(conversation, proto_rtpproxy);
589 if (!rtpproxy_conv) {
590 rtpproxy_conv = wmem_new(wmem_file_scope(), rtpproxy_conv_info_t);
591 rtpproxy_conv->trans = wmem_tree_new(wmem_file_scope());
592 conversation_add_proto_data(conversation, proto_rtpproxy, rtpproxy_conv);
593 }
594
595 /* Get payload string */
596 rawstr = tvb_format_text(pinfo->pool, tvb, offset, realsize - offset);
597
598 /* Extract command */
599 tmp = g_ascii_tolower(tvb_get_guint8(tvb, offset));
600 switch (tmp)
601 {
602 case 's':
603 /* A specific case - long info answer */
604 /* %COOKIE% sessions created %NUM0% active sessions: %NUM1% */
605 /* FIXME https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#information */
606 rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
607 if ('e' == tvb_get_guint8(tvb, offset+1)){
608 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
609 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
610
611 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
612 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_status, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
613 break;
614 }
615 /* FALL THROUGH */
616 case 'i':
617 case 'x':
618 case 'u':
619 case 'l':
620 case 'd':
621 tmp2 = tvb_get_guint8(tvb, offset+1);
622 if(('1' <= tmp2) && (tmp2 <= '9') && (tvb_get_guint8(tvb, offset+2) == ':')){
623 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy-ng");
624 col_add_fstr(pinfo->cinfo, COL_INFO, "RTPproxy-ng: %s", rawstr);
625 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ng_bencode, tvb, offset, -1, ENC_ASCII | ENC_NA);
626 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_ng_bencode);
627 subtvb = tvb_new_subset_remaining(tvb, offset);
628 call_dissector(bencode_handle, subtvb, pinfo, rtpproxy_tree);
629 break;
630 }
631 /* FALL THROUGH */
632 case 'p':
633 case 'v':
634 case 'r':
635 case 'c':
636 case 'q':
637 rtpproxy_info = rtpproxy_add_tid(TRUE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
638 col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s", rawstr);
639 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_request, tvb, offset, -1, ENC_NA);
640 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_request);
641
642 /* A specific case - version request:
643 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#get-list-of-veatures
644 *
645 * In this case a command size must be bigger or equal to a "VF YYYYMMDD" string size.
646 * It's bigger if there is more than one space inserted between "VF" and "YYYYMMDD" tokens.
647 */
648 if ((tmp == 'v') && (offset + (gint)strlen("VF YYYYMMDD") <= realsize)){
649 /* Skip whitespace between "VF" and "YYYYMMDD" tokens */
650 new_offset = tvb_skip_wsp(tvb, offset + ((guint)strlen("VF") + 1), -1);
651 ti = proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_version_request, tvb, new_offset, (gint)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA, pinfo->pool, &tmpstr);
652 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, versiontypenames, "Unknown"));
653 break;
654 }
655
656 /* All other commands */
657 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command, tvb, offset, 1, ENC_ASCII | ENC_NA);
658
659 /* A specific case - handshake/ping */
660 if (tmp == 'v')
661 break; /* No more parameters */
662
663 /* A specific case - close all calls */
664 if (tmp == 'x')
665 break; /* No more parameters */
666
667 /* Extract parameters */
668 /* Parameters should be right after the command and before EOL (in case of Info command) or before whitespace */
669 new_offset = (tmp == 'i' ? (realsize - 1 > offset ? offset + (gint)strlen("Ib") : offset + (gint)strlen("I")) : tvb_find_guint8(tvb, offset, -1, ' '));
670
671 if (new_offset != offset + 1){
672 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_command);
673 ti2 = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameters, tvb, offset+1, new_offset - (offset+1), ENC_ASCII | ENC_NA);
674 rtpproxy_add_parameter(tvb, pinfo, proto_item_add_subtree(ti2, ett_rtpproxy_command_parameters), offset+1, new_offset - (offset+1));
675 rtpproxy_tree = proto_item_get_parent(ti);
676 }
677
678 /* A specific case - query information */
679 if (tmp == 'i')
680 break; /* No more parameters */
681
682 /* Skip whitespace */
683 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
684
685 /* Extract Call-ID */
686 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
687 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
688 if(rtpproxy_info && !rtpproxy_info->callid)
689 rtpproxy_info->callid = tvb_get_string_enc(wmem_file_scope(), tvb, offset, new_offset - offset, ENC_ASCII);
690 /* Skip whitespace */
691 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
692
693 /* Extract IP and Port in case of Offer/Answer */
694 if ((tmp == 'u') || (tmp == 'l')){
695 /* Extract IP */
696 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
697 if (tvb_find_guint8(tvb, offset, new_offset - offset, ':') == -1){
698 if(str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
699 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, new_offset - offset, ipaddr[0]);
700 else
701 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, new_offset - offset);
702 }
703 else{
704 if(str_to_ip6((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
705 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, new_offset - offset, (const ws_in6_addr *)ipaddr);
706 else
707 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, new_offset - offset);
708 }
709 /* Skip whitespace */
710 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
711
712 /* Extract Port */
713 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
714 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset,
715 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
716 /* Skip whitespace */
717 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
718 }
719
720 /* Extract Copy target */
721 if (tmp == 'c'){
722 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
723 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_copy_target, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
724 /* Skip whitespace */
725 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
726 }
727
728 /* Extract Playback file and codecs */
729 if (tmp == 'p'){
730 /* Extract filename */
731 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
732 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_playback_filename, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
733 /* Skip whitespace */
734 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
735
736 /* Extract codec */
737 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
738 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_playback_codec, tvb, offset, new_offset - offset,
739 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
740 /* Skip whitespace */
741 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
742 }
743
744 /* Extract first tag */
745 new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
746 if(new_offset == -1)
747 break; /* No more parameters */
748 /* Skip whitespace */
749 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
750
751 /* Extract second tag */
752 new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
753 if(new_offset == -1)
754 break; /* No more parameters */
755 /* Skip whitespace */
756 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
757
758 /* Extract Notification address */
759 if (tmp == 'u'){
760 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
761 proto_item_set_text(ti, "Notify");
762 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_notify);
763
764 /* Check for NotifyTag parameter (separated by space) */
765 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
766 if(new_offset == -1){
767 /* NotifyTag wasn't found (we should re-use Call-ID instead) */
768 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, realsize);
769 break; /* No more parameters */
770 }
771
772 /* NotifyTag was found */
773 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, new_offset);
774 /* Skip whitespace */
775 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
776
777 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_tag, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
778 }
779 break;
780 case 'e':
781 case '0':
782 case '1':
783 case '2':
784 case '3':
785 case '4':
786 case '5':
787 case '6':
788 case '7':
789 case '8':
790 case '9':
791 rtpproxy_info = rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
792 if (tmp == 'e')
793 col_add_fstr(pinfo->cinfo, COL_INFO, "Error reply: %s", rawstr);
794 else
795 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
796
797 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
798 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
799
800 if(rtpproxy_info && rtpproxy_info->callid){
801 ti = proto_tree_add_string(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, 0, rtpproxy_info->callid);
802 proto_item_set_generated(ti);
803 }
804
805 if (tmp == 'e'){
806 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
807 tmpstr = tvb_get_string_enc(pinfo->pool, tvb, offset, tmp, ENC_ASCII);
808 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_error, tvb, offset, (gint)strlen(tmpstr), ENC_ASCII | ENC_NA);
809 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, errortypenames, "Unknown"));
810 break;
811 }
812
813 /* Check for a single '0' or '1' character followed by the end-of-line.
814 * These both are positive replies - either a 'positive reply' or a 'version ack'.
815 *
816 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#positive-reply
817 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#version-reply
818 */
819 if (((tmp == '0') || (tmp == '1')) && (realsize == offset + (gint)strlen("X"))){
820 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ok, tvb, offset, 1, ENC_ASCII | ENC_NA);
821 break;
822 }
823
824 /* Check for the VERSION_NUMBER string reply:
825 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#version-reply
826 *
827 * If a total size equals to a current offset + size of "YYYYMMDD" string
828 * then it's a version reply.
829 */
830 if (realsize == offset + (gint)strlen("YYYYMMDD")){
831 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_version_supported, tvb, offset, (guint32)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA);
832 break;
833 }
834
835 /* Extract Port */
836 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
837 /* Convert port to unsigned 16-bit number */
838 port = (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10);
839 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset, port);
840 /* Skip whitespace */
841 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
842
843 /* Extract IP */
844 memset(&addr, 0, sizeof(address));
845
846 /* Try rtpengine bogus extension first. It appends 4 or
847 * 6 depending on type of the IP. See
848 * https://github.com/sipwise/rtpengine/blob/eea3256/daemon/call_interfaces.c#L74
849 * for further details */
850 tmp = tvb_find_guint8(tvb, offset, -1, ' ');
851 if(tmp == (guint)(-1)){
852 /* No extension - operate normally */
853 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
854 }
855 else {
856 tmp -= offset;
857 }
858
859 if (tvb_find_guint8(tvb, offset, -1, ':') == -1){
860 if (str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, tmp, ENC_ASCII), ipaddr)){
861 addr.type = AT_IPv4;
862 addr.len = 4;
863 addr.data = wmem_memdup(pinfo->pool, ipaddr, 4);
864 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, tmp, ipaddr[0]);
865 }
866 else
867 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, tmp);
868 }
869 else{
870 if (str_to_ip6((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, tmp, ENC_ASCII), ipaddr)){
871 addr.type = AT_IPv6;
872 addr.len = 16;
873 addr.data = wmem_memdup(pinfo->pool, ipaddr, 16);
874 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, tmp, (const ws_in6_addr *)ipaddr);
875 }
876 else
877 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, tmp);
878 }
879
880 if(rtpproxy_establish_conversation){
881 if (rtp_handle) {
882 /* FIXME tell if isn't a video stream, and setup codec mapping */
883 if (addr.len)
884 rtp_add_address(pinfo, PT_UDP, &addr, port, 0, "RTPproxy", pinfo->num, 0, NULL);
885 }
886 if (rtcp_handle) {
887 if (addr.len)
888 rtcp_add_address(pinfo, &addr, port+1, 0, "RTPproxy", pinfo->num);
889 }
890 }
891 break;
892 default:
893 break;
894 }
895 /* TODO add an expert warning about packets w/o LF sent over TCP */
896 if (has_lf)
897 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_lf, tvb, realsize, 1, ENC_NA);
898
899 return tvb_captured_length(tvb);
900 }
901
902 void
proto_register_rtpproxy(void)903 proto_register_rtpproxy(void)
904 {
905 module_t *rtpproxy_module;
906 expert_module_t* expert_rtpproxy_module;
907
908 static hf_register_info hf[] = {
909 {
910 &hf_rtpproxy_cookie,
911 {
912 "Cookie",
913 "rtpproxy.cookie",
914 FT_STRING,
915 BASE_NONE,
916 NULL,
917 0x0,
918 NULL,
919 HFILL
920 }
921 },
922 {
923 &hf_rtpproxy_version_request,
924 {
925 "Version Request",
926 "rtpproxy.version",
927 FT_STRING,
928 BASE_NONE,
929 NULL,
930 0x0,
931 NULL,
932 HFILL
933 }
934 },
935 {
936 &hf_rtpproxy_version_supported,
937 {
938 "Version Supported",
939 "rtpproxy.version_supported",
940 FT_STRING,
941 BASE_NONE,
942 NULL,
943 0x0,
944 NULL,
945 HFILL
946 }
947 },
948 {
949 &hf_rtpproxy_error,
950 {
951 "Error",
952 "rtpproxy.error",
953 FT_STRING,
954 BASE_NONE,
955 NULL,
956 0x0,
957 NULL,
958 HFILL
959 }
960 },
961 {
962 &hf_rtpproxy_ok,
963 {
964 "Ok",
965 "rtpproxy.ok",
966 FT_CHAR,
967 BASE_HEX,
968 VALS(oktypenames),
969 0x0,
970 NULL,
971 HFILL
972 }
973 },
974 {
975 &hf_rtpproxy_status,
976 {
977 "Status",
978 "rtpproxy.status",
979 FT_STRING,
980 BASE_NONE,
981 NULL,
982 0x0,
983 NULL,
984 HFILL
985 }
986 },
987 {
988 &hf_rtpproxy_ipv4,
989 {
990 "IPv4",
991 "rtpproxy.ipv4",
992 FT_IPv4,
993 BASE_NONE,
994 NULL,
995 0x0,
996 NULL,
997 HFILL
998 }
999 },
1000 {
1001 &hf_rtpproxy_ipv6,
1002 {
1003 "IPv6",
1004 "rtpproxy.ipv6",
1005 FT_IPv6,
1006 BASE_NONE,
1007 NULL,
1008 0x0,
1009 NULL,
1010 HFILL
1011 }
1012 },
1013 {
1014 &hf_rtpproxy_port,
1015 {
1016 "Port",
1017 "rtpproxy.port",
1018 FT_UINT16, /* 0 - 65535 */
1019 BASE_DEC,
1020 NULL,
1021 0x0,
1022 NULL,
1023 HFILL
1024 }
1025 },
1026 {
1027 &hf_rtpproxy_request,
1028 {
1029 "Request",
1030 "rtpproxy.request",
1031 FT_NONE,
1032 BASE_NONE,
1033 NULL,
1034 0x0,
1035 NULL,
1036 HFILL
1037 }
1038 },
1039 {
1040 &hf_rtpproxy_command,
1041 {
1042 "Command",
1043 "rtpproxy.command",
1044 FT_CHAR,
1045 BASE_HEX,
1046 VALS(commandtypenames),
1047 0x0,
1048 NULL,
1049 HFILL
1050 }
1051 },
1052 {
1053 &hf_rtpproxy_command_parameters,
1054 {
1055 "Command parameters",
1056 "rtpproxy.command_parameters",
1057 FT_STRING,
1058 BASE_NONE,
1059 NULL,
1060 0x0,
1061 NULL,
1062 HFILL
1063 }
1064 },
1065 {
1066 &hf_rtpproxy_command_parameter,
1067 {
1068 "Parameter",
1069 "rtpproxy.command_parameter",
1070 FT_CHAR,
1071 BASE_HEX,
1072 VALS(paramtypenames),
1073 0x0,
1074 NULL,
1075 HFILL
1076 }
1077 },
1078 {
1079 &hf_rtpproxy_command_parameter_codec,
1080 {
1081 "Allowed codec",
1082 "rtpproxy.command_parameter_codec",
1083 FT_UINT8, /* 0 - 127 */
1084 BASE_DEC,
1085 NULL,
1086 0x0,
1087 NULL,
1088 HFILL
1089 }
1090 },
1091 {
1092 &hf_rtpproxy_command_parameter_local_ipv4,
1093 {
1094 "Local IPv4 address",
1095 "rtpproxy.command_parameter_local_ipv4",
1096 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1097 BASE_NONE,
1098 NULL,
1099 0x0,
1100 NULL,
1101 HFILL
1102 }
1103 },
1104 {
1105 &hf_rtpproxy_command_parameter_remote_ipv4,
1106 {
1107 "Remote IPv4 address",
1108 "rtpproxy.command_parameter_remote_ipv4",
1109 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1110 BASE_NONE,
1111 NULL,
1112 0x0,
1113 NULL,
1114 HFILL
1115 }
1116 },
1117 {
1118 &hf_rtpproxy_command_parameter_repacketize,
1119 {
1120 "Repacketize (ms)",
1121 "rtpproxy.command_parameter_repacketize",
1122 FT_UINT16, /* 0 - 1000 milliseconds */
1123 BASE_DEC,
1124 NULL,
1125 0x0,
1126 NULL,
1127 HFILL
1128 }
1129 },
1130 {
1131 &hf_rtpproxy_command_parameter_dtmf,
1132 {
1133 "DTMF payload ID",
1134 "rtpproxy.command_parameter_dtmf",
1135 FT_UINT8, /* 0 - 127 */
1136 BASE_DEC,
1137 NULL,
1138 0x0,
1139 NULL,
1140 HFILL
1141 }
1142 },
1143 {
1144 &hf_rtpproxy_command_parameter_proto,
1145 {
1146 "RTP transmission protocol",
1147 "rtpproxy.command_parameter_proto",
1148 FT_CHAR,
1149 BASE_HEX,
1150 VALS(prototypenames),
1151 0x0,
1152 NULL,
1153 HFILL
1154 }
1155 },
1156 {
1157 &hf_rtpproxy_command_parameter_transcode,
1158 {
1159 "Transcode to",
1160 "rtpproxy.command_parameter_transcode",
1161 FT_UINT8, /* 0 - 127 */
1162 BASE_DEC,
1163 NULL,
1164 0x0,
1165 NULL,
1166 HFILL
1167 }
1168 },
1169 {
1170 &hf_rtpproxy_command_parameter_acc,
1171 {
1172 "Accounting",
1173 "rtpproxy.command_parameter_acc",
1174 FT_CHAR,
1175 BASE_HEX,
1176 VALS(acctypenames),
1177 0x0,
1178 NULL,
1179 HFILL
1180 }
1181 },
1182 {
1183 &hf_rtpproxy_copy_target,
1184 {
1185 "Copy target",
1186 "rtpproxy.copy_target",
1187 FT_STRING, /* Filename or UDP address, e.g. /var/tmp/fileXXXX.yyy or IP:Port */
1188 BASE_NONE,
1189 NULL,
1190 0x0,
1191 NULL,
1192 HFILL
1193 }
1194 },
1195 {
1196 &hf_rtpproxy_playback_filename,
1197 {
1198 "Playback filename",
1199 "rtpproxy.playback_filename",
1200 FT_STRING,
1201 BASE_NONE,
1202 NULL,
1203 0x0,
1204 NULL,
1205 HFILL
1206 }
1207 },
1208 {
1209 &hf_rtpproxy_playback_codec,
1210 {
1211 "Playback codec",
1212 "rtpproxy.playback_codec",
1213 FT_UINT8, /* 0 - 127 */
1214 BASE_DEC,
1215 NULL,
1216 0x0,
1217 NULL,
1218 HFILL
1219 }
1220 },
1221 {
1222 &hf_rtpproxy_callid,
1223 {
1224 "Call-ID",
1225 "rtpproxy.callid",
1226 FT_STRING,
1227 BASE_NONE,
1228 NULL,
1229 0x0,
1230 NULL,
1231 HFILL
1232 }
1233 },
1234 {
1235 &hf_rtpproxy_notify,
1236 {
1237 "Notify",
1238 "rtpproxy.notify",
1239 FT_STRING,
1240 BASE_NONE,
1241 NULL,
1242 0x0,
1243 NULL,
1244 HFILL
1245 }
1246 },
1247 {
1248 &hf_rtpproxy_tag,
1249 {
1250 "Tag",
1251 "rtpproxy.tag",
1252 FT_STRING,
1253 BASE_NONE,
1254 NULL,
1255 0x0,
1256 NULL,
1257 HFILL
1258 }
1259 },
1260 {
1261 &hf_rtpproxy_mediaid,
1262 {
1263 "Media-ID",
1264 "rtpproxy.mediaid",
1265 FT_STRING,
1266 BASE_NONE,
1267 NULL,
1268 0x0,
1269 NULL,
1270 HFILL
1271 }
1272 },
1273 {
1274 &hf_rtpproxy_notify_ipv4,
1275 {
1276 "Notification IPv4",
1277 "rtpproxy.notify_ipv4",
1278 FT_IPv4,
1279 BASE_NONE,
1280 NULL,
1281 0x0,
1282 NULL,
1283 HFILL
1284 }
1285 },
1286 {
1287 &hf_rtpproxy_notify_ipv6,
1288 {
1289 "Notification IPv6",
1290 "rtpproxy.notify_ipv6",
1291 FT_IPv6,
1292 BASE_NONE,
1293 NULL,
1294 0x0,
1295 NULL,
1296 HFILL
1297 }
1298 },
1299 {
1300 &hf_rtpproxy_notify_port,
1301 {
1302 "Notification Port",
1303 "rtpproxy.notify_port",
1304 FT_UINT16,
1305 BASE_DEC,
1306 NULL,
1307 0x0,
1308 NULL,
1309 HFILL
1310 }
1311 },
1312 {
1313 &hf_rtpproxy_notify_tag,
1314 {
1315 "Notification Tag",
1316 "rtpproxy.notify_tag",
1317 FT_STRING,
1318 BASE_NONE,
1319 NULL,
1320 0x0,
1321 NULL,
1322 HFILL
1323 }
1324 },
1325 {
1326 &hf_rtpproxy_reply,
1327 {
1328 "Reply",
1329 "rtpproxy.reply",
1330 FT_NONE,
1331 BASE_NONE,
1332 NULL,
1333 0x0,
1334 NULL,
1335 HFILL
1336 }
1337 },
1338 {
1339 &hf_rtpproxy_lf,
1340 {
1341 "LF",
1342 "rtpproxy.lf",
1343 FT_NONE,
1344 BASE_NONE,
1345 NULL,
1346 0x0,
1347 NULL,
1348 HFILL
1349 }
1350 },
1351 {
1352 &hf_rtpproxy_request_in,
1353 {
1354 "Request In",
1355 "rtpproxy.request_in",
1356 FT_FRAMENUM,
1357 BASE_NONE,
1358 NULL,
1359 0x0,
1360 NULL,
1361 HFILL
1362 }
1363
1364 },
1365 {
1366 &hf_rtpproxy_response_in,
1367 {
1368 "Response In",
1369 "rtpproxy.response_in",
1370 FT_FRAMENUM,
1371 BASE_NONE,
1372 NULL,
1373 0x0,
1374 NULL,
1375 HFILL
1376 }
1377 },
1378 {
1379 &hf_rtpproxy_response_time,
1380 {
1381 "Response Time",
1382 "rtpproxy.response_time",
1383 FT_RELATIVE_TIME,
1384 BASE_NONE,
1385 NULL,
1386 0x0,
1387 "The time between the Request and the Reply",
1388 HFILL
1389 }
1390 },
1391 {
1392 &hf_rtpproxy_ng_bencode,
1393 {
1394 "RTPproxy-ng bencode packet",
1395 "rtpproxy.ng.bencode",
1396 FT_STRING,
1397 BASE_NONE,
1398 NULL,
1399 0x0,
1400 "Serialized structure of integers, dictionaries, strings and lists.",
1401 HFILL
1402 }
1403 }
1404 };
1405
1406 static ei_register_info ei[] = {
1407 { &ei_rtpproxy_timeout,
1408 { "rtpproxy.response_timeout", PI_RESPONSE_CODE, PI_WARN,
1409 "TIMEOUT", EXPFILL }},
1410 { &ei_rtpproxy_notify_no_ip,
1411 { "rtpproxy.notify_no_ip", PI_RESPONSE_CODE, PI_COMMENT,
1412 "No notification IP address provided. Using ip.src or ipv6.src as a value.", EXPFILL }},
1413 { &ei_rtpproxy_bad_ipv4,
1414 { "rtpproxy.bad_ipv4", PI_MALFORMED, PI_ERROR,
1415 "Bad IPv4", EXPFILL }},
1416 { &ei_rtpproxy_bad_ipv6,
1417 { "rtpproxy.bad_ipv6", PI_MALFORMED, PI_ERROR,
1418 "Bad IPv6", EXPFILL }},
1419 };
1420
1421 /* Setup protocol subtree array */
1422 static gint *ett[] = {
1423 &ett_rtpproxy,
1424 &ett_rtpproxy_request,
1425 &ett_rtpproxy_command,
1426 &ett_rtpproxy_command_parameters,
1427 &ett_rtpproxy_command_parameters_codecs,
1428 &ett_rtpproxy_command_parameters_local,
1429 &ett_rtpproxy_command_parameters_remote,
1430 &ett_rtpproxy_command_parameters_repacketize,
1431 &ett_rtpproxy_command_parameters_dtmf,
1432 &ett_rtpproxy_command_parameters_cmap,
1433 &ett_rtpproxy_command_parameters_proto,
1434 &ett_rtpproxy_command_parameters_transcode,
1435 &ett_rtpproxy_command_parameters_acc,
1436 &ett_rtpproxy_tag,
1437 &ett_rtpproxy_notify,
1438 &ett_rtpproxy_reply,
1439 &ett_rtpproxy_ng_bencode
1440 };
1441
1442 proto_rtpproxy = proto_register_protocol ("Sippy RTPproxy Protocol", "RTPproxy", "rtpproxy");
1443
1444 proto_register_field_array(proto_rtpproxy, hf, array_length(hf));
1445 proto_register_subtree_array(ett, array_length(ett));
1446
1447 expert_rtpproxy_module = expert_register_protocol(proto_rtpproxy);
1448 expert_register_field_array(expert_rtpproxy_module, ei, array_length(ei));
1449
1450 rtpproxy_module = prefs_register_protocol(proto_rtpproxy, proto_reg_handoff_rtpproxy);
1451
1452 prefs_register_bool_preference(rtpproxy_module, "establish_conversation",
1453 "Establish Media Conversation",
1454 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
1455 "upon port numbers found in RTPproxy answers",
1456 &rtpproxy_establish_conversation);
1457
1458 prefs_register_uint_preference(rtpproxy_module, "reply.timeout",
1459 "RTPproxy reply timeout", /* Title */
1460 "Maximum timeout value in waiting for reply from RTPProxy (in milliseconds).", /* Descr */
1461 10,
1462 &rtpproxy_timeout);
1463 }
1464
1465 void
proto_reg_handoff_rtpproxy(void)1466 proto_reg_handoff_rtpproxy(void)
1467 {
1468 static gboolean rtpproxy_initialized = FALSE;
1469
1470 dissector_handle_t rtpproxy_tcp_handle, rtpproxy_udp_handle;
1471
1472 if(!rtpproxy_initialized){
1473 rtpproxy_tcp_handle = create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1474 rtpproxy_udp_handle = create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1475
1476 /* Register TCP port for dissection */
1477 dissector_add_uint_with_preference("tcp.port", RTPPROXY_PORT, rtpproxy_tcp_handle);
1478 dissector_add_uint_with_preference("udp.port", RTPPROXY_PORT, rtpproxy_udp_handle);
1479 rtpproxy_initialized = TRUE;
1480 }
1481
1482 rtcp_handle = find_dissector_add_dependency("rtcp", proto_rtpproxy);
1483 rtp_events_handle = find_dissector_add_dependency("rtpevent", proto_rtpproxy);
1484 rtp_handle = find_dissector_add_dependency("rtp", proto_rtpproxy);
1485 bencode_handle = find_dissector_add_dependency("bencode", proto_rtpproxy);
1486
1487 /* Calculate nstime_t struct for the timeout from the rtpproxy_timeout value in milliseconds */
1488 rtpproxy_timeout_ns.secs = (rtpproxy_timeout - rtpproxy_timeout % 1000) / 1000;
1489 rtpproxy_timeout_ns.nsecs = (rtpproxy_timeout % 1000) * 1000;
1490 }
1491
1492 /*
1493 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1494 *
1495 * Local variables:
1496 * c-basic-offset: 4
1497 * tab-width: 8
1498 * indent-tabs-mode: nil
1499 * End:
1500 *
1501 * vi: set shiftwidth=4 tabstop=8 expandtab:
1502 * :indentSize=4:tabSize=8:noTabs=true:
1503 */
1504