Fixup: tvb_get_string(z) -> tvb_get_string(z)_enc
[metze/wireshark/wip.git] / epan / dissectors / packet-rtpproxy.c
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  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  */
28
29 #include "config.h"
30
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <glib.h>
34
35 #include <epan/address.h>
36 #include <epan/packet.h>
37 #include <epan/prefs.h>
38 #include <epan/conversation.h>
39 #include <epan/expert.h>
40 #include <epan/rtp_pt.h>
41 #include <epan/addr_resolv.h>
42
43 /* For setting up RTP/RTCP dissectors based on the RTPproxy's answers */
44 #include "packet-rtp.h"
45 #include "packet-rtcp.h"
46
47 void proto_register_rtpproxy(void);
48
49 static int proto_rtpproxy = -1;
50
51 static int hf_rtpproxy_cookie = -1;
52 static int hf_rtpproxy_error = -1;
53 static int hf_rtpproxy_status = -1;
54 static int hf_rtpproxy_ok = -1;
55 static int hf_rtpproxy_ipv4 = -1;
56 static int hf_rtpproxy_ipv6 = -1;
57 static int hf_rtpproxy_port = -1;
58 static int hf_rtpproxy_lf = -1;
59 static int hf_rtpproxy_request = -1;
60 static int hf_rtpproxy_command = -1;
61 static int hf_rtpproxy_command_parameters = -1;
62 static int hf_rtpproxy_command_parameter = -1;
63 static int hf_rtpproxy_command_parameter_codec = -1;
64 static int hf_rtpproxy_command_parameter_local_ipv4 = -1;
65 static int hf_rtpproxy_command_parameter_remote_ipv4 = -1;
66 static int hf_rtpproxy_command_parameter_repacketize = -1;
67 static int hf_rtpproxy_command_parameter_dtmf = -1;
68 /* static int hf_rtpproxy_command_parameter_cmap = -1; TODO */
69 static int hf_rtpproxy_command_parameter_proto = -1;
70 static int hf_rtpproxy_command_parameter_transcode = -1;
71 static int hf_rtpproxy_command_parameter_acc = -1;
72 static int hf_rtpproxy_callid = -1;
73 static int hf_rtpproxy_copy_target = -1;
74 static int hf_rtpproxy_playback_filename = -1;
75 static int hf_rtpproxy_playback_codec = -1;
76 static int hf_rtpproxy_notify = -1;
77 static int hf_rtpproxy_notify_ipv4 = -1;
78 static int hf_rtpproxy_notify_ipv6 = -1;
79 static int hf_rtpproxy_notify_port = -1;
80 static int hf_rtpproxy_notify_tag = -1;
81 static int hf_rtpproxy_tag = -1;
82 static int hf_rtpproxy_mediaid = -1;
83 static int hf_rtpproxy_reply = -1;
84 static int hf_rtpproxy_version_request = -1;
85 static int hf_rtpproxy_version_supported = -1;
86 static int hf_rtpproxy_ng_bencode = -1;
87
88 /* Expert fields */
89 static expert_field ei_rtpproxy_timeout = EI_INIT;
90 static expert_field ei_rtpproxy_notify_no_ip = EI_INIT;
91 static expert_field ei_rtpproxy_bad_ipv4 = EI_INIT;
92 static expert_field ei_rtpproxy_bad_ipv6 = EI_INIT;
93
94 /* Request/response tracking */
95 static int hf_rtpproxy_request_in = -1;
96 static int hf_rtpproxy_response_in = -1;
97 static int hf_rtpproxy_response_time = -1;
98
99 typedef struct _rtpproxy_info {
100         guint32 req_frame;
101         guint32 resp_frame;
102         nstime_t req_time;
103         gchar* callid;
104 } rtpproxy_info_t;
105
106 static dissector_handle_t rtcp_handle;
107 static dissector_handle_t rtp_events_handle;
108 static dissector_handle_t rtp_handle;
109 static dissector_handle_t bencode_handle;
110
111 typedef struct _rtpproxy_conv_info {
112         wmem_tree_t *trans;
113 } rtpproxy_conv_info_t;
114
115
116 static const string_string versiontypenames[] = {
117         { "20040107", "Basic RTP proxy functionality" },
118         { "20050322", "Support for multiple RTP streams and MOH" },
119         { "20060704", "Support for extra parameter in the V command" },
120         { "20071116", "Support for RTP re-packetization" },
121         { "20071218", "Support for forking (copying) RTP stream" },
122         { "20080403", "Support for RTP statistics querying" },
123         { "20081102", "Support for setting codecs in the update/lookup command" },
124         { "20081224", "Support for session timeout notifications" },
125         { "20090810", "Support for automatic bridging" },
126         { 0, NULL }
127 };
128
129 static const value_string commandtypenames[] = {
130         { 'V', "Handshake/Ping" },
131         { 'v', "Handshake/Ping" },
132         { 'U', "Offer/Update" },
133         { 'u', "Offer/Update" },
134         { 'L', "Answer/Lookup" },
135         { 'l', "Answer/Lookup" },
136         { 'I', "Information"},
137         { 'i', "Information"},
138         { 'X', "Close all active sessions"},
139         { 'x', "Close all active sessions"},
140         { 'D', "Delete an active session (Bye/Cancel/Error)"},
141         { 'd', "Delete an active session (Bye/Cancel/Error)"},
142         { 'P', "Start playback (music-on-hold)"},
143         { 'p', "Start playback (music-on-hold)"},
144         { 'S', "Stop playback (music-on-hold)"},
145         { 's', "Stop playback (music-on-hold)"},
146         { 'R', "Start recording"},
147         { 'r', "Start recording"},
148         { 'C', "Copy stream"},
149         { 'c', "Copy stream"},
150         { 'Q', "Query info about a session"},
151         { 'q', "Query info about a session"},
152         { 0, NULL }
153 };
154
155 static const value_string paramtypenames[] = {
156         /* Official command parameters */
157         {'4', "Remote address is IPv4"},
158         {'6', "Remote address is IPv6"},
159         {'a', "Asymmetric RTP"},
160         {'A', "Asymmetric RTP"},
161         {'b', "Brief stats"},
162         {'B', "Brief stats"},
163         {'c', "Codecs"},
164         {'C', "Codecs"},
165         {'e', "External network (non RFC 1918)"},
166         {'E', "External network (non RFC 1918)"},
167         {'i', "Internal network (RFC 1918)"},
168         {'I', "Internal network (RFC 1918)"},
169         {'l', "Local address"},
170         {'L', "Local address"},
171         {'r', "Remote address"},
172         {'R', "Remote address"},
173         {'s', "Symmetric RTP (default)"},
174         {'S', "Symmetric RTP (default)"},
175         {'w', "Weak connection (allows roaming)"},
176         {'W', "Weak connection (allows roaming)"},
177         {'z', "repacketiZe"},
178         {'Z', "repacketiZe"},
179         /* Unofficial command parameters / expensions */
180         {'d', "DTMF payload ID (unofficial extension)"},
181         {'D', "DTMF payload ID (unofficial extension)"},
182         {'m', "codec Mapping (unofficial extension)"},
183         {'M', "codec Mapping (unofficial extension)"},
184         {'p', "Protocol type (unofficial extension)"},
185         {'P', "Protocol type (unofficial extension)"},
186         {'t', "Transcode to (unofficial extension)"},
187         {'T', "Transcode to (unofficial extension)"},
188         {'v', "Accounting (unofficial extension)"},
189         {'V', "Accounting (unofficial extension)"},
190         {0, NULL}
191 };
192
193 static const value_string prototypenames[] = {
194         { '0', "UDP (default)"},
195         { '1', "TCP"},
196         { '2', "SCTP"},
197         { 0, NULL }
198 };
199 static const value_string acctypenames[] = {
200         { '0', "Start"},
201         { '1', "Interim update"},
202         { '2', "Stop"},
203         { 0, NULL }
204 };
205
206 static const value_string oktypenames[] = {
207         { '0', "Ok"},
208         { '1', "Version Supported"},
209         { 0, NULL }
210 };
211
212 static const string_string errortypenames[] = {
213         { "E0", "Syntax error" },
214         { "E1", "Syntax error" },
215         { "E2", "Syntax error" },
216         { "E3", "Unknown command" },
217         { "E4", "Syntax error" },
218         { "E5", "Out of memory" },
219         { "E6", "<no description>" },
220         { "E7", "Software error (can't create listener)" },
221         { "E8", "Not Found" },
222         { "E10", "Software error (can't create listener)" },
223         { "E11", "Out of memory" },
224         { "E12", "Out of memory" },
225         { "E13", "Out of memory" },
226         { "E14", "Out of memory" },
227         { 0, NULL }
228 };
229
230 static gint ett_rtpproxy = -1;
231
232 static gint ett_rtpproxy_request = -1;
233 static gint ett_rtpproxy_command = -1;
234 static gint ett_rtpproxy_command_parameters = -1;
235 static gint ett_rtpproxy_command_parameters_codecs = -1;
236 static gint ett_rtpproxy_command_parameters_local = -1;
237 static gint ett_rtpproxy_command_parameters_remote = -1;
238 static gint ett_rtpproxy_command_parameters_repacketize = -1;
239 static gint ett_rtpproxy_command_parameters_dtmf = -1;
240 static gint ett_rtpproxy_command_parameters_cmap = -1;
241 static gint ett_rtpproxy_command_parameters_proto = -1;
242 static gint ett_rtpproxy_command_parameters_transcode = -1;
243 static gint ett_rtpproxy_command_parameters_acc = -1;
244 static gint ett_rtpproxy_tag = -1;
245 static gint ett_rtpproxy_notify = -1;
246
247 static gint ett_rtpproxy_reply = -1;
248
249 static gint ett_rtpproxy_ng_bencode = -1;
250
251 /* Default values */
252 static guint rtpproxy_tcp_port = 22222;
253 static guint rtpproxy_udp_port = 22222;
254 static gboolean rtpproxy_establish_conversation = TRUE;
255 /* See - http://www.opensips.org/html/docs/modules/devel/rtpproxy.html#id250016 */
256 /* See - http://www.kamailio.org/docs/modules/devel/modules/rtpproxy.html#idm448 */
257 static guint rtpproxy_timeout = 1000;
258 static nstime_t rtpproxy_timeout_ns = {1, 0};
259
260 void proto_reg_handoff_rtpproxy(void);
261
262 static gint
263 rtpproxy_add_tag(proto_tree *rtpproxy_tree, tvbuff_t *tvb, guint begin, guint realsize)
264 {
265         proto_item *ti = NULL;
266         proto_tree *another_tree = NULL;
267         gint new_offset;
268         guint end;
269
270         new_offset = tvb_find_guint8(tvb, begin, -1, ' ');
271         if(new_offset < 0)
272                 end = realsize; /* No more parameters */
273         else
274                 end = new_offset;
275
276         /* SER/OpenSER/OpenSIPS/Kamailio adds Media-ID right after the Tag
277          * separated by a semicolon
278          */
279         new_offset = tvb_find_guint8(tvb, begin, end, ';');
280         if(new_offset == -1){
281                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, end - begin, ENC_ASCII | ENC_NA);
282                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
283                 ti = proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, 0, ENC_ASCII | ENC_NA);
284                 proto_item_append_text(ti, "<skipped>");
285                 PROTO_ITEM_SET_GENERATED(ti);
286         }
287         else{
288                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, new_offset - begin, ENC_ASCII | ENC_NA);
289                 if ((guint)new_offset == begin){
290                         proto_item_append_text(ti, "<skipped>"); /* A very first Offer/Update command */
291                         PROTO_ITEM_SET_GENERATED(ti);
292                 }
293                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag);
294                 proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, end - (new_offset+1), ENC_ASCII | ENC_NA);
295         }
296         return (end == realsize ? -1 : (gint)end);
297 }
298
299 static void
300 rtpproxy_add_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint realsize)
301 {
302         proto_item *ti;
303         proto_tree *another_tree = NULL;
304         guint offset = 0;
305         guint new_offset = 0;
306         gint i;
307         guint pt = 0;
308         gchar** codecs = NULL;
309         guint codec_len;
310         guint8* rawstr = NULL;
311         guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
312
313         /* Extract the entire parameters line. */
314         /* Something like "t4p1iic8,0,2,4,18,96,97,98,100,101" */
315         rawstr = tvb_get_string_enc(wmem_packet_scope(), tvb, begin, realsize, ENC_ASCII);
316
317         while(offset < realsize){
318                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameter, tvb, begin + offset, 1, ENC_NA);
319                 offset++; /* Skip 1-byte parameter's type */
320                 switch (g_ascii_tolower(tvb_get_guint8(tvb, begin+offset-1)))
321                 {
322                         /* Official long parameters */
323                         case 'c':
324                                 new_offset = (gint)strspn(rawstr+offset, "0123456789,");
325                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_codecs);
326                                 codecs = g_strsplit(tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ",", 0);
327                                 i = 0;
328                                 while(codecs[i]){
329                                         /* We assume strings < 2^32-1 bytes long. :-) */
330                                         codec_len = (guint)strlen(codecs[i]);
331                                         ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_codec, tvb, begin+offset, codec_len,
332                                                         (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, codec_len, ENC_ASCII), NULL, 10));
333                                         proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(tvb,begin+offset,codec_len),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
334                                         offset += codec_len;
335                                         if(codecs[i+1])
336                                                 offset++; /* skip comma */
337                                         i++;
338                                 };
339                                 g_strfreev(codecs);
340                                 break;
341                         case 'l':
342                                 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
343                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_local);
344                                 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
345                                         proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_local_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
346                                 else
347                                         proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
348                                 offset += new_offset;
349                                 break;
350                         case 'r':
351                                 new_offset = (gint)strspn(rawstr+offset, "0123456789.");
352                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_remote);
353                                 if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), ipaddr))
354                                         proto_tree_add_ipv4(another_tree, hf_rtpproxy_command_parameter_remote_ipv4, tvb, begin+offset, new_offset, ipaddr[0]);
355                                 else
356                                         proto_tree_add_expert(another_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin+offset, new_offset);
357                                 offset += new_offset;
358                                 break;
359                         case 'z':
360                                 new_offset = (gint)strspn(rawstr+offset, "0123456789");
361                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_repacketize);
362                                 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_repacketize, tvb, begin+offset, new_offset,
363                                                 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
364                                 offset += new_offset;
365                                 break;
366                         /* Unofficial long parameters */
367                         case 'd':
368                                 new_offset = (gint)strspn(rawstr+offset, "0123456789");
369                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_dtmf);
370                                 proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_dtmf, tvb, begin+offset, new_offset,
371                                                 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
372                                 if(rtpproxy_establish_conversation){
373                                         pt = (guint)strtoul(tvb_format_text(tvb,begin+offset,new_offset),NULL,10);
374                                         dissector_add_uint("rtp.pt", pt, rtp_events_handle);
375                                 }
376                                 offset += new_offset;
377                                 break;
378                         case 'm':
379                                 new_offset = (gint)strspn(rawstr+offset, "0123456789=,");
380                                 /* TODO */
381                                 offset += new_offset;
382                                 break;
383                         case 'p':
384                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_proto);
385                                 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_proto, tvb, begin+offset, 1, ENC_NA);
386                                 offset++;
387                                 break;
388                         case 't':
389                                 new_offset = (gint)strspn(rawstr+offset, "0123456789");
390                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_transcode);
391                                 ti = proto_tree_add_uint(another_tree, hf_rtpproxy_command_parameter_transcode, tvb, begin+offset, new_offset,
392                                                 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin+offset, new_offset, ENC_ASCII), NULL, 10));
393                                 proto_item_append_text(ti, " (%s)", val_to_str_ext((guint)strtoul(tvb_format_text(tvb,begin+offset, new_offset),NULL,10), &rtp_payload_type_vals_ext, "Unknown"));
394                                 offset += new_offset;
395                                 break;
396                         case 'v':
397                                 another_tree = proto_item_add_subtree(ti, ett_rtpproxy_command_parameters_acc);
398                                 proto_tree_add_item(another_tree, hf_rtpproxy_command_parameter_acc, tvb, begin+offset, 1, ENC_NA);
399                                 offset++;
400                                 break;
401                         default:
402                                 break;
403                 }
404         }
405 }
406
407 static rtpproxy_info_t *
408 rtpproxy_add_tid(gboolean is_request, tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, rtpproxy_conv_info_t *rtpproxy_conv, gchar* cookie)
409 {
410         rtpproxy_info_t *rtpproxy_info;
411         proto_item *pi;
412
413         if (!PINFO_FD_VISITED(pinfo)) {
414                 if (is_request){
415                         rtpproxy_info = wmem_new(wmem_file_scope(), rtpproxy_info_t);
416                         rtpproxy_info->req_frame = PINFO_FD_NUM(pinfo);
417                         rtpproxy_info->resp_frame = 0;
418                         rtpproxy_info->req_time = pinfo->fd->abs_ts;
419                         rtpproxy_info->callid = NULL;
420                         wmem_tree_insert_string(rtpproxy_conv->trans, cookie, rtpproxy_info, 0);
421                 } else {
422                         rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
423                         if (rtpproxy_info) {
424                                 rtpproxy_info->resp_frame = PINFO_FD_NUM(pinfo);
425                         }
426                 }
427         } else {
428                 rtpproxy_info = (rtpproxy_info_t *)wmem_tree_lookup_string(rtpproxy_conv->trans, cookie, 0);
429                 if (rtpproxy_info && (is_request ? rtpproxy_info->resp_frame : rtpproxy_info->req_frame)) {
430                         nstime_t ns;
431
432                         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);
433                         PROTO_ITEM_SET_GENERATED(pi);
434
435                         /* If reply then calculate response time */
436                         if (!is_request){
437                                 nstime_delta(&ns, &pinfo->fd->abs_ts, &rtpproxy_info->req_time);
438                                 pi = proto_tree_add_time(rtpproxy_tree, hf_rtpproxy_response_time, tvb, 0, 0, &ns);
439                                 PROTO_ITEM_SET_GENERATED(pi);
440                                 if (nstime_cmp(&rtpproxy_timeout_ns, &ns) < 0)
441                                         expert_add_info_format(pinfo, rtpproxy_tree, &ei_rtpproxy_timeout, "Response timeout %.3f seconds", nstime_to_sec(&ns));
442                         }
443                 }
444         }
445         /* Could be NULL so we should check it before dereferencing */
446         return rtpproxy_info;
447 }
448
449 static void
450 rtpproxy_add_notify_addr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rtpproxy_tree, guint begin, guint end)
451 {
452         gint offset = 0;
453         gint tmp = 0;
454         gboolean ipv6 = FALSE;
455         guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
456         proto_item *ti;
457
458         /* Check for at least one colon */
459         offset = tvb_find_guint8(tvb, begin, end, ':');
460         if(offset != -1){
461                 /* Find if it's the latest colon (not in case of a IPv6) */
462                 while((tmp = tvb_find_guint8(tvb, offset+1, end, ':')) != -1){
463                         ipv6 = TRUE;
464                         offset = tmp;
465                 }
466                 /* We have ip:port */
467                 if(ipv6){
468                         if(str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, offset - begin, ENC_ASCII), ipaddr))
469                                 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, offset - begin, (const guint8 *)ipaddr);
470                         else
471                                 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, begin, offset - begin);
472                 }
473                 else{
474                         if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, offset - begin, ENC_ASCII), ipaddr))
475                                 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, offset - begin, ipaddr[0]);
476                         else
477                                 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, begin, offset - begin);
478                 }
479                 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, offset+1, end - (offset+1),
480                         (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset+1, end - (offset+1), ENC_ASCII), NULL, 10));
481         }
482         else{
483                 /* Only port is supplied - take IPv4/IPv6 from  ip.src/ipv6.src respectively */
484                 expert_add_info(pinfo, rtpproxy_tree, &ei_rtpproxy_notify_no_ip);
485                 if (pinfo->src.type == AT_IPv4)
486                         ti = proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, 0, ((guint32*)(pinfo->src.data))[0]);
487                 else
488                         ti = proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, 0, (const guint8 *)(pinfo->src.data));
489                 PROTO_ITEM_SET_GENERATED(ti);
490                 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, begin, end - begin,
491                         (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, begin, end - begin, ENC_ASCII), NULL, 10));
492         }
493 }
494
495 static int
496 dissect_rtpproxy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
497 {
498         gboolean has_lf = FALSE;
499         gint offset = 0;
500         gint new_offset = 0;
501         guint tmp;
502         guint tmp2;
503         gint realsize = 0;
504         guint8* rawstr;
505         guint8* tmpstr;
506         proto_item *ti;
507         proto_item *ti2;
508         proto_tree *rtpproxy_tree;
509         conversation_t *conversation;
510         rtpproxy_conv_info_t *rtpproxy_conv;
511         gchar* cookie = NULL;
512         /* For RT(C)P setup */
513         address addr;
514         guint16 port;
515         guint32 ipaddr[4]; /* Enough room for IPv4 or IPv6 */
516         rtpproxy_info_t *rtpproxy_info = NULL;
517         tvbuff_t *subtvb;
518
519         /* If it does not start with a printable character it's not RTPProxy */
520         if(!isprint(tvb_get_guint8(tvb, 0)))
521                 return 0;
522
523         /* Extract Cookie */
524         offset = tvb_find_guint8(tvb, offset, -1, ' ');
525         if(offset == -1)
526                 return 0;
527
528         /* Clear out stuff in the info column - we''l set it later */
529         col_clear(pinfo->cinfo, COL_INFO);
530
531         ti = proto_tree_add_item(tree, proto_rtpproxy, tvb, 0, -1, ENC_NA);
532         rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy);
533
534         proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_cookie, tvb, 0, offset, ENC_ASCII | ENC_NA);
535         cookie = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, offset, ENC_ASCII);
536
537         /* Skip whitespace */
538         offset = tvb_skip_wsp(tvb, offset+1, -1);
539
540         /* Calculate size to prevent recalculation in the future */
541         realsize = tvb_reported_length(tvb);
542
543
544         /* Check for LF (required for TCP connection, optional for UDP) */
545         if (tvb_get_guint8(tvb, realsize - 1) == '\n'){
546                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy");
547                 /* Don't count trailing LF */
548                 realsize -= 1;
549                 has_lf = TRUE;
550         }
551         else
552                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPproxy (no LF)"); /* FIXME replace with expert info field */
553
554
555         /* Try to create conversation */
556         conversation = find_or_create_conversation(pinfo);
557         rtpproxy_conv = (rtpproxy_conv_info_t *)conversation_get_proto_data(conversation, proto_rtpproxy);
558         if (!rtpproxy_conv) {
559                 rtpproxy_conv = wmem_new(wmem_file_scope(), rtpproxy_conv_info_t);
560                 rtpproxy_conv->trans = wmem_tree_new(wmem_file_scope());
561                 conversation_add_proto_data(conversation, proto_rtpproxy, rtpproxy_conv);
562         }
563
564         /* Get payload string */
565         rawstr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, realsize - offset, ENC_ASCII);
566
567         /* Extract command */
568         tmp = g_ascii_tolower(tvb_get_guint8(tvb, offset));
569         switch (tmp)
570         {
571                 case 's':
572                         /* A specific case - long statistics answer */
573                         /* %COOKIE% sessions created %NUM0% active sessions: %NUM1% */
574                         rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
575                         if ('e' == tvb_get_guint8(tvb, offset+1)){
576                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
577                                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
578
579                                 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
580                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_status, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
581                                 break;
582                         }
583                 case 'i':
584                 case 'x':
585                 case 'u':
586                 case 'l':
587                 case 'd':
588                         tmp2 = tvb_get_guint8(tvb, offset+1);
589                         if(('1' <= tmp2) && (tmp2 <= '9') && (tvb_get_guint8(tvb, offset+2) == ':')){
590                                 col_add_fstr(pinfo->cinfo, COL_INFO, "RTPproxy-ng: %s", rawstr);
591                                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ng_bencode, tvb, offset, -1, ENC_ASCII | ENC_NA);
592                                 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_ng_bencode);
593                                 subtvb = tvb_new_subset_remaining(tvb, offset);
594                                 call_dissector(bencode_handle, subtvb, pinfo, rtpproxy_tree);
595                                 break;
596                         }
597                 case 'p':
598                 case 'v':
599                 case 'r':
600                 case 'c':
601                 case 'q':
602                         rtpproxy_info = rtpproxy_add_tid(TRUE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
603                         col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s", rawstr);
604                         ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_request, tvb, offset, -1, ENC_NA);
605                         rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_request);
606
607                         /* A specific case - version request */
608                         if ((tmp == 'v') && (offset + (gint)strlen("VF YYYMMDD") + 1 == realsize)){
609                                 /* Skip whitespace */
610                                 new_offset = tvb_skip_wsp(tvb, offset + ((guint)strlen("VF") + 1), -1);
611                                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_version_request, tvb, new_offset, (gint)strlen("YYYYMMDD"), ENC_ASCII | ENC_NA);
612                                 tmpstr = tvb_get_string_enc(wmem_packet_scope(), tvb, new_offset, (gint)strlen("YYYYMMDD"), ENC_ASCII);
613                                 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, versiontypenames, "Unknown"));
614                                 break;
615                         }
616
617                         /* All other commands */
618                         ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command, tvb, offset, 1, ENC_NA);
619
620                         /* A specific case - handshake/ping */
621                         if (tmp == 'v')
622                                 break; /* No more parameters */
623
624                         /* A specific case - close all calls */
625                         if (tmp == 'x')
626                                 break; /* No more parameters */
627
628                         /* Extract parameters */
629                         /* Parameters should be right after the command and before EOL (in case of Info command) or before whitespace */
630                         new_offset = (tmp == 'i' ? (realsize - 1 > offset ? offset + (gint)strlen("Ib") : offset + (gint)strlen("I")) : tvb_find_guint8(tvb, offset, -1, ' '));
631
632                         if (new_offset != offset + 1){
633                                 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_command);
634                                 ti2 = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_command_parameters, tvb, offset+1, new_offset - (offset+1), ENC_ASCII | ENC_NA);
635                                 rtpproxy_add_parameter(tvb, pinfo, proto_item_add_subtree(ti2, ett_rtpproxy_command_parameters), offset+1, new_offset - (offset+1));
636                                 rtpproxy_tree = proto_item_get_parent(ti);
637                         }
638
639                         /* A specific case - query information */
640                         if (tmp == 'i')
641                                 break; /* No more parameters */
642
643                         /* Skip whitespace */
644                         offset = tvb_skip_wsp(tvb, new_offset+1, -1);
645
646                         /* Extract Call-ID */
647                         new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
648                         proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
649                         if(rtpproxy_info && !rtpproxy_info->callid)
650                                 rtpproxy_info->callid = tvb_get_string_enc(wmem_file_scope(), tvb, offset, new_offset - offset, ENC_ASCII);
651                         /* Skip whitespace */
652                         offset = tvb_skip_wsp(tvb, new_offset+1, -1);
653
654                         /* Extract IP and Port in case of Offer/Answer */
655                         if ((tmp == 'u') || (tmp == 'l')){
656                                 /* Extract IP */
657                                 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
658                                 if (tvb_find_guint8(tvb, offset, new_offset - offset, ':') == -1){
659                                         if(str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
660                                                 proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, new_offset - offset, ipaddr[0]);
661                                         else
662                                                 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, new_offset - offset);
663                                 }
664                                 else{
665                                         if(str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), ipaddr))
666                                                 proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, new_offset - offset, (const guint8 *)ipaddr);
667                                         else
668                                                 proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, new_offset - offset);
669                                 }
670                                 /* Skip whitespace */
671                                 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
672
673                                 /* Extract Port */
674                                 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
675                                 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset,
676                                                 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
677                                 /* Skip whitespace */
678                                 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
679                         }
680
681                         /* Extract Copy target */
682                         if (tmp == 'c'){
683                                 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
684                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_copy_target, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
685                                 /* Skip whitespace */
686                                 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
687                         }
688
689                         /* Extract Playback file and codecs */
690                         if (tmp == 'p'){
691                                 /* Extract filename */
692                                 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
693                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_playback_filename, tvb, offset, new_offset - offset, ENC_ASCII | ENC_NA);
694                                 /* Skip whitespace */
695                                 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
696
697                                 /* Extract codec */
698                                 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
699                                 proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_playback_codec, tvb, offset, new_offset - offset,
700                                                 (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10));
701                                 /* Skip whitespace */
702                                 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
703                         }
704
705                         /* Extract first tag */
706                         new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
707                         if(new_offset == -1)
708                                 break; /* No more parameters */
709                         /* Skip whitespace */
710                         offset = tvb_skip_wsp(tvb, new_offset+1, -1);
711
712                         /* Extract second tag */
713                         new_offset = rtpproxy_add_tag(rtpproxy_tree, tvb, offset, realsize);
714                         if(new_offset == -1)
715                                 break; /* No more parameters */
716                         /* Skip whitespace */
717                         offset = tvb_skip_wsp(tvb, new_offset+1, -1);
718
719                         /* Extract Notification address */
720                         if (tmp == 'u'){
721                                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
722                                 proto_item_set_text(ti, "Notify");
723                                 rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_notify);
724
725                                 /* Check for NotifyTag parameter (separated by space) */
726                                 new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
727                                 if(new_offset == -1){
728                                         /* NotifyTag wasn't found (we should re-use Call-ID instead) */
729                                         rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, realsize);
730                                         break; /* No more parameters */
731                                 }
732
733                                 /* NotifyTag was found */
734                                 rtpproxy_add_notify_addr(tvb, pinfo, rtpproxy_tree, offset, new_offset);
735                                 /* Skip whitespace */
736                                 offset = tvb_skip_wsp(tvb, new_offset+1, -1);
737
738                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_tag, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
739                         }
740                         break;
741                 case 'a':
742                 case 'e':
743                 case '0':
744                 case '1':
745                 case '2':
746                 case '3':
747                 case '4':
748                 case '5':
749                 case '6':
750                 case '7':
751                 case '8':
752                 case '9':
753                         rtpproxy_info = rtpproxy_add_tid(FALSE, tvb, pinfo, rtpproxy_tree, rtpproxy_conv, cookie);
754                         if (tmp == 'e')
755                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Error reply: %s", rawstr);
756                         else
757                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Reply: %s", rawstr);
758
759                         ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_reply, tvb, offset, -1, ENC_NA);
760                         rtpproxy_tree = proto_item_add_subtree(ti, ett_rtpproxy_reply);
761
762                         if(rtpproxy_info && rtpproxy_info->callid){
763                                 ti = proto_tree_add_string(rtpproxy_tree, hf_rtpproxy_callid, tvb, offset, 0, rtpproxy_info->callid);
764                                 PROTO_ITEM_SET_GENERATED(ti);
765                         }
766
767                         if (tmp == 'e'){
768                                 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
769                                 tmpstr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII);
770                                 ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_error, tvb, offset, (gint)strlen(tmpstr), ENC_ASCII | ENC_NA);
771                                 proto_item_append_text(ti, " (%s)", str_to_str(tmpstr, errortypenames, "Unknown"));
772                                 break;
773                         }
774
775                         if (tmp == 'a'){
776                                 /* A specific case - short statistics answer */
777                                 /* %COOKIE% active sessions: %NUM1% */
778                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_status, tvb, offset, realsize - offset, ENC_ASCII | ENC_NA);
779                                 break;
780                         }
781                         if ((tmp == '0')&& ((tvb_reported_length(tvb) == (guint)(offset+1))||(tvb_reported_length(tvb) == (guint)(offset+2)))){
782                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ok, tvb, offset, 1, ENC_ASCII | ENC_NA);
783                                 break;
784                         }
785                         if ((tmp == '1') && ((tvb_reported_length(tvb) == (guint)(offset+1))||(tvb_reported_length(tvb) == (guint)(offset+2)))){
786                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_ok, tvb, offset, 1, ENC_ASCII | ENC_NA);
787                                 break;
788                         }
789                         if (tvb_reported_length(tvb) == (guint)(offset+9)){
790                                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_version_supported, tvb, offset, 8, ENC_ASCII | ENC_NA);
791                                 break;
792                         }
793
794                         /* Extract Port */
795                         new_offset = tvb_find_guint8(tvb, offset, -1, ' ');
796                         /* Convert port to unsigned 16-bit number */
797                         port = (guint16) g_ascii_strtoull((gchar*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, new_offset - offset, ENC_ASCII), NULL, 10);
798                         proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_port, tvb, offset, new_offset - offset, port);
799                         /* Skip whitespace */
800                         offset = tvb_skip_wsp(tvb, new_offset+1, -1);
801
802                         /* Extract IP */
803                         memset(&addr, 0, sizeof(address));
804
805                         /* Try rtpengine bogus extension first. It appends 4 or
806                          * 6 depending on type of the IP. See
807                          * https://github.com/sipwise/rtpengine/blob/master/daemon/call_interfaces.c#L66
808                          * for further details */
809                         tmp = tvb_find_guint8(tvb, offset, -1, ' ');
810                         if(tmp == (guint)(-1)){
811                                 /* No extension - operate normally */
812                                 tmp = tvb_find_line_end(tvb, offset, -1, &new_offset, FALSE);
813                         }
814                         else {
815                                 tmp -= offset;
816                         }
817
818                         if (tvb_find_guint8(tvb, offset, -1, ':') == -1){
819                                 if (str_to_ip((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII), ipaddr)){
820                                         addr.type = AT_IPv4;
821                                         addr.len  = 4;
822                                         addr.data = wmem_memdup(wmem_packet_scope(), ipaddr, 4);
823                                         proto_tree_add_ipv4(rtpproxy_tree, hf_rtpproxy_ipv4, tvb, offset, tmp, ipaddr[0]);
824                                 }
825                                 else
826                                         proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv4, tvb, offset, tmp);
827                         }
828                         else{
829                                 if (str_to_ip6((char*)tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tmp, ENC_ASCII), ipaddr)){
830                                         addr.type = AT_IPv6;
831                                         addr.len  = 16;
832                                         addr.data = wmem_memdup(wmem_packet_scope(), ipaddr, 16);
833                                         proto_tree_add_ipv6(rtpproxy_tree, hf_rtpproxy_ipv6, tvb, offset, tmp, (const guint8 *)ipaddr);
834                                 }
835                                 else
836                                         proto_tree_add_expert(rtpproxy_tree, pinfo, &ei_rtpproxy_bad_ipv6, tvb, offset, tmp);
837                         }
838
839                         if(rtpproxy_establish_conversation){
840                                 if (rtp_handle) {
841                                         /* FIXME tell if isn't a video stream, and setup codec mapping */
842                                         if (addr.len)
843                                                 rtp_add_address(pinfo, &addr, port, 0, "RTPproxy", pinfo->fd->num, 0, NULL);
844                                 }
845                                 if (rtcp_handle) {
846                                         if (addr.len)
847                                                 rtcp_add_address(pinfo, &addr, port+1, 0, "RTPproxy", pinfo->fd->num);
848                                 }
849                         }
850                         break;
851                 default:
852                         break;
853         }
854         if (has_lf)
855                 proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_lf, tvb, realsize, 1, ENC_NA);
856
857         return tvb_length(tvb);
858 }
859
860 void
861 proto_register_rtpproxy(void)
862 {
863         module_t *rtpproxy_module;
864         expert_module_t* expert_rtpproxy_module;
865
866         static hf_register_info hf[] = {
867                 {
868                         &hf_rtpproxy_cookie,
869                         {
870                                 "Cookie",
871                                 "rtpproxy.cookie",
872                                 FT_STRING,
873                                 BASE_NONE,
874                                 NULL,
875                                 0x0,
876                                 NULL,
877                                 HFILL
878                         }
879                 },
880                 {
881                         &hf_rtpproxy_version_request,
882                         {
883                                 "Version Request",
884                                 "rtpproxy.version",
885                                 FT_STRING,
886                                 BASE_NONE,
887                                 NULL,
888                                 0x0,
889                                 NULL,
890                                 HFILL
891                         }
892                 },
893                 {
894                         &hf_rtpproxy_version_supported,
895                         {
896                                 "Version Supported",
897                                 "rtpproxy.version_supported",
898                                 FT_STRING,
899                                 BASE_NONE,
900                                 NULL,
901                                 0x0,
902                                 NULL,
903                                 HFILL
904                         }
905                 },
906                 {
907                         &hf_rtpproxy_error,
908                         {
909                                 "Error",
910                                 "rtpproxy.error",
911                                 FT_STRING,
912                                 BASE_NONE,
913                                 NULL,
914                                 0x0,
915                                 NULL,
916                                 HFILL
917                         }
918                 },
919                 {
920                         &hf_rtpproxy_ok,
921                         {
922                                 "Ok",
923                                 "rtpproxy.ok",
924                                 FT_UINT8,
925                                 BASE_DEC,
926                                 VALS(oktypenames),
927                                 0x0,
928                                 NULL,
929                                 HFILL
930                         }
931                 },
932                 {
933                         &hf_rtpproxy_status,
934                         {
935                                 "Status",
936                                 "rtpproxy.status",
937                                 FT_STRING,
938                                 BASE_NONE,
939                                 NULL,
940                                 0x0,
941                                 NULL,
942                                 HFILL
943                         }
944                 },
945                 {
946                         &hf_rtpproxy_ipv4,
947                         {
948                                 "IPv4",
949                                 "rtpproxy.ipv4",
950                                 FT_IPv4,
951                                 BASE_NONE,
952                                 NULL,
953                                 0x0,
954                                 NULL,
955                                 HFILL
956                         }
957                 },
958                 {
959                         &hf_rtpproxy_ipv6,
960                         {
961                                 "IPv6",
962                                 "rtpproxy.ipv6",
963                                 FT_IPv6,
964                                 BASE_NONE,
965                                 NULL,
966                                 0x0,
967                                 NULL,
968                                 HFILL
969                         }
970                 },
971                 {
972                         &hf_rtpproxy_port,
973                         {
974                                 "Port",
975                                 "rtpproxy.port",
976                                 FT_UINT16, /* 0 - 65535 */
977                                 BASE_DEC,
978                                 NULL,
979                                 0x0,
980                                 NULL,
981                                 HFILL
982                         }
983                 },
984                 {
985                         &hf_rtpproxy_request,
986                         {
987                                 "Request",
988                                 "rtpproxy.request",
989                                 FT_NONE,
990                                 BASE_NONE,
991                                 NULL,
992                                 0x0,
993                                 NULL,
994                                 HFILL
995                         }
996                 },
997                 {
998                         &hf_rtpproxy_command,
999                         {
1000                                 "Command",
1001                                 "rtpproxy.command",
1002                                 FT_UINT8,
1003                                 BASE_DEC,
1004                                 VALS(commandtypenames),
1005                                 0x0,
1006                                 NULL,
1007                                 HFILL
1008                         }
1009                 },
1010                 {
1011                         &hf_rtpproxy_command_parameters,
1012                         {
1013                                 "Command parameters",
1014                                 "rtpproxy.command_parameters",
1015                                 FT_STRING,
1016                                 BASE_NONE,
1017                                 NULL,
1018                                 0x0,
1019                                 NULL,
1020                                 HFILL
1021                         }
1022                 },
1023                 {
1024                         &hf_rtpproxy_command_parameter,
1025                         {
1026                                 "Parameter",
1027                                 "rtpproxy.command_parameter",
1028                                 FT_UINT8,
1029                                 BASE_DEC,
1030                                 VALS(paramtypenames),
1031                                 0x0,
1032                                 NULL,
1033                                 HFILL
1034                         }
1035                 },
1036                 {
1037                         &hf_rtpproxy_command_parameter_codec,
1038                         {
1039                                 "Allowed codec",
1040                                 "rtpproxy.command_parameter_codec",
1041                                 FT_UINT8, /* 0 - 127 */
1042                                 BASE_DEC,
1043                                 NULL,
1044                                 0x0,
1045                                 NULL,
1046                                 HFILL
1047                         }
1048                 },
1049                 {
1050                         &hf_rtpproxy_command_parameter_local_ipv4,
1051                         {
1052                                 "Local IPv4 address",
1053                                 "rtpproxy.command_parameter_local_ipv4",
1054                                 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1055                                 BASE_NONE,
1056                                 NULL,
1057                                 0x0,
1058                                 NULL,
1059                                 HFILL
1060                         }
1061                 },
1062                 {
1063                         &hf_rtpproxy_command_parameter_remote_ipv4,
1064                         {
1065                                 "Remote IPv4 address",
1066                                 "rtpproxy.command_parameter_remote_ipv4",
1067                                 FT_IPv4, /* FIXME - is it ever possible to see IPv6 here? */
1068                                 BASE_NONE,
1069                                 NULL,
1070                                 0x0,
1071                                 NULL,
1072                                 HFILL
1073                         }
1074                 },
1075                 {
1076                         &hf_rtpproxy_command_parameter_repacketize,
1077                         {
1078                                 "Repacketize (ms)",
1079                                 "rtpproxy.command_parameter_repacketize",
1080                                 FT_UINT16, /* 0 - 1000 milliseconds */
1081                                 BASE_DEC,
1082                                 NULL,
1083                                 0x0,
1084                                 NULL,
1085                                 HFILL
1086                         }
1087                 },
1088                 {
1089                         &hf_rtpproxy_command_parameter_dtmf,
1090                         {
1091                                 "DTMF payload ID",
1092                                 "rtpproxy.command_parameter_dtmf",
1093                                 FT_UINT8, /* 0 - 127 */
1094                                 BASE_DEC,
1095                                 NULL,
1096                                 0x0,
1097                                 NULL,
1098                                 HFILL
1099                         }
1100                 },
1101                 {
1102                         &hf_rtpproxy_command_parameter_proto,
1103                         {
1104                                 "RTP tramsission protocol",
1105                                 "rtpproxy.command_parameter_proto",
1106                                 FT_UINT8,
1107                                 BASE_DEC,
1108                                 VALS(prototypenames),
1109                                 0x0,
1110                                 NULL,
1111                                 HFILL
1112                         }
1113                 },
1114                 {
1115                         &hf_rtpproxy_command_parameter_transcode,
1116                         {
1117                                 "Transcode to",
1118                                 "rtpproxy.command_parameter_transcode",
1119                                 FT_UINT8, /* 0 - 127 */
1120                                 BASE_DEC,
1121                                 NULL,
1122                                 0x0,
1123                                 NULL,
1124                                 HFILL
1125                         }
1126                 },
1127                 {
1128                         &hf_rtpproxy_command_parameter_acc,
1129                         {
1130                                 "Accounting",
1131                                 "rtpproxy.command_parameter_acc",
1132                                 FT_UINT8,
1133                                 BASE_DEC,
1134                                 VALS(acctypenames),
1135                                 0x0,
1136                                 NULL,
1137                                 HFILL
1138                         }
1139                 },
1140                 {
1141                         &hf_rtpproxy_copy_target,
1142                         {
1143                                 "Copy target",
1144                                 "rtpproxy.copy_target",
1145                                 FT_STRING, /* Filename or UDP address, e.g. /var/tmp/fileXXXX.yyy or IP:Port */
1146                                 BASE_NONE,
1147                                 NULL,
1148                                 0x0,
1149                                 NULL,
1150                                 HFILL
1151                         }
1152                 },
1153                 {
1154                         &hf_rtpproxy_playback_filename,
1155                         {
1156                                 "Playback filename",
1157                                 "rtpproxy.playback_filename",
1158                                 FT_STRING,
1159                                 BASE_NONE,
1160                                 NULL,
1161                                 0x0,
1162                                 NULL,
1163                                 HFILL
1164                         }
1165                 },
1166                 {
1167                         &hf_rtpproxy_playback_codec,
1168                         {
1169                                 "Playback codec",
1170                                 "rtpproxy.playback_codec",
1171                                 FT_UINT8, /* 0 - 127 */
1172                                 BASE_DEC,
1173                                 NULL,
1174                                 0x0,
1175                                 NULL,
1176                                 HFILL
1177                         }
1178                 },
1179                 {
1180                         &hf_rtpproxy_callid,
1181                         {
1182                                 "Call-ID",
1183                                 "rtpproxy.callid",
1184                                 FT_STRING,
1185                                 BASE_NONE,
1186                                 NULL,
1187                                 0x0,
1188                                 NULL,
1189                                 HFILL
1190                         }
1191                 },
1192                 {
1193                         &hf_rtpproxy_notify,
1194                         {
1195                                 "Notify",
1196                                 "rtpproxy.notify",
1197                                 FT_STRING,
1198                                 BASE_NONE,
1199                                 NULL,
1200                                 0x0,
1201                                 NULL,
1202                                 HFILL
1203                         }
1204                 },
1205                 {
1206                         &hf_rtpproxy_tag,
1207                         {
1208                                 "Tag",
1209                                 "rtpproxy.tag",
1210                                 FT_STRING,
1211                                 BASE_NONE,
1212                                 NULL,
1213                                 0x0,
1214                                 NULL,
1215                                 HFILL
1216                         }
1217                 },
1218                 {
1219                         &hf_rtpproxy_mediaid,
1220                         {
1221                                 "Media-ID",
1222                                 "rtpproxy.mediaid",
1223                                 FT_STRING,
1224                                 BASE_NONE,
1225                                 NULL,
1226                                 0x0,
1227                                 NULL,
1228                                 HFILL
1229                         }
1230                 },
1231                 {
1232                         &hf_rtpproxy_notify_ipv4,
1233                         {
1234                                 "Notification IPv4",
1235                                 "rtpproxy.notify_ipv4",
1236                                 FT_IPv4,
1237                                 BASE_NONE,
1238                                 NULL,
1239                                 0x0,
1240                                 NULL,
1241                                 HFILL
1242                         }
1243                 },
1244                 {
1245                         &hf_rtpproxy_notify_ipv6,
1246                         {
1247                                 "Notification IPv6",
1248                                 "rtpproxy.notify_ipv6",
1249                                 FT_IPv6,
1250                                 BASE_NONE,
1251                                 NULL,
1252                                 0x0,
1253                                 NULL,
1254                                 HFILL
1255                         }
1256                 },
1257                 {
1258                         &hf_rtpproxy_notify_port,
1259                         {
1260                                 "Notification Port",
1261                                 "rtpproxy.notify_port",
1262                                 FT_UINT16,
1263                                 BASE_DEC,
1264                                 NULL,
1265                                 0x0,
1266                                 NULL,
1267                                 HFILL
1268                         }
1269                 },
1270                 {
1271                         &hf_rtpproxy_notify_tag,
1272                         {
1273                                 "Notification Tag",
1274                                 "rtpproxy.notify_tag",
1275                                 FT_STRING,
1276                                 BASE_NONE,
1277                                 NULL,
1278                                 0x0,
1279                                 NULL,
1280                                 HFILL
1281                         }
1282                 },
1283                 {
1284                         &hf_rtpproxy_reply,
1285                         {
1286                                 "Reply",
1287                                 "rtpproxy.reply",
1288                                 FT_NONE,
1289                                 BASE_NONE,
1290                                 NULL,
1291                                 0x0,
1292                                 NULL,
1293                                 HFILL
1294                         }
1295                 },
1296                 {
1297                         &hf_rtpproxy_lf,
1298                         {
1299                                 "LF",
1300                                 "rtpproxy.lf",
1301                                 FT_NONE,
1302                                 BASE_NONE,
1303                                 NULL,
1304                                 0x0,
1305                                 NULL,
1306                                 HFILL
1307                         }
1308                 },
1309                 {
1310                         &hf_rtpproxy_request_in,
1311                         {
1312                                 "Request In",
1313                                 "rtpproxy.request_in",
1314                                 FT_FRAMENUM,
1315                                 BASE_NONE,
1316                                 NULL,
1317                                 0x0,
1318                                 NULL,
1319                                 HFILL
1320                         }
1321
1322                 },
1323                 {
1324                         &hf_rtpproxy_response_in,
1325                         {
1326                                 "Response In",
1327                                 "rtpproxy.response_in",
1328                                 FT_FRAMENUM,
1329                                 BASE_NONE,
1330                                 NULL,
1331                                 0x0,
1332                                 NULL,
1333                                 HFILL
1334                         }
1335                 },
1336                 {
1337                         &hf_rtpproxy_response_time,
1338                         {
1339                                 "Response Time",
1340                                 "rtpproxy.response_time",
1341                                 FT_RELATIVE_TIME,
1342                                 BASE_NONE,
1343                                 NULL,
1344                                 0x0,
1345                                 "The time between the Request and the Reply",
1346                                 HFILL
1347                          }
1348                 },
1349                 {
1350                         &hf_rtpproxy_ng_bencode,
1351                         {
1352                                 "RTPproxy-ng bencode packet",
1353                                 "rtpproxy.ng.bencode",
1354                                 FT_STRING,
1355                                 BASE_NONE,
1356                                 NULL,
1357                                 0x0,
1358                                 "Serialized structure of integers, dictionaries, strings and lists.",
1359                                 HFILL
1360                         }
1361                 }
1362         };
1363
1364         static ei_register_info ei[] = {
1365                 { &ei_rtpproxy_timeout, { "rtpproxy.response_timeout", PI_RESPONSE_CODE, PI_WARN, "TIMEOUT", EXPFILL }},
1366                 { &ei_rtpproxy_notify_no_ip, { "rtpproxy.notify_no_ip", PI_RESPONSE_CODE, PI_COMMENT, "No notification IP address provided. Using ip.src or ipv6.src as a value.", EXPFILL }},
1367                 { &ei_rtpproxy_bad_ipv4, { "rtpproxy.bad_ipv4", PI_MALFORMED, PI_ERROR, "Bad IPv4", EXPFILL }},
1368                 { &ei_rtpproxy_bad_ipv6, { "rtpproxy.bad_ipv6", PI_MALFORMED, PI_ERROR, "Bad IPv6", EXPFILL }},
1369         };
1370
1371         /* Setup protocol subtree array */
1372         static gint *ett[] = {
1373                 &ett_rtpproxy,
1374                 &ett_rtpproxy_request,
1375                 &ett_rtpproxy_command,
1376                 &ett_rtpproxy_command_parameters,
1377                 &ett_rtpproxy_command_parameters_codecs,
1378                 &ett_rtpproxy_command_parameters_local,
1379                 &ett_rtpproxy_command_parameters_remote,
1380                 &ett_rtpproxy_command_parameters_repacketize,
1381                 &ett_rtpproxy_command_parameters_dtmf,
1382                 &ett_rtpproxy_command_parameters_cmap,
1383                 &ett_rtpproxy_command_parameters_proto,
1384                 &ett_rtpproxy_command_parameters_transcode,
1385                 &ett_rtpproxy_command_parameters_acc,
1386                 &ett_rtpproxy_tag,
1387                 &ett_rtpproxy_notify,
1388                 &ett_rtpproxy_reply,
1389                 &ett_rtpproxy_ng_bencode
1390         };
1391
1392         proto_rtpproxy = proto_register_protocol (
1393                         "Sippy RTPproxy Protocol", /* name       */
1394                         "RTPproxy",      /* short name */
1395                         "rtpproxy"       /* abbrev     */
1396                         );
1397
1398         proto_register_field_array(proto_rtpproxy, hf, array_length(hf));
1399         proto_register_subtree_array(ett, array_length(ett));
1400
1401         expert_rtpproxy_module = expert_register_protocol(proto_rtpproxy);
1402         expert_register_field_array(expert_rtpproxy_module, ei, array_length(ei));
1403
1404         rtpproxy_module = prefs_register_protocol(proto_rtpproxy, proto_reg_handoff_rtpproxy);
1405
1406         prefs_register_uint_preference(rtpproxy_module, "tcp.port",
1407                                                                  "RTPproxy TCP Port", /* Title */
1408                                                                  "RTPproxy TCP Port", /* Descr */
1409                                                                  10,
1410                                                                  &rtpproxy_tcp_port);
1411
1412         prefs_register_uint_preference(rtpproxy_module, "udp.port",
1413                                                                  "RTPproxy UDP Port", /* Title */
1414                                                                  "RTPproxy UDP Port", /* Descr */
1415                                                                  10,
1416                                                                  &rtpproxy_udp_port);
1417
1418         prefs_register_bool_preference(rtpproxy_module, "establish_conversation",
1419                                  "Establish Media Conversation",
1420                                  "Specifies that RTP/RTCP/T.38/MSRP/etc streams are decoded based "
1421                                  "upon port numbers found in RTPproxy answers",
1422                                  &rtpproxy_establish_conversation);
1423
1424         prefs_register_uint_preference(rtpproxy_module, "reply.timeout",
1425                                                                  "RTPproxy reply timeout", /* Title */
1426                                                                  "Maximum timeout value in waiting for reply from RTPProxy (in milliseconds).", /* Descr */
1427                                                                  10,
1428                                                                  &rtpproxy_timeout);
1429 }
1430
1431 void
1432 proto_reg_handoff_rtpproxy(void)
1433 {
1434         static guint old_rtpproxy_tcp_port = 0;
1435         static guint old_rtpproxy_udp_port = 0;
1436
1437         static gboolean rtpproxy_initialized = FALSE;
1438
1439         static dissector_handle_t rtpproxy_tcp_handle, rtpproxy_udp_handle;
1440
1441         if(!rtpproxy_initialized){
1442                 rtpproxy_tcp_handle = new_create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1443                 rtpproxy_udp_handle = new_create_dissector_handle(dissect_rtpproxy, proto_rtpproxy);
1444                 rtpproxy_initialized = TRUE;
1445         }
1446
1447         /* Register TCP port for dissection */
1448         if(old_rtpproxy_tcp_port != 0 && old_rtpproxy_tcp_port != rtpproxy_tcp_port)
1449                 dissector_delete_uint("tcp.port", old_rtpproxy_tcp_port, rtpproxy_tcp_handle);
1450         if(rtpproxy_tcp_port != 0 && old_rtpproxy_tcp_port != rtpproxy_tcp_port)
1451                 dissector_add_uint("tcp.port", rtpproxy_tcp_port, rtpproxy_tcp_handle);
1452         old_rtpproxy_tcp_port = rtpproxy_tcp_port;
1453
1454         /* Register UDP port for dissection */
1455         if(old_rtpproxy_udp_port != 0 && old_rtpproxy_udp_port != rtpproxy_udp_port)
1456                 dissector_delete_uint("udp.port", old_rtpproxy_udp_port, rtpproxy_udp_handle);
1457         if(rtpproxy_udp_port != 0 && old_rtpproxy_udp_port != rtpproxy_udp_port)
1458                 dissector_add_uint("udp.port", rtpproxy_udp_port, rtpproxy_udp_handle);
1459         old_rtpproxy_udp_port = rtpproxy_udp_port;
1460
1461         rtcp_handle   = find_dissector("rtcp");
1462         rtp_events_handle    = find_dissector("rtpevent");
1463         rtp_handle    = find_dissector("rtp");
1464         bencode_handle = find_dissector("bencode");
1465
1466         /* Calculate nstime_t struct for the timeout from the rtpproxy_timeout value in milliseconds */
1467         rtpproxy_timeout_ns.secs = (rtpproxy_timeout - rtpproxy_timeout % 1000) / 1000;
1468         rtpproxy_timeout_ns.nsecs = (rtpproxy_timeout % 1000) * 1000;
1469 }
1470
1471 /*
1472  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1473  *
1474  * Local variables:
1475  * c-basic-offset: 8
1476  * tab-width: 8
1477  * indent-tabs-mode: t
1478  * End:
1479  *
1480  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1481  * :indentSize=8:tabSize=8:noTabs=false:
1482  */