Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rtpproxy.c
blobf8ef82dae90a72a60b141138c2249d2b150e9b47
1 /* packet-rtpproxy.c
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
17 #include "config.h"
19 #include <stdlib.h>
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 #include <epan/strutil.h>
29 /* For setting up RTP/RTCP dissectors based on the RTPproxy's answers */
30 #include "packet-rtp.h"
31 #include "packet-rtcp.h"
33 void proto_register_rtpproxy(void);
35 static dissector_handle_t rtpproxy_handle;
37 static int proto_rtpproxy;
39 static int hf_rtpproxy_cookie;
40 static int hf_rtpproxy_error;
41 static int hf_rtpproxy_status;
42 static int hf_rtpproxy_ok;
43 static int hf_rtpproxy_ipv4;
44 static int hf_rtpproxy_ipv6;
45 static int hf_rtpproxy_port;
46 static int hf_rtpproxy_lf;
47 static int hf_rtpproxy_request;
48 static int hf_rtpproxy_command;
49 static int hf_rtpproxy_command_parameters;
50 static int hf_rtpproxy_command_parameter;
51 static int hf_rtpproxy_command_parameter_codec;
52 static int hf_rtpproxy_command_parameter_local_ipv4;
53 static int hf_rtpproxy_command_parameter_remote_ipv4;
54 static int hf_rtpproxy_command_parameter_repacketize;
55 static int hf_rtpproxy_command_parameter_dtmf;
56 /* static int hf_rtpproxy_command_parameter_cmap; TODO */
57 static int hf_rtpproxy_command_parameter_proto;
58 static int hf_rtpproxy_command_parameter_transcode;
59 static int hf_rtpproxy_command_parameter_acc;
60 static int hf_rtpproxy_callid;
61 static int hf_rtpproxy_copy_target;
62 static int hf_rtpproxy_playback_filename;
63 static int hf_rtpproxy_playback_codec;
64 static int hf_rtpproxy_notify;
65 static int hf_rtpproxy_notify_ipv4;
66 static int hf_rtpproxy_notify_ipv6;
67 static int hf_rtpproxy_notify_port;
68 static int hf_rtpproxy_notify_tag;
69 static int hf_rtpproxy_tag;
70 static int hf_rtpproxy_mediaid;
71 static int hf_rtpproxy_reply;
72 static int hf_rtpproxy_version_request;
73 static int hf_rtpproxy_version_supported;
74 static int hf_rtpproxy_ng_bencode;
76 /* Expert fields */
77 static expert_field ei_rtpproxy_timeout;
78 static expert_field ei_rtpproxy_notify_no_ip;
79 static expert_field ei_rtpproxy_bad_ipv4;
80 static expert_field ei_rtpproxy_bad_ipv6;
82 /* Request/response tracking */
83 static int hf_rtpproxy_request_in;
84 static int hf_rtpproxy_response_in;
85 static int hf_rtpproxy_response_time;
87 typedef struct _rtpproxy_info {
88 uint32_t req_frame;
89 uint32_t resp_frame;
90 nstime_t req_time;
91 char* callid;
92 } rtpproxy_info_t;
94 static dissector_handle_t rtcp_handle;
95 static dissector_handle_t rtp_events_handle;
96 static dissector_handle_t rtp_handle;
97 static dissector_handle_t bencode_handle;
99 typedef struct _rtpproxy_conv_info {
100 wmem_tree_t *trans;
101 } rtpproxy_conv_info_t;
104 static const string_string versiontypenames[] = {
105 { "20040107", "Basic RTP proxy functionality" },
106 { "20050322", "Support for multiple RTP streams and MOH" },
107 { "20060704", "Support for extra parameter in the V command" },
108 { "20071116", "Support for RTP re-packetization" },
109 { "20071218", "Support for forking (copying) RTP stream" },
110 { "20080403", "Support for RTP statistics querying" },
111 { "20081102", "Support for setting codecs in the update/lookup command" },
112 { "20081224", "Support for session timeout notifications" },
113 { "20090810", "Support for automatic bridging" },
114 { "20140323", "Support for tracking/reporting load" },
115 { "20140617", "Support for anchoring session connect time" },
116 { "20141004", "Support for extendable performance counters" },
117 { "20150330", "Support for allocating a new port (\"Un\"/\"Ln\" commands)" },
118 { NULL, NULL }
121 static const value_string commandtypenames[] = {
122 { 'V', "Handshake/Ping" },
123 { 'v', "Handshake/Ping" },
124 { 'U', "Offer/Update" },
125 { 'u', "Offer/Update" },
126 { 'L', "Answer/Lookup" },
127 { 'l', "Answer/Lookup" },
128 { 'I', "Information"},
129 { 'i', "Information"},
130 { 'X', "Close all active sessions"},
131 { 'x', "Close all active sessions"},
132 { 'D', "Delete an active session (Bye/Cancel/Error)"},
133 { 'd', "Delete an active session (Bye/Cancel/Error)"},
134 { 'P', "Start playback (music-on-hold)"},
135 { 'p', "Start playback (music-on-hold)"},
136 { 'S', "Stop playback (music-on-hold)"},
137 { 's', "Stop playback (music-on-hold)"},
138 { 'R', "Start recording"},
139 { 'r', "Start recording"},
140 { 'C', "Copy stream"},
141 { 'c', "Copy stream"},
142 { 'Q', "Query info about a session"},
143 { 'q', "Query info about a session"},
144 { 0, NULL }
147 static const value_string paramtypenames[] = {
148 /* Official command parameters */
149 {'4', "Remote address is IPv4"},
150 {'6', "Remote address is IPv6"},
151 {'a', "Asymmetric stream"},
152 {'A', "Asymmetric stream"},
153 {'b', "Brief stats"},
154 {'B', "Brief stats"},
155 {'c', "Codecs"},
156 {'C', "Codecs"},
157 {'e', "External network (non RFC 1918)"},
158 {'E', "External network (non RFC 1918)"},
159 {'i', "Internal network (RFC 1918)"},
160 {'I', "Internal network (RFC 1918)"},
161 {'l', "Local address / Load average"},
162 {'L', "Local address / Load average"},
163 {'n', "request New port"},
164 {'N', "request New port"},
165 {'r', "Remote address"},
166 {'R', "Remote address"},
167 {'s', "Symmetric stream / Single file"},
168 {'S', "Symmetric stream / Single file"},
169 {'w', "Weak connection (allows roaming)"},
170 {'W', "Weak connection (allows roaming)"},
171 {'z', "repacketiZe"},
172 {'Z', "repacketiZe"},
173 /* Unofficial command parameters / extensions */
174 {'d', "DTMF payload ID (unofficial extension)"},
175 {'D', "DTMF payload ID (unofficial extension)"},
176 {'m', "codec Mapping (unofficial extension)"},
177 {'M', "codec Mapping (unofficial extension)"},
178 {'p', "Protocol type (unofficial extension)"},
179 {'P', "Protocol type (unofficial extension)"},
180 {'t', "Transcode to (unofficial extension)"},
181 {'T', "Transcode to (unofficial extension)"},
182 {'u', "accoUnting (unofficial extension)"},
183 {'U', "accoUnting (unofficial extension)"},
184 {0, NULL}
187 static const value_string prototypenames[] = {
188 { '0', "UDP (default)"},
189 { '1', "TCP"},
190 { '2', "SCTP"},
191 { 0, NULL }
193 static const value_string acctypenames[] = {
194 { '0', "Start"},
195 { '1', "Interim update"},
196 { '2', "Stop"},
197 { 0, NULL }
200 static const value_string oktypenames[] = {
201 { '0', "Ok"},
202 { '1', "Version Supported"},
203 { 0, NULL }
206 static const string_string errortypenames[] = {
207 { "E0", "Syntax error: unknown command (CMDUNKN)" },
208 { "E1", "Syntax error: invalid number of arguments (PARSE_NARGS)" },
209 { "E2", "Syntax error: modifiers are not supported by the command (PARSE_MODS)" },
210 { "E3", "Syntax error: subcommand is not supported (PARSE_SUBC)" },
211 { "E5", "PARSE_1" },
212 { "E6", "PARSE_2" },
213 { "E7", "PARSE_3" },
214 { "E8", "PARSE_4" },
215 { "E9", "PARSE_5" },
216 { "E10", "PARSE_10" },
217 { "E11", "PARSE_11" },
218 { "E12", "PARSE_12" },
219 { "E13", "PARSE_13" },
220 { "E14", "PARSE_14" },
221 { "E15", "PARSE_15" },
222 { "E16", "PARSE_16" },
223 { "E17", "PARSE_6" },
224 { "E18", "PARSE_7" },
225 { "E19", "PARSE_8" },
226 { "E25", "Software error: output buffer overflow (RTOOBIG_1)" },
227 { "E26", "Software error: output buffer overflow (RTOOBIG_2)" },
228 { "E31", "Syntax error: invalid local address (INVLARG_1)" },
229 { "E32", "Syntax error: invalid remote address (INVLARG_2)" },
230 { "E33", "Syntax error: can't find local address for remote address (INVLARG_3)" },
231 { "E34", "Syntax error: invalid local address (INVLARG_4)" },
232 { "E35", "Syntax error: no codecs (INVLARG_5)" },
233 { "E36", "Syntax error: cannot match local address for the session (INVLARG_6)" },
234 { "E50", "Software error: session not found (SESUNKN)" },
235 { "E60", "PLRFAIL" },
236 { "E62", "Software error: unsupported/invalid counter name (QRYFAIL)" },
237 { "E65", "CPYFAIL" },
238 { "E68", "STSFAIL" },
239 { "E71", "Software error: can't create listener (LSTFAIL_1)" },
240 { "E72", "Software error: can't create listener (LSTFAIL_2)" },
241 { "E75", "Software error: must permit notification socket with -n (NSOFF)" },
242 { "E81", "Out of memory (NOMEM_1)" },
243 { "E82", "Out of memory (NOMEM_2)" },
244 { "E83", "Out of memory (NOMEM_3)" },
245 { "E84", "Out of memory (NOMEM_4)" },
246 { "E85", "Out of memory (NOMEM_5)" },
247 { "E86", "Out of memory (NOMEM_6)" },
248 { "E87", "Out of memory (NOMEM_7)" },
249 { "E88", "Out of memory (NOMEM_8)" },
250 { "E89", "Out of memory (NOMEM_9)" },
251 { "E98", "OVERLOAD" },
252 { "E99", "Software error: proxy is in the deorbiting-burn mode, new session rejected (SLOWSHTDN)" },
253 { NULL, NULL }
256 static int ett_rtpproxy;
258 static int ett_rtpproxy_request;
259 static int ett_rtpproxy_command;
260 static int ett_rtpproxy_command_parameters;
261 static int ett_rtpproxy_command_parameters_codecs;
262 static int ett_rtpproxy_command_parameters_local;
263 static int ett_rtpproxy_command_parameters_remote;
264 static int ett_rtpproxy_command_parameters_repacketize;
265 static int ett_rtpproxy_command_parameters_dtmf;
266 static int ett_rtpproxy_command_parameters_cmap;
267 static int ett_rtpproxy_command_parameters_proto;
268 static int ett_rtpproxy_command_parameters_transcode;
269 static int ett_rtpproxy_command_parameters_acc;
270 static int ett_rtpproxy_tag;
271 static int ett_rtpproxy_notify;
273 static int ett_rtpproxy_reply;
275 static int ett_rtpproxy_ng_bencode;
277 /* Default values */
278 #define RTPPROXY_PORT "22222" /* Not IANA registered */
279 static range_t* rtpproxy_tcp_range;
280 static range_t* rtpproxy_udp_range;
282 static bool rtpproxy_establish_conversation = true;
283 /* See - https://www.opensips.org/html/docs/modules/1.10.x/rtpproxy.html#id293555 */
284 /* See - http://www.kamailio.org/docs/modules/4.3.x/modules/rtpproxy.html#idp15794952 */
285 static unsigned rtpproxy_timeout = 1000;
286 static nstime_t rtpproxy_timeout_ns;
288 void proto_reg_handoff_rtpproxy(void);
290 static int
291 rtpproxy_add_tag(tvbuff_t *tvb, packet_info* pinfo, proto_tree* rtpproxy_tree, unsigned begin, unsigned realsize)
293 proto_item *ti = NULL;
294 proto_tree *another_tree = NULL;
295 int new_offset;
296 unsigned end;
297 const uint8_t* tmpstr;
299 new_offset = tvb_find_uint8(tvb, begin, -1, ' ');
300 if(new_offset < 0)
301 end = realsize; /* No more parameters */
302 else
303 end = new_offset;
305 /* SER/OpenSER/OpenSIPS/Kamailio adds Media-ID right after the Tag
306 * separated by a semicolon
308 new_offset = tvb_find_uint8(tvb, begin, end, ';');
309 if(new_offset == -1){
310 ti = proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, end - begin, ENC_ASCII | ENC_NA, pinfo->pool, &tmpstr);
311 col_append_fstr(pinfo->cinfo, COL_INFO, ", Tag: %s", tmpstr);
312 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
313 ti = proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, 0, ENC_ASCII | ENC_NA);
314 proto_item_append_text(ti, "<skipped>");
315 proto_item_set_generated(ti);
317 else{
318 ti = proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, new_offset - begin, ENC_ASCII | ENC_NA, pinfo->pool, &tmpstr);
319 col_append_fstr(pinfo->cinfo, COL_INFO, ", Tag: %s", tmpstr);
320 if ((unsigned)new_offset == begin){
321 proto_item_append_text(ti, "<skipped>"); /* A very first Offer/Update command */
322 proto_item_set_generated(ti);
324 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
325 proto_tree_add_item_ret_string(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, end - (new_offset+1), ENC_ASCII | ENC_NA, pinfo->pool, &tmpstr);
326 col_append_fstr(pinfo->cinfo, COL_INFO, ", Media id: %s", tmpstr);
328 return (end == realsize ? -1 : (int)end);
331 static void
332 rtpproxy_add_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, unsigned begin, unsigned realsize)
334 proto_item *ti;
335 proto_tree *another_tree = NULL;
336 unsigned offset = 0;
337 unsigned new_offset = 0;
338 int i;
339 unsigned pt = 0;
340 char** codecs = NULL;
341 unsigned codec_len;
342 uint8_t* rawstr = NULL;
343 uint32_t ipaddr[4]; /* Enough room for IPv4 or IPv6 */
345 /* Extract the entire parameters line. */
346 /* Something like "t4p1iic8,0,2,4,18,96,97,98,100,101" */
347 rawstr = tvb_get_string_enc(pinfo->pool, tvb, begin, realsize, ENC_ASCII);
349 while(offset < realsize){
350 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameter, tvb, begin + offset, 1, ENC_ASCII | ENC_NA);
351 offset++; /* Skip 1-byte parameter's type */
352 switch (g_ascii_tolower(tvb_get_uint8(tvb, begin+offset-1)))
354 /* Official long parameters */
355 case 'c':
356 new_offset = (int)strspn(rawstr+offset, "0123456789,");
357 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_codecs);
358 codecs = wmem_strsplit(pinfo->pool, tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), ",", 0);
359 i = 0;
360 while(codecs[i]){
361 /* We assume strings < 2^32-1 bytes long. :-) */
362 codec_len = (unsigned)strlen(codecs[i]);
363 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_codec, tvb, begin+offset, codec_len,
364 (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, codec_len, ENC_ASCII), NULL, 10));
365 proto_item_append_text(ti, " (%s)", val_to_str_ext_const((unsigned)strtoul(tvb_format_text(pinfo->pool, tvb,begin+offset,codec_len),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
366 offset += codec_len;
367 if(codecs[i+1])
368 offset++; /* skip comma */
369 i++;
371 break;
372 case 'l':
373 /* That's another one protocol shortcoming - the same parameter used twice. */
374 /* https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#createupdatelookup-session */
375 /* https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#get-information */
376 new_offset = (int)strspn(rawstr+offset, "0123456789.");
377 if(new_offset){
378 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_local);
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_local_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;
385 break;
386 case 'r':
387 new_offset = (int)strspn(rawstr+offset, "0123456789.");
388 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_remote);
389 if(str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
390 proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_remote_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
391 else
392 proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
393 offset += new_offset;
394 break;
395 case 'z':
396 new_offset = (int)strspn(rawstr+offset, "0123456789");
397 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_repacketize);
398 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_repacketize, tvb, begin+offset, new_offset,
399 (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
400 offset += new_offset;
401 break;
402 /* Unofficial long parameters */
403 case 'd':
404 new_offset = (int)strspn(rawstr+offset, "0123456789");
405 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_dtmf);
406 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_dtmf, tvb, begin+offset, new_offset,
407 (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
408 if(rtpproxy_establish_conversation){
409 pt = (unsigned)strtoul(tvb_format_text(pinfo->pool, tvb,begin+offset,new_offset),NULL,10);
410 dissector_add_uint("rtp.pt", pt, rtp_events_handle);
412 offset += new_offset;
413 break;
414 case 'm':
415 new_offset = (int)strspn(rawstr+offset, "0123456789=,");
416 /* TODO */
417 offset += new_offset;
418 break;
419 case 'p':
420 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_proto);
421 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_proto, tvb, begin+offset, 1, ENC_ASCII | ENC_NA);
422 offset++;
423 break;
424 case 't':
425 new_offset = (int)strspn(rawstr+offset, "0123456789");
426 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_transcode);
427 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_transcode, tvb, begin+offset, new_offset,
428 (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
429 proto_item_append_text(ti, " (%s)", val_to_str_ext_const((unsigned)strtoul(tvb_format_text(pinfo->pool, tvb,begin+offset, new_offset),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
430 offset += new_offset;
431 break;
432 case 'u':
433 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_acc);
434 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_acc, tvb, begin+offset, 1, ENC_ASCII | ENC_NA);
435 offset++;
436 break;
437 default:
438 break;
443 static rtpproxy_info_t *
444 rtpproxy_add_tid(bool is_request, tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, rtpproxy_conv_info_t *rtpproxy_conv, const uint8_t* cookie)
446 rtpproxy_info_t *rtpproxy_info;
447 proto_item *pi;
449 if (!PINFO_FD_VISITED(pinfo)) {
450 if (is_request){
451 rtpproxy_info = wmem_new0(wmem_file_scope(), rtpproxy_info_t);
452 rtpproxy_info->req_frame = pinfo->num;
453 rtpproxy_info->req_time = pinfo->abs_ts;
454 wmem_tree_insert_string(rtpproxy_conv->trans, cookie, rtpproxy_info, 0);
455 } else {
456 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
457 if (rtpproxy_info) {
458 rtpproxy_info->resp_frame = pinfo->num;
461 } else {
462 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
463 if (rtpproxy_info && (is_request ? rtpproxy_info->resp_frame : rtpproxy_info->req_frame)) {
464 nstime_t ns;
466 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);
467 proto_item_set_generated(pi);
469 /* If not a request (so it's a reply) then calculate response time */
470 if (!is_request){
471 nstime_delta(&ns, &pinfo->abs_ts, &rtpproxy_info->req_time);
472 pi = proto_tree_add_time(rtpproxy_tree, hf_rtpproxy_response_time, tvb, 0, 0, &ns);
473 proto_item_set_generated(pi);
474 if (nstime_cmp(&rtpproxy_timeout_ns, &ns) < 0)
475 expert_add_info_format(pinfo, rtpproxy_tree, &ei_rtpproxy_timeout, "Response timeout %.3f seconds", nstime_to_sec(&ns));
479 /* Could be NULL so we should check it before dereferencing */
480 return rtpproxy_info;
483 static void
484 rtpproxy_add_notify_addr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, unsigned begin, unsigned end)
486 int offset = 0;
487 int tmp;
488 bool ipv6 = false;
489 uint32_t ipaddr[4]; /* Enough room for IPv4 or IPv6 */
491 /* Check for at least one colon */
492 offset = tvb_find_uint8(tvb, begin, end, ':');
493 if(offset != -1){
494 /* Find if it's the latest colon (not in case of a IPv6) */
495 while((tmp = tvb_find_uint8(tvb, offset+1, end, ':')) != -1){
496 ipv6 = true;
497 offset = tmp;
499 /* We have ip:port */
500 if(ipv6){
501 if(str_to_ip6((char*)tvb_get_string_enc(pinfo->pool, tvb, begin, offset - begin, ENC_ASCII), ipaddr))
502 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, offset - begin, (const ws_in6_addr*)ipaddr);
503 else
504 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, begin, offset - begin);
506 else{
507 if(str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, begin, offset - begin, ENC_ASCII), ipaddr))
508 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, offset - begin, ipaddr[0]);
509 else
510 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin, offset - begin);
512 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, offset+1, end - (offset+1),
513 (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, offset+1, end - (offset+1), ENC_ASCII), NULL, 10));
515 else{
516 proto_item *ti = NULL;
517 /* Only port is supplied - take IPv4/IPv6 from ip.src/ipv6.src respectively */
518 expert_add_info(pinfo, rtpproxy_tree, &ei_rtpproxy_notify_no_ip);
519 if (pinfo->src.type == AT_IPv4) {
520 uint32_t addr;
521 memcpy(&addr, pinfo->src.data, 4);
522 ti = proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, 0, addr);
523 } else if (pinfo->src.type == AT_IPv6) {
524 ti = proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, 0, (const ws_in6_addr *)(pinfo->src.data));
526 if (ti) {
527 proto_item_set_generated(ti);
528 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, begin, end - begin,
529 (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, begin, end - begin, ENC_ASCII), NULL, 10));
534 static int
535 dissect_rtpproxy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
537 bool has_lf = false;
538 int offset = 0;
539 int new_offset = 0;
540 unsigned tmp;
541 unsigned tmp2;
542 int realsize = 0;
543 uint8_t* rawstr;
544 const uint8_t* tmpstr;
545 proto_item *ti;
546 proto_item *ti2;
547 proto_tree *rtpproxy_tree;
548 conversation_t *conversation;
549 rtpproxy_conv_info_t *rtpproxy_conv;
550 const uint8_t* cookie = NULL;
551 /* For RT(C)P setup */
552 address addr;
553 uint16_t port;
554 uint32_t ipaddr[4]; /* Enough room for IPv4 or IPv6 */
555 rtpproxy_info_t *rtpproxy_info = NULL;
556 tvbuff_t *subtvb;
558 /* If it does not start with a printable character it's not RTPProxy */
559 if(!g_ascii_isprint(tvb_get_uint8(tvb, 0)))
560 return 0;
562 /* Extract Cookie */
563 offset = tvb_find_uint8(tvb, offset, -1, ' ');
564 if(offset == -1)
565 return 0;
567 /* We believe it's likely a RTPproxy / RTPproxy-ng protocol */
568 /* Note: we no longer distinct between packets with or w/o LF - it turned
569 * out to be useless */
570 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy");
572 /* Clear out stuff in the info column - we'll set it later */
573 col_clear(pinfo->cinfo, COL_INFO);
575 ti = proto_tree_add_item(tree, proto_rtpproxy, tvb, 0, -1, ENC_NA);
576 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy);
578 proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_cookie, tvb, 0, offset, ENC_ASCII | ENC_NA, pinfo->pool, &cookie);
580 /* Skip whitespace */
581 offset = tvb_skip_wsp(tvb, offset+1, -1);
583 /* Calculate size to prevent recalculation in the future */
584 realsize = tvb_reported_length(tvb);
586 /* Don't count trailing zeroes (inserted by some SIP-servers sometimes) */
587 while (tvb_get_uint8(tvb, realsize - 1) == 0){
588 realsize -= 1;
591 /* Check for LF (required for TCP connection, optional for UDP) */
592 if (tvb_get_uint8(tvb, realsize - 1) == '\n'){
593 /* Don't count trailing LF */
594 realsize -= 1;
595 has_lf = true;
598 /* Try to create conversation */
599 conversation = find_or_create_conversation(pinfo);
600 rtpproxy_conv = (rtpproxy_conv_info_t *)conversation_get_proto_data(conversation, proto_rtpproxy);
601 if (!rtpproxy_conv) {
602 rtpproxy_conv = wmem_new(wmem_file_scope(), rtpproxy_conv_info_t);
603 rtpproxy_conv->trans = wmem_tree_new(wmem_file_scope());
604 conversation_add_proto_data(conversation, proto_rtpproxy, rtpproxy_conv);
607 /* Get payload string */
608 rawstr = tvb_format_text_wsp(pinfo->pool, tvb, offset, realsize - offset);
610 /* Extract command */
611 tmp = g_ascii_tolower(tvb_get_uint8(tvb, offset));
612 switch (tmp)
614 case 's':
615 /* A specific case - long info answer */
616 /* %COOKIE% sessions created %NUM0% active sessions: %NUM1% */
617 /* FIXME https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#information */
618 rtpproxy_add_tid(false, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
619 if ('e' == tvb_get_uint8(tvb, offset+1)){
620 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
621 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
623 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
624 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_status, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
625 break;
627 /* FALL THROUGH */
628 case 'i':
629 case 'x':
630 case 'u':
631 case 'l':
632 case 'd':
633 tmp2 = tvb_get_uint8(tvb, offset+1);
634 if(('1' <= tmp2) && (tmp2 <= '9') && (tvb_get_uint8(tvb, offset+2) == ':')){
635 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy-ng");
636 col_add_fstr(pinfo->cinfo, COL_INFO, "RTPproxy-ng: %s", rawstr);
637 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ng_bencode, tvb, offset, -1, ENC_ASCII | ENC_NA);
638 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_ng_bencode);
639 subtvb = tvb_new_subset_remaining(tvb, offset);
640 call_dissector(bencode_handle, subtvb, pinfo, rtpproxy_tree);
641 break;
643 /* FALL THROUGH */
644 case 'p':
645 case 'v':
646 case 'r':
647 case 'c':
648 case 'q':
649 rtpproxy_info = rtpproxy_add_tid(true, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
650 col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s", val_to_str_const(tvb_get_uint8(tvb, offset), commandtypenames, "Unknown command code"));
651 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_request, tvb, offset, -1, ENC_NA);
652 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_request);
654 /* A specific case - version request:
655 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#get-list-of-veatures
657 * In this case a command size must be bigger or equal to a "VF YYYYMMDD" string size.
658 * It's bigger if there is more than one space inserted between "VF" and "YYYYMMDD" tokens.
660 if ((tmp == 'v') && (offset + (int)strlen("VF YYYYMMDD") <= realsize)){
661 /* Skip whitespace between "VF" and "YYYYMMDD" tokens */
662 new_offset = tvb_skip_wsp(tvb, offset + ((unsigned)strlen("VF") + 1), -1);
663 ti = proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_version_request, tvb, new_offset, (int)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA, pinfo->pool, &tmpstr);
664 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, versiontypenames, "Unknown"));
665 break;
668 /* All other commands */
669 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command, tvb, offset, 1, ENC_ASCII | ENC_NA);
671 /* A specific case - handshake/ping */
672 if (tmp == 'v')
673 break; /* No more parameters */
675 /* A specific case - close all calls */
676 if (tmp == 'x')
677 break; /* No more parameters */
679 /* Extract parameters */
680 /* Parameters should be right after the command and before EOL (in case of Info command) or before whitespace */
681 new_offset = (tmp == 'i' ? (realsize - 1 > offset ? offset + (int)strlen("Ib") : offset + (int)strlen("I")) : tvb_find_uint8(tvb, offset, -1, ' '));
683 if (new_offset != offset + 1){
684 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_command);
685 ti2 = proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_command_parameters, tvb, offset+1, new_offset - (offset+1), ENC_ASCII | ENC_NA, pinfo->pool, &tmpstr);
686 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tmpstr);
687 rtpproxy_add_parameter(tvb, pinfo, proto_item_add_subtree(ti2, ett_rtpproxy_command_parameters), offset+1, new_offset - (offset+1));
688 rtpproxy_tree = proto_item_get_parent(ti);
691 /* A specific case - query information */
692 if (tmp == 'i')
693 break; /* No more parameters */
695 /* Skip whitespace */
696 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
698 /* Extract Call-ID */
699 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
700 proto_tree_add_item_ret_string(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA, pinfo->pool, &tmpstr);
701 col_append_fstr(pinfo->cinfo, COL_INFO, ", Call-ID: %s", tmpstr);
702 if(rtpproxy_info && !rtpproxy_info->callid)
703 rtpproxy_info->callid = tvb_get_string_enc(wmem_file_scope(), tvb, offset, new_offset - offset, ENC_ASCII);
704 /* Skip whitespace */
705 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
707 /* Extract IP and Port in case of Offer/Answer */
708 if ((tmp == 'u') || (tmp == 'l')){
709 /* Extract IP */
710 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
711 if (tvb_find_uint8(tvb, offset, new_offset - offset, ':') == -1){
712 tmpstr = tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII);
713 if (str_to_ip(tmpstr, ipaddr)) {
714 col_append_fstr(pinfo->cinfo, COL_INFO, ", IP: %s", tmpstr);
715 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, new_offset - offset, ipaddr[0]);
717 else {
718 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, new_offset - offset);
720 } else{
721 tmpstr = tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII);
722 if (str_to_ip6(tmpstr, ipaddr)) {
723 col_append_fstr(pinfo->cinfo, COL_INFO, ", IP: [%s]", tmpstr);
724 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, new_offset - offset, (const ws_in6_addr*)ipaddr);
725 } else {
726 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, new_offset - offset);
729 /* Skip whitespace */
730 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
732 /* Extract Port */
733 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
734 tmpstr = tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII);
735 col_append_fstr(pinfo->cinfo, COL_INFO, ":%s", tmpstr);
736 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset,
737 (uint16_t) g_ascii_strtoull((char*)tmpstr, NULL, 10));
738 /* Skip whitespace */
739 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
742 /* Extract Copy target */
743 if (tmp == 'c'){
744 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
745 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_copy_target, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
746 /* Skip whitespace */
747 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
750 /* Extract Playback file and codecs */
751 if (tmp == 'p'){
752 /* Extract filename */
753 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
754 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_playback_filename, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
755 /* Skip whitespace */
756 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
758 /* Extract codec */
759 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
760 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_playback_codec, tvb, offset, new_offset - offset,
761 (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
762 /* Skip whitespace */
763 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
766 /* Extract first tag */
767 new_offset = rtpproxy_add_tag(tvb, pinfo, rtpproxy_tree, offset, realsize);
768 if(new_offset == -1)
769 break; /* No more parameters */
770 /* Skip whitespace */
771 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
773 /* Extract second tag */
774 new_offset = rtpproxy_add_tag(tvb, pinfo, rtpproxy_tree, offset, realsize);
775 if(new_offset == -1)
776 break; /* No more parameters */
777 /* Skip whitespace */
778 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
780 /* Extract Notification address */
781 if (tmp == 'u'){
782 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
783 proto_item_set_text(ti, "Notify");
784 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_notify);
786 /* Check for NotifyTag parameter (separated by space) */
787 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
788 if(new_offset == -1){
789 /* NotifyTag wasn't found (we should re-use Call-ID instead) */
790 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, realsize);
791 break; /* No more parameters */
794 /* NotifyTag was found */
795 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, new_offset);
796 /* Skip whitespace */
797 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
799 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_tag, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
801 break;
802 case 'e':
803 case '0':
804 case '1':
805 case '2':
806 case '3':
807 case '4':
808 case '5':
809 case '6':
810 case '7':
811 case '8':
812 case '9':
813 rtpproxy_info = rtpproxy_add_tid(false, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
814 if (tmp == 'e')
815 col_add_fstr(pinfo->cinfo, COL_INFO, "Error reply: %s", rawstr);
816 else
817 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
819 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
820 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
822 if(rtpproxy_info && rtpproxy_info->callid){
823 ti = proto_tree_add_string(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, 0, rtpproxy_info->callid);
824 proto_item_set_generated(ti);
827 if (tmp == 'e'){
828 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, false);
829 tmpstr = tvb_get_string_enc(pinfo->pool, tvb, offset, tmp, ENC_ASCII);
830 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_error, tvb, offset, (int)strlen(tmpstr), ENC_ASCII | ENC_NA);
831 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, errortypenames, "Unknown"));
832 break;
835 /* Check for a single '0' or '1' character followed by the end-of-line.
836 * These both are positive replies - either a 'positive reply' or a 'version ack'.
838 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#positive-reply
839 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#version-reply
841 if (((tmp == '0') || (tmp == '1')) && (realsize == offset + (int)strlen("X"))){
842 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ok, tvb, offset, 1, ENC_ASCII | ENC_NA);
843 break;
846 /* Check for the VERSION_NUMBER string reply:
847 * https://github.com/sippy/rtpproxy/wiki/RTPP-%28RTPproxy-protocol%29-technical-specification#version-reply
849 * If a total size equals to a current offset + size of "YYYYMMDD" string
850 * then it's a version reply.
852 if (realsize == offset + (int)strlen("YYYYMMDD")){
853 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_version_supported, tvb, offset, (uint32_t)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA);
854 break;
857 /* Extract Port */
858 new_offset = tvb_find_uint8(tvb, offset, -1, ' ');
859 /* Convert port to unsigned 16-bit number */
860 port = (uint16_t) g_ascii_strtoull((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10);
861 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset, port);
862 /* Skip whitespace */
863 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
865 /* Extract IP */
866 memset(&addr, 0, sizeof(address));
868 /* Try rtpengine bogus extension first. It appends 4 or
869 * 6 depending on type of the IP. See
870 * https://github.com/sipwise/rtpengine/blob/eea3256/daemon/call_interfaces.c#L74
871 * for further details */
872 tmp = tvb_find_uint8(tvb, offset, -1, ' ');
873 if(tmp == (unsigned)(-1)){
874 /* No extension - operate normally */
875 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, false);
877 else {
878 tmp -= offset;
881 if (tvb_find_uint8(tvb, offset, -1, ':') == -1){
882 if (str_to_ip((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, tmp, ENC_ASCII), ipaddr)){
883 addr.type = AT_IPv4;
884 addr.len = 4;
885 addr.data = wmem_memdup(pinfo->pool, ipaddr, 4);
886 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, tmp, ipaddr[0]);
888 else
889 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, tmp);
891 else{
892 if (str_to_ip6((char*)tvb_get_string_enc(pinfo->pool, tvb, offset, tmp, ENC_ASCII), ipaddr)){
893 addr.type = AT_IPv6;
894 addr.len = 16;
895 addr.data = wmem_memdup(pinfo->pool, ipaddr, 16);
896 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, tmp, (const ws_in6_addr *)ipaddr);
898 else
899 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, tmp);
902 if(rtpproxy_establish_conversation){
903 if (rtp_handle) {
904 /* FIXME tell if isn't a video stream, and setup codec mapping */
905 if (addr.len)
906 rtp_add_address(pinfo, PT_UDP, &addr, port, 0, "RTPproxy", pinfo->num, 0, NULL);
908 if (rtcp_handle) {
909 if (addr.len)
910 rtcp_add_address(pinfo, &addr, port+1, 0, "RTPproxy", pinfo->num);
913 break;
914 default:
915 break;
917 /* TODO add an expert warning about packets w/o LF sent over TCP */
918 if (has_lf)
919 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_lf, tvb, realsize, 1, ENC_NA);
921 return tvb_captured_length(tvb);
924 /* Preference callbacks */
925 static void
926 rtpproxy_prefs_apply(void) {
928 rtpproxy_tcp_range = prefs_get_range_value("rtpproxy", "tcp.port");
929 rtpproxy_udp_range = prefs_get_range_value("rtpproxy", "udp.port");
932 void
933 proto_register_rtpproxy(void)
935 module_t *rtpproxy_module;
936 expert_module_t* expert_rtpproxy_module;
938 static hf_register_info hf[] = {
940 &hf_rtpproxy_cookie,
942 "Cookie",
943 "rtpproxy.cookie",
944 FT_STRING,
945 BASE_NONE,
946 NULL,
947 0x0,
948 NULL,
949 HFILL
953 &hf_rtpproxy_version_request,
955 "Version Request",
956 "rtpproxy.version",
957 FT_STRING,
958 BASE_NONE,
959 NULL,
960 0x0,
961 NULL,
962 HFILL
966 &hf_rtpproxy_version_supported,
968 "Version Supported",
969 "rtpproxy.version_supported",
970 FT_STRING,
971 BASE_NONE,
972 NULL,
973 0x0,
974 NULL,
975 HFILL
979 &hf_rtpproxy_error,
981 "Error",
982 "rtpproxy.error",
983 FT_STRING,
984 BASE_NONE,
985 NULL,
986 0x0,
987 NULL,
988 HFILL
992 &hf_rtpproxy_ok,
994 "Ok",
995 "rtpproxy.ok",
996 FT_CHAR,
997 BASE_HEX,
998 VALS(oktypenames),
999 0x0,
1000 NULL,
1001 HFILL
1005 &hf_rtpproxy_status,
1007 "Status",
1008 "rtpproxy.status",
1009 FT_STRING,
1010 BASE_NONE,
1011 NULL,
1012 0x0,
1013 NULL,
1014 HFILL
1018 &hf_rtpproxy_ipv4,
1020 "IPv4",
1021 "rtpproxy.ipv4",
1022 FT_IPv4,
1023 BASE_NONE,
1024 NULL,
1025 0x0,
1026 NULL,
1027 HFILL
1031 &hf_rtpproxy_ipv6,
1033 "IPv6",
1034 "rtpproxy.ipv6",
1035 FT_IPv6,
1036 BASE_NONE,
1037 NULL,
1038 0x0,
1039 NULL,
1040 HFILL
1044 &hf_rtpproxy_port,
1046 "Port",
1047 "rtpproxy.port",
1048 FT_UINT16, /* 0 - 65535 */
1049 BASE_DEC,
1050 NULL,
1051 0x0,
1052 NULL,
1053 HFILL
1057 &hf_rtpproxy_request,
1059 "Request",
1060 "rtpproxy.request",
1061 FT_NONE,
1062 BASE_NONE,
1063 NULL,
1064 0x0,
1065 NULL,
1066 HFILL
1070 &hf_rtpproxy_command,
1072 "Command",
1073 "rtpproxy.command",
1074 FT_CHAR,
1075 BASE_HEX,
1076 VALS(commandtypenames),
1077 0x0,
1078 NULL,
1079 HFILL
1083 &hf_rtpproxy_command_parameters,
1085 "Command parameters",
1086 "rtpproxy.command_parameters",
1087 FT_STRING,
1088 BASE_NONE,
1089 NULL,
1090 0x0,
1091 NULL,
1092 HFILL
1096 &hf_rtpproxy_command_parameter,
1098 "Parameter",
1099 "rtpproxy.command_parameter",
1100 FT_CHAR,
1101 BASE_HEX,
1102 VALS(paramtypenames),
1103 0x0,
1104 NULL,
1105 HFILL
1109 &hf_rtpproxy_command_parameter_codec,
1111 "Allowed codec",
1112 "rtpproxy.command_parameter_codec",
1113 FT_UINT8, /* 0 - 127 */
1114 BASE_DEC,
1115 NULL,
1116 0x0,
1117 NULL,
1118 HFILL
1122 &hf_rtpproxy_command_parameter_local_ipv4,
1124 "Local IPv4 address",
1125 "rtpproxy.command_parameter_local_ipv4",
1126 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1127 BASE_NONE,
1128 NULL,
1129 0x0,
1130 NULL,
1131 HFILL
1135 &hf_rtpproxy_command_parameter_remote_ipv4,
1137 "Remote IPv4 address",
1138 "rtpproxy.command_parameter_remote_ipv4",
1139 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1140 BASE_NONE,
1141 NULL,
1142 0x0,
1143 NULL,
1144 HFILL
1148 &hf_rtpproxy_command_parameter_repacketize,
1150 "Repacketize (ms)",
1151 "rtpproxy.command_parameter_repacketize",
1152 FT_UINT16, /* 0 - 1000 milliseconds */
1153 BASE_DEC,
1154 NULL,
1155 0x0,
1156 NULL,
1157 HFILL
1161 &hf_rtpproxy_command_parameter_dtmf,
1163 "DTMF payload ID",
1164 "rtpproxy.command_parameter_dtmf",
1165 FT_UINT8, /* 0 - 127 */
1166 BASE_DEC,
1167 NULL,
1168 0x0,
1169 NULL,
1170 HFILL
1174 &hf_rtpproxy_command_parameter_proto,
1176 "RTP transmission protocol",
1177 "rtpproxy.command_parameter_proto",
1178 FT_CHAR,
1179 BASE_HEX,
1180 VALS(prototypenames),
1181 0x0,
1182 NULL,
1183 HFILL
1187 &hf_rtpproxy_command_parameter_transcode,
1189 "Transcode to",
1190 "rtpproxy.command_parameter_transcode",
1191 FT_UINT8, /* 0 - 127 */
1192 BASE_DEC,
1193 NULL,
1194 0x0,
1195 NULL,
1196 HFILL
1200 &hf_rtpproxy_command_parameter_acc,
1202 "Accounting",
1203 "rtpproxy.command_parameter_acc",
1204 FT_CHAR,
1205 BASE_HEX,
1206 VALS(acctypenames),
1207 0x0,
1208 NULL,
1209 HFILL
1213 &hf_rtpproxy_copy_target,
1215 "Copy target",
1216 "rtpproxy.copy_target",
1217 FT_STRING, /* Filename or UDP address, e.g. /var/tmp/fileXXXX.yyy or IP:Port */
1218 BASE_NONE,
1219 NULL,
1220 0x0,
1221 NULL,
1222 HFILL
1226 &hf_rtpproxy_playback_filename,
1228 "Playback filename",
1229 "rtpproxy.playback_filename",
1230 FT_STRING,
1231 BASE_NONE,
1232 NULL,
1233 0x0,
1234 NULL,
1235 HFILL
1239 &hf_rtpproxy_playback_codec,
1241 "Playback codec",
1242 "rtpproxy.playback_codec",
1243 FT_UINT8, /* 0 - 127 */
1244 BASE_DEC,
1245 NULL,
1246 0x0,
1247 NULL,
1248 HFILL
1252 &hf_rtpproxy_callid,
1254 "Call-ID",
1255 "rtpproxy.callid",
1256 FT_STRING,
1257 BASE_NONE,
1258 NULL,
1259 0x0,
1260 NULL,
1261 HFILL
1265 &hf_rtpproxy_notify,
1267 "Notify",
1268 "rtpproxy.notify",
1269 FT_STRING,
1270 BASE_NONE,
1271 NULL,
1272 0x0,
1273 NULL,
1274 HFILL
1278 &hf_rtpproxy_tag,
1280 "Tag",
1281 "rtpproxy.tag",
1282 FT_STRING,
1283 BASE_NONE,
1284 NULL,
1285 0x0,
1286 NULL,
1287 HFILL
1291 &hf_rtpproxy_mediaid,
1293 "Media-ID",
1294 "rtpproxy.mediaid",
1295 FT_STRING,
1296 BASE_NONE,
1297 NULL,
1298 0x0,
1299 NULL,
1300 HFILL
1304 &hf_rtpproxy_notify_ipv4,
1306 "Notification IPv4",
1307 "rtpproxy.notify_ipv4",
1308 FT_IPv4,
1309 BASE_NONE,
1310 NULL,
1311 0x0,
1312 NULL,
1313 HFILL
1317 &hf_rtpproxy_notify_ipv6,
1319 "Notification IPv6",
1320 "rtpproxy.notify_ipv6",
1321 FT_IPv6,
1322 BASE_NONE,
1323 NULL,
1324 0x0,
1325 NULL,
1326 HFILL
1330 &hf_rtpproxy_notify_port,
1332 "Notification Port",
1333 "rtpproxy.notify_port",
1334 FT_UINT16,
1335 BASE_DEC,
1336 NULL,
1337 0x0,
1338 NULL,
1339 HFILL
1343 &hf_rtpproxy_notify_tag,
1345 "Notification Tag",
1346 "rtpproxy.notify_tag",
1347 FT_STRING,
1348 BASE_NONE,
1349 NULL,
1350 0x0,
1351 NULL,
1352 HFILL
1356 &hf_rtpproxy_reply,
1358 "Reply",
1359 "rtpproxy.reply",
1360 FT_NONE,
1361 BASE_NONE,
1362 NULL,
1363 0x0,
1364 NULL,
1365 HFILL
1369 &hf_rtpproxy_lf,
1371 "LF",
1372 "rtpproxy.lf",
1373 FT_NONE,
1374 BASE_NONE,
1375 NULL,
1376 0x0,
1377 NULL,
1378 HFILL
1382 &hf_rtpproxy_request_in,
1384 "Request In",
1385 "rtpproxy.request_in",
1386 FT_FRAMENUM,
1387 BASE_NONE,
1388 FRAMENUM_TYPE(FT_FRAMENUM_REQUEST),
1389 0x0,
1390 NULL,
1391 HFILL
1396 &hf_rtpproxy_response_in,
1398 "Response In",
1399 "rtpproxy.response_in",
1400 FT_FRAMENUM,
1401 BASE_NONE,
1402 FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE),
1403 0x0,
1404 NULL,
1405 HFILL
1409 &hf_rtpproxy_response_time,
1411 "Response Time",
1412 "rtpproxy.response_time",
1413 FT_RELATIVE_TIME,
1414 BASE_NONE,
1415 NULL,
1416 0x0,
1417 "The time between the Request and the Reply",
1418 HFILL
1422 &hf_rtpproxy_ng_bencode,
1424 "RTPproxy-ng bencode packet",
1425 "rtpproxy.ng.bencode",
1426 FT_STRING,
1427 BASE_NONE,
1428 NULL,
1429 0x0,
1430 "Serialized structure of integers, dictionaries, strings and lists.",
1431 HFILL
1436 static ei_register_info ei[] = {
1437 { &ei_rtpproxy_timeout,
1438 { "rtpproxy.response_timeout", PI_RESPONSE_CODE, PI_WARN,
1439 "TIMEOUT", EXPFILL }},
1440 { &ei_rtpproxy_notify_no_ip,
1441 { "rtpproxy.notify_no_ip", PI_RESPONSE_CODE, PI_COMMENT,
1442 "No notification IP address provided. Using ip.src or ipv6.src as a value.", EXPFILL }},
1443 { &ei_rtpproxy_bad_ipv4,
1444 { "rtpproxy.bad_ipv4", PI_MALFORMED, PI_ERROR,
1445 "Bad IPv4", EXPFILL }},
1446 { &ei_rtpproxy_bad_ipv6,
1447 { "rtpproxy.bad_ipv6", PI_MALFORMED, PI_ERROR,
1448 "Bad IPv6", EXPFILL }},
1451 /* Setup protocol subtree array */
1452 static int *ett[] = {
1453 &ett_rtpproxy,
1454 &ett_rtpproxy_request,
1455 &ett_rtpproxy_command,
1456 &ett_rtpproxy_command_parameters,
1457 &ett_rtpproxy_command_parameters_codecs,
1458 &ett_rtpproxy_command_parameters_local,
1459 &ett_rtpproxy_command_parameters_remote,
1460 &ett_rtpproxy_command_parameters_repacketize,
1461 &ett_rtpproxy_command_parameters_dtmf,
1462 &ett_rtpproxy_command_parameters_cmap,
1463 &ett_rtpproxy_command_parameters_proto,
1464 &ett_rtpproxy_command_parameters_transcode,
1465 &ett_rtpproxy_command_parameters_acc,
1466 &ett_rtpproxy_tag,
1467 &ett_rtpproxy_notify,
1468 &ett_rtpproxy_reply,
1469 &ett_rtpproxy_ng_bencode
1472 proto_rtpproxy = proto_register_protocol ("Sippy RTPproxy Protocol", "RTPproxy", "rtpproxy");
1473 rtpproxy_handle = register_dissector("rtpproxy", dissect_rtpproxy, proto_rtpproxy);
1475 proto_register_field_array(proto_rtpproxy, hf, array_length(hf));
1476 proto_register_subtree_array(ett, array_length(ett));
1478 expert_rtpproxy_module = expert_register_protocol(proto_rtpproxy);
1479 expert_register_field_array(expert_rtpproxy_module, ei, array_length(ei));
1481 rtpproxy_module = prefs_register_protocol(proto_rtpproxy, rtpproxy_prefs_apply);
1483 prefs_register_bool_preference(rtpproxy_module, "establish_conversation",
1484 "Establish Media Conversation",
1485 "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
1486 "upon port numbers found in RTPproxy answers",
1487 &rtpproxy_establish_conversation);
1489 prefs_register_uint_preference(rtpproxy_module, "reply.timeout",
1490 "RTPproxy reply timeout", /* Title */
1491 "Maximum timeout value in waiting for reply from RTPProxy (in milliseconds).", /* Descr */
1493 &rtpproxy_timeout);
1496 void
1497 proto_reg_handoff_rtpproxy(void)
1499 static bool rtpproxy_initialized = false;
1501 if(!rtpproxy_initialized){
1502 /* Register TCP port for dissection */
1503 dissector_add_uint_range_with_preference("tcp.port", RTPPROXY_PORT, rtpproxy_handle);
1504 dissector_add_uint_range_with_preference("udp.port", RTPPROXY_PORT, rtpproxy_handle);
1505 rtpproxy_prefs_apply();
1506 rtpproxy_initialized = true;
1509 rtcp_handle = find_dissector_add_dependency("rtcp", proto_rtpproxy);
1510 rtp_events_handle = find_dissector_add_dependency("rtpevent", proto_rtpproxy);
1511 rtp_handle = find_dissector_add_dependency("rtp", proto_rtpproxy);
1512 bencode_handle = find_dissector_add_dependency("bencode", proto_rtpproxy);
1514 /* Calculate nstime_t struct for the timeout from the rtpproxy_timeout value in milliseconds */
1515 rtpproxy_timeout_ns.secs = (rtpproxy_timeout - rtpproxy_timeout % 1000) / 1000;
1516 rtpproxy_timeout_ns.nsecs = (rtpproxy_timeout % 1000) * 1000;
1520 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1522 * Local variables:
1523 * c-basic-offset: 4
1524 * tab-width: 8
1525 * indent-tabs-mode: nil
1526 * End:
1528 * vi: set shiftwidth=4 tabstop=8 expandtab:
1529 * :indentSize=4:tabSize=8:noTabs=true: