diff options
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/Makefile.common | 1 | ||||
-rw-r--r-- | epan/tvbuff.c | 291 | ||||
-rw-r--r-- | epan/tvbuff_zlib.c | 323 |
4 files changed, 325 insertions, 291 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 6d16eb9db9..6dbec41b87 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -1534,6 +1534,7 @@ set(LIBWIRESHARK_FILES tvbuff_composite.c tvbuff_real.c tvbuff_subset.c + tvbuff_zlib.c uat.c value_string.c xdlc.c diff --git a/epan/Makefile.common b/epan/Makefile.common index 0cb1052e19..2accf5deaa 100644 --- a/epan/Makefile.common +++ b/epan/Makefile.common @@ -97,6 +97,7 @@ LIBWIRESHARK_SRC = \ tvbuff_composite.c \ tvbuff_real.c \ tvbuff_subset.c \ + tvbuff_zlib.c \ tvbuff.c \ uat.c \ value_string.c \ diff --git a/epan/tvbuff.c b/epan/tvbuff.c index a1db5f0a2e..26f5276ac0 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -39,10 +39,6 @@ #include <string.h> -#ifdef HAVE_LIBZ -#include <zlib.h> -#endif - #include "wsutil/pint.h" #include "tvbuff.h" #include "tvbuff-int.h" @@ -2671,293 +2667,6 @@ tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, const gint haystack_o return -1; } -#ifdef HAVE_LIBZ -/* - * Uncompresses a zlib compressed packet inside a message of tvb at offset with - * length comprlen. Returns an uncompressed tvbuffer if uncompression - * succeeded or NULL if uncompression failed. - */ -#define TVB_Z_MIN_BUFSIZ 32768 -#define TVB_Z_MAX_BUFSIZ 1048576 * 10 -/* #define TVB_Z_DEBUG 1 */ -#undef TVB_Z_DEBUG - -tvbuff_t * -tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen) -{ - gint err = Z_OK; - guint bytes_out = 0; - guint8 *compr = NULL; - guint8 *uncompr = NULL; - tvbuff_t *uncompr_tvb = NULL; - z_streamp strm = NULL; - Bytef *strmbuf = NULL; - guint inits_done = 0; - gint wbits = MAX_WBITS; - guint8 *next = NULL; - guint bufsiz = TVB_Z_MIN_BUFSIZ; -#ifdef TVB_Z_DEBUG - guint inflate_passes = 0; - guint bytes_in = tvb_length_remaining(tvb, offset); -#endif - - if (tvb == NULL) { - return NULL; - } - - compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen); - - if (!compr) - return NULL; - - /* - * Assume that the uncompressed data is at least twice as big as - * the compressed size. - */ - bufsiz = tvb_length_remaining(tvb, offset) * 2; - bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ); - -#ifdef TVB_Z_DEBUG - printf("bufsiz: %u bytes\n", bufsiz); -#endif - - next = compr; - - strm = g_new0(z_stream, 1); - strm->next_in = next; - strm->avail_in = comprlen; - - strmbuf = (Bytef *)g_malloc0(bufsiz); - strm->next_out = strmbuf; - strm->avail_out = bufsiz; - - err = inflateInit2(strm, wbits); - inits_done = 1; - if (err != Z_OK) { - inflateEnd(strm); - g_free(strm); - g_free(compr); - g_free(strmbuf); - return NULL; - } - - while (1) { - memset(strmbuf, '\0', bufsiz); - strm->next_out = strmbuf; - strm->avail_out = bufsiz; - - err = inflate(strm, Z_SYNC_FLUSH); - - if (err == Z_OK || err == Z_STREAM_END) { - guint bytes_pass = bufsiz - strm->avail_out; - -#ifdef TVB_Z_DEBUG - ++inflate_passes; -#endif - - if (uncompr == NULL) { - /* - * This is ugly workaround for bug #6480 - * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480) - * - * g_memdup(..., 0) returns NULL (g_malloc(0) also) - * when uncompr is NULL logic below doesn't create tvb - * which is later interpreted as decompression failed. - */ - uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ? - g_memdup(strmbuf, bytes_pass) : - g_strdup("")); - } else { - guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass); - - memcpy(new_data, uncompr, bytes_out); - memcpy(new_data + bytes_out, strmbuf, bytes_pass); - - g_free(uncompr); - uncompr = new_data; - } - - bytes_out += bytes_pass; - - if (err == Z_STREAM_END) { - inflateEnd(strm); - g_free(strm); - g_free(strmbuf); - break; - } - } else if (err == Z_BUF_ERROR) { - /* - * It's possible that not enough frames were captured - * to decompress this fully, so return what we've done - * so far, if any. - */ - inflateEnd(strm); - g_free(strm); - g_free(strmbuf); - - if (uncompr != NULL) { - break; - } else { - g_free(compr); - return NULL; - } - - } else if (err == Z_DATA_ERROR && inits_done == 1 - && uncompr == NULL && (*compr == 0x1f) && - (*(compr + 1) == 0x8b)) { - /* - * inflate() is supposed to handle both gzip and deflate - * streams automatically, but in reality it doesn't - * seem to handle either (at least not within the - * context of an HTTP response.) We have to try - * several tweaks, depending on the type of data and - * version of the library installed. - */ - - /* - * Gzip file format. Skip past the header, since the - * fix to make it work (setting windowBits to 31) - * doesn't work with all versions of the library. - */ - Bytef *c = compr + 2; - Bytef flags = 0; - - if (*c == Z_DEFLATED) { - c++; - } else { - inflateEnd(strm); - g_free(strm); - g_free(compr); - g_free(strmbuf); - return NULL; - } - - flags = *c; - - /* Skip past the MTIME, XFL, and OS fields. */ - c += 7; - - if (flags & (1 << 2)) { - /* An Extra field is present. */ - gint xsize = (gint)(*c | - (*(c + 1) << 8)); - - c += xsize; - } - - if (flags & (1 << 3)) { - /* A null terminated filename */ - - while ((c - compr) < comprlen && *c != '\0') { - c++; - } - - c++; - } - - if (flags & (1 << 4)) { - /* A null terminated comment */ - - while ((c - compr) < comprlen && *c != '\0') { - c++; - } - - c++; - } - - - inflateReset(strm); - next = c; - strm->next_in = next; - if (c - compr > comprlen) { - inflateEnd(strm); - g_free(strm); - g_free(compr); - g_free(strmbuf); - return NULL; - } - comprlen -= (int) (c - compr); - - inflateEnd(strm); - inflateInit2(strm, wbits); - inits_done++; - } else if (err == Z_DATA_ERROR && uncompr == NULL && - inits_done <= 3) { - - /* - * Re-init the stream with a negative - * MAX_WBITS. This is necessary due to - * some servers (Apache) not sending - * the deflate header with the - * content-encoded response. - */ - wbits = -MAX_WBITS; - - inflateReset(strm); - - strm->next_in = next; - strm->avail_in = comprlen; - - inflateEnd(strm); - memset(strmbuf, '\0', bufsiz); - strm->next_out = strmbuf; - strm->avail_out = bufsiz; - - err = inflateInit2(strm, wbits); - - inits_done++; - - if (err != Z_OK) { - g_free(strm); - g_free(strmbuf); - g_free(compr); - g_free(uncompr); - - return NULL; - } - } else { - inflateEnd(strm); - g_free(strm); - g_free(strmbuf); - - if (uncompr == NULL) { - g_free(compr); - return NULL; - } - - break; - } - } - -#ifdef TVB_Z_DEBUG - printf("inflate() total passes: %u\n", inflate_passes); - printf("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out); -#endif - - if (uncompr != NULL) { - uncompr_tvb = tvb_new_real_data((guint8*) uncompr, bytes_out, bytes_out); - tvb_set_free_cb(uncompr_tvb, g_free); - } - g_free(compr); - return uncompr_tvb; -} -#else -tvbuff_t * -tvb_uncompress(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_) -{ - return NULL; -} -#endif - -tvbuff_t * -tvb_child_uncompress(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen) -{ - tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen); - if (new_tvb) - tvb_set_child_real_data_tvbuff (parent, new_tvb); - return new_tvb; -} - gint tvb_raw_offset(tvbuff_t *tvb) { diff --git a/epan/tvbuff_zlib.c b/epan/tvbuff_zlib.c new file mode 100644 index 0000000000..4f8e2e9dbe --- /dev/null +++ b/epan/tvbuff_zlib.c @@ -0,0 +1,323 @@ +/* tvbuff_zlib.c + * + * $Id$ + * + * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib.h> + +#include <string.h> + +#ifdef HAVE_LIBZ +#include <zlib.h> +#endif + +#include "tvbuff.h" + +#ifdef HAVE_LIBZ +/* + * Uncompresses a zlib compressed packet inside a message of tvb at offset with + * length comprlen. Returns an uncompressed tvbuffer if uncompression + * succeeded or NULL if uncompression failed. + */ +#define TVB_Z_MIN_BUFSIZ 32768 +#define TVB_Z_MAX_BUFSIZ 1048576 * 10 +/* #define TVB_Z_DEBUG 1 */ +#undef TVB_Z_DEBUG + +tvbuff_t * +tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen) +{ + gint err = Z_OK; + guint bytes_out = 0; + guint8 *compr = NULL; + guint8 *uncompr = NULL; + tvbuff_t *uncompr_tvb = NULL; + z_streamp strm = NULL; + Bytef *strmbuf = NULL; + guint inits_done = 0; + gint wbits = MAX_WBITS; + guint8 *next = NULL; + guint bufsiz = TVB_Z_MIN_BUFSIZ; +#ifdef TVB_Z_DEBUG + guint inflate_passes = 0; + guint bytes_in = tvb_length_remaining(tvb, offset); +#endif + + if (tvb == NULL) { + return NULL; + } + + compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen); + + if (!compr) + return NULL; + + /* + * Assume that the uncompressed data is at least twice as big as + * the compressed size. + */ + bufsiz = tvb_length_remaining(tvb, offset) * 2; + bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ); + +#ifdef TVB_Z_DEBUG + printf("bufsiz: %u bytes\n", bufsiz); +#endif + + next = compr; + + strm = g_new0(z_stream, 1); + strm->next_in = next; + strm->avail_in = comprlen; + + strmbuf = (Bytef *)g_malloc0(bufsiz); + strm->next_out = strmbuf; + strm->avail_out = bufsiz; + + err = inflateInit2(strm, wbits); + inits_done = 1; + if (err != Z_OK) { + inflateEnd(strm); + g_free(strm); + g_free(compr); + g_free(strmbuf); + return NULL; + } + + while (1) { + memset(strmbuf, '\0', bufsiz); + strm->next_out = strmbuf; + strm->avail_out = bufsiz; + + err = inflate(strm, Z_SYNC_FLUSH); + + if (err == Z_OK || err == Z_STREAM_END) { + guint bytes_pass = bufsiz - strm->avail_out; + +#ifdef TVB_Z_DEBUG + ++inflate_passes; +#endif + + if (uncompr == NULL) { + /* + * This is ugly workaround for bug #6480 + * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480) + * + * g_memdup(..., 0) returns NULL (g_malloc(0) also) + * when uncompr is NULL logic below doesn't create tvb + * which is later interpreted as decompression failed. + */ + uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ? + g_memdup(strmbuf, bytes_pass) : + g_strdup("")); + } else { + guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass); + + memcpy(new_data, uncompr, bytes_out); + memcpy(new_data + bytes_out, strmbuf, bytes_pass); + + g_free(uncompr); + uncompr = new_data; + } + + bytes_out += bytes_pass; + + if (err == Z_STREAM_END) { + inflateEnd(strm); + g_free(strm); + g_free(strmbuf); + break; + } + } else if (err == Z_BUF_ERROR) { + /* + * It's possible that not enough frames were captured + * to decompress this fully, so return what we've done + * so far, if any. + */ + inflateEnd(strm); + g_free(strm); + g_free(strmbuf); + + if (uncompr != NULL) { + break; + } else { + g_free(compr); + return NULL; + } + + } else if (err == Z_DATA_ERROR && inits_done == 1 + && uncompr == NULL && (*compr == 0x1f) && + (*(compr + 1) == 0x8b)) { + /* + * inflate() is supposed to handle both gzip and deflate + * streams automatically, but in reality it doesn't + * seem to handle either (at least not within the + * context of an HTTP response.) We have to try + * several tweaks, depending on the type of data and + * version of the library installed. + */ + + /* + * Gzip file format. Skip past the header, since the + * fix to make it work (setting windowBits to 31) + * doesn't work with all versions of the library. + */ + Bytef *c = compr + 2; + Bytef flags = 0; + + if (*c == Z_DEFLATED) { + c++; + } else { + inflateEnd(strm); + g_free(strm); + g_free(compr); + g_free(strmbuf); + return NULL; + } + + flags = *c; + + /* Skip past the MTIME, XFL, and OS fields. */ + c += 7; + + if (flags & (1 << 2)) { + /* An Extra field is present. */ + gint xsize = (gint)(*c | + (*(c + 1) << 8)); + + c += xsize; + } + + if (flags & (1 << 3)) { + /* A null terminated filename */ + + while ((c - compr) < comprlen && *c != '\0') { + c++; + } + + c++; + } + + if (flags & (1 << 4)) { + /* A null terminated comment */ + + while ((c - compr) < comprlen && *c != '\0') { + c++; + } + + c++; + } + + + inflateReset(strm); + next = c; + strm->next_in = next; + if (c - compr > comprlen) { + inflateEnd(strm); + g_free(strm); + g_free(compr); + g_free(strmbuf); + return NULL; + } + comprlen -= (int) (c - compr); + + inflateEnd(strm); + inflateInit2(strm, wbits); + inits_done++; + } else if (err == Z_DATA_ERROR && uncompr == NULL && + inits_done <= 3) { + + /* + * Re-init the stream with a negative + * MAX_WBITS. This is necessary due to + * some servers (Apache) not sending + * the deflate header with the + * content-encoded response. + */ + wbits = -MAX_WBITS; + + inflateReset(strm); + + strm->next_in = next; + strm->avail_in = comprlen; + + inflateEnd(strm); + memset(strmbuf, '\0', bufsiz); + strm->next_out = strmbuf; + strm->avail_out = bufsiz; + + err = inflateInit2(strm, wbits); + + inits_done++; + + if (err != Z_OK) { + g_free(strm); + g_free(strmbuf); + g_free(compr); + g_free(uncompr); + + return NULL; + } + } else { + inflateEnd(strm); + g_free(strm); + g_free(strmbuf); + + if (uncompr == NULL) { + g_free(compr); + return NULL; + } + + break; + } + } + +#ifdef TVB_Z_DEBUG + printf("inflate() total passes: %u\n", inflate_passes); + printf("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out); +#endif + + if (uncompr != NULL) { + uncompr_tvb = tvb_new_real_data((guint8*) uncompr, bytes_out, bytes_out); + tvb_set_free_cb(uncompr_tvb, g_free); + } + g_free(compr); + return uncompr_tvb; +} +#else +tvbuff_t * +tvb_uncompress(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_) +{ + return NULL; +} +#endif + +tvbuff_t * +tvb_child_uncompress(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen) +{ + tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen); + if (new_tvb) + tvb_set_child_real_data_tvbuff (parent, new_tvb); + return new_tvb; +} |