sdp: move SDP parsing to packet_sdp dissector

This commit is contained in:
Kaian 2018-04-20 20:16:46 +02:00
parent 0db67ad858
commit 4d4ff634d0
17 changed files with 339 additions and 435 deletions

View File

@ -23,6 +23,7 @@ set(SOURCES
src/packet/dissectors/packet_tcp.c
src/packet/dissectors/packet_udp.c
src/packet/dissectors/packet_sip.c
src/packet/dissectors/packet_sdp.c
src/packet/dissectors/packet_rtp.c
src/packet/dissectors/packet_rtcp.c
src/capture/capture.c
@ -43,7 +44,6 @@ set(SOURCES
src/group.c
src/keybinding.c
src/main.c
src/packet/media.c
src/option.c
src/packet/old_packet.c
src/packet/rtp.c

View File

@ -423,7 +423,7 @@ call_flow_draw_message(ui_t *ui, call_flow_arrow_t *arrow, int cline)
{
call_flow_info_t *info;
WINDOW *flow_win;
sdp_media_t *media;
PacketSdpMedia *media;
const char *callid;
char msg_method[SIP_ATTR_MAXLEN];
char msg_time[80];
@ -486,12 +486,12 @@ call_flow_draw_message(ui_t *ui, call_flow_arrow_t *arrow, int cline)
if (msg_has_sdp(msg) && setting_has_value(SETTING_CF_SDP_INFO, "first")) {
sprintf(method, "%.3s (%s:%u)",
msg_method,
media->address.ip,
media->address.port);
media->sconn->address,
media->rtpport);
}
if (msg_has_sdp(msg) && setting_has_value(SETTING_CF_SDP_INFO, "full")) {
sprintf(method, "%.3s (%s)", msg_method, media->address.ip);
sprintf(method, "%.3s (%s)", msg_method, media->sconn->address);
}
// Draw message type or status and line
@ -568,16 +568,10 @@ call_flow_draw_message(ui_t *ui, call_flow_arrow_t *arrow, int cline)
for (;!g_sequence_iter_is_end(it); it = g_sequence_iter_next(it)) {
media = g_sequence_get(it);
sprintf(mediastr, "%s %d (%s)",
media->type,
media->address.port,
media_get_prefered_format(media));
if (arrow->dir == CF_ARROW_SPIRAL) {
mvwprintw(flow_win, cline + 1, startpos + 5, mediastr);
} else {
mvwprintw(flow_win, cline + 1, startpos + distance / 2 - strlen(mediastr) / 2 + 2, mediastr);
}
cline++;
aline++;
packet_sdp_media_type_str(media->type),
media->rtpport,
msg_get_preferred_codec_alias(msg));
mvwprintw(flow_win, cline++, startpos + distance / 2 - strlen(mediastr) / 2 + 2, mediastr);
}
}
@ -701,7 +695,7 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
sprintf(text, "RTP (%s) %d", stream_get_format(stream), stream_get_count(stream));
// Get message data
call = stream->media->msg->call;
call = stream->msg->call;
/**
* This logic will try to use the same columns for the stream representation
@ -709,7 +703,7 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
* if they share the same IP addresses.
*/
// Message with Stream destination configured in SDP content
msg = stream->media->msg;
msg = stream->msg;
// If message and stream share the same IP address
if (address_equals(msg->packet->src, stream->dst)) {
@ -747,7 +741,7 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
// Prefer message that configured this stream rather than any column
if (!arrow->scolumn) {
msg = stream->media->msg;
msg = stream->msg;
// If message and stream share the same IP address
if (address_equals(msg->packet->dst, stream->src)) {
// Reuse the msg arrow columns as destination column
@ -954,7 +948,7 @@ call_flow_arrow_message(const call_flow_arrow_t *arrow)
if (arrow->type == CF_ARROW_RTP) {
rtp_stream_t *stream = arrow->item;
return stream->media->msg;
return stream->msg;
}
return NULL;

View File

@ -27,6 +27,7 @@
*/
#include "config.h"
#include <glib.h>
#include <stdlib.h>
#include "packet_sdp.h"
/**
@ -40,7 +41,7 @@
* preferrence and may or may not match reality.
*
*/
SDPFormat formats[] = {
PacketSdpFormat formats[] = {
{ 0, "PCMU/8000", "g711u" },
{ 3, "GSM/8000", "gsm" },
{ 4, "G723/8000", "g723" },
@ -65,12 +66,170 @@ SDPFormat formats[] = {
{ 32, "MPV/90000", "mpv" },
{ 33, "MP2T/90000", "mp2t" },
{ 34, "H263/90000", "h263" },
{ 0, NULL, NULL }
};
void
packet_parse_sdp(PacketDissector *handler, Packet *packet, GByteArray *data)
{
const struct {
const gchar *str;
enum PacketSdpMediaType type;
} media_types[] = {
{ "audio", SDP_MEDIA_AUDIO },
{ "video", SDP_MEDIA_VIDEO },
{ "text", SDP_MEDIA_TEXT },
{ "application", SDP_MEDIA_APPLICATION },
{ "message", SDP_MEDIA_MESSAGE },
{ "image", SDP_MEDIA_IMAGE }
};
const gchar*
packet_sdp_media_type_str(enum PacketSdpMediaType type)
{
for (guint i = 0; i < G_N_ELEMENTS(media_types); i++) {
if (media_types[i].type == type) {
return media_types[i].str;
}
}
return NULL;
}
static void
packet_sdp_dissect_connection(PacketSdpData *sdp, PacketSdpMedia *media, gchar *line)
{
// c=<nettype> <addrtype> <connection-address>
gchar **conn_data = g_strsplit(line, " ", 3);
// Get connection address
PacketSdpConnection *conn = g_malloc(sizeof(PacketSdpConnection));
g_utf8_strncpy(conn->address, conn_data[SDP_CONN_ADDRESS], ADDRESSLEN);
// Set media/session connection data
if (media == NULL) {
sdp->sconn = conn;
} else {
media->sconn = conn;
}
}
static enum PacketSdpMediaType
packet_sdp_media_type(const gchar *media)
{
g_return_val_if_fail(media != NULL, 0);
for (guint i = 0; i < G_N_ELEMENTS(media_types); i++) {
if (g_ascii_strcasecmp(media, media_types[i].str) == 0) {
return media_types[i].type;
}
}
return SDP_MEDIA_UNKNOWN;
}
static PacketSdpFormat *
packet_sdp_standard_format(guint32 code)
{
for (guint i = 0;i < G_N_ELEMENTS(formats); i++) {
if (formats[i].id == code) {
return &formats[i];
}
}
return NULL;
}
static PacketSdpMedia *
packet_sdp_dissect_media(PacketSdpData *sdp, gchar *line)
{
// m=<media> <port> <proto> <fmt>
gchar **media_data = g_strsplit(line, " ", 4);
// Create a new media container
PacketSdpMedia *media = g_malloc0(sizeof(PacketSdpMedia));
media->sconn = sdp->sconn;
media->rtpport = (guint16)strtoul(media_data[SDP_MEDIA_PORT], NULL, 10);
media->type = packet_sdp_media_type(media_data[SDP_MEDIA_MEDIA]);
// Parse SDP preferred codec order
gchar **formats = g_strsplit(media_data[SDP_MEDIA_FORMAT], " ", -1);
for (guint i = 0; i < g_strv_length(formats); i++ ) {
// Check if format code is standard
guint32 code = (guint32)strtoul(formats[i], NULL, 10);
PacketSdpFormat *format = packet_sdp_standard_format(code);
if (format == NULL) {
// Unknown media format for this code
format = g_malloc0(sizeof(PacketSdpFormat));
format->id = code;
}
// Add new format for this media
media->formats = g_list_append(media->formats, format);
}
return media;
}
static void
packet_sdp_dissect_attribute(PacketSdpData *sdp G_GNUC_UNUSED, PacketSdpMedia *media, gchar *line)
{
// a=<attribute>
// a=<attribute>:<value>
gchar **rtpattr = g_strsplit_set(line, " :", -1);
if (g_ascii_strncasecmp(rtpattr[SDP_ATTR_NAME], "rtpmap", 6) == 0) {
// Check if format code is standard
guint32 code = (guint32)strtoul(rtpattr[2], NULL, 10);
PacketSdpFormat *format = packet_sdp_standard_format(code);
if (format == NULL) {
for (guint i = 0; i < g_list_length(media->formats); i++) {
format = g_list_nth_data(media->formats, i);
if (format->id == code) {
format->name = format->alias = rtpattr[3];
break;
}
}
}
} else if (g_ascii_strncasecmp(rtpattr[SDP_ATTR_NAME], "rtcp", 4) == 0) {
media->rtcpport = (guint16)strtoul(rtpattr[SDP_ATTR_VALUE], NULL, 10);
}
}
static GByteArray *
packet_sdp_dissect(PacketParser *parser G_GNUC_UNUSED, Packet *packet, GByteArray *data)
{
GString *payload = g_string_new_len((const gchar *) data->data, data->len);
PacketSdpData *sdp = g_malloc0(sizeof(PacketSdpData));
PacketSdpMedia *media = NULL;
gchar **lines = g_strsplit(payload->str, "\r\n", -1);
for (guint i = 0; i < g_strv_length(lines); i++ ) {
gchar *line = lines[i] + 2;
switch (lines[i][0]) {
case 'c':
packet_sdp_dissect_connection(sdp, media, line);
break;
case 'm':
media = packet_sdp_dissect_media(sdp, line);
sdp->medias = g_list_append(sdp->medias, media);
break;
case 'a':
packet_sdp_dissect_attribute(sdp, media, line);
default:
break;
}
}
// Set packet SDP data
g_ptr_array_insert(packet->proto, PACKET_SDP, sdp);
}
PacketDissector *
packet_sdp_new()
{
PacketDissector *proto = g_malloc0(sizeof(PacketDissector));
proto->id = PACKET_SDP;
proto->dissect = packet_sdp_dissect;
return proto;
}

View File

@ -34,21 +34,39 @@
#include "packet/dissector.h"
//! Connection Data fields
#define SDP_CONN_NETTYPE 0
#define SDP_CONN_ADDRTYPE 1
#define SDP_CONN_ADDRESS 2
//! Media Description fields
#define SDP_MEDIA_MEDIA 0
#define SDP_MEDIA_PORT 1
#define SDP_MEDIA_PROTO 2
#define SDP_MEDIA_FORMAT 3
//! Attribute fields
#define SDP_ATTR_NAME 0
#define SDP_ATTR_VALUE 1
//! SDP handled media types
enum sdp_media_type
enum PacketSdpMediaType
{
SDP_MEDIA_AUDIO = 0,
SDP_MEDIA_VIDEO,
SDP_MEDIA_TEXT,
SDP_MEDIA_APPLICATION,
SDP_MEDIA_MESSAGE,
SDP_MEDIA_IMAGE,
SDP_MEDIA_UNKNOWN = -1,
SDP_MEDIA_AUDIO = 0,
SDP_MEDIA_VIDEO = 1,
SDP_MEDIA_TEXT = 2,
SDP_MEDIA_APPLICATION = 3,
SDP_MEDIA_MESSAGE = 4,
SDP_MEDIA_IMAGE = 5,
};
//! Shorter declaration of SDP structures
typedef struct _SDPConnection SDPConnection;
typedef struct _SDPMedia SDPMedia;
typedef struct _SDPFormat SDPFormat;
typedef struct _PacketSdpConnection PacketSdpConnection;
typedef struct _PacketSdpMedia PacketSdpMedia;
typedef struct _PacketSdpFormat PacketSdpFormat;
typedef struct _PacketSdpData PacketSdpData;
/**
* @brief SDP ConnectionData (c=) information
@ -67,9 +85,10 @@ typedef struct _SDPFormat SDPFormat;
* We only support one connection data per media description. If multicast
* connection strings are provided, only one will be parsed.
*/
struct _SDPConnection {
struct _PacketSdpConnection
{
//! Connection Address
Address addr;
gchar address[ADDRESSLEN];
};
/**
@ -82,11 +101,18 @@ struct _SDPConnection {
* present in one of the media formats description lines.
*
*/
struct SDPMedia {
struct _PacketSdpMedia
{
//! Media type
enum sdp_media_type type;
//! Transport port + connection data Address
Address port;
enum PacketSdpMediaType type;
//! Session connection address (if not global)
PacketSdpConnection *sconn;
//! RTP Transport port
guint16 rtpport;
//! RTCP Transport port
guint16 rtcpport;
//! RTP Address (Connection IP + RTP port)
Address address;
//! Media formats list (SDPFormat)
GList *formats;
};
@ -100,7 +126,8 @@ struct SDPMedia {
* Note that sngrep only supports RTP transport protocol so all SDP format
* ids are actually RTP Payload type numbers.
*/
struct _SDPFormat {
struct _PacketSdpFormat
{
//! RTP payload
guint32 id;
//! RTP Encoding name from RFC3551 or SDP fmt attribute
@ -109,16 +136,18 @@ struct _SDPFormat {
const gchar *alias;
};
struct sdp_pvt {
struct _PacketSdpData
{
//! Session connection address (optional)
SDPConnection sconn;
PacketSdpConnection *sconn;
//! SDP Media description list (SDPMedia)
GList *medias;
};
void
packet_parse_sdp(PacketDissector *handler, Packet *packet, GByteArray *data);
const gchar*
packet_sdp_media_type_str(enum PacketSdpMediaType type);
PacketDissector *
packet_sdp_new();
#endif /* PACKET_PACKET_SDP_H_ */

View File

@ -29,11 +29,10 @@
#include "config.h"
#include <stdlib.h>
#include <packet/old_packet.h>
#include "packet_sip.h"
#include "packet_ip.h"
#include "packet_tcp.h"
#include "packet_udp.h"
#include "packet_sdp.h"
#include "sip.h"
#include "packet_sip.h"
#include "packet/old_packet.h"
/* @brief list of methods and responses */
@ -156,12 +155,15 @@ static GByteArray *
packet_sip_parse(PacketParser *parser, Packet *packet, GByteArray *data)
{
GMatchInfo *pmatch;
DissectorSipData *sip = g_ptr_array_index(parser->dissectors, PACKET_SIP);
gint start, end;
// Only handle UTF-8 SIP payloads
if (!g_utf8_validate(data->data, data->len, NULL)) {
return data;
}
DissectorSipData *sip = g_ptr_array_index(parser->dissectors, PACKET_SIP);
// Convert payload to something we can parse with regular expressions
GString *payload = g_string_new_len(data->data, data->len);
@ -185,7 +187,6 @@ packet_sip_parse(PacketParser *parser, Packet *packet, GByteArray *data)
// Not a SIP message or not complete
return data;
}
gint start, end;
g_match_info_fetch_pos(pmatch, 1, &start, &end);
// The SDP body of the SIP message ends in another packet
@ -216,6 +217,10 @@ packet_sip_parse(PacketParser *parser, Packet *packet, GByteArray *data)
}
g_match_info_free(pmatch);
// Check we have a valid SIP packet
if (sip_data->callid == NULL)
return data;
// Method
if (g_regex_match(sip->reg_method, payload->str, 0, &pmatch)) {
sip_data->reqresp = sip_method_from_str(g_match_info_fetch_named(pmatch, "method"));
@ -269,13 +274,21 @@ packet_sip_parse(PacketParser *parser, Packet *packet, GByteArray *data)
}
g_match_info_free(pmatch);
// Add SIP information to the packet
g_ptr_array_insert(packet->proto, PACKET_SIP, sip_data);
if (sip_data->callid != NULL) {
sip_check_packet(packet);
return NULL;
}
// Check if we have Body separator field
g_regex_match(sip->reg_body, payload->str, 0, &pmatch);
g_match_info_fetch_pos(pmatch, 0, &start, &end);
// Remove SIP headers from data
data = g_byte_array_remove_range(data, 0, end);
// Pass data to subdissectors
packet_parser_next_dissector(parser, packet, data);
// Add data to storage
sip_check_packet(packet);
return data;
}
@ -327,7 +340,7 @@ packet_sip_init(PacketParser *parser)
cflags, mflags, NULL);
sip->reg_body = g_regex_new(
"\r\n\r\n(.*)",
"\r\n\r\n",
cflags & ~G_REGEX_MULTILINE, mflags, NULL);
sip->reg_reason = g_regex_new(
@ -374,5 +387,6 @@ packet_sip_new()
proto->init = packet_sip_init;
proto->dissect = packet_sip_parse;
proto->deinit = packet_sip_deinit;
proto->subdissectors = g_slist_append(proto->subdissectors, GUINT_TO_POINTER(PACKET_SDP));
return proto;
}

View File

@ -1,128 +0,0 @@
/**************************************************************************
**
** sngrep - SIP Messages flow viewer
**
** Copyright (C) 2013-2018 Ivan Alonso (Kaian)
** Copyright (C) 2013-2018 Irontec SL. All rights reserved.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
/**
* @file media.c
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
*
* @brief Source of functions defined in media.h
*/
#include "config.h"
#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include "glib-utils.h"
#include "media.h"
#include "packet/rtp.h"
#include "util.h"
sdp_media_t *
media_create(struct sip_msg *msg)
{
sdp_media_t *media;;
// Allocate memory for this media structure
if (!(media = sng_malloc(sizeof(sdp_media_t))))
return NULL;
// Initialize all fields
media->msg = msg;
media->formats = g_sequence_new(sng_free);
return media;
}
void
media_destroy(void *item)
{
sdp_media_t *media = (sdp_media_t *) item;
if (!item)
return;
g_sequence_free(media->formats);
sng_free(media);
}
void
media_set_type(sdp_media_t *media, const char *type)
{
strcpy(media->type, type);
}
void
media_set_address(sdp_media_t *media, Address addr)
{
media->address = addr;
}
void
media_set_prefered_format(sdp_media_t *media, uint32_t code)
{
media->fmtcode = code;
}
void
media_add_format(sdp_media_t *media, uint32_t code, const char *format)
{
sdp_media_fmt_t *fmt;
if (!(fmt = sng_malloc(sizeof(sdp_media_fmt_t))))
return;
fmt->id = code;
strcpy(fmt->format, format);
g_sequence_append(media->formats, fmt);
}
const char *
media_get_format(sdp_media_t *media, uint32_t code)
{
sdp_media_fmt_t *format;
GSequenceIter *it = g_sequence_get_begin_iter(media->formats);
for (;!g_sequence_iter_is_end(it); it = g_sequence_iter_next(it)) {
format = g_sequence_get(it);
if (format->id == code)
return format->format;
}
return "Unassigned";
}
const char *
media_get_prefered_format(sdp_media_t *media)
{
const char *format;
// Check if format is standard
if ((format = rtp_get_standard_format(media->fmtcode))) {
return format;
}
// Try to get format form SDP payload
return media_get_format(media, media->fmtcode);
}
int
media_get_format_code(sdp_media_t *media)
{
return media->fmtcode;
}

View File

@ -1,103 +0,0 @@
/**************************************************************************
**
** sngrep - SIP Messages flow viewer
**
** Copyright (C) 2013-2018 Ivan Alonso (Kaian)
** Copyright (C) 2013-2018 Irontec SL. All rights reserved.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
/**
* @file media.h
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
*
* @brief Functions to manage call media
*
*/
#ifndef __SNGREP_MEDIA_H_
#define __SNGREP_MEDIA_H_
#include "config.h"
#include <sys/types.h>
#include <glib.h>
#include "capture/capture_pcap.h"
#define MEDIATYPELEN 15
//! Shorter declaration of sdp_media structure
typedef struct sdp_media sdp_media_t;
//! Shorter declaration of sdp_media_fmt structure
typedef struct sdp_media_fmt sdp_media_fmt_t;
struct sip_msg;
struct sip_call;
struct sdp_media_fmt {
uint32_t id;
char format[50];
};
struct sdp_media {
//! SDP Addresses information
Address address;
char type[MEDIATYPELEN];
uint32_t fmtcode;
//! List of described formats in this media
GSequence *formats;
//! Message with this SDP content
struct sip_msg *msg;
};
/**
* @brief Allocate memory for a new media structure
*
* Create a structure for a new message sdp connection data.
*
* @param msg SIP Message pointer owner of this media
* @return new allocated structure
*/
sdp_media_t *
media_create(struct sip_msg *msg);
void
media_destroy(void *item);
void
media_set_type(sdp_media_t *media, const char *type);
void
media_set_address(sdp_media_t *media, Address addr);
void
media_set_prefered_format(sdp_media_t *media, uint32_t code);
void
media_add_format(sdp_media_t *media, uint32_t code, const char *format);
const char *
media_get_type(sdp_media_t *media);
const char *
media_get_format(sdp_media_t *media, uint32_t code);
const char *
media_get_prefered_format(sdp_media_t *media);
int
media_get_format_code(sdp_media_t *media);
#endif /* __SNGREP_MEDIA_H_ */

View File

@ -57,6 +57,8 @@ enum packet_oldtype {
typedef struct old_packet packet_t;
//! Shorter declaration of frame structure
typedef struct frame frame_t;
//! Forward declaration Packet structure
typedef struct _Packet Packet;
/**
* @brief Packet capture data.
@ -66,6 +68,7 @@ typedef struct frame frame_t;
* packet can only contain one SIP message.
*/
struct old_packet {
Packet *newpacket;
//! IP protocol
uint8_t ip_version;
//! Transport protocol

View File

@ -56,7 +56,6 @@ packet_free(Packet *packet)
gboolean
packet_has_type(Packet *packet, enum packet_proto type)
{
// return (packet->types & ( 1 << type)) != 0;
return g_ptr_array_index(packet->proto, type) != NULL;
}
@ -81,6 +80,7 @@ packet_to_oldpkt(Packet *packet)
packet_t *oldpkt = g_malloc0(sizeof(packet_t));
PacketIpData *ipdata = g_ptr_array_index(packet->proto, PACKET_IP);
oldpkt->newpacket = packet;
oldpkt->src = ipdata->saddr;
oldpkt->dst = ipdata->daddr;

View File

@ -33,6 +33,7 @@
#include "packet/dissectors/packet_tcp.h"
#include "packet/dissectors/packet_tls.h"
#include "packet/dissectors/packet_sip.h"
#include "packet/dissectors/packet_sdp.h"
#include "packet/dissectors/packet_rtp.h"
#include "packet/dissectors/packet_rtcp.h"
#include "parser.h"
@ -80,6 +81,9 @@ packet_parser_add_proto(PacketParser *parser, GNode *parent, enum packet_proto i
case PACKET_SIP:
dissector = packet_sip_new();
break;
case PACKET_SDP:
dissector = packet_sdp_new();
break;
case PACKET_RTP:
dissector = packet_rtp_new();
break;

View File

@ -38,7 +38,7 @@
#include "sip.h"
rtp_stream_t *
stream_create(sdp_media_t *media, Address dst, int type)
stream_create(Packet *packet, PacketSdpMedia *media)
{
rtp_stream_t *stream;
@ -47,9 +47,9 @@ stream_create(sdp_media_t *media, Address dst, int type)
return NULL;
// Initialize all fields
stream->type = type;
stream->type = media->type;
stream->media = media;
stream->dst = dst;
stream->dst = media->address;
return stream;
}
@ -85,8 +85,8 @@ stream_get_count(rtp_stream_t *stream)
struct sip_call *
stream_get_call(rtp_stream_t *stream) {
if (stream && stream->media && stream->media->msg)
return stream->media->msg->call;
if (stream && stream->media && stream->msg)
return stream->msg->call;
return NULL;
}
@ -105,8 +105,12 @@ stream_get_format(rtp_stream_t *stream)
return fmt;
// Try to get format form SDP payload
if ((fmt = media_get_format(stream->media, stream->rtpinfo.fmtcode)))
return fmt;
for (guint i = 0; i < g_list_length(stream->media->formats); i++) {
PacketSdpFormat *format = g_list_nth_data(stream->media->formats, i);
if (format->id == stream->rtpinfo.fmtcode) {
return format->alias;
}
}
// Not found format for this code
return NULL;
@ -153,10 +157,10 @@ rtp_check_packet(packet_t *packet)
// We have found a stream, but with different format
if (stream_is_complete(stream) && stream->rtpinfo.fmtcode != format) {
// Create a new stream for this new format
stream = stream_create(stream->media, dst, PACKET_RTP);
stream = stream_create(packet->newpacket, stream->media);
stream_complete(stream, src);
stream_set_format(stream, format);
call_add_stream(msg_get_call(stream->media->msg), stream);
call_add_stream(msg_get_call(stream->msg), stream);
}
// First packet for this stream, set source data
@ -184,20 +188,20 @@ rtp_check_packet(packet_t *packet)
*/
// Check if an stream in the opposite direction exists
if (!(reverse = rtp_find_call_stream(stream->media->msg->call, stream->dst, stream->src))) {
reverse = stream_create(stream->media, stream->src, PACKET_RTP);
if (!(reverse = rtp_find_call_stream(stream->msg->call, stream->dst, stream->src))) {
reverse = stream_create(packet->newpacket, stream->media);
stream_complete(reverse, stream->dst);
stream_set_format(reverse, format);
call_add_stream(msg_get_call(stream->media->msg), reverse);
call_add_stream(msg_get_call(stream->msg), reverse);
} else {
// If the reverse stream has other source configured
if (reverse->src.port && !addressport_equals(stream->src, reverse->src)) {
if (!(reverse = rtp_find_call_exact_stream(stream->media->msg->call, stream->dst, stream->src))) {
if (!(reverse = rtp_find_call_exact_stream(stream->msg->call, stream->dst, stream->src))) {
// Create a new reverse stream
reverse = stream_create(stream->media, stream->src, PACKET_RTP);
reverse = stream_create(packet->newpacket, stream->media);
stream_complete(reverse, stream->dst);
stream_set_format(reverse, format);
call_add_stream(msg_get_call(stream->media->msg), reverse);
call_add_stream(msg_get_call(stream->msg), reverse);
}
}
}

View File

@ -33,8 +33,9 @@
#define __SNGREP_RTP_H
#include "config.h"
#include "sip_msg.h"
#include "capture/capture_pcap.h"
#include "media.h"
#include "packet/dissectors/packet_sdp.h"
#include "packet/dissectors/packet_rtp.h"
#include "packet/dissectors/packet_rtcp.h"
@ -49,7 +50,9 @@ struct rtp_stream {
//! Destination address
Address dst;
//! SDP media that setup this stream
sdp_media_t *media;
PacketSdpMedia *media;
//! SIP message that setup this stream
sip_msg_t *msg;
//! Packet count for this stream
uint32_t pktcnt;
//! Time of first received packet of stream
@ -79,7 +82,7 @@ struct rtp_stream {
};
rtp_stream_t *
stream_create(sdp_media_t *media, Address dst, int type);
stream_create(Packet *packet, PacketSdpMedia *media);
rtp_stream_t *
stream_complete(rtp_stream_t *stream, Address src);

129
src/sip.c
View File

@ -188,7 +188,7 @@ sip_check_packet(Packet *packet)
if (call_is_invite(call)) {
// Parse media data
sip_parse_msg_media(msg, sip_data->payload);
sip_parse_msg_media(msg);
// Update Call State
call_update_state(call, msg);
// Check if this call should be in active call list
@ -305,106 +305,43 @@ sip_get_msg_reqresp_str(sip_msg_t *msg)
}
void
sip_parse_msg_media(sip_msg_t *msg, const u_char *payload)
sip_parse_msg_media(sip_msg_t *msg)
{
Packet *packet = msg->packet->newpacket;
Address emptyaddr = {};
#define ADD_STREAM(stream) \
if (stream) { \
if (!rtp_find_call_stream(call, src, stream->dst)) { \
call_add_stream(call, stream); \
} else { \
sng_free(stream); \
stream = NULL; \
} \
PacketSdpData *sdp = g_ptr_array_index(packet->proto, PACKET_SDP);
if (sdp == NULL) return;
for (guint i = 0; i < g_list_length(sdp->medias); i++) {
PacketSdpMedia *media = g_list_nth_data(sdp->medias, i);
// Add to the message
g_sequence_append(msg->medias, media);
// Create RTP stream for this media
if (rtp_find_call_stream(msg->call, emptyaddr, media->address) == NULL) {
rtp_stream_t *stream = stream_create(packet, media);
call_add_stream(msg->call, stream);
}
// Create RTCP stream for this media
if (rtp_find_call_stream(msg->call, emptyaddr, media->address) == NULL) {
rtp_stream_t *stream = stream_create(packet, media);
stream->dst.port = (media->rtcpport) ? media->rtcpport : (guint16) (media->rtpport + 1);
call_add_stream(msg->call, stream);
}
// Create RTP stream with source of message as destination address
if (rtp_find_call_stream(msg->call, msg->packet->src, media->address) == NULL) {
rtp_stream_t *stream = stream_create(packet, media);
stream->dst = msg->packet->src;
stream->dst.port = media->rtpport;
call_add_stream(msg->call, stream);
}
}
Address dst, src = { };
rtp_stream_t *rtp_stream = NULL, *rtcp_stream = NULL, *msg_rtp_stream = NULL;
char media_type[MEDIATYPELEN] = { };
char media_format[30] = { };
uint32_t media_fmt_pref;
uint32_t media_fmt_code;
sdp_media_t *media = NULL;
char *payload2, *tofree, *line;
sip_call_t *call = msg_get_call(msg);
// Parse each line of payload looking for sdp information
tofree = payload2 = strdup((char*)payload);
while ((line = strsep(&payload2, "\r\n")) != NULL) {
// Check if we have a media string
if (!strncmp(line, "m=", 2)) {
if (sscanf(line, "m=%s %hu RTP/%*s %u", media_type, &dst.port, &media_fmt_pref) == 3) {
// Add streams from previous 'm=' line to the call
ADD_STREAM(msg_rtp_stream);
ADD_STREAM(rtp_stream);
ADD_STREAM(rtcp_stream);
// Create a new media structure for this message
if ((media = media_create(msg))) {
media_set_type(media, media_type);
media_set_address(media, dst);
media_set_prefered_format(media, media_fmt_pref);
msg_add_media(msg, media);
/**
* From SDP we can only guess destination address port. RTP Capture proccess
* will determine when the stream has been completed, getting source address
* and port of the stream.
*/
// Create a new stream with this destination address:port
// Create RTP stream with source of message as destination address
msg_rtp_stream = stream_create(media, dst, PACKET_RTP);
msg_rtp_stream->dst = msg->packet->src;
msg_rtp_stream->dst.port = dst.port;
// Create RTP stream
rtp_stream = stream_create(media, dst, PACKET_RTP);
// Create RTCP stream
rtcp_stream = stream_create(media, dst, PACKET_RTCP);
rtcp_stream->dst.port++;
}
}
}
// Check if we have a connection string
if (!strncmp(line, "c=", 2)) {
if (sscanf(line, "c=IN IP4 %s", dst.ip) && media) {
media_set_address(media, dst);
strcpy(rtp_stream->dst.ip, dst.ip);
strcpy(rtcp_stream->dst.ip, dst.ip);
}
}
// Check if we have attribute format string
if (!strncmp(line, "a=rtpmap:", 9)) {
if (media && sscanf(line, "a=rtpmap:%u %[^ ]", &media_fmt_code, media_format)) {
media_add_format(media, media_fmt_code, media_format);
}
}
// Check if we have attribute format RTCP port
if (!strncmp(line, "a=rtcp:", 7) && rtcp_stream) {
sscanf(line, "a=rtcp:%hu", &rtcp_stream->dst.port);
}
}
// Add streams from last 'm=' line to the call
ADD_STREAM(msg_rtp_stream);
ADD_STREAM(rtp_stream);
ADD_STREAM(rtcp_stream);
sng_free(tofree);
#undef ADD_STREAM
}
void
sip_calls_clear()
{

View File

@ -306,7 +306,7 @@ sip_get_msg_reqresp_str(sip_msg_t *msg);
* @return 0 in all cases
*/
void
sip_parse_msg_media(sip_msg_t *msg, const u_char *payload);
sip_parse_msg_media(sip_msg_t *msg);
/**
* @brief Get Capture Matching expression

View File

@ -177,7 +177,7 @@ sip_msg_t *
call_msg_with_media(sip_call_t *call, Address dst)
{
sip_msg_t *msg;
sdp_media_t *media;
PacketSdpMedia *media;
GSequenceIter *itmsg;
GSequenceIter *itmedia;

View File

@ -33,7 +33,7 @@
#include "glib-utils.h"
#include "sip_msg.h"
#include "packet/dissectors/packet_sip.h"
#include "packet/media.h"
#include "packet/dissectors/packet_sdp.h"
#include "sip.h"
sip_msg_t *
@ -42,7 +42,7 @@ msg_create()
sip_msg_t *msg;
if (!(msg = sng_malloc(sizeof(sip_msg_t))))
return NULL;
msg->medias = g_sequence_new(media_destroy);
msg->medias = g_sequence_new(NULL);
return msg;
}
@ -87,12 +87,6 @@ msg_is_request(sip_msg_t *msg)
return msg->reqresp < 100;
}
void
msg_add_media(sip_msg_t *msg, sdp_media_t *media)
{
g_sequence_append(msg->medias, media);
}
const char *
msg_get_payload(sip_msg_t *msg)
{
@ -169,3 +163,15 @@ msg_is_older(sip_msg_t *one, sip_msg_t *two)
// Otherwise
return timeval_is_older(msg_get_time(one), msg_get_time(two));
}
const gchar *
msg_get_preferred_codec_alias(sip_msg_t *msg)
{
PacketSdpMedia *media = g_sequence_first(msg->medias);
g_return_val_if_fail(media != NULL, NULL);
PacketSdpFormat *format = g_list_nth_data(media->formats, 0);
g_return_val_if_fail(format != NULL, NULL);
return format->alias;
}

View File

@ -31,7 +31,6 @@
#include <stdarg.h>
#include <glib.h>
#include "packet/media.h"
#include "sip_attr.h"
#include "util.h"
@ -121,15 +120,6 @@ msg_media_count(sip_msg_t *msg);
int
msg_has_sdp(void *item);
/**
* @brief Add a media structure to a msg
*
* @param cmsg SIP Message to be updated
* @param media Media structure to be added
*/
void
msg_add_media(sip_msg_t *msg, sdp_media_t *media);
/**
* @brief Check if a message is a Request or response
*
@ -139,18 +129,6 @@ msg_add_media(sip_msg_t *msg, sdp_media_t *media);
int
msg_is_request(sip_msg_t *msg);
/**
* @brief Add a new media for given message
*
* A SIP message can have multiple media description in
* the SIP payload content
*
* @param msg SIP message that will store this packet
* @param media parsed media structure from payload
*/
void
msg_add_media(sip_msg_t *msg, sdp_media_t *media);
/**
* @brief Get SIP Message payload
*/
@ -192,4 +170,8 @@ int
msg_is_older(sip_msg_t *one, sip_msg_t *two);
const gchar *
msg_get_preferred_codec_alias(sip_msg_t *msg);
#endif /* __SNGREP_SIP_MSG_H */