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):