Skip to content

Commit

Permalink
Merge pull request #407 from g-v-egidy/pcap-gzip
Browse files Browse the repository at this point in the history
Implement reading & writing of gzip compressed pcap files
  • Loading branch information
Kaian authored Jul 18, 2022
2 parents 56c5e8e + 58b7601 commit 3d590fe
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Prerequisites
- gnutls - (optional) for TLS transport decrypt using GnuTLS and libgcrypt
- libncursesw5 - (optional) for UI, windows, panels (wide-character support)
- libpcre - (optional) for Perl Compatible regular expressions
- zlib - (optional) for gzip compressed pcap files

On most systems the commands to build will be the standard autotools procedure:

Expand All @@ -42,6 +43,7 @@ You can pass following flags to ./configure to enable some features
| `--with-openssl` | Adds OpenSSL support to parse TLS captured messages (req. libssl) |
| `--with-gnutls` | Adds GnuTLS support to parse TLS captured messages (req. gnutls) |
| `--with-pcre`| Adds Perl Compatible regular expressions support in regexp fields |
| `--with-zlib`| Enable zlib to support gzip compressed pcap files |
| `--enable-unicode` | Adds Ncurses UTF-8/Unicode support (req. libncursesw5) |
| `--enable-ipv6` | Enable IPv6 packet capture support. |
| `--enable-eep` | Enable EEP packet send/receive support. |
Expand Down
25 changes: 25 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ AC_PROG_EGREP
AC_LANG(C)
AM_PROG_CC_C_O

# we might want to use this with zlib for compressed pcap support
AC_CHECK_FUNCS([fopencookie])

#######################################################################
# Check for other REQUIRED libraries
AC_CHECK_LIB([pthread], [pthread_create], [], [
Expand Down Expand Up @@ -255,12 +258,33 @@ AS_IF([test "x$USE_EEP" = "xyes"], [
AC_DEFINE([USE_EEP],[],[Compile With EEP support])
], [])

####
#### zlib Support
####
AC_ARG_WITH([zlib],
AS_HELP_STRING([--with-zlib], [Enable zlib to support gzip compressed pcap files]),
[AC_SUBST(WITH_ZLIB, $withval)],
[AC_SUBST(WITH_ZLIB, no)]
)

AS_IF([test "x$WITH_ZLIB" = "xyes"], [
AC_CHECK_HEADER([zlib.h], [], [
AC_MSG_ERROR([ You need libz header files installed to compile with zlib support.])
])
AC_CHECK_LIB([z], [gzdopen], [], [
AC_MSG_ERROR([ You need libz library installed to compile with zlib support.])
])
AC_DEFINE([WITH_ZLIB],[],[Compile With zlib support])
], [])



# Conditional Source inclusion
AM_CONDITIONAL([WITH_PCRE2], [test "x$WITH_PCRE2" = "xyes"])
AM_CONDITIONAL([WITH_GNUTLS], [test "x$WITH_GNUTLS" = "xyes"])
AM_CONDITIONAL([WITH_OPENSSL], [test "x$WITH_OPENSSL" = "xyes"])
AM_CONDITIONAL([USE_EEP], [test "x$USE_EEP" = "xyes"])
AM_CONDITIONAL([WITH_ZLIB], [test "x$WITH_ZLIB" = "xyes"])


######################################################################
Expand Down Expand Up @@ -291,6 +315,7 @@ AC_MSG_NOTICE( Perl Expressions Support : ${WITH_PCRE} )
AC_MSG_NOTICE( Perl Expressions Support (v2): ${WITH_PCRE2} )
AC_MSG_NOTICE( IPv6 Support : ${USE_IPV6} )
AC_MSG_NOTICE( EEP Support : ${USE_EEP} )
AC_MSG_NOTICE( Zlib Support : ${WITH_ZLIB} )
AC_MSG_NOTICE( ====================================================== )
AC_MSG_NOTICE

Expand Down
5 changes: 5 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ if WITH_PCRE2
sngrep_CFLAGS+=$(PCRE2_CFLAGS)
sngrep_LDADD+=$(PCRE2_LIBS)
endif
if WITH_ZLIB
sngrep_CFLAGS+=$(ZLIB_CFLAGS)
sngrep_LDADD+=$(ZLIB_LIBS)
endif

sngrep_SOURCES+=address.c packet.c sip.c sip_call.c sip_msg.c sip_attr.c main.c
sngrep_SOURCES+=option.c group.c filter.c keybinding.c media.c setting.c rtp.c
sngrep_SOURCES+=util.c hash.c vector.c curses/ui_panel.c curses/scrollbar.c
Expand Down
85 changes: 85 additions & 0 deletions src/capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
#ifdef WITH_OPENSSL
#include "capture_openssl.h"
#endif
#ifdef WITH_ZLIB
#include <zlib.h>
#endif
#include "sip.h"
#include "rtp.h"
#include "setting.h"
Expand All @@ -71,6 +74,26 @@ void sighup_handler(int signum)
sighup_received = 1;
}

#if defined(WITH_ZLIB)
static ssize_t
gzip_cookie_write(void *cookie, const char *buf, size_t size)
{
return gzwrite((gzFile)cookie, (voidpc)buf, size);
}

static ssize_t
gzip_cookie_read(void *cookie, char *buf, size_t size)
{
return gzread((gzFile)cookie, (voidp)buf, size);
}

static int
gzip_cookie_close(void *cookie)
{
return gzclose((gzFile)cookie);
}
#endif

void
capture_init(size_t limit, bool rtp_capture, bool rotate, size_t pcap_buffer_size)
{
Expand Down Expand Up @@ -235,9 +258,36 @@ capture_offline(const char *infile)

// Open PCAP file
if ((capinfo->handle = pcap_open_offline(infile, errbuf)) == NULL) {
#if defined(HAVE_FOPENCOOKIE) && defined(WITH_ZLIB)
// we can't directly parse the file as pcap - could it be gzip compressed?
gzFile zf = gzopen(infile, "rb");
if (!zf)
goto openerror;

static cookie_io_functions_t cookiefuncs = {
gzip_cookie_read, NULL, NULL, gzip_cookie_close
};

// reroute the file access functions
// use the gzip read+close functions when accessing the file
FILE *fp = fopencookie(zf, "r", cookiefuncs);
if (!fp)
{
gzclose(zf);
goto openerror;
}

if ((capinfo->handle = pcap_fopen_offline(fp, errbuf)) == NULL) {
openerror:
fprintf(stderr, "Couldn't open pcap file %s: %s\n", infile, errbuf);
return 1;
}
}
#else
fprintf(stderr, "Couldn't open pcap file %s: %s\n", infile, errbuf);
return 1;
}
#endif

// Reopen tty for ncurses after pcap have used stdin
if (!strncmp(infile, "/dev/stdin", 10)) {
Expand Down Expand Up @@ -1310,6 +1360,17 @@ datalink_size(int datalink)

}

bool
is_gz_filename(const char *filename)
{
// does the filename end on ".gz"?
char *dotpos = strrchr(filename, '.');
if (dotpos && (strcmp(dotpos, ".gz") == 0))
return true;
else
return false;
}

pcap_dumper_t *
dump_open(const char *dumpfile, ino_t* dump_inode)
{
Expand All @@ -1335,6 +1396,30 @@ dump_open(const char *dumpfile, ino_t* dump_inode)
*dump_inode = sb.st_ino;
}

if (is_gz_filename(dumpfile))
{
#if defined(HAVE_FOPENCOOKIE) && defined(WITH_ZLIB)
// create a gzip file stream out of the already opened file
gzFile zf = gzdopen(fileno(fp), "w");
if (!zf)
return NULL;

static cookie_io_functions_t cookiefuncs = {
NULL, gzip_cookie_write, NULL, gzip_cookie_close
};

// reroute the file access functions
// use the gzip write+close functions when accessing the file
fp = fopencookie(zf, "w", cookiefuncs);
if (!fp)
return NULL;
#else
// no support for gzip compressed pcap files compiled in -> abort
fclose(fp);
return NULL;
#endif
}

return pcap_dump_fopen(capinfo->handle, fp);
}
return NULL;
Expand Down
3 changes: 3 additions & 0 deletions src/curses/ui_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ ui_wait_for_input()
// While there are still panels
while ((panel = panel_below(NULL))) {

if (was_sigterm_received())
return 0;

// Get panel interface structure
ui = ui_find_by_panel(panel);

Expand Down
4 changes: 3 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ main(int argc, char* argv[])
}
}

