Ethereal-dev: [Ethereal-dev] Heuristic decode of RTP packets

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Ruud Linders <moztest@xxxxxxxxxxxxxxxxxxxx>
Date: Sat, 26 Jun 2004 19:48:50 +0200

As I often capture traces with RTP packets WITHOUT the corresponding call
control messages, ethereal doesn't decode the UDP packets as RTP.
This is not so unusual as one might think, the trace can be incomplete
or rather common, the SIP/H323 or whatever call control are send out of
different interfaces or even other boxes.

'Decode as' has the disadvantage that it has be be selected for every ip/port
combination.


Here is a PATCH for packet-rtp.c which adds an heuristic UDP/RTP decoder.
Since it is difficult to determine if an UDP packet is actually an RTP
packet, i.e. the heuristic isn't perfect, the decoding can be turned off
using a preference setting.
Default the preference is OFF thus current behaviour is unchanged.

While I was at it, I removed some dead code probably a leftover from
years ago when Andreas Sikkema's used some of it for the external H323
plugin.

Please consider applying.

Thanks.

--- packet-rtp.c.ORIG	Sun Feb 15 22:33:16 2004
+++ packet-rtp.c	Sat Jun 26 18:45:44 2004
@@ -6,6 +6,9 @@
  * Copyright 2000, Philips Electronics N.V.
  * Written by Andreas Sikkema <h323@xxxxxxxxxx>
  *
+ * 20040626 Ruud Linders <ruud_at_lucent.com>
+ * added heuristic RTP controlled by preference
+ * 
  * $Id: packet-rtp.c,v 1.45 2004/02/14 22:48:53 guy Exp $
  *
  * Ethereal - Network traffic analyzer
@@ -55,6 +58,8 @@
 # include "config.h"
 #endif
 
+#include <prefs.h>
+
 #include <glib.h>
 #include <epan/packet.h>
 
@@ -67,6 +72,7 @@
 #include "tap.h"
 
 static int rtp_tap = -1;
+static int global_rtp_heur = FALSE;
 
 static dissector_table_t rtp_pt_dissector_table;
 
@@ -169,105 +175,52 @@
 	{ 0,		NULL },
 };
 
-static address fake_addr;
-static int heur_init = FALSE;
-
-void rtp_add_address( packet_info *pinfo, const unsigned char* ip_addr,
-    int prt )
+static gboolean
+dissect_rtp_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
 {
-	address src_addr;
-	conversation_t* pconv;
-
-	/*
-	 * If this isn't the first time this packet has been processed,
-	 * we've already done this work, so we don't need to do it
-	 * again.
-	 */
-	if (pinfo->fd->flags.visited)
-		return;
-
-	src_addr.type = AT_IPv4;
-	src_addr.len = 4;
-	src_addr.data = ip_addr;
 
-	/*
-	 * The first time the function is called let the tcp dissector
-	 * know that we're interested in traffic
-	 */
-	if ( ! heur_init ) {
-		heur_dissector_add( "udp", dissect_rtp_heur, proto_rtp );
-		heur_init = TRUE;
-	}
+	guint8      octet1, octet2;
+	unsigned int version;
+	unsigned int payload_type;
+	unsigned int offset = 0;
 
-	/*
-	 * Check if the ip address an dport combination is not
-	 * already registered
+	/* This is a heuristic dissector, which means we get all the UDP
+	 * traffic not sent to a known dissector and not claimed by
+	 * a heuristic dissector called before us!
 	 */
-	pconv = find_conversation( &src_addr, &fake_addr, PT_UDP, prt, 0, 0 );
+        if (! global_rtp_heur)
+     		return FALSE;
 
-	/*
-	 * If not, add
-	 * XXX - use wildcard address and port B?
+	/* This is the check for a valid RTP packet, note that this
+	 * has change of 1/256 * 34/256 * 2 of being wrong
 	 */
-	if ( ! pconv ) {
-		pconv = conversation_new( &src_addr, &fake_addr, PT_UDP,
-		    (guint32) prt, (guint32) 0, 0 );
-		conversation_add_proto_data(pconv, proto_rtp, NULL);
-	}
-
-}
-
-#if 0
-static void rtp_init( void )
-{
-	unsigned char* tmp_data;
-	int i;
-
-	/* Create a fake adddress... */
-	fake_addr.type = AT_IPv4;
-	fake_addr.len = 4;
-
-	tmp_data = malloc( fake_addr.len );
-	for ( i = 0; i < fake_addr.len; i++) {
-		tmp_data[i] = 0;
-	}
-	fake_addr.data = tmp_data;
-}
-#endif
 
