diff options
author | Michael Richardson <mcr@sandelman.ca> | 2020-08-21 15:14:24 -0400 |
---|---|---|
committer | Michael Richardson <mcr@sandelman.ca> | 2020-12-19 14:01:02 -0500 |
commit | 675dbfeb4fe6c1bbad4300ae9229db9d033bf57d (patch) | |
tree | ac13d0e9ef96a9ed391f0ce4c604028996aea5c3 | |
parent | 8897f7823a9e8674148a4b6f89eef4c43990ef7a (diff) | |
download | libpcap-675dbfeb4fe6c1bbad4300ae9229db9d033bf57d.tar.gz |
IO plugins for libpcap
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | Win32/Prj/wpcap.vcxproj | 1 | ||||
-rw-r--r-- | config.h.in | 9 | ||||
-rwxr-xr-x | configure | 69 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | pcap-int.h | 21 | ||||
-rw-r--r-- | pcap-ioplugin.c | 259 | ||||
-rw-r--r-- | pcap/pcap.h | 17 | ||||
-rw-r--r-- | savefile.c | 24 | ||||
-rw-r--r-- | sf-pcap.c | 49 | ||||
-rw-r--r-- | testprogs/selpolltest.c | 2 |
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 @@ -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) @@ -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 @@ -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) @@ -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; |