mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
6.4 KiB
C
215 lines
6.4 KiB
C
/*
|
|
* LibHTP (http://www.libhtp.org)
|
|
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
|
|
*
|
|
* LibHTP is an open source product, released under terms of the General Public Licence
|
|
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
|
|
* of the license.
|
|
*
|
|
* In addition, there is a special exception that allows LibHTP to be freely
|
|
* used with any OSI-approved open source licence. Please refer to the file
|
|
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
|
|
*
|
|
*/
|
|
|
|
#include "htp.h"
|
|
#include "htp_decompressors.h"
|
|
|
|
/**
|
|
* Decompress a chunk of gzip-compressed data.
|
|
*
|
|
* @param drec
|
|
* @param d
|
|
*/
|
|
static int htp_gzip_decompressor_decompress(htp_decompressor_gzip_t *drec, htp_tx_data_t *d) {
|
|
size_t consumed = 0;
|
|
|
|
// Return if we've previously had an error
|
|
if (drec->initialized < 0) {
|
|
return drec->initialized;
|
|
}
|
|
|
|
// Do we need to initialize?
|
|
if (drec->initialized == 0) {
|
|
// Check the header
|
|
if ((drec->header_len == 0) && (d->len >= 10)) {
|
|
// We have received enough data initialize; use the input buffer directly
|
|
if ((d->data[0] != DEFLATE_MAGIC_1) || (d->data[1] != DEFLATE_MAGIC_2)) {
|
|
htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
|
|
"GZip decompressor: Magic bytes mismatch");
|
|
drec->initialized = -1;
|
|
return -1;
|
|
}
|
|
|
|
if (d->data[3] != 0) {
|
|
htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
|
|
"GZip decompressor: Unable to handle flags: %d", d->data[3]);
|
|
drec->initialized = -1;
|
|
return -1;
|
|
}
|
|
|
|
drec->initialized = 1;
|
|
consumed = 10;
|
|
} else {
|
|
// We do not (or did not) have enough bytes, so we have
|
|
// to copy some data into our internal header buffer.
|
|
|
|
// How many bytes do we need?
|
|
size_t copylen = 10 - drec->header_len;
|
|
|
|
// Is there enough in input?
|
|
if (copylen > d->len) copylen = d->len;
|
|
|
|
// Copy the bytes
|
|
memcpy(drec->header + drec->header_len, d->data, copylen);
|
|
drec->header_len += copylen;
|
|
consumed = copylen;
|
|
|
|
// Do we have enough now?
|
|
if (drec->header_len == 10) {
|
|
// We do!
|
|
if ((drec->header[0] != DEFLATE_MAGIC_1) || (drec->header[1] != DEFLATE_MAGIC_2)) {
|
|
htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
|
|
"GZip decompressor: Magic bytes mismatch");
|
|
drec->initialized = -1;
|
|
return -1;
|
|
}
|
|
|
|
if (drec->header[3] != 0) {
|
|
htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
|
|
"GZip decompressor: Unable to handle flags: %d", d->data[3]);
|
|
drec->initialized = -1;
|
|
return -1;
|
|
}
|
|
|
|
drec->initialized = 1;
|
|
} else {
|
|
// Need more data
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Decompress data
|
|
int rc = 0;
|
|
drec->stream.next_in = d->data + consumed;
|
|
drec->stream.avail_in = d->len - consumed;
|
|
|
|
while (drec->stream.avail_in != 0) {
|
|
// If there's no more data left in the
|
|
// buffer, send that information out
|
|
if (drec->stream.avail_out == 0) {
|
|
drec->crc = crc32(drec->crc, drec->buffer, GZIP_BUF_SIZE);
|
|
|
|
// Prepare data for callback
|
|
htp_tx_data_t d2;
|
|
d2.tx = d->tx;
|
|
d2.data = drec->buffer;
|
|
d2.len = GZIP_BUF_SIZE;
|
|
|
|
// Send decompressed data to callback
|
|
if (drec->super.callback(&d2) < 0) {
|
|
inflateEnd(&drec->stream);
|
|
drec->zlib_initialized = 0;
|
|
return -1;
|
|
}
|
|
|
|
drec->stream.next_out = drec->buffer;
|
|
drec->stream.avail_out = GZIP_BUF_SIZE;
|
|
}
|
|
|
|
rc = inflate(&drec->stream, Z_NO_FLUSH);
|
|
|
|
if (rc == Z_STREAM_END) {
|
|
// How many bytes do we have?
|
|
size_t len = GZIP_BUF_SIZE - drec->stream.avail_out;
|
|
|
|
// Update CRC
|
|
drec->crc = crc32(drec->crc, drec->buffer, len);
|
|
|
|
// Prepare data for callback
|
|
htp_tx_data_t d2;
|
|
d2.tx = d->tx;
|
|
d2.data = drec->buffer;
|
|
d2.len = len;
|
|
|
|
// Send decompressed data to callback
|
|
if (drec->super.callback(&d2) < 0) {
|
|
inflateEnd(&drec->stream);
|
|
drec->zlib_initialized = 0;
|
|
return -1;
|
|
}
|
|
|
|
// TODO Handle trailer
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (rc != Z_OK) {
|
|
htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
|
|
"GZip decompressor: inflate failed with %d", rc);
|
|
|
|
inflateEnd(&drec->stream);
|
|
drec->zlib_initialized = 0;
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Shut down gzip decompressor.
|
|
*
|
|
* @param drec
|
|
*/
|
|
static void htp_gzip_decompressor_destroy(htp_decompressor_gzip_t * drec) {
|
|
if (drec == NULL) return;
|
|
|
|
if (drec->zlib_initialized) {
|
|
inflateEnd(&drec->stream);
|
|
drec->zlib_initialized = 0;
|
|
}
|
|
|
|
free(drec->buffer);
|
|
free(drec);
|
|
}
|
|
|
|
/**
|
|
* Initialize gzip decompressor.
|
|
*
|
|
* @param connp
|
|
*/
|
|
htp_decompressor_t * htp_gzip_decompressor_create(htp_connp_t *connp) {
|
|
htp_decompressor_gzip_t *drec = calloc(1, sizeof (htp_decompressor_gzip_t));
|
|
if (drec == NULL) return NULL;
|
|
|
|
drec->super.decompress = (int (*)(htp_decompressor_t *, htp_tx_data_t *)) htp_gzip_decompressor_decompress;
|
|
drec->super.destroy = (void (*)(htp_decompressor_t *))htp_gzip_decompressor_destroy;
|
|
|
|
drec->buffer = malloc(GZIP_BUF_SIZE);
|
|
if (drec->buffer == NULL) {
|
|
free(drec);
|
|
return NULL;
|
|
}
|
|
|
|
int rc = inflateInit2(&drec->stream, GZIP_WINDOW_SIZE);
|
|
if (rc != Z_OK) {
|
|
htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
|
|
"GZip decompressor: inflateInit2 failed with code %d", rc);
|
|
|
|
inflateEnd(&drec->stream);
|
|
free(drec->buffer);
|
|
free(drec);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
drec->zlib_initialized = 1;
|
|
drec->stream.avail_out = GZIP_BUF_SIZE;
|
|
drec->stream.next_out = drec->buffer;
|
|
|
|
return (htp_decompressor_t *) drec;
|
|
}
|