From 4d4ff634d03059331a16257b901b3229757373dc Mon Sep 17 00:00:00 2001 From: Kaian Date: Fri, 20 Apr 2018 20:16:46 +0200 Subject: [PATCH] sdp: move SDP parsing to packet_sdp dissector --- CMakeLists.txt | 2 +- src/curses/ui_call_flow.c | 30 ++--- src/packet/dissectors/packet_sdp.c | 169 ++++++++++++++++++++++++++++- src/packet/dissectors/packet_sdp.h | 73 +++++++++---- src/packet/dissectors/packet_sip.c | 36 ++++-- src/packet/media.c | 128 ---------------------- src/packet/media.h | 103 ------------------ src/packet/old_packet.h | 3 + src/packet/packet.c | 2 +- src/packet/parser.c | 4 + src/packet/rtp.c | 34 +++--- src/packet/rtp.h | 9 +- src/sip.c | 129 ++++++---------------- src/sip.h | 2 +- src/sip_call.c | 2 +- src/sip_msg.c | 22 ++-- src/sip_msg.h | 26 +---- 17 files changed, 339 insertions(+), 435 deletions(-) delete mode 100644 src/packet/media.c delete mode 100644 src/packet/media.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f399922..81f3bd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/curses/ui_call_flow.c b/src/curses/ui_call_flow.c index 8248036..4b42264 100644 --- a/src/curses/ui_call_flow.c +++ b/src/curses/ui_call_flow.c @@ -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; diff --git a/src/packet/dissectors/packet_sdp.c b/src/packet/dissectors/packet_sdp.c index 51f5a29..4b072b9 100644 --- a/src/packet/dissectors/packet_sdp.c +++ b/src/packet/dissectors/packet_sdp.c @@ -27,6 +27,7 @@ */ #include "config.h" #include +#include #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= + 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= + 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= + // a=: + 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; } diff --git a/src/packet/dissectors/packet_sdp.h b/src/packet/dissectors/packet_sdp.h index b0494f9..14c6ef2 100644 --- a/src/packet/dissectors/packet_sdp.h +++ b/src/packet/dissectors/packet_sdp.h @@ -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_ */ diff --git a/src/packet/dissectors/packet_sip.c b/src/packet/dissectors/packet_sip.c index 7137c58..0895148 100644 --- a/src/packet/dissectors/packet_sip.c +++ b/src/packet/dissectors/packet_sip.c @@ -29,11 +29,10 @@ #include "config.h" #include #include -#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; } \ No newline at end of file diff --git a/src/packet/media.c b/src/packet/media.c deleted file mode 100644 index 9c6a381..0000000 --- a/src/packet/media.c +++ /dev/null @@ -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 . - ** - ****************************************************************************/ -/** - * @file media.c - * @author Ivan Alonso [aka Kaian] - * - * @brief Source of functions defined in media.h - */ - -#include "config.h" -#include -#include -#include -#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; -} - - - diff --git a/src/packet/media.h b/src/packet/media.h deleted file mode 100644 index a965f8c..0000000 --- a/src/packet/media.h +++ /dev/null @@ -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 . - ** - ****************************************************************************/ -/** - * @file media.h - * @author Ivan Alonso [aka Kaian] - * - * @brief Functions to manage call media - * - */ - -#ifndef __SNGREP_MEDIA_H_ -#define __SNGREP_MEDIA_H_ - -#include "config.h" -#include -#include -#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_ */ diff --git a/src/packet/old_packet.h b/src/packet/old_packet.h index 5386f5f..3492ca3 100644 --- a/src/packet/old_packet.h +++ b/src/packet/old_packet.h @@ -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 diff --git a/src/packet/packet.c b/src/packet/packet.c index 99c0747..867acad 100644 --- a/src/packet/packet.c +++ b/src/packet/packet.c @@ -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; diff --git a/src/packet/parser.c b/src/packet/parser.c index 3ebef3f..1757119 100644 --- a/src/packet/parser.c +++ b/src/packet/parser.c @@ -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; diff --git a/src/packet/rtp.c b/src/packet/rtp.c index 418e4c7..13fb2e1 100644 --- a/src/packet/rtp.c +++ b/src/packet/rtp.c @@ -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); } } } diff --git a/src/packet/rtp.h b/src/packet/rtp.h index 15f16ad..94669d3 100644 --- a/src/packet/rtp.h +++ b/src/packet/rtp.h @@ -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); diff --git a/src/sip.c b/src/sip.c index d77bae1..47a6452 100644 --- a/src/sip.c +++ b/src/sip.c @@ -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() { diff --git a/src/sip.h b/src/sip.h index 6e61aac..d781859 100644 --- a/src/sip.h +++ b/src/sip.h @@ -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 diff --git a/src/sip_call.c b/src/sip_call.c index 5570698..14fc1fd 100644 --- a/src/sip_call.c +++ b/src/sip_call.c @@ -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; diff --git a/src/sip_msg.c b/src/sip_msg.c index 4695602..1e2ed45 100644 --- a/src/sip_msg.c +++ b/src/sip_msg.c @@ -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; +} diff --git a/src/sip_msg.h b/src/sip_msg.h index 77960b7..40b2b59 100644 --- a/src/sip_msg.h +++ b/src/sip_msg.h @@ -31,7 +31,6 @@ #include #include -#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 */