Ethereal-dev: [Ethereal-dev] sdp
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: PC Drew <drewpc@xxxxxxxxxxxx>
Date: Wed, 06 Jun 2001 09:51:32 -0600
I've added a bunch of code to the SDP dissector so that it creates an RTP
conversation for the addresses and ports listed in the SDP packet. I
haven't been able to find a capture that contains multiple connection
addresses or multiple ports...if anyone has such captures, I'd really like
some feedback.
Attached are the c file that I used (from ethereal 0.8.16) and a diff with the packet-sdp.c file from ethereal 0.8.18.
-- PC Drew Be nice, or I'll replace you with a very small shell script
Attachment:
packet-sdp.diff
Description: Binary data
/* packet-sdp.c
* Routines for SDP packet disassembly (RFC 2327)
*
* Jason Lango <jal@xxxxxxxxxx>
* Liberally copied from packet-http.c, by Guy Harris <guy@xxxxxxxxxxxx>
*
* $Id: packet-sdp.c,v 1.20 2001/01/25 06:14:14 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@xxxxxxxx>
* Copyright 1998 Gerald Combs
*
* * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*/
#include "config.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <string.h>
#include <ctype.h>
#include <glib.h>
#include "packet.h"
#include "conversation.h"
#include "strutil.h"
#include "packet-rtp.h"
#include "packet-rtcp.h"
static int proto_sdp = -1;
static int ett_sdp = -1;
static GMemChunk *address_chunk = NULL;
static GMemChunk *ipv4_chunk = NULL;
static address fake_addr;
static void
dissect_sdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
proto_tree *sdp_tree = NULL;
proto_item *ti;
gint offset = 0;
const u_char *line;
gint next_offset;
int linelen;
u_char section;
u_char type;
const u_char *value;
int valuelen;
const char *typename;
int datalen;
char **conn_list;
char **media_list;
int conn_i = 0;
int media_i = 0;
int max_conn_i = 25; /* this is a bad idea!! */
int max_media_i = 25; /* this is a bad idea!! */
address **addrs;
char *tmp_ptr;
int i, j, k, m;
/* the list of connections. since there can be many connections, we
* have to have an array of char*'s
*/
conn_list = (char **)malloc(sizeof(char *) * max_conn_i);
/* the list of media types. since there can be many ports, we
* have to have an array of char*'s
*/
media_list = (char **)malloc(sizeof(char *) * max_media_i);
/* the list of addresses being invited to the call. since there can be
* many addresses, we have to have an array of address*'s
*/
addrs = (address **)malloc(sizeof(address *) * max_conn_i);
/*
* As RFC 2327 says, "SDP is purely a format for session
* description - it does not incorporate a transport protocol,
* and is intended to use different transport protocols as
* appropriate including the Session Announcement Protocol,
* Session Initiation Protocol, Real-Time Streaming Protocol,
* electronic mail using the MIME extensions, and the
* Hypertext Transport Protocol."
*
* We therefore don't set the protocol or info columns;
* instead, we append to them, so that we don't erase
* what the protocol inside which the SDP stuff resides
* put there.
*/
if (check_col(pinfo->fd, COL_PROTOCOL))
col_append_str(pinfo->fd, COL_PROTOCOL, "/SDP");
if (check_col(pinfo->fd, COL_INFO)) {
/* XXX: Needs description. */
col_append_str(pinfo->fd, COL_INFO, ", with session description");
}
if (tree) {
ti = proto_tree_add_item(tree, proto_sdp, tvb, offset, tvb_length_remaining(tvb, offset), FALSE);
sdp_tree = proto_item_add_subtree(ti, ett_sdp);
}
/*
* Show the SDP message a line at a time.
*/
section = 0;
while (tvb_offset_exists(tvb, offset)) {
/*
* Find the end of the line.
*/
linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
/*
* Line must contain at least e.g. "v=".
*
* This use to be just a break inside the { }, but because most of
* the decoding needs to be done regardless of whether or not
* if(tree) is true, I changed this a little.
*/
if (linelen < 2) {
offset = next_offset;
continue;
}
line = tvb_get_ptr(tvb, offset, next_offset - offset);
type = line[0];
if (line[1] != '=') {
if (tree) {
proto_tree_add_text(sdp_tree, tvb, offset, next_offset - offset, "Invalid line: %s", tvb_format_text(tvb, offset, next_offset - offset));
}
offset = next_offset;
continue;
}
value = line + 2;
valuelen = linelen - 2;
/*
* Attributes.
*/
switch (type) {
case 'v':
section = 'v';
typename = "Session Description, version";
break;
case 'o':
typename = "Owner/Creator, Session Id";
break;
case 's':
typename = "Session Name";
break;
case 'i':
if (section == 'v')
typename = "Session Information";
else if (section == 'm')
typename = "Media Title";
else
typename = "Misplaced";
break;
case 'u':
typename = "URI of Description";
break;
case 'e':
typename = "E-mail Address";
break;
case 'p':
typename = "Phone Number";
break;
case 'c':
typename = "Connection Information";
/* the first time this packet gets decoded, I need to add this
* string to the list of connections
*/
if (pinfo->fd->flags.visited == 0 && conn_i < max_conn_i) {
conn_list[conn_i] = (char *)malloc(sizeof(char) * valuelen);
conn_list[conn_i] = strncpy(conn_list[conn_i], value, valuelen);
conn_i++;
}
break;
case 'b':
typename = "Bandwidth Information";
break;
case 't':
section = 't';
typename = "Time Description, active time";
break;
case 'r':
typename = "Repeat Time";
break;
case 'm':
section = 'm';
typename = "Media Description, name and address";
/* the first time this packet gets decoded, I need to add this
* string to the list of media.
*/
if (pinfo->fd->flags.visited == 0 && media_i < max_media_i) {
media_list[media_i] = (char *)malloc(sizeof(char) * valuelen);
media_list[media_i] = strncpy(media_list[media_i], value, valuelen);
media_i++;
}
break;
case 'k':
typename = "Encryption Key";
break;
case 'a':
if (section == 'v')
typename = "Session Attribute";
else if (section == 'm')
typename = "Media Attribute";
else
typename = "Misplaced";
break;
case 'z':
typename = "Time Zone Adjustment";
break;
default:
typename = "Unknown";
break;
}
if (tree) {
proto_tree_add_text(sdp_tree, tvb, offset,
next_offset - offset,
"%s (%c): %s", typename, type,
format_text(value, valuelen));
}
offset = next_offset;
}
datalen = tvb_length_remaining(tvb, offset);
if (datalen > 0) {
if (tree) {
proto_tree_add_text(sdp_tree, tvb, offset, datalen, "Data (%d bytes)", datalen);
}
}
/* only do this the first time the packet is decoded */
if (pinfo->fd->flags.visited == 0) {
/* parse through all of the conn strings */
for (i = 0; i < conn_i; i++) {
guint8 *addr_data;
address *addr;
/* network type
* because I'm decoding this to dissect RTP/RTCP, we only care
* about network types of IN
*/
tmp_ptr = strtok(conn_list[i], " ");
if (tmp_ptr == NULL || strcmp(tmp_ptr, "IN") != 0) {
break;
}
/* address type
* again, because I'm decoding this to dissect RTP/RTCP, we only care
* about network types of IP4. This could be changed...?
*/
tmp_ptr = strtok(NULL, " ");
if (tmp_ptr == NULL || strcmp(tmp_ptr, "IP4") != 0) {
break;
}
/* address
* This can be a multicast or unicast address.
*/
tmp_ptr = strtok(NULL, " ");
if (tmp_ptr == NULL) {
break;
}
/* address
* There can actually be stuff after the address, within the
* address field, seperated by '/'. For creating RTP/RTCP
* conversations, we only care about the first string after
* tokenizing by '/'.
*/
tmp_ptr = strtok(tmp_ptr, "/");
if (tmp_ptr == NULL) {
break;
}
addr_data = g_mem_chunk_alloc(ipv4_chunk);
addr = g_mem_chunk_alloc(address_chunk);
/* load the address into an array */
addr_data[0] = atoi(strtok(tmp_ptr, "."));
addr_data[1] = atoi(strtok(NULL, "."));
addr_data[2] = atoi(strtok(NULL, "."));
addr_data[3] = atoi(strtok(NULL, "."));
/* set the data in the address* structure */
SET_ADDRESS(addr, AT_IPv4, 4, addr_data);
/* add to the list of addresses */
addrs[i] = addr;
}
/* this goes through all of the media strings (which contain port
* information) */
for (j = 0; j < media_i; j++) {
/* if there's more than 0 addresses... */
if (i > 0) {
guint16 port;
guint8 num_ports;
char *port_str;
void *func_ptr = NULL;
conversation_t *conv = NULL;
/* media type */
tmp_ptr = strtok(media_list[j], " ");
if (tmp_ptr == NULL) {
break;
}
/* port */
tmp_ptr = strtok(NULL, " ");
if (tmp_ptr == NULL) {
break;
}
/* much to our dismay, the port can actually be specified
* like 3040/2, which means there will be two ports (or in
* the case of RTP/RTCP, 2 pairs of RTP/RTCP ports. This
* logic tries to figure all of that out.
*/
port_str = strtok(tmp_ptr, "/");
port = (guint16)atoi(port_str);
/* fix our char* after strtok */
tmp_ptr += strlen(port_str) + 1;
port_str = strtok(NULL, "/");
if (port_str != NULL) {
/* there was a / and let's get the number of ports it
* wants.
*/
num_ports = atoi(port_str);
tmp_ptr += strlen(port_str) + 1;
} else {
/* there was no /, so we're assuming 1 port (or one
* RTP/RTCP pair.
*/
num_ports = 1;
}
/* transport */
tmp_ptr = strtok(tmp_ptr, " ");
if (tmp_ptr == NULL) {
break;
}
/* right now we only care about rtp, if the first 3 chars
* of the transport string are RTP, then we're in business.
* Otherwise, ethereal will handle it and make it dissect
* to UDP data. Other dissectors should be listed in this
* if statement.
*/
if (strncmp(tmp_ptr, "RTP", 3) == 0) {
func_ptr = &dissect_rtp;
}
/* if we've got anything to report... */
if (func_ptr != NULL) {
/* for every address in the address list... */
for (k = 0, m = 0; k < i; k++) {
/* if it's already there, we don't need to do any
* more work.
*/
conv = find_conversation(addrs[k], &fake_addr, PT_UDP, port + m, 0, NO_DST_ADDR | NO_DST_PORT);
if (conv == NULL) {
/* create the conversation and set the
* dissector to be the func_ptr we set above.
*/
conv = conversation_new(addrs[k], &fake_addr, PT_UDP, port + m, 0, 0, NO_DST_ADDR | NO_DST_PORT);
conversation_set_dissector(conv, func_ptr);
m++;
/* if it's RTP, the SDP RFC (RFC 2327) says to
* follow the RTP standard and make RTCP the
* next port (i.e. the RTP port should be an
* even number, and the RTCP should be the next
* higher odd number)
*/
if (func_ptr == &dissect_rtp) {
conv = conversation_new(addrs[k], &fake_addr, PT_UDP, port + m, 0, 0, NO_DST_ADDR | NO_DST_PORT);
conversation_set_dissector(conv, dissect_rtcp);
m++;
}
}
}
}
}
}
}
}
void
proto_register_sdp(void)
{
/* static hf_register_info hf[] = {
{ &variable,
{ "Name", "sdp.abbreviation", TYPE, VALS_POINTER }},
};*/
static gint *ett[] = {
&ett_sdp,
};
proto_sdp = proto_register_protocol("Session Description Protocol",
"SDP", "sdp");
/* proto_register_field_array(proto_sdp, hf, array_length(hf));*/
proto_register_subtree_array(ett, array_length(ett));
/*
* Register the dissector by name, so other dissectors can
* grab it by name rather than just referring to it directly
* (you can't refer to it directly from a plugin dissector
* on Windows without stuffing it into the Big Transfer Vector).
*/
register_dissector("sdp", dissect_sdp, proto_sdp);
address_chunk = g_mem_chunk_new("sdp address change", sizeof(address), sizeof(address) * 128, G_ALLOC_ONLY);
ipv4_chunk = g_mem_chunk_new("sdp address change 2", sizeof(guint8), sizeof(guint8) * 4, G_ALLOC_ONLY);
}
- Prev by Date: [Ethereal-dev] patch for packet-ranap.c
- Next by Date: Re: [Ethereal-dev] patch for packet-ranap.c
- Previous by thread: Re: [Ethereal-dev] patch for packet-ranap.c
- Next by thread: [Ethereal-dev] ethereal 0.8.17 RPM doesn't build
- Index(es):