-static gboolean
-dissect_rtp_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
-{
-	conversation_t* pconv;
+	/* Get the fields in the first octet */
+	octet1 = tvb_get_guint8( tvb, offset );
+	version = RTP_VERSION( octet1 );
 
-	/* This is a heuristic dissector, which means we get all the TCP
-	 * traffic not sent to a known dissector and not claimed by
-	 * a heuristic dissector called before us!
-	 * So we first check if the frame is really meant for us.
-	 */
-	if ( ( pconv = find_conversation( &pinfo->src, &fake_addr, pinfo->ptype,
-	    pinfo->srcport, 0, 0 ) ) == NULL ) {
+	if (version != 2) {
 		/*
-		 * The source ip:port combination was not what we were
-		 * looking for, check the destination
+		 * Unknown or unsupported version.
 		 */
-		if ( ( pconv = find_conversation( &pinfo->dst, &fake_addr,
-		    pinfo->ptype, pinfo->destport, 0, 0 ) ) == NULL ) {
-			return FALSE;
-		}
-	}
-
-	/*
-	 * An RTP conversation always has a data item for RTP.
-	 * (Its existence is sufficient to indicate that this is an RTP
-	 * conversation.)
-	 */
-	if (conversation_get_proto_data(pconv, proto_rtp) == NULL)
 		return FALSE;
+	}
 
-	dissect_rtp( tvb, pinfo, tree );
-
-	return TRUE;
+	/* Get the fields in the second octet */
+	octet2 = tvb_get_guint8( tvb, offset + 1 );
+	payload_type = RTP_PAYLOAD_TYPE( octet2 );
+  	/*   	if (payload_type == PT_PCMU ||
+		    payload_type == PT_PCMA) 
+	            payload_type == PT_G729) 
+	*/
+       	if (payload_type <= PT_H263)
+	     {
+		dissect_rtp( tvb, pinfo, tree );
+		return TRUE;
+	     }
+	else {
+		return FALSE; 
+	}
 }
 
 static void
@@ -779,20 +732,28 @@
 	};
 
 
+        module_t *rtp_module;
+   
 	proto_rtp = proto_register_protocol("Real-Time Transport Protocol",
 	    "RTP", "rtp");
 	proto_register_field_array(proto_rtp, hf, array_length(hf));
 	proto_register_subtree_array(ett, array_length(ett));
 
+        /* for prefs dialog, dis/enable heuristic RTP decoding */
+	//        rtp_module = prefs_register_protocol(proto_rtp, proto_reg_handoff_rtp);
+        rtp_module = prefs_register_protocol(proto_rtp, NULL);
+        prefs_register_bool_preference(rtp_module, "heuristic_rtp",
+				                   "Try to decode RTP outside of conversations ",
+				                   "If call control SIP/H323/.. messages are missing in the trace, "
+				                        "RTP isn't decoded without this",
+				                   &global_rtp_heur);
+   
 	register_dissector("rtp", dissect_rtp, proto_rtp);
 	rtp_tap = register_tap("rtp");
 
 	rtp_pt_dissector_table = register_dissector_table("rtp.pt",
 	    "RTP payload type", FT_UINT8, BASE_DEC);
 
-#if 0
-	register_init_routine( &rtp_init );
-#endif
 }
 
 void
@@ -808,4 +769,6 @@
 	 */
 	rtp_handle = find_dissector("rtp");
 	dissector_add_handle("udp.port", rtp_handle);
+
+        heur_dissector_add( "udp", dissect_rtp_heur, proto_rtp );
 }