diff --git a/daemon/Makefile b/daemon/Makefile index 941a520e5..ac353440f 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -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 diff --git a/daemon/call.c b/daemon/call.c index 6728e5903..f7552e36f 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -17,6 +17,7 @@ #include #include #include +#include #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; + } +} diff --git a/daemon/call.h b/daemon/call.h index 99f04a89e..25678ec45 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -14,6 +14,7 @@ #include #include #include +#include #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 { diff --git a/daemon/main.c b/daemon/main.c index b43e1d9cd..374796df7 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -108,7 +108,7 @@ static void sighandler(gpointer x) { continue; abort(); } - + if (ret == SIGINT || ret == SIGTERM) g_shutdown = 1; else if (ret == SIGUSR1) { diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 78a566134..a27965f51 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -3,6 +3,7 @@ #include #include #include +#include #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); diff --git a/daemon/media_socket.h b/daemon/media_socket.h index 78e3453a4..5c233a94a 100644 --- a/daemon/media_socket.h +++ b/daemon/media_socket.h @@ -5,6 +5,7 @@ #include #include #include +#include #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; }; diff --git a/debian/control b/debian/control index 500078f00..9a55c3522 100644 --- a/debian/control +++ b/debian/control @@ -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),