summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Richardson <mcr@sandelman.ca>2020-08-21 15:14:24 -0400
committerMichael Richardson <mcr@sandelman.ca>2020-12-19 14:01:02 -0500
commit675dbfeb4fe6c1bbad4300ae9229db9d033bf57d (patch)
treeac13d0e9ef96a9ed391f0ce4c604028996aea5c3
parent8897f7823a9e8674148a4b6f89eef4c43990ef7a (diff)
downloadlibpcap-675dbfeb4fe6c1bbad4300ae9229db9d033bf57d.tar.gz
IO plugins for libpcap
-rw-r--r--CMakeLists.txt1
-rw-r--r--Makefile.in3
-rw-r--r--Win32/Prj/wpcap.vcxproj1
-rw-r--r--config.h.in9
-rwxr-xr-xconfigure69
-rw-r--r--configure.ac5
-rw-r--r--pcap-int.h21
-rw-r--r--pcap-ioplugin.c259
-rw-r--r--pcap/pcap.h17
-rw-r--r--savefile.c24
-rw-r--r--sf-pcap.c49
-rw-r--r--testprogs/selpolltest.c2
12 files changed, 408 insertions, 52 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7a04671c..6fd6838e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1043,6 +1043,7 @@ set(PROJECT_SOURCE_LIST_C
optimize.c
pcap-common.c
pcap.c
+ pcap-ioplugin.c
savefile.c
sf-pcapng.c
sf-pcap.c
diff --git a/Makefile.in b/Makefile.in
index d8b8507b..cb56a771 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -94,7 +94,7 @@ MODULE_C_SRC = @MODULE_C_SRC@
REMOTE_C_SRC = @REMOTE_C_SRC@
COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \
fmtutils.c \
- savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \
+ pcap-ioplugin.c savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \
bpf_image.c bpf_filter.c bpf_dump.c
GENERATED_C_SRC = scanner.c grammar.c
LIBOBJS = @LIBOBJS@
@@ -331,6 +331,7 @@ EXTRA_DIST = \
pcap-enet.c \
pcap-haiku.cpp \
pcap-int.h \
+ pcap-ioplugin.c \
pcap-libdlpi.c \
pcap-linux.c \
pcap-namedb.h \
diff --git a/Win32/Prj/wpcap.vcxproj b/Win32/Prj/wpcap.vcxproj
index 43b7099b..2f5cbb02 100644
--- a/Win32/Prj/wpcap.vcxproj
+++ b/Win32/Prj/wpcap.vcxproj
@@ -209,6 +209,7 @@ win_bison -ppcap_ --yacc --output=..\..\grammar.c --defines ..\..\grammar.y</Com
<ClCompile Include="..\..\pcap-rpcap.c" />
<ClCompile Include="..\..\pcap-win32.c" />
<ClCompile Include="..\..\pcap.c" />
+ <ClCompile Include="..\..\pcap-ioplugin.c" />
<ClCompile Include="..\..\savefile.c" />
<ClCompile Include="..\..\scanner.c" />
<ClCompile Include="..\..\sf-pcapng.c" />
diff --git a/config.h.in b/config.h.in
index 00618aec..c2868429 100644
--- a/config.h.in
+++ b/config.h.in
@@ -42,6 +42,12 @@
/* Define to 1 if you have the declaration of `ether_hostton' */
#undef HAVE_DECL_ETHER_HOSTTON
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `dlopen' function. */
+#undef HAVE_DLOPEN
+
/* Define to 1 if `dl_module_id_1' is a member of `dl_hp_ppa_info_t'. */
#undef HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1
@@ -75,6 +81,9 @@
/* Define to 1 if you have the `dag' library (-ldag). */
#undef HAVE_LIBDAG
+/* Define to 1 if you have the `dl' library (-ldl). */
+#undef HAVE_LIBDL
+
/* if libdlpi exists */
#undef HAVE_LIBDLPI
diff --git a/configure b/configure
index d85be30f..be7687f8 100755
--- a/configure
+++ b/configure
@@ -11778,6 +11778,75 @@ fi
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+ LIBS="-ldl $LIBS"
+
+fi
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in dlopen
+do :
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLOPEN 1
+_ACEOF
+
+fi
+done
+
+
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
# incompatible versions:
diff --git a/configure.ac b/configure.ac
index 2ad28bbe..2f1973c9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2819,6 +2819,11 @@ if test "x$enable_rdma" != "xno"; then
AC_SUBST(PCAP_SUPPORT_RDMASNIFF)
fi
+dnl check for dynamic gzip support
+AC_CHECK_LIB(dl, dlopen)
+AC_CHECK_HEADERS(dlfcn.h)
+AC_CHECK_FUNCS(dlopen)
+
AC_PROG_INSTALL
AC_CONFIG_HEADER(config.h)
diff --git a/pcap-int.h b/pcap-int.h
index 3c18dae8..54fb31fc 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -99,6 +99,22 @@ extern int pcap_utf_8_mode;
((ull & 0x00000000000000ffULL) << 56)
/*
+ * Setting O_BINARY on DOS/Windows is a bit tricky
+ */
+#if defined(_WIN32)
+ #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY)
+#elif defined(MSDOS)
+ #if defined(__HIGHC__)
+ #define SET_BINMODE(f) setmode(f, O_BINARY)
+ #else
+ #define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
+ #endif
+#else
+ #define SET_BINMODE(f) do {} while(0)
+#endif
+
+
+/*
* Maximum snapshot length.
*
* Somewhat arbitrary, but chosen to be:
@@ -641,6 +657,11 @@ int pcap_parsesrcstr_ex(const char *, int *, char *, char *,
extern int pcap_debug;
#endif
+/*
+ * Internal interfaces for I/O plugins
+ */
+const pcap_ioplugin_t* pcap_ioplugin_init(const char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/pcap-ioplugin.c b/pcap-ioplugin.c
new file mode 100644
index 00000000..d8e5c83e
--- /dev/null
+++ b/pcap-ioplugin.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017
+ * Internet Systems Consortium, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-ioplugin.c - supports dynamic loading of compression modules
+ * Created by Ray Bellis, ISC.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ftmacros.h"
+
+#ifdef _WIN32
+#include <pcap-stdinc.h>
+#else /* _WIN32 */
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#elif HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#include <sys/types.h>
+#endif /* _WIN32 */
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcap-int.h"
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+static FILE*
+stdio_open_read(const char *fname, char *errbuf)
+{
+ FILE *fp = NULL;
+
+ if (fname == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "A null pointer was supplied as the file name");
+ return (NULL);
+ }
+
+ if (fname[0] == '-' && fname[1] == '\0')
+ {
+ fp = stdin;
+ if (stdin == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The standard input is not open");
+ return (NULL);
+ }
+ SET_BINMODE(fp);
+ } else {
+ /*
+ * "b" is supported as of C90, so *all* UN*Xes should
+ * support it, even though it does nothing. It's
+ * required on Windows, as the file is a binary file
+ * and must be written in binary mode.
+ *
+ * Use charset_fopen(); on Windows, it tests whether we're
+ * in "local code page" or "UTF-8" mode, and treats the
+ * pathname appropriately, and on other platforms, it just
+ * wraps fopen().
+ *
+ */
+ fp = charset_fopen(fname, "rb");
+ if (fp == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: fopen: %s", fname,
+ pcap_strerror(errno));
+ return (NULL);
+ }
+ }
+
+ return fp;
+}
+
+static FILE*
+stdio_open_write(const char *fname, char *errbuf)
+{
+ FILE *fp = NULL;
+
+ if (strcmp(fname, "-") == 0) {
+ fp = stdout;
+ if (stdout == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The standard input is not open");
+ return (NULL);
+ }
+
+ SET_BINMODE(fp);
+ } else {
+ /*
+ * "b" is supported as of C90, so *all* UN*Xes should
+ * support it, even though it does nothing. It's
+ * required on Windows, as the file is a binary file
+ * and must be written in binary mode.
+ */
+ fp = charset_fopen(fname, "rb");
+ if (fp == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: fopen: %s", fname,
+ pcap_strerror(errno));
+ return (NULL);
+ }
+ }
+
+ return fp;
+}
+
+static const pcap_ioplugin_t*
+pcap_ioplugin_stdio(void) {
+ static pcap_ioplugin_t plugin = {
+ .open_read = stdio_open_read,
+ .open_write = stdio_open_write
+ };
+
+ return &plugin;
+}
+
+/*
+ * loads an I/O plugin with the given name
+ * (on UNIX, a .so shared library)
+ *
+ * NB: fails silently and falls back to existing uncompressed
+ * stdio-based output if the plugin fails to load
+ */
+
+const pcap_ioplugin_t*
+pcap_ioplugin_init(const char *name)
+{
+ void *lib = NULL;
+ if (name == NULL) {
+ goto fail;
+ }
+
+#if HAVE_DLOPEN
+ lib = dlopen(name, RTLD_NOW);
+ if (lib != NULL) {
+ pcap_ioplugin_init_fn ioplugin_init = dlsym(lib, "ioplugin_init");
+ if (ioplugin_init == NULL) {
+ dlclose(lib);
+ goto fail;
+ } else {
+ return ioplugin_init();
+ }
+ }
+#endif /* HAVE_DLOPEN */
+
+fail:
+ return pcap_ioplugin_stdio();
+}
+
+struct file_entry {
+ FILE *fp;
+ const void *cookie;
+ struct file_entry *next;
+};
+
+static struct {
+ struct file_entry *head;
+} file_list = { NULL };
+
+static int registered_atexit = 0;
+static int running_atexit = 0;
+
+static void
+pcap_ioplugin_closeall(void)
+{
+ struct file_entry *entry = file_list.head;
+
+ running_atexit = 1;
+
+ while (entry) {
+ struct file_entry *tmp = entry;
+ entry = entry->next;
+ fclose(tmp->fp);
+ free(tmp);
+ }
+
+ file_list.head = NULL;
+}
+
+void
+pcap_ioplugin_register_fp_cookie(FILE *fp, const void *cookie)
+{
+ struct file_entry *entry = malloc(sizeof *entry);
+ if (!entry) {
+ return;
+ }
+ entry->fp = fp;
+ entry->cookie = cookie;
+
+ if (!registered_atexit) {
+ registered_atexit = 1;
+ atexit(pcap_ioplugin_closeall);
+ }
+
+ /* O(1) insertion to front of list */
+ entry->next = file_list.head;
+ file_list.head = entry;
+}
+
+void
+pcap_ioplugin_unregister_fp_cookie(const void *cookie)
+{
+ struct file_entry *entry = file_list.head;
+
+ /* atexit handler does its own list traversal */
+ if (running_atexit) {
+ return;
+ }
+
+ /* check head of list */
+ if (entry && entry->cookie == cookie) {
+ file_list.head = entry->next;
+ free(entry);
+ return;
+ }
+
+ /* otherwise check following nodes */
+ while (entry) {
+ struct file_entry *next = entry->next;
+ if (next && next->cookie == cookie) {
+ /* remove following node */
+ entry->next = next->next;
+ free(next);
+ return;
+ }
+ entry = next;
+ }
+}
diff --git a/pcap/pcap.h b/pcap/pcap.h
index 39b12d25..08ef57f7 100644
--- a/pcap/pcap.h
+++ b/pcap/pcap.h
@@ -1042,6 +1042,23 @@ PCAP_API int pcap_remoteact_list(char *hostlist, char sep, int size,
PCAP_API int pcap_remoteact_close(const char *host, char *errbuf);
PCAP_API void pcap_remoteact_cleanup(void);
+/*
+ * I/O Plugin Support
+ */
+
+typedef FILE* (*pcap_ioplugin_open_read_fn)(const char *fname, char *errbuf);
+typedef FILE* (*pcap_ioplugin_open_write_fn)(const char *fname, char *errbuf);
+
+typedef struct pcap_ioplugin {
+ pcap_ioplugin_open_read_fn open_read;
+ pcap_ioplugin_open_write_fn open_write;
+} pcap_ioplugin_t;
+
+typedef const pcap_ioplugin_t* (*pcap_ioplugin_init_fn)(void);
+
+PCAP_API void pcap_ioplugin_register_fp_cookie(FILE *fp, const void *cookie);
+PCAP_API void pcap_ioplugin_unregister_fp_cookie(const void *cookie);
+
#ifdef __cplusplus
}
#endif
diff --git a/savefile.c b/savefile.c
index d04b917a..6bf66f4d 100644
--- a/savefile.c
+++ b/savefile.c
@@ -72,19 +72,6 @@
static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *);
#endif
-/*
- * Setting O_BINARY on DOS/Windows is a bit tricky
- */
-#if defined(_WIN32)
- #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY)
-#elif defined(MSDOS)
- #if defined(__HIGHC__)
- #define SET_BINMODE(f) setmode(f, O_BINARY)
- #else
- #define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
- #endif
-#endif
-
static int
sf_getnonblock(pcap_t *p _U_)
{
@@ -339,12 +326,18 @@ pcap_t *
pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
char *errbuf)
{
+ const pcap_ioplugin_t *plugin = pcap_ioplugin_init(getenv("PCAP_IOPLUGIN_READ"));
FILE *fp;
pcap_t *p;
- if (fname == NULL) {
+ if (plugin->open_read == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "A null pointer was supplied as the file name");
+ "No file reading function found");
+ return NULL;
+ }
+
+ fp = plugin->open_read(fname, errbuf);
+ if (fp == NULL) {
return (NULL);
}
if (fname[0] == '-' && fname[1] == '\0')
@@ -381,6 +374,7 @@ pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
return (NULL);
}
}
+
p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf);
if (p == NULL) {
if (fp != stdin)
diff --git a/sf-pcap.c b/sf-pcap.c
index d8443e98..961c2785 100644
--- a/sf-pcap.c
+++ b/sf-pcap.c
@@ -56,19 +56,6 @@
#include "sf-pcap.h"
/*
- * Setting O_BINARY on DOS/Windows is a bit tricky
- */
-#if defined(_WIN32)
- #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY)
-#elif defined(MSDOS)
- #if defined(__HIGHC__)
- #define SET_BINMODE(f) setmode(f, O_BINARY)
- #else
- #define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
- #endif
-#endif
-
-/*
* Standard libpcap format.
*/
#define TCPDUMP_MAGIC 0xa1b2c3d4
@@ -767,15 +754,11 @@ pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
#if defined(_WIN32) || defined(MSDOS)
/*
- * If we're writing to the standard output, put it in binary
- * mode, as savefiles are binary files.
+ * If we're not writing to the standard output, turn of buffering.
*
- * Otherwise, we turn off buffering.
* XXX - why? And why not on the standard output?
*/
- if (f == stdout)
- SET_BINMODE(f);
- else
+ if (f != stdout)
setvbuf(f, NULL, _IONBF, 0);
#endif
if (sf_write_header(p, f, linktype, p->snapshot) == -1) {
@@ -794,6 +777,7 @@ pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
pcap_dumper_t *
pcap_dump_open(pcap_t *p, const char *fname)
{
+ const pcap_ioplugin_t *plugin = pcap_ioplugin_init(getenv("PCAP_IOPLUGIN_WRITE"));
FILE *f;
int linktype;
@@ -821,23 +805,18 @@ pcap_dump_open(pcap_t *p, const char *fname)
"A null pointer was supplied as the file name");
return NULL;
}
- if (fname[0] == '-' && fname[1] == '\0') {
- f = stdout;
- fname = "standard output";
- } else {
- /*
- * "b" is supported as of C90, so *all* UN*Xes should
- * support it, even though it does nothing. It's
- * required on Windows, as the file is a binary file
- * and must be written in binary mode.
- */
- f = charset_fopen(fname, "wb");
- if (f == NULL) {
- pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
- errno, "%s", fname);
- return (NULL);
- }
+
+ if (plugin->open_write == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "No file writing function found");
+ return NULL;
}
+
+ f = plugin->open_write(fname, p->errbuf);
+ if (f == NULL) {
+ return NULL;
+ }
+
return (pcap_setup_dump(p, linktype, f, fname));
}
diff --git a/testprogs/selpolltest.c b/testprogs/selpolltest.c
index 569c8294..ab7f8f46 100644
--- a/testprogs/selpolltest.c
+++ b/testprogs/selpolltest.c
@@ -74,7 +74,7 @@ main(int argc, char **argv)
struct bpf_program fcode;
char ebuf[PCAP_ERRBUF_SIZE];
pcap_if_t *devlist;
- int selectable_fd;
+ int selectable_fd = -1;
const struct timeval *required_timeout;
int status;
int packet_count;