diff options
-rw-r--r-- | CMakeLists.txt | 18 | ||||
-rw-r--r-- | CMakeOptions.txt | 2 | ||||
-rw-r--r-- | acinclude.m4 | 160 | ||||
-rw-r--r-- | cmake/modules/FindLZ4.cmake | 39 | ||||
-rw-r--r-- | cmake/modules/FindSNAPPY.cmake | 38 | ||||
-rw-r--r-- | cmakeconfig.h.in | 6 | ||||
-rw-r--r-- | configure.ac | 88 | ||||
-rw-r--r-- | epan/CMakeLists.txt | 14 | ||||
-rw-r--r-- | epan/Makefile.am | 10 | ||||
-rw-r--r-- | epan/dissectors/packet-cql.c | 148 | ||||
-rw-r--r-- | epan/epan.c | 17 |
11 files changed, 512 insertions, 28 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ebfe8a1342..68af9a53bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -830,6 +830,16 @@ if(ENABLE_ZLIB) set(PACKAGELIST ${PACKAGELIST} ZLIB) endif() +# LZ4 compression +if(ENABLE_LZ4) + set(PACKAGELIST ${PACKAGELIST} LZ4) +endif() + +# Snappy compression +if(ENABLE_SNAPPY) + set(PACKAGELIST ${PACKAGELIST} SNAPPY) +endif() + # Embedded Lua interpreter if(ENABLE_LUA) set(PACKAGELIST ${PACKAGELIST} LUA) @@ -975,6 +985,12 @@ if(HAVE_LIBZLIB) # bug in the Windows setup of GTK[23] which has a faulty zconf.h. include_directories(BEFORE ${ZLIB_INCLUDE_DIRS}) endif() +if(HAVE_LIBLZ4) + set(HAVE_LZ4 1) +endif() +if(SNAPPY_FOUND) + set(HAVE_SNAPPY 1) +endif() if (Qt5Widgets_FOUND) # # Qt5CoreConfigExtras.cmake in Qt 5.5.0 sets -fPIC unconditionally: @@ -1452,6 +1468,8 @@ set(LIBEPAN_LIBS ${GNUTLS_LIBRARIES} ${SMI_LIBRARIES} ${ZLIB_LIBRARIES} + ${LZ4_LIBRARIES} + ${SNAPPY_LIBRARIES} ${M_LIBRARIES} ${WINSPARKLE_LIBRARIES} ) diff --git a/CMakeOptions.txt b/CMakeOptions.txt index fa0d354e7d..00351ed49c 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -61,6 +61,8 @@ option(ENABLE_PCAP_NG_DEFAULT "Enable pcap-ng as default file format" ON) option(ENABLE_PORTAUDIO "Build with PortAudio support" ON) option(ENABLE_ZLIB "Build with zlib compression support" ON) +option(ENABLE_LZ4 "Build with LZ4 compression support" ON) +option(ENABLE_SNAPPY "Build with Snappy compression support" ON) option(ENABLE_LUA "Build with Lua dissector support" ON) option(ENABLE_SMI "Build with libsmi snmp support" ON) option(ENABLE_GNUTLS "Build with GNU TLS support" ON) diff --git a/acinclude.m4 b/acinclude.m4 index 8d5efd37de..38cc9f2713 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1920,3 +1920,163 @@ AC_DEFUN([AC_WIRESHARK_QT_TOOL_CHECK_LRELEASE], ]) AC_MSG_RESULT([ok, $lrelease_version]) ]) + +# +# AC_WIRESHARK_LZ4_CHECK +# +AC_DEFUN([AC_WIRESHARK_LZ4_CHECK], +[ + AC_WIRESHARK_PUSH_FLAGS + + if test "x$lz4_dir" != "x" + then + # + # The user specified a directory in which lz4 resides, + # so add the "include" subdirectory of that directory to + # the include file search path and the "lib" subdirectory + # of that directory to the library search path. + # + # XXX - if there's also a lz4 in a directory that's + # already in CPPFLAGS or LDFLAGS, this won't make us find + # the version in the specified directory, as the compiler + # and/or linker will search that other directory before it + # searches the specified directory. + # + LZ4_CFLAGS="-I$lz4_dir/include" + fi + + # + # Make sure we have "lz4.h". If we don't, it means we probably + # don't have lz4, so don't use it. + # + AC_CHECK_HEADER(lz4.h,, + [ + if test "x$lz4_dir" != "x" + then + # + # The user used "--with-lz4=" to specify a directory + # containing lz4, but we didn't find the header file + # there; that either means they didn't specify the + # right directory or are confused about whether lz4 + # is, in fact, installed. Report the error and give up. + # + AC_MSG_ERROR([lz4 header not found in directory specified in --with-lz4]) + else + if test "x$want_lz4" = "xyes" + then + # + # The user tried to force us to use the library, but we + # couldn't find the header file; report an error. + # + AC_MSG_ERROR(Header file lz4.h not found.) + else + # + # We couldn't find the header file; don't use the + # library, as it's probably not present. + # + want_lz4=no + fi + fi + ]) + + if test "x$want_lz4" != "xno" + then + # + # Well, we at least have the lz4 header file. + # We link with lz4 to support uncompression of + # CQL traffic. + # + LZ4_LIBS="-llz4" + ac_save_LIBS="$LIBS" + LIBS="$LZ4_LIBS $LIBS" + AC_DEFINE(HAVE_LZ4, 1, [Define to use lz4 library]) + # + # Check for "LZ4_decompress_safe()" in lz4, which we need + # in order to read compressed capture files. + # + AC_CHECK_FUNCS(LZ4_decompress_safe) + LIBS="$ac_save_LIBS" + fi + + AC_WIRESHARK_POP_FLAGS +]) + +# +# AC_WIRESHARK_SNAPPY_CHECK +# +AC_DEFUN([AC_WIRESHARK_SNAPPY_CHECK], +[ + AC_WIRESHARK_PUSH_FLAGS + + if test "x$snappy_dir" != "x" + then + # + # The user specified a directory in which snappy resides, + # so add the "include" subdirectory of that directory to + # the include file search path and the "lib" subdirectory + # of that directory to the library search path. + # + # XXX - if there's also a snappy in a directory that's + # already in CPPFLAGS or LDFLAGS, this won't make us find + # the version in the specified directory, as the compiler + # and/or linker will search that other directory before it + # searches the specified directory. + # + SNAPPY_CFLAGS="-I$snappy_dir/include" + fi + + # + # Make sure we have "snappy-c.h". If we don't, it means we probably + # don't have snappy, so don't use it. + # + AC_CHECK_HEADER(snappy-c.h,, + [ + if test "x$snappy_dir" != "x" + then + # + # The user used "--with-snappy=" to specify a directory + # containing snappy, but we didn't find the header file + # there; that either means they didn't specify the + # right directory or are confused about whether snappy + # is, in fact, installed. Report the error and give up. + # + AC_MSG_ERROR([snappy-c.header not found in directory specified in --with-snappy]) + else + if test "x$want_snappy" = "xyes" + then + # + # The user tried to force us to use the library, but we + # couldn't find the header file; report an error. + # + AC_MSG_ERROR(Header file snappy-c.h not found.) + else + # + # We couldn't find the header file; don't use the + # library, as it's probably not present. + # + want_snappy=no + fi + fi + ]) + + if test "x$want_snappy" != "xno" + then + # + # Well, we at least have the snappy-c.header file. + # We link with snappy to support uncompression of + # compressed CQL traffic. + # + SNAPPY_LIBS=-lsnappy + ac_save_LIBS="$LIBS" + LIBS="$SNAPPY_LIBS $LIBS" + AC_DEFINE(HAVE_SNAPPY, 1, [Define to use snappy library]) + # + # Check for "snappy_uncompress()" in snappy, which we need + # in order to read compressed capture files. + # + AC_CHECK_FUNCS(snappy_uncompress) + LIBS="$ac_save_LIBS" + fi + + AC_WIRESHARK_POP_FLAGS +]) diff --git a/cmake/modules/FindLZ4.cmake b/cmake/modules/FindLZ4.cmake new file mode 100644 index 0000000000..5445c573ca --- /dev/null +++ b/cmake/modules/FindLZ4.cmake @@ -0,0 +1,39 @@ +# +# - Find lz4 +# Find LZ4 includes and library +# +# LZ4_INCLUDE_DIRS - where to find lz4.h, etc. +# LZ4_LIBRARIES - List of libraries when using lz4. +# LZ4_FOUND - True if lz4 found. + +find_package(PkgConfig) +pkg_search_module(LZ4 lz4 liblz4) + +find_path(LZ4_INCLUDE_DIR + NAMES lz4.h + HINTS "${LZ4_INCLUDEDIR}" + PATHS + /usr/local/include + /usr/include +) + +find_library(LZ4_LIBRARY + NAMES lz4 liblz4 + HINTS "${LZ4_LIBDIR}" + PATHS + /usr/local/lib + /usr/lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( LZ4 DEFAULT_MSG LZ4_INCLUDE_DIR LZ4_LIBRARY ) + +if( LZ4_FOUND ) + set( LZ4_INCLUDE_DIRS ${LZ4_INCLUDE_DIR} ) + set( LZ4_LIBRARIES ${LZ4_LIBRARY} ) +else() + set( LZ4_INCLUDE_DIRS ) + set( LZ4_LIBRARIES ) +endif() + +mark_as_advanced( LZ4_LIBRARIES LZ4_INCLUDE_DIRS ) diff --git a/cmake/modules/FindSNAPPY.cmake b/cmake/modules/FindSNAPPY.cmake new file mode 100644 index 0000000000..cc018bbcba --- /dev/null +++ b/cmake/modules/FindSNAPPY.cmake @@ -0,0 +1,38 @@ +# +# - Find snappy +# Find Snappy includes and library +# +# SNAPPY_INCLUDE_DIRS - where to find snappy.h, etc. +# SNAPPY_LIBRARIES - List of libraries when using snappy. +# SNAPPY_FOUND - True if snappy found. + +find_package(PkgConfig) +pkg_search_module(SNAPPY libsnappy) + +find_path(SNAPPY_INCLUDE_DIR + NAMES snappy.h + HINTS "${SNAPPY_INCLUDEDIR}" + /usr/include + /usr/local/include +) + +find_library(SNAPPY_LIBRARY + NAMES snappy + HINTS "${SNAPPY_LIBDIR}" + PATHS + /usr/lib + /usr/local/lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( SNAPPY DEFAULT_MSG SNAPPY_INCLUDE_DIR SNAPPY_LIBRARY ) + +if( SNAPPY_FOUND ) + set( SNAPPY_INCLUDE_DIRS ${SNAPPY_INCLUDE_DIR} ) + set( SNAPPY_LIBRARIES ${SNAPPY_LIBRARY} ) +else() + set( SNAPPY_INCLUDE_DIRS ) + set( SNAPPY_LIBRARIES ) +endif() + +mark_as_advanced( SNAPPY_LIBRARIES SNAPPY_INCLUDE_DIRS ) diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in index 4856a22e54..71ea10cbd0 100644 --- a/cmakeconfig.h.in +++ b/cmakeconfig.h.in @@ -160,6 +160,12 @@ /* Define to use zlib library */ #cmakedefine HAVE_ZLIB 1 +/* Define to use lz4 library */ +#cmakedefine HAVE_LZ4 1 + +/* Define to use snappy library */ +#cmakedefine HAVE_SNAPPY 1 + /* Define to 1 if you have the <linux/sockios.h> header file. */ #cmakedefine HAVE_LINUX_SOCKIOS_H 1 diff --git a/configure.ac b/configure.ac index 2fbf021c98..378477a1de 100644 --- a/configure.ac +++ b/configure.ac @@ -1995,6 +1995,92 @@ else fi fi +dnl lz4 check +LZ4_LIBS='' +AC_MSG_CHECKING(whether to use lz4 compression and decompression) + +AC_ARG_WITH(lz4, + AC_HELP_STRING([--with-lz4@<:@=DIR@:>@], + [use lz4 (located in directory DIR, if supplied) for lz4 compression and decompression @<:@default=yes, if available@:>@]), +[ + if test "x$withval" = "xno" + then + want_lz4=no + elif test "x$withval" = "xyes" + then + want_lz4=yes + else + want_lz4=yes + lz4_dir="$withval" + fi +],[ + # + # Use lz4 if it's present, otherwise don't. + # + want_lz4=ifavailable + lz4_dir= +]) +have_lz4=no +if test "x$want_lz4" = "xno" ; then + AC_MSG_RESULT(no) +else + AC_MSG_RESULT(yes) + AC_WIRESHARK_LZ4_CHECK + if test "x$want_lz4" = "xno" ; then + AC_MSG_RESULT(lz4 not found - disabling lz4 compression and decompression) + else + if test "x$ac_cv_func_LZ4_decompress_safe" = "xno" ; then + AC_MSG_RESULT(LZ4_decompress_safe not found in lz4 - disabling cql lz4 decompression) + else + have_lz4=yes + fi + fi +fi +AC_SUBST(LZ4_LIBS) + +dnl snappy check +SNAPPY_LIBS='' +AC_MSG_CHECKING(whether to use snappy compression and decompression) + +AC_ARG_WITH(snappy, + AC_HELP_STRING([--with-snappy@<:@=DIR@:>@], + [use snappy (located in directory DIR, if supplied) for snappy compression and decompression @<:@default=yes, if available@:>@]), +[ + if test "x$withval" = "xno" + then + want_snappy=no + elif test "x$withval" = "xyes" + then + want_snappy=yes + else + want_snappy=yes + snappy_dir="$withval" + fi +],[ + # + # Use snappy if it's present, otherwise don't. + # + want_snappy=ifavailable + snappy_dir= +]) +have_snappy=no +if test "x$want_snappy" = "xno" ; then + AC_MSG_RESULT(no) +else + AC_MSG_RESULT(yes) + AC_WIRESHARK_SNAPPY_CHECK + if test "x$want_snappy" = "xno" ; then + AC_MSG_RESULT(snappy not found - disabling snappy compression and decompression) + else + if test "x$ac_cv_func_snappy_uncompress" = "xno" ; then + AC_MSG_RESULT(snappy_uncompress not found in snappy - disabling cql snappy decompression) + else + have_snappy=yes + fi + fi +fi +AC_SUBST(SNAPPY_LIBS) + dnl Lua check AC_ARG_WITH(lua, AC_HELP_STRING( [--with-lua@<:@=DIR@:>@], @@ -3083,4 +3169,6 @@ echo " Have ssh_userauth_agent : $ssh_userauth_agent_message" echo " Use nl library : $libnl_message" echo " Use SBC codec library : $have_sbc" echo " Use nghttp2 library : $nghttp2_message" +echo " Use LZ4 library : $have_lz4" +echo " Use Snappy library : $have_snappy" #echo " Use GDK-Pixbuf with GResource: $have_gresource_pixbuf" diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 4e48ff56b3..3bb415589c 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -189,17 +189,19 @@ add_lemon_files(LEMON_FILES GENERATED_FILES set(epan_LIBS wiretap wsutil - ${GLIB2_LIBRARIES} - ${PCAP_LIBRARIES} ${CARES_LIBRARIES} - ${KERBEROS_LIBRARIES} - ${GEOIP_LIBRARIES} ${GCRYPT_LIBRARIES} + ${GEOIP_LIBRARIES} + ${GLIB2_LIBRARIES} ${GNUTLS_LIBRARIES} - ${SMI_LIBRARIES} + ${KERBEROS_LIBRARIES} + ${LUA_LIBRARIES} + ${LZ4_LIBRARIES} ${M_LIBRARIES} ${NGHTTP2_LIBRARIES} - ${LUA_LIBRARIES} + ${PCAP_LIBRARIES} + ${SMI_LIBRARIES} + ${SNAPPY_LIBRARIES} ${WIN_PSAPI_LIBRARY} ) diff --git a/epan/Makefile.am b/epan/Makefile.am index e9eee8e0ba..5c53b84e94 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -40,7 +40,7 @@ DIST_SUBDIRS = $(SUBDIRS) $(wslua_dist_dir) AM_CPPFLAGS = $(INCLUDEDIRS) -I$(builddir)/wslua $(WS_CPPFLAGS) \ $(GLIB_CFLAGS) $(LUA_CFLAGS) $(LIBGNUTLS_CFLAGS) \ $(LIBGCRYPT_CFLAGS) $(LIBSMI_CFLAGS) $(LIBGEOIP_CFLAGS) \ - $(KRB5_CFLAGS) + $(LZ4_CFLAGS) $(KRB5_CFLAGS) $(SNAPPY_CFLAGS) noinst_LTLIBRARIES = libwireshark_generated.la libwireshark_asmopt.la lib_LTLIBRARIES = libwireshark.la @@ -323,13 +323,15 @@ libwireshark_la_LIBADD = \ ${top_builddir}/wiretap/libwiretap.la \ ${top_builddir}/wsutil/libwsutil.la \ @C_ARES_LIBS@ \ + @GEOIP_LIBS@ \ + @KRB5_LIBS@ \ @LIBGCRYPT_LIBS@ \ @LIBGNUTLS_LIBS@ \ - @KRB5_LIBS@ \ - @SSL_LIBS@ \ @LIBSMI_LDFLAGS@ \ - @GEOIP_LIBS@ \ + @LZ4_LIBS@ \ @NGHTTP2_LIBS@ \ + @SSL_LIBS@ \ + @SNAPPY_LIBS@ \ @GLIB_LIBS@ libwireshark_la_DEPENDENCIES = \ diff --git a/epan/dissectors/packet-cql.c b/epan/dissectors/packet-cql.c index e9577ed5a7..c524c3b684 100644 --- a/epan/dissectors/packet-cql.c +++ b/epan/dissectors/packet-cql.c @@ -31,10 +31,17 @@ #include <epan/dissectors/packet-tcp.h> #include <epan/wmem/wmem.h> #include <epan/expert.h> - +#ifdef HAVE_LZ4 +#include <lz4.h> +#endif +#ifdef HAVE_SNAPPY +#include <snappy-c.h> +#endif #define CQL_DEFAULT_PORT 9042 /* Not IANA registered */ +/* the code can reasonably attempt to decompress buffer up to 10MB */ +#define MAX_UNCOMPRESSED_SIZE (10 * 1024 * 1024) void proto_reg_handoff_cql(void); void proto_register_cql(void); @@ -71,6 +78,7 @@ static int hf_cql_value_count = -1; static int hf_cql_short_bytes_length = -1; static int hf_cql_bytes_length = -1; static int hf_cql_bytes = -1; +static int hf_cql_raw_compressed_bytes = -1; static int hf_cql_paging_state = -1; static int hf_cql_page_size = -1; static int hf_cql_timestamp = -1; @@ -515,10 +523,18 @@ cql_transaction_lookup(cql_conversation_type* conv, return NULL; } +typedef enum { + CQL_COMPRESSION_NONE = 0, + CQL_COMPRESSION_LZ4 = 1, + CQL_COMPRESSION_SNAPPY = 2, + CQL_DECOMPRESSION_ATTEMPTED = 3, +} cql_compression_level; + static int -dissect_cql_tcp_pdu(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_) +dissect_cql_tcp_pdu(tvbuff_t* raw_tvb, packet_info* pinfo, proto_tree* tree, void* data _U_) { proto_item* ti; + tvbuff_t* tvb = NULL; proto_tree* cql_tree; proto_tree* version_tree; proto_tree* cql_subtree = NULL; @@ -526,6 +542,7 @@ dissect_cql_tcp_pdu(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* d proto_tree* metadata_subtree = NULL; gint offset = 0; + guint8 flags = 0; guint8 first_byte = 0; guint8 cql_version = 0; guint8 server_to_client = 0; @@ -548,6 +565,7 @@ dissect_cql_tcp_pdu(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* d conversation_t* conversation; cql_conversation_type* cql_conv; cql_transaction_type* cql_trans = NULL; + cql_compression_level compression_level = CQL_COMPRESSION_NONE; static const int * cql_header_bitmaps_v3[] = { &hf_cql_flag_compression, @@ -568,10 +586,10 @@ dissect_cql_tcp_pdu(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* d col_set_str(pinfo->cinfo, COL_PROTOCOL, "CQL"); col_clear(pinfo->cinfo, COL_INFO); - first_byte = tvb_get_guint8(tvb, 0); + first_byte = tvb_get_guint8(raw_tvb, 0); cql_version = first_byte & (guint8)0x7F; server_to_client = first_byte & (guint8)0x80; - opcode = tvb_get_guint8(tvb, 4); + opcode = tvb_get_guint8(raw_tvb, 4); col_add_fstr(pinfo->cinfo, COL_INFO, "v%d %s Type %s", cql_version, @@ -587,34 +605,34 @@ dissect_cql_tcp_pdu(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* d conversation_add_proto_data(conversation, proto_cql, cql_conv); } - ti = proto_tree_add_item(tree, proto_cql, tvb, 0, -1, ENC_NA); + ti = proto_tree_add_item(tree, proto_cql, raw_tvb, 0, -1, ENC_NA); cql_tree = proto_item_add_subtree(ti, ett_cql_protocol); - ti = proto_tree_add_item(cql_tree, hf_cql_version, tvb, offset, 1, ENC_BIG_ENDIAN); + ti = proto_tree_add_item(cql_tree, hf_cql_version, raw_tvb, offset, 1, ENC_BIG_ENDIAN); version_tree = proto_item_add_subtree(ti, ett_cql_version); - proto_tree_add_item(version_tree, hf_cql_protocol_version, tvb, offset, 1, ENC_BIG_ENDIAN); - proto_tree_add_item(version_tree, hf_cql_direction, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(version_tree, hf_cql_protocol_version, raw_tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(version_tree, hf_cql_direction, raw_tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; switch(cql_version){ case 3: - proto_tree_add_bitmask(cql_tree, tvb, offset, hf_cql_flags_bitmap, ett_cql_header_flags_bitmap, cql_header_bitmaps_v3, ENC_BIG_ENDIAN); + proto_tree_add_bitmask(cql_tree, raw_tvb, offset, hf_cql_flags_bitmap, ett_cql_header_flags_bitmap, cql_header_bitmaps_v3, ENC_BIG_ENDIAN); break; case 4: - proto_tree_add_bitmask(cql_tree, tvb, offset, hf_cql_flags_bitmap, ett_cql_header_flags_bitmap, cql_header_bitmaps_v4, ENC_BIG_ENDIAN); + proto_tree_add_bitmask(cql_tree, raw_tvb, offset, hf_cql_flags_bitmap, ett_cql_header_flags_bitmap, cql_header_bitmaps_v4, ENC_BIG_ENDIAN); break; default: - proto_tree_add_item(cql_tree, hf_cql_flags_bitmap, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(cql_tree, hf_cql_flags_bitmap, raw_tvb, offset, 1, ENC_BIG_ENDIAN); break; } + flags = tvb_get_guint8(raw_tvb, offset); offset += 1; - proto_tree_add_item_ret_int(cql_tree, hf_cql_stream, tvb, offset, 2, ENC_BIG_ENDIAN, &stream); + proto_tree_add_item_ret_int(cql_tree, hf_cql_stream, raw_tvb, offset, 2, ENC_BIG_ENDIAN, &stream); offset += 2; - proto_tree_add_item(cql_tree, hf_cql_opcode, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(cql_tree, hf_cql_opcode, raw_tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; - proto_tree_add_item_ret_uint(cql_tree, hf_cql_length, tvb, offset, 4, ENC_BIG_ENDIAN, &message_length); + proto_tree_add_item_ret_uint(cql_tree, hf_cql_length, raw_tvb, offset, 4, ENC_BIG_ENDIAN, &message_length); offset += 4; - /* Track the request/response. */ if (!pinfo->fd->flags.visited) { if (server_to_client == 0) { @@ -637,20 +655,104 @@ dissect_cql_tcp_pdu(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* d /* Add state tracking to tree */ if (server_to_client == 0 && cql_trans->rep_frame) { /* request */ - ti = proto_tree_add_uint(cql_tree, hf_cql_response_in, tvb, 0, 0, cql_trans->rep_frame); + ti = proto_tree_add_uint(cql_tree, hf_cql_response_in, raw_tvb, 0, 0, cql_trans->rep_frame); PROTO_ITEM_SET_GENERATED(ti); } if (server_to_client && cql_trans->req_frame) { /* reply */ nstime_t ns; - ti = proto_tree_add_uint(cql_tree, hf_cql_response_to, tvb, 0, 0, cql_trans->req_frame); + ti = proto_tree_add_uint(cql_tree, hf_cql_response_to, raw_tvb, 0, 0, cql_trans->req_frame); PROTO_ITEM_SET_GENERATED(ti); nstime_delta(&ns, &pinfo->fd->abs_ts, &cql_trans->req_time); - ti = proto_tree_add_time(cql_tree, hf_cql_response_time, tvb, 0, 0, &ns); + ti = proto_tree_add_time(cql_tree, hf_cql_response_time, raw_tvb, 0, 0, &ns); PROTO_ITEM_SET_GENERATED(ti); } + /* We cannot rely on compression negociation in the STARTUP message because the + * capture can be done at a random time hence missing the negociation. + * So we will first try to decompress LZ4 then snappy + */ + if (flags & CQL_HEADER_FLAG_COMPRESSION) { + compression_level = CQL_DECOMPRESSION_ATTEMPTED; +#ifdef HAVE_LZ4 + if (tvb_captured_length_remaining(raw_tvb, offset) > 4) { + /* Set ret == 0 to make it fail in case decompression is skipped + * due to orig_size being too big + */ + guint32 ret = 0, orig_size = tvb_get_ntohl(raw_tvb, offset); + guchar *decompressed_buffer = NULL; + offset += 4; + + /* if the decompressed size is reasonably small try to decompress data */ + if (orig_size <= MAX_UNCOMPRESSED_SIZE) { + decompressed_buffer = (guchar*)wmem_alloc(pinfo->pool, orig_size); + ret = LZ4_decompress_safe(tvb_get_ptr(raw_tvb, offset, -1), + decompressed_buffer, + tvb_captured_length_remaining(raw_tvb, offset), + orig_size); + } + /* Decompression attempt failed: rewind offset */ + if (ret != orig_size) { + wmem_free(pinfo->pool, decompressed_buffer); + offset -= 4; + } else { + /* Now re-setup the tvb buffer to have the new data */ + tvb = tvb_new_child_real_data(raw_tvb, decompressed_buffer, orig_size, orig_size); + add_new_data_source(pinfo, tvb, "Decompressed Data"); + /* mark the decompression as successfull */ + compression_level = CQL_COMPRESSION_LZ4; + message_length= orig_size; + } + } +#endif +#ifdef HAVE_SNAPPY + if (compression_level == CQL_DECOMPRESSION_ATTEMPTED) { + guchar *decompressed_buffer = NULL; + size_t orig_size = 0; + snappy_status ret; + + /* get the raw data length */ + ret = snappy_uncompressed_length(tvb_get_ptr(raw_tvb, offset, -1), + tvb_captured_length_remaining(raw_tvb, offset), + &orig_size); + /* if we get the length and it's reasonably short to allocate a buffer for it + * proceed to try decompressing the data + */ + if (ret == SNAPPY_OK && orig_size <= MAX_UNCOMPRESSED_SIZE) { + decompressed_buffer = (guchar*)wmem_alloc(pinfo->pool, orig_size); + + ret = snappy_uncompress(tvb_get_ptr(raw_tvb, offset, -1), + tvb_captured_length_remaining(raw_tvb, offset), + decompressed_buffer, + &orig_size); + } else { + /* else mark the input as invalid in order to skip the rest of the + * procedure + */ + ret = SNAPPY_INVALID_INPUT; + } + /* if the decompression succeeded build the new tvb */ + if (ret == SNAPPY_OK) { + tvb = tvb_new_child_real_data(raw_tvb, decompressed_buffer, orig_size, orig_size); + add_new_data_source(pinfo, tvb, "Decompressed Data"); + compression_level = CQL_COMPRESSION_SNAPPY; + message_length= orig_size; + } + } +#endif + } + if (compression_level == CQL_COMPRESSION_NONE) { + /* In case of decompression failure or uncompressed packet */ + tvb = tvb_new_subset_remaining(raw_tvb, offset); + } else if (compression_level == CQL_DECOMPRESSION_ATTEMPTED) { + proto_tree_add_item(cql_tree, hf_cql_raw_compressed_bytes, raw_tvb, offset, + tvb_captured_length_remaining(raw_tvb, offset), ENC_NA); + return tvb_captured_length(raw_tvb); + } + offset = 0; + + /* Dissect the operation. */ if (server_to_client == 0) { switch (opcode) { @@ -1375,6 +1477,16 @@ proto_register_cql(void) } }, { + &hf_cql_raw_compressed_bytes, + { + "Raw compressed bytes", "cql.raw_compressed_bytes", + FT_BYTES, BASE_NONE, + NULL, 0x0, + "Raw byte that failed to be decompressed", HFILL + } + }, + + { &hf_cql_paging_state, { "Paging State", "cql.paging_state", diff --git a/epan/epan.c b/epan/epan.c index 056a447fbb..82e0d397e6 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -574,6 +574,23 @@ epan_get_compiled_version_info(GString *str) #else g_string_append(str, "without nghttp2"); #endif /* HAVE_NGHTTP2 */ + + /* LZ4 */ + g_string_append(str, ", "); +#ifdef HAVE_LZ4 + g_string_append(str, "with LZ4"); +#else + g_string_append(str, "without LZ4"); +#endif /* HAVE_LZ4 */ + + /* Snappy */ + g_string_append(str, ", "); +#ifdef HAVE_SNAPPY + g_string_append(str, "with Snappy"); +#else + g_string_append(str, "without Snappy"); +#endif /* HAVE_SNAPPY */ + } /* |