debug keys
[metze/wireshark/wip.git] / epan / tvbuff_zlib.c
1 /* tvbuff_zlib.c
2  *
3  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11
12 #include <config.h>
13
14 #include <glib.h>
15
16 #include <string.h>
17
18 #ifdef HAVE_ZLIB
19 #define ZLIB_CONST
20 #include <zlib.h>
21 #endif
22
23 #include "tvbuff.h"
24 #ifdef TVB_Z_DEBUG
25 #include <wsutil/ws_printf.h> /* ws_debug_printf */
26 #endif
27
28 #ifdef HAVE_ZLIB
29 /*
30  * Uncompresses a zlib compressed packet inside a message of tvb at offset with
31  * length comprlen.  Returns an uncompressed tvbuffer if uncompression
32  * succeeded or NULL if uncompression failed.
33  */
34 #define TVB_Z_MIN_BUFSIZ 32768
35 #define TVB_Z_MAX_BUFSIZ 1048576 * 10
36 /* #define TVB_Z_DEBUG 1 */
37 #undef TVB_Z_DEBUG
38
39 tvbuff_t *
40 tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen)
41 {
42         gint       err;
43         guint      bytes_out      = 0;
44         guint8    *compr;
45         guint8    *uncompr        = NULL;
46         tvbuff_t  *uncompr_tvb    = NULL;
47         z_streamp  strm;
48         Bytef     *strmbuf;
49         guint      inits_done     = 0;
50         gint       wbits          = MAX_WBITS;
51         guint8    *next;
52         guint      bufsiz;
53 #ifdef TVB_Z_DEBUG
54         guint      inflate_passes = 0;
55         guint      bytes_in       = tvb_captured_length_remaining(tvb, offset);
56 #endif
57
58         if (tvb == NULL || comprlen <= 0) {
59                 return NULL;
60         }
61
62         compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen);
63         if (compr == NULL) {
64                 return NULL;
65         }
66
67         /*
68          * Assume that the uncompressed data is at least twice as big as
69          * the compressed size.
70          */
71         bufsiz = tvb_captured_length_remaining(tvb, offset) * 2;
72         bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ);
73
74 #ifdef TVB_Z_DEBUG
75         ws_debug_printf("bufsiz: %u bytes\n", bufsiz);
76 #endif
77
78         next = compr;
79
80         strm            = g_new0(z_stream, 1);
81         strm->next_in   = next;
82         strm->avail_in  = comprlen;
83
84         strmbuf         = (Bytef *)g_malloc0(bufsiz);
85         strm->next_out  = strmbuf;
86         strm->avail_out = bufsiz;
87
88         err = inflateInit2(strm, wbits);
89         inits_done = 1;
90         if (err != Z_OK) {
91                 inflateEnd(strm);
92                 g_free(strm);
93                 wmem_free(NULL, compr);
94                 g_free(strmbuf);
95                 return NULL;
96         }
97
98         while (1) {
99                 memset(strmbuf, '\0', bufsiz);
100                 strm->next_out  = strmbuf;
101                 strm->avail_out = bufsiz;
102
103                 err = inflate(strm, Z_SYNC_FLUSH);
104
105                 if (err == Z_OK || err == Z_STREAM_END) {
106                         guint bytes_pass = bufsiz - strm->avail_out;
107
108 #ifdef TVB_Z_DEBUG
109                         ++inflate_passes;
110 #endif
111
112                         if (uncompr == NULL) {
113                                 /*
114                                  * This is ugly workaround for bug #6480
115                                  * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480)
116                                  *
117                                  * g_memdup(..., 0) returns NULL (g_malloc(0) also)
118                                  * when uncompr is NULL logic below doesn't create tvb
119                                  * which is later interpreted as decompression failed.
120                                  */
121                                 uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ?
122                                                 g_memdup(strmbuf, bytes_pass) :
123                                                 g_strdup(""));
124                         } else {
125                                 guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass);
126
127                                 memcpy(new_data, uncompr, bytes_out);
128                                 memcpy(new_data + bytes_out, strmbuf, bytes_pass);
129
130                                 g_free(uncompr);
131                                 uncompr = new_data;
132                         }
133
134                         bytes_out += bytes_pass;
135
136                         if (err == Z_STREAM_END) {
137                                 inflateEnd(strm);
138                                 g_free(strm);
139                                 g_free(strmbuf);
140                                 break;
141                         }
142                 } else if (err == Z_BUF_ERROR) {
143                         /*
144                          * It's possible that not enough frames were captured
145                          * to decompress this fully, so return what we've done
146                          * so far, if any.
147                          */
148                         inflateEnd(strm);
149                         g_free(strm);
150                         g_free(strmbuf);
151
152                         if (uncompr != NULL) {
153                                 break;
154                         } else {
155                                 wmem_free(NULL, compr);
156                                 return NULL;
157                         }
158
159                 } else if (err == Z_DATA_ERROR && inits_done == 1
160                         && uncompr == NULL && comprlen >= 2 &&
161                         (*compr  == 0x1f) && (*(compr + 1) == 0x8b)) {
162                         /*
163                          * inflate() is supposed to handle both gzip and deflate
164                          * streams automatically, but in reality it doesn't
165                          * seem to handle either (at least not within the
166                          * context of an HTTP response.)  We have to try
167                          * several tweaks, depending on the type of data and
168                          * version of the library installed.
169                          */
170
171                         /*
172                          * Gzip file format.  Skip past the header, since the
173                          * fix to make it work (setting windowBits to 31)
174                          * doesn't work with all versions of the library.
175                          */
176                         Bytef *c = compr + 2;
177                         Bytef  flags = 0;
178
179                         /* we read two bytes already (0x1f, 0x8b) and
180                            need at least Z_DEFLATED, 1 byte flags, 4
181                            bytes MTIME, 1 byte XFL, 1 byte OS */
182                         if (comprlen < 10 || *c != Z_DEFLATED) {
183                                 inflateEnd(strm);
184                                 g_free(strm);
185                                 wmem_free(NULL, compr);
186                                 g_free(strmbuf);
187                                 return NULL;
188                         }
189
190                         c++;
191                         flags = *c;
192                         c++;
193
194                         /* Skip past the MTIME (4 bytes),
195                            XFL, and OS fields (1 byte each). */
196                         c += 6;
197
198                         if (flags & (1 << 2)) {
199                                 /* An Extra field is present. It
200                                    consists of 2 bytes xsize and xsize
201                                    bytes of data.
202                                    Read byte-by-byte (least significant
203                                    byte first) to make sure we abort
204                                    cleanly when the xsize is truncated
205                                    after the first byte. */
206                                 guint16 xsize = 0;
207
208                                 if (c-compr < comprlen) {
209                                         xsize += *c;
210                                         c++;
211                                 }
212                                 if (c-compr < comprlen) {
213                                         xsize += *c << 8;
214                                         c++;
215                                 }
216
217                                 c += xsize;
218                         }
219
220                         if (flags & (1 << 3)) {
221                                 /* A null terminated filename */
222
223                                 while ((c - compr) < comprlen && *c != '\0') {
224                                         c++;
225                                 }
226
227                                 c++;
228                         }
229
230                         if (flags & (1 << 4)) {
231                                 /* A null terminated comment */
232
233                                 while ((c - compr) < comprlen && *c != '\0') {
234                                         c++;
235                                 }
236
237                                 c++;
238                         }
239
240
241                         if (c - compr > comprlen) {
242                                 inflateEnd(strm);
243                                 g_free(strm);
244                                 wmem_free(NULL, compr);
245                                 g_free(strmbuf);
246                                 return NULL;
247                         }
248                         /* Drop gzip header */
249                         comprlen -= (int) (c - compr);
250                         next = c;
251
252                         inflateReset(strm);
253                         strm->next_in   = next;
254                         strm->avail_in  = comprlen;
255
256                         inflateEnd(strm);
257                         inflateInit2(strm, wbits);
258                         inits_done++;
259                 } else if (err == Z_DATA_ERROR && uncompr == NULL &&
260                         inits_done <= 3) {
261
262                         /*
263                          * Re-init the stream with a negative
264                          * MAX_WBITS. This is necessary due to
265                          * some servers (Apache) not sending
266                          * the deflate header with the
267                          * content-encoded response.
268                          */
269                         wbits = -MAX_WBITS;
270
271                         inflateReset(strm);
272
273                         strm->next_in   = next;
274                         strm->avail_in  = comprlen;
275
276                         inflateEnd(strm);
277                         memset(strmbuf, '\0', bufsiz);
278                         strm->next_out  = strmbuf;
279                         strm->avail_out = bufsiz;
280
281                         err = inflateInit2(strm, wbits);
282
283                         inits_done++;
284
285                         if (err != Z_OK) {
286                                 g_free(strm);
287                                 g_free(strmbuf);
288                                 wmem_free(NULL, compr);
289                                 g_free(uncompr);
290
291                                 return NULL;
292                         }
293                 } else {
294                         inflateEnd(strm);
295                         g_free(strm);
296                         g_free(strmbuf);
297
298                         if (uncompr == NULL) {
299                                 wmem_free(NULL, compr);
300                                 return NULL;
301                         }
302
303                         break;
304                 }
305         }
306
307 #ifdef TVB_Z_DEBUG
308         ws_debug_printf("inflate() total passes: %u\n", inflate_passes);
309         ws_debug_printf("bytes  in: %u\nbytes out: %u\n\n", bytes_in, bytes_out);
310 #endif
311
312         if (uncompr != NULL) {
313                 uncompr_tvb =  tvb_new_real_data(uncompr, bytes_out, bytes_out);
314                 tvb_set_free_cb(uncompr_tvb, g_free);
315         }
316         wmem_free(NULL, compr);
317         return uncompr_tvb;
318 }
319 #else
320 tvbuff_t *
321 tvb_uncompress(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_)
322 {
323         return NULL;
324 }
325 #endif
326
327 tvbuff_t *
328 tvb_child_uncompress(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen)
329 {
330         tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen);
331         if (new_tvb)
332                 tvb_set_child_real_data_tvbuff (parent, new_tvb);
333         return new_tvb;
334 }
335
336 /*
337  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
338  *
339  * Local variables:
340  * c-basic-offset: 8
341  * tab-width: 8
342  * indent-tabs-mode: t
343  * End:
344  *
345  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
346  * :indentSize=8:tabSize=8:noTabs=false:
347  */