diff --git a/.github/ISSUE_TEMPLATE/bug_template.md b/.github/ISSUE_TEMPLATE/bug_template.md index cce00f2fa6d..f75c07c42c0 100644 --- a/.github/ISSUE_TEMPLATE/bug_template.md +++ b/.github/ISSUE_TEMPLATE/bug_template.md @@ -21,7 +21,7 @@ A clear and concise description of what happening. * OS version: [e.g. 18.04] * Architecture: [e.g. arm64] * nDPI version or commit hash: [e.g. 4.0-stable or 937357e4bc55610f116f66d15a8e0fc1e260c02c]. -* nDPI compilation flags used: if you are building from source [e.g. --with-pcre --disable-gcrypt]. +* nDPI compilation flags used: if you are building from source [e.g. --with-pcre --with-local-libgcrypt]. * Attach the `config.log` file generated after `./configure` ran (if you are building from source). ## How to reproduce the reported bug diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index adcf7fe6b56..05c23f65964 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: sudo apt-get update sudo apt-get install autoconf automake libtool pkg-config gettext libjson-c-dev flex bison libpcap-dev sudo apt-get install rrdtool librrd-dev - sudo apt-get install libgcrypt20-dev libpcre3-dev libmaxminddb-dev lcov + sudo apt-get install libpcre3-dev libmaxminddb-dev lcov - name: Configure run: env CC=gcc CFLAGS='-Werror' ./autogen.sh --enable-debug-messages --enable-code-coverage --with-pcre --with-maxminddb - name: Build @@ -51,7 +51,7 @@ jobs: matrix: os: ["ubuntu-latest", "ubuntu-18.04", "macOS-latest", "macos-11"] arch: ["x86_64"] - gcrypt: ["--disable-gcrypt", ""] + gcrypt: ["--with-local-libgcrypt", ""] compiler: ["default-cc"] pcre: [""] maxminddb: [""] @@ -151,7 +151,7 @@ jobs: sudo apt-get install doxygen python3-sphinx python3-sphinx-rtd-theme python3-breathe python3-pip sudo apt-get install rrdtool librrd-dev - name: Install Ubuntu Prerequisites (libgcrypt) - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64') && !startsWith(matrix.gcrypt, '--disable-gcrypt') + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64') && startsWith(matrix.gcrypt, '--with-local-libgcrypt') run: | sudo apt-get install libgcrypt20-dev - name: Install Ubuntu Prerequisites (libpcre) @@ -177,7 +177,7 @@ jobs: brew install coreutils brew install rrdtool - name: Install MacOS Prerequisites (libgcrypt) - if: startsWith(matrix.os, 'macOS') && startsWith(matrix.arch, 'x86_64') && !startsWith(matrix.gcrypt, '--disable-gcrypt') + if: startsWith(matrix.os, 'macOS') && startsWith(matrix.arch, 'x86_64') && startsWith(matrix.gcrypt, '--with-local-libgcrypt') run: | brew install libgcrypt - name: Install MacOS Prerequisites (libpcre) @@ -241,7 +241,7 @@ jobs: - name: Configure nDPI [Mingw-w64] (runs only on ubuntu jobs) if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64') run: | - make distclean && ./autogen.sh --host=x86_64-w64-mingw32 ${{ matrix.gcrypt }} ${{ matrix.pcre }} ${{ matrix.maxminddb }} + make distclean && ./autogen.sh --host=x86_64-w64-mingw32 ${{ matrix.pcre }} ${{ matrix.maxminddb }} - name: Build nDPI [Mingw-w64] (runs only on ubuntu jobs) if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64') run: | diff --git a/configure.ac b/configure.ac index 8d5de80f75b..d10435fa8c6 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ AS_IF([test "${with_only_libndpi+set}" = set],[ AC_ARG_WITH(sanitizer, AS_HELP_STRING([--with-sanitizer], [Build with support for address, undefined and leak sanitizer])) AC_ARG_ENABLE(fuzztargets, AS_HELP_STRING([--enable-fuzztargets], [Enable fuzz targets]),[enable_fuzztargets=$enableval],[enable_fuzztargets=no]) AC_ARG_ENABLE(code-coverage, AS_HELP_STRING([--enable-code-coverage], [Generate Code Coverage report])) -AC_ARG_WITH(libgcrypt, AS_HELP_STRING([--with-libgcrypt], [Build with libgcrypt (if present) instead of the enclosed gcrypt light])) +AC_ARG_WITH(local-libgcrypt, AS_HELP_STRING([--with-local-libgcrypt], [Build with libgcrypt (if present) instead of the enclosed gcrypt light])) AS_IF([test "x$enable_fuzztargets" = "xyes"], [BUILD_FUZZTARGETS=1], [BUILD_FUZZTARGETS=0]) AM_CONDITIONAL([BUILD_FUZZTARGETS], [test "x$enable_fuzztargets" = "xyes"]) @@ -238,27 +238,20 @@ 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])) -AS_IF([test "${with_libgcrypt+set}" = set],[ -dnl> GCRYPT -GCRYPT_ENABLED=1 -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])], - [GCRYPT_ENABLED=0], - [AC_CHECK_LIB(gcrypt, gcry_cipher_checktag)]) -AS_IF([test ${GCRYPT_ENABLED} -eq 1], [ +dnl> libgcrypt (external) +USE_HOST_LIBGCRYPT=0 +AS_IF([test "${with_local_libgcrypt+set}" = set],[ + USE_HOST_LIBGCRYPT=1 + AC_CHECK_LIB(gcrypt, gcry_cipher_checktag) if test "x$ac_cv_lib_gcrypt_gcry_cipher_checktag" = xyes; then : ADDITIONAL_LIBS="${ADDITIONAL_LIBS} -lgcrypt" else $as_unset ac_cv_lib_gcrypt_gcry_cipher_checktag - AC_CHECK_LIB(gpg-error, gpg_strerror_r) - AC_CHECK_LIB(gcrypt, gcry_cipher_checktag) - if test "x$ac_cv_lib_gcrypt_gcry_cipher_checktag" = xyes -a "x$ac_cv_lib_gpg_error_gpg_strerror_r" = xyes; then : - ADDITIONAL_LIBS="${ADDITIONAL_LIBS} -lgcrypt -lgpg-error" - else - GCRYPT_ENABLED=0 - fi + AC_CHECK_LIB(gpg-error, gpg_strerror_r, [], AC_MSG_ERROR([libgpg-error required (because of --with-local-libgcrypt) but not found or too old.])) + AC_CHECK_LIB(gcrypt, gcry_cipher_checktag, [], AC_MSG_ERROR([libgcrypt required (because of --with-local-libgcrypt) but not found or too old.])) + ADDITIONAL_LIBS="${ADDITIONAL_LIBS} -lgcrypt -lgpg-error" fi -]) + AC_DEFINE_UNQUOTED(USE_HOST_LIBGCRYPT, 1, [Use locally installed libgcrypt instead of builtin gcrypt-light]) ]) dnl> PCRE @@ -314,6 +307,6 @@ AC_SUBST(BUILD_MINGW_X64) AC_SUBST(BUILD_FUZZTARGETS) AC_SUBST(JSONC_CFLAGS) AC_SUBST(JSONC_LIBS) -AC_SUBST(GCRYPT_ENABLED) +AC_SUBST(USE_HOST_LIBGCRYPT) AC_SUBST(PCRE_ENABLED) AC_OUTPUT diff --git a/packages/openwrt/Makefile b/packages/openwrt/Makefile index e24b5d5ede0..4b9c779636f 100644 --- a/packages/openwrt/Makefile +++ b/packages/openwrt/Makefile @@ -28,8 +28,8 @@ PKG_BUILD_PARALLEL:=1 include $(INCLUDE_DIR)/uclibc++.mk include $(INCLUDE_DIR)/package.mk -ifeq ($(CONFIG_LIBNDPI_GCRYPT),) -CONFIGURE_ARGS += --disable-gcrypt +ifneq ($(CONFIG_LIBNDPI_GCRYPT),) +CONFIGURE_ARGS += --with-local-libgcrypt endif define Package/libndpi @@ -47,11 +47,12 @@ endef define Package/libndpi/config config LIBNDPI_GCRYPT - bool "GCrypt support" + bool "Use external libgcrypt" depends on PACKAGE_libndpi default n help - This option enables QUIC client hello decryption. + This option enables QUIC client hello decryption through + an external libgcrypt instead of a lightweight builtin version. Disabled by default. endef diff --git a/packages/openwrt/Makefile.dev b/packages/openwrt/Makefile.dev index 5f11eceea84..d174475ebbc 100644 --- a/packages/openwrt/Makefile.dev +++ b/packages/openwrt/Makefile.dev @@ -27,8 +27,8 @@ PKG_BUILD_PARALLEL:=1 include $(INCLUDE_DIR)/uclibc++.mk include $(INCLUDE_DIR)/package.mk -ifeq ($(CONFIG_LIBNDPI_GCRYPT),) -CONFIGURE_ARGS += --disable-gcrypt +ifneq ($(CONFIG_LIBNDPI_GCRYPT),) +CONFIGURE_ARGS += --with-local-libgcrypt endif define Package/libndpi @@ -46,11 +46,12 @@ endef define Package/libndpi/config config LIBNDPI_GCRYPT - bool "GCrypt support" + bool "Use external libgcrypt" depends on PACKAGE_libndpi default n help - This option enables QUIC client hello decryption. + This option enables QUIC client hello decryption through + an external libgcrypt instead of a lightweight builtin version. Disabled by default. endef diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in index e3a3f9a9aa6..67ed0c758a9 100644 --- a/src/lib/Makefile.in +++ b/src/lib/Makefile.in @@ -25,6 +25,12 @@ NDPI_LIB_STATIC = libndpi.a NDPI_LIB_SHARED_BASE = libndpi.so NDPI_LIB_SHARED = $(NDPI_LIB_SHARED_BASE).@NDPI_VERSION_SHORT@ NDPI_LIBS = $(NDPI_LIB_STATIC) $(NDPI_LIB_SHARED) +USE_HOST_LIBGCRYPT = @USE_HOST_LIBGCRYPT@ + +ifneq ($(USE_HOST_LIBGCRYPT),0) +TMP_OBJS := $(OBJECTS) +OBJECTS = $(filter-out third_party/src/gcrypt_light.o,$(TMP_OBJS)) +endif ifneq ($(OS),Windows_NT) OS := $(shell uname) diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index f85ff831df6..c9ca62ea3d4 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -32,11 +32,10 @@ #include "ahocorasick.h" #include "libcache.h" -#ifdef HAVE_LIBGCRYPT +#ifdef USE_HOST_LIBGCRYPT #include #else #include -#define HAVE_LIBGCRYPT 1 #endif #include @@ -2420,7 +2419,6 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs if(prefs & ndpi_enable_ja3_plus) ndpi_str->enable_ja3_plus = 1; -#ifdef HAVE_LIBGCRYPT if(!(prefs & ndpi_dont_init_libgcrypt)) { if(!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { const char *gcrypt_ver = gcry_check_version(NULL); @@ -2436,7 +2434,6 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs } else { NDPI_LOG_DBG(ndpi_str, "Libgcrypt initialization skipped\n"); } -#endif if((ndpi_str->protocols_ptree = ndpi_patricia_new(32 /* IPv4 */)) != NULL) { ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, host_protocol_list); @@ -7554,10 +7551,7 @@ u_int16_t ndpi_get_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) { diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c index a25fa75df61..39fc968f58e 100644 --- a/src/lib/protocols/quic.c +++ b/src/lib/protocols/quic.c @@ -26,10 +26,9 @@ #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_QUIC #include "ndpi_api.h" -#ifdef HAVE_LIBGCRYPT +#ifdef USE_HOST_LIBGCRYPT #include #else -#define HAVE_LIBGCRYPT 1 #include #endif @@ -124,13 +123,13 @@ static uint8_t get_u8_quic_ver(uint32_t version) return 0; } -#ifdef HAVE_LIBGCRYPT + static int is_quic_ver_less_than(uint32_t version, uint8_t max_version) { uint8_t u8_ver = get_u8_quic_ver(version); return u8_ver && u8_ver <= max_version; } -#endif + static int is_quic_ver_greater_than(uint32_t version, uint8_t min_version) { return get_u8_quic_ver(version) >= min_version; @@ -191,7 +190,6 @@ int is_version_with_ietf_long_header(uint32_t version) ((version & 0xFFFFFF00) == 0x51303500) /* Q05X */ || ((version & 0xFFFFFF00) == 0x54303500) /* T05X */; } -#ifdef HAVE_LIBGCRYPT int is_version_with_v1_labels(uint32_t version) { if(((version & 0xFFFFFF00) == 0x51303500) /* Q05X */ || @@ -199,7 +197,6 @@ int is_version_with_v1_labels(uint32_t version) return 1; return is_quic_ver_less_than(version, 33); } -#endif int quic_len(const uint8_t *buf, uint64_t *value) { @@ -246,12 +243,10 @@ static uint16_t gquic_get_u16(const uint8_t *buf, uint32_t version) } -#if defined(HAVE_LIBGCRYPT) - #ifdef DEBUG_CRYPT char *__gcry_err(gpg_error_t err, char *buf, size_t buflen) { -#if defined(HAVE_LIBGPG_ERROR) || defined(LIBGCRYPT_INTERNAL) +#if defined(HAVE_LIBGPG_ERROR) || !defined(USE_HOST_LIBGCRYPT) gpg_strerror_r(err, buf, buflen); /* I am not sure if the string will be always null-terminated... Better safe than sorry */ @@ -555,7 +550,7 @@ static int quic_hp_cipher_init(quic_hp_cipher *hp_cipher, int hash_algo, { uint8_t hp_key[256/8]; /* Maximum key size is for AES256 cipher. */ uint32_t hash_len = gcry_md_get_algo_dlen(hash_algo); - char *label = is_version_with_v1_labels(version) ? "quic hp" : "quicv2 hp"; + char const * const label = is_version_with_v1_labels(version) ? "quic hp" : "quicv2 hp"; if(!quic_hkdf_expand_label(hash_algo, secret, hash_len, label, hp_key, key_length)) { return 0; @@ -569,8 +564,8 @@ static int quic_pp_cipher_init(quic_pp_cipher *pp_cipher, int hash_algo, { uint8_t write_key[256/8]; /* Maximum key size is for AES256 cipher. */ uint32_t hash_len = gcry_md_get_algo_dlen(hash_algo); - char *key_label = is_version_with_v1_labels(version) ? "quic key" : "quicv2 key"; - char *iv_label = is_version_with_v1_labels(version) ? "quic iv" : "quicv2 iv"; + char const * const key_label = is_version_with_v1_labels(version) ? "quic key" : "quicv2 key"; + char const * const iv_label = is_version_with_v1_labels(version) ? "quic iv" : "quicv2 iv"; if(key_length > sizeof(write_key)) { return 0; @@ -955,7 +950,6 @@ static int quic_derive_initial_secrets(uint32_t version, static uint8_t *decrypt_initial_packet(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, const uint8_t *dest_conn_id, uint8_t dest_conn_id_len, uint8_t source_conn_id_len, uint32_t version, uint32_t *clear_payload_len) @@ -1036,8 +1030,6 @@ static uint8_t *decrypt_initial_packet(struct ndpi_detection_module_struct *ndpi return NULL; } -#endif /* HAVE_LIBGCRYPT */ - static int __reassemble(struct ndpi_flow_struct *flow, const u_int8_t *frag, uint64_t frag_len, uint64_t frag_offset, @@ -1053,7 +1045,7 @@ static int __reassemble(struct ndpi_flow_struct *flow, const u_int8_t *frag, */ if(!flow->l4.udp.quic_reasm_buf) { - flow->l4.udp.quic_reasm_buf = ndpi_malloc(max_quic_reasm_buffer_len); + flow->l4.udp.quic_reasm_buf = (uint8_t *)ndpi_malloc(max_quic_reasm_buffer_len); if(!flow->l4.udp.quic_reasm_buf) return -1; /* Memory error */ flow->l4.udp.quic_reasm_buf_len = 0; @@ -1090,7 +1082,7 @@ static int is_ch_reassembler_pending(struct ndpi_flow_struct *flow) flow->l4.udp.quic_reasm_buf_len); } static const uint8_t *get_reassembled_crypto_data(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, + struct ndpi_flow_struct *flow, const u_int8_t *frag, uint64_t frag_offset, uint64_t frag_len, uint64_t *crypto_data_len) @@ -1265,15 +1257,12 @@ static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_ } static uint8_t *get_clear_payload(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, uint32_t version, uint32_t *clear_payload_len) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int8_t *clear_payload; u_int8_t dest_conn_id_len; -#ifdef HAVE_LIBGCRYPT u_int8_t source_conn_id_len; -#endif if(is_gquic_ver_less_than(version, 43)) { clear_payload = (uint8_t *)&packet->payload[26]; @@ -1300,16 +1289,13 @@ static uint8_t *get_clear_payload(struct ndpi_detection_module_struct *ndpi_stru version, dest_conn_id_len); return NULL; } -#ifdef HAVE_LIBGCRYPT + source_conn_id_len = packet->payload[6 + dest_conn_id_len]; const u_int8_t *dest_conn_id = &packet->payload[6]; - clear_payload = decrypt_initial_packet(ndpi_struct, flow, + clear_payload = decrypt_initial_packet(ndpi_struct, dest_conn_id, dest_conn_id_len, source_conn_id_len, version, clear_payload_len); -#else - clear_payload = NULL; -#endif } return clear_payload; @@ -1435,7 +1421,6 @@ static void process_chlo(struct ndpi_detection_module_struct *ndpi_struct, static int may_be_initial_pkt(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, uint32_t *version) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; @@ -1529,7 +1514,7 @@ static int may_be_initial_pkt(struct ndpi_detection_module_struct *ndpi_struct, /* ***************************************************************** */ static int eval_extra_processing(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, u_int32_t version) + struct ndpi_flow_struct *flow, u_int32_t version) { /* For the time being we need extra processing in two cases only: 1) to detect Snapchat calls, i.e. RTP/RTCP multiplxed with QUIC. @@ -1631,7 +1616,7 @@ static void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct, * anyone complains... */ - is_quic = may_be_initial_pkt(ndpi_struct, flow, &version); + is_quic = may_be_initial_pkt(ndpi_struct, &version); if(!is_quic) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; @@ -1659,7 +1644,7 @@ static void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct, /* * 4) Extract the Payload from Initial Packets */ - clear_payload = get_clear_payload(ndpi_struct, flow, version, &clear_payload_len); + clear_payload = get_clear_payload(ndpi_struct, version, &clear_payload_len); if(!clear_payload) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; diff --git a/src/lib/third_party/include/gcrypt_light.h b/src/lib/third_party/include/gcrypt_light.h index de77c8e3822..5edacd6c6f2 100644 --- a/src/lib/third_party/include/gcrypt_light.h +++ b/src/lib/third_party/include/gcrypt_light.h @@ -2,8 +2,6 @@ #ifndef GCRY_LIGHT_H #define GCRY_LIGHT_H -#define LIBGCRYPT_INTERNAL - #define HMAC_SHA256_DIGEST_SIZE 32 /* Same as SHA-256's output size. */ #define SHA256_DIGEST_SIZE 32 #define GCRY_MD_BUFF_SIZE 256 diff --git a/src/lib/third_party/src/gcrypt_light.c b/src/lib/third_party/src/gcrypt_light.c index ecd4b6fc4bc..c048e870409 100644 --- a/src/lib/third_party/src/gcrypt_light.c +++ b/src/lib/third_party/src/gcrypt_light.c @@ -8,8 +8,6 @@ #include "ndpi_api.h" -#if !defined(HAVE_LIBGCRYPT) - #if defined(__GNUC__) && \ ( defined(__amd64__) || defined(__x86_64__) ) && \ ! defined(MBEDTLS_HAVE_X86_64) @@ -372,6 +370,4 @@ gcry_error_t gcry_cipher_decrypt (gcry_cipher_hd_t h, return _gcry_cipher_crypt(h,out,outsize,in,inlen,0); } -#endif /* HAVE_LIBGCRYPT */ - /* vim: set ts=4 sw=4 et: */ diff --git a/tests/do.sh.in b/tests/do.sh.in index 3e91510e1bf..9bcedaeed67 100755 --- a/tests/do.sh.in +++ b/tests/do.sh.in @@ -13,7 +13,6 @@ if [ "$NDPI_TESTS_VALGRIND" = "1" ]; then VALGRIND="valgrind -q --leak-check=full" fi -GCRYPT_ENABLED=1 PCRE_ENABLED=@PCRE_ENABLED@ PCRE_PCAPS="WebattackRCE.pcap" GCRYPT_PCAPS="gquic.pcap quic-23.pcap quic-24.pcap quic-27.pcap quic-28.pcap quic-29.pcap quic-mvfst-22.pcap quic-mvfst-27.pcapng quic-mvfst-exp.pcap quic_q50.pcap quic_t50.pcap quic_t51.pcap quic_0RTT.pcap quic_interop_V.pcapng quic-33.pcapng doq.pcapng doq_adguard.pcapng dlt_ppp.pcap os_detected.pcapng quic_frags_ch_out_of_order_same_packet_craziness.pcapng quic_frags_ch_in_multiple_packets.pcapng quic-v2-00.pcapng" @@ -53,14 +52,6 @@ check_results() { [ $SKIP_PCAP = 1 ] && continue fi SKIP_PCAP=0 - if [ $GCRYPT_ENABLED -eq 0 ]; then - for g in $GCRYPT_PCAPS; do - if [ $f = $g ]; then - SKIP_PCAP=1 - break - fi - done - fi if [ $PCRE_ENABLED -eq 0 ]; then for p in $PCRE_PCAPS; do if [ $f = $p ]; then