Create a dissection mode for the deflate function.

This is to be used by protocol analysers which wants to show as much as
possible of the header even if packets are missing. In this case a dummy
header is inserted ":Failed deflate", "Index not seen before".
This commit is contained in:
Anders Broman 2020-05-13 15:31:04 +02:00
parent ef41583614
commit 75950c2e65
2 changed files with 58 additions and 5 deletions

View File

@ -398,6 +398,11 @@ typedef enum {
* receives an other type of frame.
*/
NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
/**
* Integer exceeded the maximum value
*/
NGHTTP2_ERR_HEADER_COMP_MAX_LEN_EX = -537,
/**
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
* under unexpected condition and processing was terminated (e.g.,
@ -5080,7 +5085,12 @@ typedef enum {
/**
* Indicates a header was emitted.
*/
NGHTTP2_HD_INFLATE_EMIT = 0x02
NGHTTP2_HD_INFLATE_EMIT = 0x02,
/**
* Input value: Indicates that the inflater is run in decode mode
* e.g will not stop on unknown indexes.
*/
NGHTTP2_HD_INFLATE_DECODE = 0x04
} nghttp2_hd_inflate_flag;
/**
@ -5179,6 +5189,11 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
* and the function returns. The caller must not free the members of
* |nv_out|.
*
* If :|*inflate_flags| is set to enum:`NGHTTP2_HD_INFLATE_DECODE` as
* an IN parameter the deflater will act as a decoder and atempt to
* decode the header even if unknown indexes occure. This is aimed
* at analysers such as Wireshark.
*
* The |nv_out| may include pointers to the memory region in the |in|.
* The caller must retain the |in| while the |nv_out| is used.
*

View File

@ -109,6 +109,10 @@ static const nghttp2_hd_static_entry static_table[] = {
MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u),
};
static const nghttp2_hd_static_entry dissect_index_table[] = {
MAKE_STATIC_ENT(":Failed deflate", "Index not seen before", "", -1, NGHTTP2_NV_FLAG_NONE),
};
static int memeq(const void *s1, const void *s2, size_t n) {
return memcmp(s1, s2, n) == 0;
}
@ -1654,8 +1658,9 @@ static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin,
}
if (out > maxlen) {
DEBUGF("inflatehd: integer exceeded the maximum value %zu\n", maxlen);
return NGHTTP2_ERR_HEADER_COMP;
DEBUGF("inflatehd: integer %zu exceeded the maximum value %zu\n", out, maxlen);
inflater->left = out;
return NGHTTP2_ERR_HEADER_COMP_MAX_LEN_EX;
}
inflater->left = out;
@ -1870,6 +1875,12 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
int rfin = 0;
int busy = 0;
nghttp2_mem *mem;
int dissection = 0;
if (*inflate_flags == NGHTTP2_HD_INFLATE_DECODE) {
dissection = 1;
DEBUGF("inflatehd: dissection = 1 inflate flag %d\n", *inflate_flags);
}
mem = inflater->ctx.mem;
@ -1963,7 +1974,34 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
rv = hd_inflate_read_len(inflater, &rfin, in, last, prefixlen,
get_max_index(&inflater->ctx));
if (rv < 0) {
goto fail;
if ((dissection == 1) && (rv == NGHTTP2_ERR_HEADER_COMP_MAX_LEN_EX)) {
/* We recived an index not seen before, make a dissect header entry */
rv = 1;
in += rv;
if (!rfin) {
goto almost_ok;
}
if (inflater->left == 0) {
rv = NGHTTP2_ERR_HEADER_COMP;
goto fail;
}
const nghttp2_hd_static_entry *ent = &dissect_index_table[0];
nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name,
(nghttp2_rcbuf *)&ent->value, ent->token,
NGHTTP2_NV_FLAG_NONE};
emit_header(nv_out, &nv);
DEBUGF("inflatehd dissect: index=%zu\n", inflater->left);
inflater->index = inflater->left;
--inflater->index;
inflater->state = NGHTTP2_HD_STATE_OPCODE;
*inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
return (ssize_t)(in - first);
} else {
goto fail;
}
}
in += rv;
@ -2223,7 +2261,7 @@ almost_ok:
return (ssize_t)(in - first);
fail:
DEBUGF("inflatehd: error return %zd\n", rv);
DEBUGF("inflatehd: error return %d\n", rv);
inflater->ctx.bad = 1;
return rv;