Record RTP in PCAP files in the /tmp directory.

RTP Engine creates PCAP files for recorded calls on offer answer instead
of initial offer.

We make up bogus values for the nonessential parts of the PCAP, UDP, and
IP headers. We might be able to pull these from other parts of the RTP
Engine, but that information was unnecessary for recording calls so they
can be recorded to audio files.

If you change the packet headers, be really careful about byte order and
datatype size!
pull/245/head
Dylan Mikus 10 years ago committed by Eric Green
parent 70eb6b9e81
commit a714fbc462

@ -6,6 +6,7 @@ CFLAGS+= `pkg-config --cflags gthread-2.0`
CFLAGS+= `pkg-config --cflags zlib`
CFLAGS+= `pkg-config --cflags openssl`
CFLAGS+= `pkg-config --cflags libevent_pthreads`
CFLAGS+= "-lpcap"
CFLAGS+= `pcre-config --cflags`
CFLAGS+= -I../kernel-module/
CFLAGS+= -D_GNU_SOURCE
@ -50,6 +51,7 @@ LDFLAGS+= `pkg-config --libs libpcre`
LDFLAGS+= `pkg-config --libs libcrypto`
LDFLAGS+= `pkg-config --libs openssl`
LDFLAGS+= `pkg-config --libs libevent_pthreads`
LDFLAGS+= "-lpcap"
LDFLAGS+= `pcre-config --libs`
LDFLAGS+= `xmlrpc-c-config client --libs`
LDFLAGS+= -lhiredis