setup_sigterm_handler();

#if defined(WITH_GNUTLS) || defined(WITH_OPENSSL)
// Set capture decrypt key file
capture_set_keyfile(keyfile);
Expand Down Expand Up @@ -443,7 +445,7 @@ main(int argc, char* argv[])
ui_wait_for_input();
} else {
setbuf(stdout, NULL);
while(capture_is_running()) {
while(capture_is_running() && !was_sigterm_received()) {
if (!quiet)
printf("\rDialog count: %d", sip_calls_count_unrotated());
usleep(500 * 1000);
Expand Down
37 changes: 37 additions & 0 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,45 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>
#include "util.h"

#if __STDC_VERSION__ >= 201112L && __STDC_NO_ATOMICS__ != 1
// modern C with atomics
#include <stdatomic.h>
typedef atomic_int signal_flag_type;
#else
// no atomics available
typedef volatile sig_atomic_t signal_flag_type;
#endif

static signal_flag_type sigterm_received = 0;

static void sigterm_handler(int signum)
{
sigterm_received = 1;
}

void setup_sigterm_handler(void)
{
// set up SIGTERM handler (also used for SIGINT and SIGQUIT)
// the handler will be served by any of the running threads
// so we just set a flag and check it in one of the two available
// main loops of the program (main for --no-interface and
// ui_wait_for_input() for curses)

if (signal(SIGTERM, sigterm_handler) == SIG_ERR)
exit(EXIT_FAILURE);
if (signal(SIGINT, sigterm_handler) == SIG_ERR)
exit(EXIT_FAILURE);
if (signal(SIGQUIT, sigterm_handler) == SIG_ERR)
exit(EXIT_FAILURE);
}

bool was_sigterm_received(void)
{
return (sigterm_received == 1);
}

void *
sng_malloc(size_t size)
Expand Down
12 changes: 12 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,16 @@ timeval_to_delta(struct timeval start, struct timeval end, char *out);
char *
strtrim(char *str);

/**
* @brief Set up handler for SIGTERM, SIGINT and SIGQUIT
*/
void setup_sigterm_handler(void);

/**
* @brief Check if SIGTERM, SIGINT or SIGQUIT were received
*
* @return true if any of the exit signals were received
*/
bool was_sigterm_received(void);

#endif /* __SNGREP_UTIL_H */

0 comments on commit 3d590fe

Please sign in to comment.