diff options
author | Nardi Ivan <nardi.ivan@gmail.com> | 2020-08-21 14:40:54 +0200 |
---|---|---|
committer | Nardi Ivan <nardi.ivan@gmail.com> | 2020-08-21 22:04:55 +0200 |
commit | d62ae567d1274328cfbb5e767011cdbe821060c9 (patch) | |
tree | c57aa2ca6e52ec8db93d6b5c4f5b2d42e23359f7 | |
parent | 23ec82b59dd4757508d9d99db05537d1278dd7d1 (diff) |
Add (optional) dependency on external libraries: libgcrypt and libgpg-error
To support QUIC payload and header decryption, it is necessary to choose an
external crypto library to handle the low-level crypto stuff. Since we will
use some Wireshark code, it is quite natural to choose the same library used
by Wireshark itself: libgcrypt.
More precisely, we will use libgcrypt and libgpg-error.
Both libraries have LGPL license, so there should be no issue from this point
of view.
These libraries are not required to build nDPI, and their usage is optional:
nDPI will keep working (and compiling) even if they are not available.
However, without them, QUIC sub-classification is next to impossible.
The configure flag "--disable-gcrypt" forces the build system to ignore these
libraries.
libgpg-error is only used for debug to have meaningful error messages and its
usage is trivial.
The same cannot be said for libgcrypt because its initialization is a significant
issue.
The rest of this commit message try explaining how libgcrypt is
initialized.
According to the documentation
https://gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html
https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html#Multi_002dThreading
libgcrypt must be initialized before using it, but such initialization should
be performed by the actual application and not by any library.
Forcing the users to proper initialize libgcrypt in their own code seems
unreasonable: most people using nDPI might be complete unaware of any crypto
stuff and update each and every one application linking to nDPI with specific
libgcrypt code should be out of question, anyway.
Fortunately, it seems a workaround exists to initialize libgcrypt in a library
https://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html
Therefore, we could provide a wrapper to this initialization stuff in a nDPI
function. Unfortunately nDPI API lacks a global init function that must be
called only once, before any other functions. We could add it, but that would
be a major API break.
AFAIK, ndpi_init_detection_module() might be called multiple times, for example
to create multiple independent dpi engines in the same program.
The proposed solution is to (optionally) initialize libgcrypt in
ndpi_init_detection_module() anyway:
* if the actual application doesn't directly use libgcrypt and only calls
ndpi_init_detection_module() once, everything is formally correct and it
should work out of the box [by far the most common user case];
* if the actual application already uses libgcrypt directly, it already
performs the required initialization. In this case the ndpi_prefs.ndpi_dont_init_libgcrypt
flag should be passed to ndpi_init_detection_module() to avoid further
initializations.
The only scenario not supported by this solution is when the application is
unaware of libgcrypt and calls ndpi_init_detection_module() multiple times
concurrently. But this scenario should be uncommon.
A completely different option should be to switch to another crypto library,
with a huge impact on the QUIC dissector code.
Bottom line: crypto is hard, using libgcrypt is complex and the proposed
initialization, even if not perfect, should cover the most frequent user
cases and should work, for the time being.
If anyone has some suggestions...
-rw-r--r-- | configure.seed | 6 | ||||
-rw-r--r-- | example/Makefile.in | 2 | ||||
-rw-r--r-- | example/ndpiReader.c | 4 | ||||
-rw-r--r-- | fuzz/Makefile.am | 6 | ||||
-rw-r--r-- | src/include/ndpi_api.h.in | 5 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 1 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 29 |
7 files changed, 49 insertions, 4 deletions
diff --git a/configure.seed b/configure.seed index ecde0579b..aed5c3529 100644 --- a/configure.seed +++ b/configure.seed @@ -169,6 +169,12 @@ AM_CONDITIONAL([HAS_FUZZLDFLAGS], [test "x$has_sanitizefuzzer" = "xyes"]) AC_CHECK_LIB(pthread, pthread_setaffinity_np, AC_DEFINE_UNQUOTED(HAVE_PTHREAD_SETAFFINITY_NP, 1, [libc has pthread_setaffinity_np])) +AC_ARG_ENABLE([gcrypt], + [AS_HELP_STRING([--disable-gcrypt], [Avoid compiling with libgcrypt/libgpg-error, even if they are present. QUIC sub-classification may be missing])], + [:], + [AC_CHECK_LIB(gcrypt, gcry_cipher_checktag) + AC_CHECK_LIB(gpg-error, gpg_strerror_r)]) + dnl> PCRE AC_ARG_WITH(pcre, [ --with-pcre Enable nDPI build with libpcre]) if test "${with_pcre+set}" = set; then : diff --git a/example/Makefile.in b/example/Makefile.in index df7885166..32e36677d 100644 --- a/example/Makefile.in +++ b/example/Makefile.in @@ -3,7 +3,7 @@ CXX=@CXX@ SRCHOME=../src CFLAGS=-g -fPIC -DPIC -I$(SRCHOME)/include @CFLAGS@ LIBNDPI=$(SRCHOME)/lib/libndpi.a -LDFLAGS=$(LIBNDPI) @PCAP_LIB@ @ADDITIONAL_LIBS@ -lpthread -lm @LDFLAGS@ +LDFLAGS=$(LIBNDPI) @PCAP_LIB@ @LIBS@ @ADDITIONAL_LIBS@ -lpthread -lm @LDFLAGS@ HEADERS=intrusion_detection.h reader_util.h $(SRCHOME)/include/ndpi_api.h \ $(SRCHOME)/include/ndpi_typedefs.h $(SRCHOME)/include/ndpi_protocol_ids.h OBJS=ndpiReader.o reader_util.o intrusion_detection.o diff --git a/example/ndpiReader.c b/example/ndpiReader.c index 5202c8b78..ed56c2114 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -3699,6 +3699,10 @@ int orginal_main(int argc, char **argv) { "------------------------------------------------------------\n\n"); printf("Using nDPI (%s) [%d thread(s)]\n", ndpi_revision(), num_threads); + + const char *gcrypt_ver = ndpi_get_gcrypt_version(); + if(gcrypt_ver) + printf("Using libgcrypt version %s\n", gcrypt_ver); } signal(SIGINT, sigproc); diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index 959bedda8..b70eae2d8 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -3,7 +3,7 @@ bin_PROGRAMS = fuzz_process_packet fuzz_ndpi_reader fuzz_ndpi_reader_with_main fuzz_process_packet_SOURCES = fuzz_process_packet.c fuzz_process_packet_CFLAGS = fuzz_process_packet_LDADD = ../src/lib/libndpi.a -fuzz_process_packet_LDFLAGS = $(ADDITIONAL_LIBS) +fuzz_process_packet_LDFLAGS = $(ADDITIONAL_LIBS) $(LIBS) if HAS_FUZZLDFLAGS fuzz_process_packet_CFLAGS += $(LIB_FUZZING_ENGINE) fuzz_process_packet_LDFLAGS += $(LIB_FUZZING_ENGINE) @@ -16,7 +16,7 @@ fuzz_process_packet_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ fuzz_ndpi_reader_SOURCES = fuzz_ndpi_reader.c fuzz_ndpi_reader_CFLAGS = -I../example/ fuzz_ndpi_reader_LDADD = ../src/lib/libndpi.a -fuzz_ndpi_reader_LDFLAGS = ../example/libndpiReader.a $(PCAP_LIB) $(ADDITIONAL_LIBS) +fuzz_ndpi_reader_LDFLAGS = ../example/libndpiReader.a $(PCAP_LIB) $(ADDITIONAL_LIBS) $(LIBS) if HAS_FUZZLDFLAGS fuzz_ndpi_reader_CFLAGS += $(LIB_FUZZING_ENGINE) fuzz_ndpi_reader_LDFLAGS += $(LIB_FUZZING_ENGINE) @@ -29,7 +29,7 @@ fuzz_ndpi_reader_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ fuzz_ndpi_reader_with_main_SOURCES = fuzz_ndpi_reader.c fuzz_ndpi_reader_with_main_CFLAGS = -I../example/ -DBUILD_MAIN fuzz_ndpi_reader_with_main_LDADD = ../src/lib/libndpi.a -fuzz_ndpi_reader_with_main_LDFLAGS = ../example/libndpiReader.a $(PCAP_LIB) $(ADDITIONAL_LIBS) +fuzz_ndpi_reader_with_main_LDFLAGS = ../example/libndpiReader.a $(PCAP_LIB) $(ADDITIONAL_LIBS) $(LIBS) # force usage of CXX for linker fuzz_ndpi_reader_with_main_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \ diff --git a/src/include/ndpi_api.h.in b/src/include/ndpi_api.h.in index 1141e054c..de3f90885 100644 --- a/src/include/ndpi_api.h.in +++ b/src/include/ndpi_api.h.in @@ -182,6 +182,10 @@ extern "C" { * hosts and do other things. As soon as you are ready to use * it do not forget to call first ndpi_finalize_initalization() * + * You can call this function multiple times, (i.e. to create multiple + * indipendent detection contexts) but all these calls MUST NOT run + * in parallel + * * @par prefs = load preferences * @return the initialized detection module * @@ -879,6 +883,7 @@ extern "C" { //void * ndpi_calloc(unsigned long count, size_t size); //void ndpi_free(void *ptr); u_int16_t ndpi_get_api_version(void); + const char *ndpi_get_gcrypt_version(void); /* https://github.com/corelight/community-id-spec */ int ndpi_flowv4_flow_hash(u_int8_t l4_proto, u_int32_t src_ip, u_int32_t dst_ip, u_int16_t src_port, u_int16_t dst_port, diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index d585ccd23..b4d9b3dd5 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1412,6 +1412,7 @@ typedef enum { ndpi_no_prefs = 0, ndpi_dont_load_tor_hosts, + ndpi_dont_init_libgcrypt, } ndpi_prefs; typedef struct { diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index a2b9b7d42..4ce2527ee 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -32,6 +32,10 @@ #include "ahocorasick.h" #include "libcache.h" +#ifdef HAVE_LIBGCRYPT +#include <gcrypt.h> +#endif + #include <time.h> #ifndef WIN32 #include <unistd.h> @@ -1979,6 +1983,24 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs NDPI_BITMASK_RESET(ndpi_str->debug_bitmask); #endif /* NDPI_ENABLE_DEBUG_MESSAGES */ +#ifdef HAVE_LIBGCRYPT + if(!(prefs & ndpi_dont_init_libgcrypt)) { + if(!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { + const char *gcrypt_ver = gcry_check_version(NULL); + if (!gcrypt_ver) { + NDPI_LOG_ERR(ndpi_str, "Error initializing libgcrypt\n"); + ndpi_free(ndpi_str); + return NULL; + } + NDPI_LOG_DBG(ndpi_str, "Libgcrypt %s\n", gcrypt_ver); + /* Tell Libgcrypt that initialization has completed. */ + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + } + } else { + NDPI_LOG_DBG(ndpi_str, "Libgcrypt initialization skipped\n"); + } +#endif + if((ndpi_str->protocols_ptree = ndpi_New_Patricia(32 /* IPv4 */)) != NULL) ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, host_protocol_list, prefs & ndpi_dont_load_tor_hosts); @@ -6311,6 +6333,13 @@ u_int16_t ndpi_get_api_version() { return(NDPI_API_VERSION); } +const char *ndpi_get_gcrypt_version(void) { +#ifdef HAVE_LIBGCRYPT + return gcry_check_version(NULL); +#endif + return NULL; +} + ndpi_proto_defaults_t *ndpi_get_proto_defaults(struct ndpi_detection_module_struct *ndpi_str) { return(ndpi_str->proto_defaults); } |