@ -17,6 +17,7 @@
#include <time.h>
#include <sys/time.h>
#include <inttypes.h>
#include <pcap.h>
#include "poller.h"
#include "aux.h"
@ -699,6 +700,8 @@ static struct endpoint_map *__get_endpoint_map(struct call_media *media, unsigne
socket_t *sock;
struct intf_list *il, *em_il;
ilog(LOG_INFO, "XXDylan: __get_endpoint_map");
for (l = media->endpoint_maps.tail; l; l = l->prev) {
em = l->data;
if (em->logical_intf != media->logical_intf)
@ -1503,7 +1506,6 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
struct endpoint_map *em;
struct call *call;
call = monologue->call;
call->last_signal = poller_now;
@ -1524,6 +1526,8 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
ml_media = other_ml_media = NULL;
setup_recording_files(call, monologue);
for (media_iter = streams->head; media_iter; media_iter = media_iter->next) {
sp = media_iter->data;
__C_DBG("processing media stream #%u", sp->index);
@ -2406,26 +2410,8 @@ struct call_monologue *__monologue_create(struct call *call) {
ret->call = call;
ret->created = poller_now;
ret->other_tags = g_hash_table_new(str_hash, str_equal);
if (call->record_call) {
char recording_path[15];
char logbuf[15];
/*
*
* create a file descriptor per monologue which can be used for writing rtp to disk
* aka call recording.
*/
sprintf(recording_path, "/tmp/%d", rand());
GSList *list = NULL;
call->recording_pcaps = g_slist_prepend(call->recording_pcaps, g_strdup(recording_path));
ilog(LOG_INFO, "xxegreen: path2 %s", call->recording_pcaps->data);
ilog(LOG_INFO, "XXXECT: Creating new file descriptor for recording at path %s", recording_path);
ret->recording_fd = open(recording_path, O_WRONLY | O_CREAT | O_TRUNC);
sprintf(logbuf, "%d", ret->recording_fd);
ilog(LOG_INFO, "XXXECT: FD created: %s", logbuf);
} else {
ret->recording_fd = -1;
}
ret->recording_pd = NULL;
ret->recording_pdumper = NULL;
g_queue_init(&ret->medias);
gettimeofday(&ret->started, NULL);
@ -2500,9 +2486,14 @@ static void __monologue_destroy(struct call_monologue *monologue) {
GList *l;
call = monologue->call;
/* XXXECT BEGIN */
close(monologue->recording_fd);
/* XXXECT END */
ilog(LOG_INFO, "XXXDylan: closing pcap stuff");
if (monologue->recording_pdumper != NULL) {
pcap_dump_flush(monologue->recording_pdumper);
pcap_dump_close(monologue->recording_pdumper);
}
if (monologue->recording_pd != NULL) {
pcap_close(monologue->recording_pd);
}
g_hash_table_remove(call->tags, &monologue->tag);
@ -2862,3 +2853,26 @@ const struct transport_protocol *transport_protocol(const str *s) {
out:
return NULL;
}
void setup_recording_files(struct call *call, struct call_monologue *monologue) {
if (call->record_call
&& monologue->recording_pd == NULL && monologue->recording_pdumper == NULL) {
char rec_path_prefix[16];
char recording_path[21];
/*
*
* create a file descriptor per monologue which can be used for writing rtp to disk
* aka call recording.
*/
snprintf(rec_path_prefix, 15, "/tmp/%d", rand());
snprintf(recording_path, 20, "%s.pcap", rec_path_prefix);
call->recording_pcaps = g_slist_prepend(call->recording_pcaps, g_strdup(recording_path));
ilog(LOG_INFO, "XXXDylan: Creating new pcap dumper for recording at path %s", recording_path);
monologue->recording_pd = pcap_open_dead(DLT_RAW, 65535);
monologue->recording_pdumper = pcap_dump_open(monologue->recording_pd, recording_path);
} else {
monologue->recording_pd = NULL;
monologue->recording_pdumper = NULL;
}
}

@ -14,6 +14,7 @@
#include <pcre.h>
#include <openssl/x509.h>
#include <limits.h>
#include <pcap.h>
#include "compat.h"
#include "socket.h"
@ -397,8 +398,9 @@ struct call_monologue {
enum termination_reason term_reason;
GHashTable *other_tags;
struct call_monologue *active_dialogue;
int recording_fd;
GQueue medias;
pcap_t *recording_pd;
pcap_dumper_t *recording_pdumper;
};
struct call {

@ -108,7 +108,7 @@ static void sighandler(gpointer x) {
continue;
abort();
}
if (ret == SIGINT || ret == SIGTERM)
g_shutdown = 1;
else if (ret == SIGUSR1) {

@ -3,6 +3,7 @@
#include <string.h>
#include <glib.h>
#include <errno.h>
#include <netinet/in.h>
#include "str.h"
#include "ice.h"
#include "socket.h"
@ -47,6 +48,8 @@ struct streamhandler {
static void determine_handler(struct packet_stream *in, const struct packet_stream *out);
static void stream_pcap_dump(pcap_dumper_t *pdumper, str *s);
static int __k_null(struct rtpengine_srtp *s, struct packet_stream *);
static int __k_srtp_encrypt(struct rtpengine_srtp *s, struct packet_stream *);
static int __k_srtp_decrypt(struct rtpengine_srtp *s, struct packet_stream *);
@ -1027,8 +1030,7 @@ static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin,
int ret = 0, update = 0, stun_ret = 0, handler_ret = 0, muxed_rtcp = 0, rtcp = 0,
unk = 0;
int i;
// XXEGREEN... This makes me nervous.
int recording_fd = sfd->stream->media->monologue->recording_fd;
pcap_dumper_t *recording_pdumper;
struct call *call;
struct callmaster *cm;
/*unsigned char cc;*/
@ -1038,6 +1040,7 @@ static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin,
struct rtp_header *rtp_h;
struct rtp_stats *rtp_s;
recording_pdumper = sfd->stream->media->monologue->recording_pdumper;
call = sfd->call;
cm = call->callmaster;
@ -1179,20 +1182,13 @@ loop_ok:
* 1 = forward and push update to redis */
if (rwf_in) {
handler_ret = rwf_in(s, in_srtp);
ilog(LOG_INFO, "xxegreen peer address as %s", endpoint_print_buf(fsin));
}
// This might be the hook that rfuchs might be referring to
// ilog(LOG_WARNING, "xxegreen0: %s", s->s);
// EGREEN: This is working pretty nicely but we need to remove the first 12 bytes from each packet that it is dumping
if (recording_fd && recording_fd != -1) {
// I am aware that we need to do better and that this is a naive approach
int writelen = (s->len)-12;
char towrite[writelen];
memcpy(towrite, &s->s[12], writelen);
write(recording_fd, towrite, writelen);
// EGREEN: This is going to happen for every packet. We need to do better
PS_SET(stream, FORCE_DAEMON_MODE);
// If recording pcap dumper is set, then we record the call.
if (recording_pdumper != NULL) {
stream_pcap_dump(recording_pdumper, s);
// EGREEN: This is going to happen for every packet. We need to do better
PS_SET(stream, FORCE_DAEMON_MODE);
}
if (handler_ret >= 0) {
@ -1329,7 +1325,6 @@ forward:
goto drop;
// s is my packet?
ilog(LOG_INFO, "XXEGREEN NOT");
ret = socket_sendto(&sink->selected_sfd->socket, s->s, s->len, &sink->endpoint);
__C_DBG("Forward to sink endpoint: %s:%d", sockaddr_print_buf(&sink->endpoint.address), sink->endpoint.port);
@ -1374,6 +1369,54 @@ unlock_out:
}
static void stream_pcap_dump(pcap_dumper_t *pdumper, str *s) {
// Wrap RTP in fake UDP packet header
// Right now, we spoof it all
u_int16_t udp_len = ((u_int16_t)s->len) + 8;
u_int16_t udp_header[4];
udp_header[0] = htons(5028); // source port
udp_header[1] = htons(50116); // destination port
udp_header[2] = htons(udp_len); // packet length
udp_header[3] = 0; // checksum
// Wrap RTP in fake IP packet header
u_int8_t ip_header[20];
u_int16_t *ip_total_length = (u_int16_t*)(ip_header + 2);
u_int32_t *ip_src_addr = (u_int32_t*)(ip_header + 12);
u_int32_t *ip_dst_addr = (u_int32_t*)(ip_header + 16);
memset(ip_header, 0, 20);
ip_header[0] = 4 << 4; // IP version - 4 bits
ip_header[0] = ip_header[0] | 5; // Internet Header Length (IHL) - 4 bits
ip_header[1] = 0; // DSCP - 6 bits
ip_header[1] = 0; // ECN - 2 bits
*ip_total_length = htons(udp_len + 20); // Total Length (entire packet size) - 2 bytes
ip_header[4] = 0; ip_header[5] = 0 ; // Identification - 2 bytes
ip_header[6] = 0; // Flags - 3 bits
ip_header[7] = 0; // Fragment Offset - 13 bits
ip_header[8] = 64; // TTL - 1 byte
ip_header[9] = 17; // Protocol (defines protocol in data portion) - 1 byte
ip_header[10] = 0; ip_header[11] = 0; // Header Checksum - 2 bytes
*ip_src_addr = htonl(2130706433); // Source IP (set to localhost) - 4 bytes
*ip_dst_addr = htonl(2130706433); // Destination IP (set to localhost) - 4 bytes
// Set up PCAP packet header
struct pcap_pkthdr header;
ZERO(header);
header.ts = g_now;
header.caplen = s->len + 28;
// This must be the same value we use in `pcap_open_dead`
header.len = s->len + 28;
// Copy all the headers and payload into a new string
unsigned char pkt_s[*ip_total_length];
memcpy(pkt_s, ip_header, 20);
memcpy(pkt_s + 20, udp_header, 8);
memcpy(pkt_s + 28, s->s, s->len);
// Write the packet to the PCAP file
// Casting quiets compiler warning.
pcap_dump((unsigned char *)pdumper, &header, (unsigned char *)pkt_s);
}
static void stream_fd_readable(int fd, void *p, uintptr_t u) {
@ -1472,7 +1515,6 @@ struct stream_fd *stream_fd_new(socket_t *fd, struct call *call, const struct lo
sfd->call = obj_get(call);
sfd->local_intf = lif;
g_queue_push_tail(&call->stream_fds, sfd); /* hand over ref */
//sfd->recording_fd = recording_fd;
__C_DBG("stream_fd_new localport=%d", sfd->socket.local.port);

@ -5,6 +5,7 @@
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <pcap.h>
#include "str.h"
#include "obj.h"
#include "aux.h"
@ -64,7 +65,8 @@ struct stream_fd {
struct packet_stream *stream; /* LOCK: call->master_lock */
struct crypto_context crypto; /* IN direction, LOCK: stream->in_lock */
struct dtls_connection dtls; /* LOCK: stream->in_lock */
int recording_fd; /* XXEGREEN file descriptor to record rtp to */
pcap_t *recording_pd;
pcap_dumper_t *recording_pdumper;
};

1
debian/control vendored

@ -8,6 +8,7 @@ Build-Depends: debhelper (>= 5),
libevent-dev (>= 2.0),
libglib2.0-dev (>= 2.30),
libhiredis-dev,
libpcap-dev,
libpcre3-dev,
libssl-dev (>= 1.0.1),
libxmlrpc-c3-dev (>= 1.16.07) | libxmlrpc-core-c3-dev (>= 1.16.07),

Loading…
Cancel
Save