Bug Summary

File:builds/wireshark/wireshark/epan/dissectors/packet-http3.c
Warning:line 1667, column 13
Value stored to 'datalen' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-http3.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-07-07-100348-3595-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-http3.c
1/* packet-http3.c
2 * Routines for HTTP/3 dissection
3 * Copyright 2019, Peter Wu <peter@lekensteyn.nl>
4 * Copyright 2023, Omer Shapira <oesh@github.com>
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13/*
14 * https://tools.ietf.org/html/draft-ietf-quic-http-29
15 * https://tools.ietf.org/html/draft-ietf-quic-qpack-16
16 *
17 * Depends on the QUIC dissector for providing a reassembled stream of data, see
18 * packet-quic.c for details about supported QUIC draft versions.
19 * Depends on nghttp3 for HTTP header dissection.
20 * Currently supported HTTP/3 versions: h3-23 up to and including h3-29.
21 */
22
23#include "config.h"
24#define WS_LOG_DOMAIN"HTTP3" "HTTP3"
25
26#include <stdint.h>
27#include <string.h>
28
29#include <epan/wmem_scopes.h>
30#include <epan/addr_resolv.h>
31#include <epan/conversation_table.h>
32#include <epan/decode_as.h>
33#include <epan/exceptions.h>
34#include <epan/expert.h>
35#include <epan/follow.h>
36#include <epan/packet.h>
37#include <epan/proto_data.h>
38#include <epan/reassemble.h>
39#include <epan/to_str.h>
40#include <epan/uat.h>
41
42#include <epan/dissectors/packet-http.h> /* for getting status reason-phrase */
43#include <epan/dissectors/packet-media-type.h>
44#include <epan/dissectors/packet-quic.h>
45#include <epan/dissectors/packet-udp.h>
46
47#include <wsutil/pint.h>
48#include <wsutil/str_util.h>
49#include <wsutil/ws_assert.h>
50#include <wsutil/zlib_compat.h>
51
52#include "charsets.h"
53
54#ifdef HAVE_NGHTTP31
55#include <nghttp3/nghttp3.h>
56#endif
57
58void proto_reg_handoff_http3(void);
59void proto_register_http3(void);
60
61static dissector_handle_t http3_handle;
62static dissector_handle_t http3_datagram_handle;
63
64static int http3_follow_tap;
65
66#ifdef HAVE_NGHTTP31
67static reassembly_table http3_body_reassembly_table;
68
69static dissector_table_t media_type_dissector_table;
70
71/*
72 * Decompression of content-encoded entities.
73 */
74#if defined(HAVE_ZLIB1) || defined(HAVE_ZLIBNG) || defined(HAVE_BROTLI1) || defined(HAVE_ZSTD1)
75static bool_Bool http3_decompress_body = true1;
76#else
77static bool_Bool http3_decompress_body;
78#endif
79
80#endif /* HAVE_NGHTTP3 */
81
82#define PROTO_DATA_KEY_HEADER0 0
83#define PROTO_DATA_KEY_QPACK1 1
84
85static int proto_http3;
86static int hf_http3_stream_uni;
87static int hf_http3_stream_uni_type;
88static int hf_http3_stream_bidi;
89static int hf_http3_push_id;
90static int hf_http3_frame;
91static int hf_http3_frame_streamid;
92static int hf_http3_frame_type;
93static int hf_http3_frame_length;
94static int hf_http3_frame_payload;
95
96static int hf_http3_data;
97static int hf_http3_encoded_entity;
98static int hf_http3_body_fragments;
99static int hf_http3_body_fragment;
100static int hf_http3_body_fragment_overlap;
101static int hf_http3_body_fragment_overlap_conflicts;
102static int hf_http3_body_fragment_multiple_tails;
103static int hf_http3_body_fragment_too_long_fragment;
104static int hf_http3_body_fragment_error;
105static int hf_http3_body_fragment_count;
106static int hf_http3_body_reassembled_in;
107static int hf_http3_body_reassembled_length;
108static int hf_http3_body_reassembled_data;
109
110static int hf_http3_headers_count;
111static int hf_http3_header;
112static int hf_http3_headers_decoded_length;
113static int hf_http3_header_name_length;
114static int hf_http3_header_name;
115static int hf_http3_header_value_length;
116static int hf_http3_header_value;
117static int hf_http3_header_request_full_uri;
118
119static int hf_http3_header_qpack_blocked;
120static int hf_http3_header_qpack_blocked_stream_rcint;
121static int hf_http3_header_qpack_blocked_decoder_wicnt;
122
123#ifdef HAVE_NGHTTP31
124/* Static HTTP3 headers */
125static int hf_http3_headers_status;
126static int hf_http3_headers_path;
127static int hf_http3_headers_protocol;
128static int hf_http3_headers_method;
129static int hf_http3_headers_scheme;
130static int hf_http3_headers_accept;
131static int hf_http3_headers_accept_charset;
132static int hf_http3_headers_accept_encoding;
133static int hf_http3_headers_accept_language;
134static int hf_http3_headers_accept_ranges;
135static int hf_http3_headers_access_control_allow_origin;
136static int hf_http3_headers_age;
137static int hf_http3_headers_allow;
138static int hf_http3_headers_authorization;
139static int hf_http3_headers_authority;
140static int hf_http3_headers_cache_control;
141static int hf_http3_headers_content_disposition;
142static int hf_http3_headers_content_encoding;
143static int hf_http3_headers_content_language;
144static int hf_http3_headers_content_length;
145static int hf_http3_headers_content_location;
146static int hf_http3_headers_content_range;
147static int hf_http3_headers_content_type;
148static int hf_http3_headers_cookie;
149static int hf_http3_headers_date;
150static int hf_http3_headers_etag;
151static int hf_http3_headers_expect;
152static int hf_http3_headers_expires;
153static int hf_http3_headers_from;
154static int hf_http3_headers_if_match;
155static int hf_http3_headers_if_modified_since;
156static int hf_http3_headers_if_none_match;
157static int hf_http3_headers_if_range;
158static int hf_http3_headers_if_unmodified_since;
159static int hf_http3_headers_last_modified;
160static int hf_http3_headers_link;
161static int hf_http3_headers_location;
162static int hf_http3_headers_max_forwards;
163static int hf_http3_headers_proxy_authenticate;
164static int hf_http3_headers_proxy_authorization;
165static int hf_http3_headers_range;
166static int hf_http3_headers_referer;
167static int hf_http3_headers_refresh;
168static int hf_http3_headers_retry_after;
169static int hf_http3_headers_server;
170static int hf_http3_headers_set_cookie;
171static int hf_http3_headers_strict_transport_security;
172static int hf_http3_headers_user_agent;
173static int hf_http3_headers_vary;
174static int hf_http3_headers_via;
175static int hf_http3_headers_www_authenticate;
176#endif
177
178static int hf_http3_qpack_encoder;
179static int hf_http3_qpack_encoder_icnt;
180static int hf_http3_qpack_encoder_icnt_inc;
181static int hf_http3_qpack_encoder_opcode_insert_indexed;
182static int hf_http3_qpack_encoder_opcode_insert_indexed_ref;
183static int hf_http3_qpack_encoder_opcode_insert_indexed_val;
184static int hf_http3_qpack_encoder_opcode_insert_indexed_hval;
185static int hf_http3_qpack_encoder_opcode_insert;
186static int hf_http3_qpack_encoder_opcode_insert_name;
187static int hf_http3_qpack_encoder_opcode_insert_hname;
188static int hf_http3_qpack_encoder_opcode_insert_val;
189static int hf_http3_qpack_encoder_opcode_insert_hval;
190static int hf_http3_qpack_encoder_opcode_duplicate;
191static int hf_http3_qpack_encoder_opcode_dtable_cap;
192static int hf_http3_qpack_encoder_opcode_dtable_cap_val;
193
194static int hf_http3_qpack_decoder;
195static int hf_http3_qpack_decoder_opcode_section_ack;
196static int hf_http3_qpack_decoder_opcode_section_ack_stream_id;
197static int hf_http3_qpack_decoder_opcode_cancel_stream;
198static int hf_http3_qpack_decoder_opcode_cancel_stream_id;
199static int hf_http3_qpack_decoder_opcode_icnt_increment;
200static int hf_http3_qpack_decoder_opcode_icnt_increment_value;
201
202static int hf_http3_settings;
203static int hf_http3_settings_identifier;
204static int hf_http3_settings_value;
205static int hf_http3_settings_qpack_max_table_capacity;
206static int hf_http3_settings_max_field_section_size;
207static int hf_http3_settings_qpack_blocked_streams;
208static int hf_http3_settings_extended_connect;
209static int hf_http3_settings_webtransport;
210static int hf_http3_settings_h3_datagram;
211static int hf_http3_settings_h3_datagram_draft04;
212static int hf_http3_priority_update_element_id;
213static int hf_http3_priority_update_field_value;
214
215static int hf_http3_datagram;
216static int hf_http3_datagram_quarter_stream_id;
217static int hf_http3_datagram_request_stream_id;
218static int hf_http3_datagram_payload;
219
220static expert_field ei_http3_qpack_failed;
221static expert_field ei_http3_prefix_int_failed;
222static expert_field ei_http3_huffman_failed;
223/* HTTP3 dissection EIs */
224static expert_field ei_http3_unknown_stream_type;
225/* Encoded data EIs */
226static expert_field ei_http3_header_encoded_state;
227/* HTTP3 header decoding EIs */
228static expert_field ei_http3_header_decoding_failed;
229static expert_field ei_http3_header_decoding_blocked;
230static expert_field ei_http3_header_decoding_no_output;
231static expert_field ei_http3_header_size;
232static expert_field ei_http3_header_transfer_encoding;
233/* HTTP3 body decoding EIs */
234static expert_field ei_http3_body_decompression_failed;
235/* HTTP3 datagram prefix EIs */
236static expert_field ei_http3_datagram_invalid_stream_id;
237
238/* Initialize the subtree pointers */
239static int ett_http3;
240static int ett_http3_stream_uni;
241static int ett_http3_stream_bidi;
242static int ett_http3_frame;
243static int ett_http3_body_fragment;
244static int ett_http3_body_fragments;
245static int ett_http3_encoded_entity;
246static int ett_http3_settings;
247static int ett_http3_headers;
248static int ett_http3_headers_qpack_blocked;
249static int ett_http3_qpack_update;
250static int ett_http3_qpack_opcode;
251static int ett_http3_datagram;
252static int ett_http3_datagram_stream_id;
253
254#ifdef HAVE_NGHTTP31
255static const fragment_items http3_body_fragment_items = {
256 /* Fragment subtrees */
257 &ett_http3_body_fragment,
258 &ett_http3_body_fragments,
259 /* Fragment fields */
260 &hf_http3_body_fragments,
261 &hf_http3_body_fragment,
262 &hf_http3_body_fragment_overlap,
263 &hf_http3_body_fragment_overlap_conflicts,
264 &hf_http3_body_fragment_multiple_tails,
265 &hf_http3_body_fragment_too_long_fragment,
266 &hf_http3_body_fragment_error,
267 &hf_http3_body_fragment_count,
268 &hf_http3_body_reassembled_in,
269 &hf_http3_body_reassembled_length,
270 &hf_http3_body_reassembled_data,
271 "Body fragments"
272};
273#endif
274
275/**
276 * HTTP3 header constants.
277 * The below constants are used for dissecting the
278 * code. This is not an exhaustive list.
279 */
280#define HTTP3_HEADER_NAME_CONTENT_ENCODING"content-encoding" "content-encoding"
281#define HTTP3_HEADER_NAME_CONTENT_TYPE"content-type" "content-type"
282#define HTTP3_HEADER_NAME_CONTENT_LENGTH"content-length" "content-length"
283#define HTTP3_HEADER_NAME_TRANSFER_ENCODING"transfer-encoding" "transfer-encoding"
284#define HTTP3_HEADER_NAME_AUTHORITY":authority" ":authority"
285#define HTTP3_HEADER_NAME_METHOD":method" ":method"
286#define HTTP3_HEADER_NAME_PATH":path" ":path"
287#define HTTP3_HEADER_NAME_PROTOCOL":protocol" ":protocol"
288#define HTTP3_HEADER_NAME_SCHEME":scheme" ":scheme"
289#define HTTP3_HEADER_NAME_STATUS":status" ":status"
290
291#define HTTP3_HEADER_METHOD_CONNECT"CONNECT" "CONNECT"
292#define HTTP3_HEADER_STATUS_PARTIAL_CONTENT"206" "206"
293
294#define HTTP3_HEADER_UNKNOWN"<unknown>" "<unknown>"
295
296/**
297 * Unidirectional stream types.
298 * https://tools.ietf.org/html/draft-ietf-quic-http-29#section-6.2
299 * https://tools.ietf.org/html/draft-ietf-quic-qpack-16#section-4.2
300 */
301enum http3_stream_type {
302 HTTP3_STREAM_TYPE_CONTROL,
303 HTTP3_STREAM_TYPE_PUSH,
304 HTTP3_STREAM_TYPE_QPACK_ENCODER,
305 HTTP3_STREAM_TYPE_QPACK_DECODER,
306 HTTP3_STREAM_TYPE_WEBTRANSPORT = 0x54, // draft-ietf-webtrans-http3-03
307};
308
309/**
310 * Unidirectional stream types (62-bit code space).
311 * https://tools.ietf.org/html/draft-ietf-quic-http-29#section-11.2.4
312 */
313// clang-format off
314static const val64_string http3_stream_types[] = {
315 /* 0x00 - 0x3f Assigned via Standards Action or IESG Approval. */
316 { 0x00, "Control Stream" },
317 { 0x01, "Push Stream" },
318 { 0x02, "QPACK Encoder Stream" },
319 { 0x03, "QPACK Decoder Stream" },
320 { 0x54, "WebTransport Stream" },
321 /* 0x40 - 0x3FFFFFFFFFFFFFFF Assigned via Specification Required policy */
322 { 0, NULL((void*)0) }
323};
324// clang-format on
325
326/**
327 * Frame type codes (62-bit code space).
328 * https://tools.ietf.org/html/draft-ietf-quic-http-29#section-11.2.1
329 */
330#define HTTP3_DATA0x0 0x0
331#define HTTP3_HEADERS0x1 0x1
332#define HTTP3_CANCEL_PUSH0x3 0x3
333#define HTTP3_SETTINGS0x4 0x4
334#define HTTP3_PUSH_PROMISE0x5 0x5
335#define HTTP3_GOAWAY0x7 0x7
336#define HTTP3_MAX_PUSH_ID0xD 0xD
337#define HTTP3_WEBTRANSPORT_BISTREAM0x41 0x41
338#define HTTP3_PRIORITY_UPDATE_REQUEST_STREAM0xF0700 0xF0700
339#define HTTP3_PRIORITY_UPDATE_PUSH_STREAM0xF0701 0xF0701
340
341static const val64_string http3_frame_types[] = {
342 /* 0x00 - 0x3f Assigned via Standards Action or IESG Approval. */
343 { HTTP3_DATA0x0, "DATA" },
344 { HTTP3_HEADERS0x1, "HEADERS" },
345 { 0x02, "Reserved" }, // "PRIORITY" in draft-22 and before
346 { HTTP3_CANCEL_PUSH0x3, "CANCEL_PUSH" },
347 { HTTP3_SETTINGS0x4, "SETTINGS" },
348 { HTTP3_PUSH_PROMISE0x5, "PUSH_PROMISE" },
349 { 0x06, "Reserved" },
350 { HTTP3_GOAWAY0x7, "GOAWAY" },
351 { 0x08, "Reserved" },
352 { 0x09, "Reserved" },
353 { HTTP3_MAX_PUSH_ID0xD, "MAX_PUSH_ID" },
354 { 0x0e, "Reserved" }, // "DUPLICATE_PUSH" in draft-26 and before
355 /* 0x40 - 0x3FFFFFFFFFFFFFFF Assigned via Specification Required policy */
356 { HTTP3_WEBTRANSPORT_BISTREAM0x41, "WEBTRANSPORT_BISTREAM" }, // draft-ietf-webtrans-http3-03
357 { HTTP3_PRIORITY_UPDATE_REQUEST_STREAM0xF0700, "PRIORITY_UPDATE" }, // RFC 9218
358 { HTTP3_PRIORITY_UPDATE_PUSH_STREAM0xF0701, "PRIORITY_UPDATE" }, // RFC 9218
359 { 0, NULL((void*)0) }
360};
361
362/**
363 * Settings parameter type codes (62-bit code space).
364 * https://tools.ietf.org/html/draft-ietf-quic-http-29#name-http-2-settings-parameters
365 */
366#define HTTP3_QPACK_MAX_TABLE_CAPACITY0x01 0x01
367#define HTTP3_SETTINGS_MAX_FIELD_SECTION_SIZE0x06 0x06
368#define HTTP3_QPACK_BLOCKED_STREAMS0x07 0x07
369#define HTTP3_EXTENDED_CONNECT0x08 0x08 /* https://datatracker.ietf.org/doc/draft-ietf-httpbis-h3-websockets */
370#define HTTP3_H3_DATAGRAM0x33 0x33 /* rfc9297 */
371#define HTTP3_H3_DATAGRAM_DRAFT040xffd277 0xffd277 /* draft-ietf-masque-h3-datagram-04 */
372#define HTTP3_WEBTRANSPORT0x2b603742 0x2b603742 /* draft-ietf-webtrans-http3-03 */
373
374static const val64_string http3_settings_vals[] = {
375 { HTTP3_QPACK_MAX_TABLE_CAPACITY0x01, "Max Table Capacity" },
376 { HTTP3_SETTINGS_MAX_FIELD_SECTION_SIZE0x06, "Max Field Section Size" },
377 { HTTP3_QPACK_BLOCKED_STREAMS0x07, "Blocked Streams" },
378 { HTTP3_EXTENDED_CONNECT0x08, "Extended CONNECT" },
379 { HTTP3_WEBTRANSPORT0x2b603742, "Enable WebTransport" },
380 { HTTP3_H3_DATAGRAM0x33, "Enable Datagram" },
381 { HTTP3_H3_DATAGRAM_DRAFT040xffd277, "Enable Datagram Draft04" },
382 { 0, NULL((void*)0) }
383};
384
385/**
386 * QPACK encoder stream opcodes.
387 */
388#define QPACK_OPCODE_MASK0xE0 0xE0
389#define QPACK_OPCODE_INSERT_INDEXED0x80 0x80
390#define QPACK_OPCODE_INSERT0x40 0x40
391#define QPACK_OPCODE_SET_DTABLE_CAP0x20 0x20
392#define QPACK_OPCODE_DUPLICATE0x00 0x00
393
394/**
395 * QPACK decoder stream opcodes.
396 */
397#define QPACK_OPCODE_SECTION_ACK0x80 0x80
398#define QPACK_OPCODE_STREAM_CANCEL0x40 0x40
399#define QPACK_OPCODE_ICNT_INCREMENT0x00 0x00
400
401#define QPACK_HUFFMAN_5_STRING0x20 0x20
402#define QPACK_HUFFMAN_6_STRING0x40 0x40
403#define QPACK_HUFFMAN_7_STRINGq0x80 q0x80
404
405typedef enum _http3_stream_dir {
406 FROM_CLIENT_TO_SERVER = 0,
407 FROM_SERVER_TO_CLIENT = 1,
408} http3_stream_dir;
409
410/**
411 * Essential data structures.
412 */
413
414/**
415 * HTTP3 stream info - contains information about HTTP3 stream.
416 * HTTP3 streams roughly correspond to QUIC streams, with the
417 * HTTP3 Server Push being an exception to the rule.
418 */
419typedef struct _http3_stream_info {
420 uint64_t id; /**< HTTP3 stream id */
421 uint64_t uni_stream_type; /**< Unidirectional stream type */
422 uint64_t broken_from_offset; /**< Unrecognized stream starting at offset (if non-zero). */
423 http3_stream_dir direction;
424 wmem_list_t *request_header_data; /**< List of request header data */
425 wmem_list_t *response_header_data; /**< List of response header data */
426 const char *protocol; /**< Protocol from extended CONNECT */
427 dissector_handle_t next_handle; /**< Dissector for extended CONNECT protocol */
428 http_upgrade_info_t *upgrade_info; /**< Data for new protocol */
429 bool_Bool is_connect; /**< Method is CONNECT (plain or extended) */
430} http3_stream_info_t;
431
432/**
433 * HTTP3 session info - contains information about the HTTP3 session.
434 * HTTP3 sessions roughly correspond to QUIC connections, at least
435 * until the dissector will support connection migration and/or
436 * Multipath QUIC. When that happens, a single HTTP3 session would
437 * be mapped to multiple QUIC connections, or to multiple QUIC
438 * paths (in the MP-QUIC terminology).
439 */
440
441typedef void *qpack_decoder_t;
442typedef void *qpack_decoder_ctx_t;
443typedef struct _http3_session_info {
444 unsigned id;
445 qpack_decoder_t qpack_decoder[2]; /**< Decoders for outgoing/incoming QPACK streams. */
446 http3_stream_info_t *current_stream; /**< Currently processed stream */
447} http3_session_info_t;
448
449/**
450 * Lookup or create new HTTP3 session object for the pinfo.
451 */
452static http3_session_info_t *http3_session_lookup_or_create(packet_info *pinfo);
453
454/**
455 * HTTP3 Header dissection support.
456 */
457#define QPACK_MAX_DTABLE_SIZE65536 65536 /**< Max size of the QPACK dynamic table. */
458#define QPACK_MAX_BLOCKED512 512 /**< Upper limit on number of streams blocked on QPACK updates. */
459
460/**
461 * Limit the maximum header size to handle legitimate use cases while
462 * protecting against hostile traffic (in practice, decompression bombs,
463 * as libnghttp3 puts a limit on the compressed size of a single header.)
464 *
465 * Note that server limits tend to be lower than those supported by clients;
466 * some clients have supported hundreds of MiB of headers (?!) at least in
467 * the past. Chrome has had a consistent limit of 256 KiB. This is more than
468 * enough, but still reasonably fast. We shouldn't need to limit the number
469 * of headers after speeding up tvb_composite.
470 *
471 * https://stackoverflow.com/questions/686217/maximum-on-http-header-values
472 * https://stackoverflow.com/questions/1097651/is-there-a-practical-http-header-length-limit/
473 * https://stackoverflow.com/questions/3326210/can-http-headers-be-too-big-for-browsers
474 */
475#define QPACK_MAX_HEADER_SIZE1048576 1048576 /**< Max size of decompressed headers (1 MiB) */
476
477/**
478 * Header caching scheme
479 *
480 * The HTTP/3 headers are sent on the wire in QPACK-encoded form.
481 * To dissect the headers, Wireshark needs to keep the decoded
482 * header names and values in memory.
483 *
484 * To optimize dissection time, and to conserve memory
485 * the HTTP/3 dissector keeps all *unique* combinations
486 * of header-name, header-value in a cache.
487 *
488 * The cached values are stored in the "pstr" format:
489 * name length (uint32_t)
490 * name
491 * value length (uint32_t)
492 * value
493 */
494
495/**
496 * HTTP3 header field.
497 *
498 * The header field contains two sections:
499 * - encoded points to the location of the encoded field in the *original* packet TVB.
500 * - decoded points to the formatted header string, which is allocated in a cache map,
501 * to conserve memory.
502 * The decoded fields are used to create an auxiliary TVB which will
503 * be used for dissection of decoded header values.
504 */
505typedef struct _http3_header_field {
506 struct {
507 unsigned len; /**< Length of the encoded header field. */
508 unsigned offset; /**< Offset of the encoded header field in the decrypted TVB. */
509 } encoded;
510 struct {
511 const char *bytes; /**< Decoded header field bytes. */
512 unsigned len; /**< Length of the decoded header field. */
513 } decoded;
514} http3_header_field_t;
515
516/**
517 * HTTP3 encoded header data block.
518 *
519 * This helper structure is used to support header dissection.
520 */
521typedef struct _header_block_encoded_iter {
522 uint8_t *bytes;
523 uint32_t len;
524 uint32_t pos;
525} header_block_encoded_iter_t;
526
527#define HEADER_BLOCK_ENC_ITER_PTR(hdata)((hdata)->encoded.bytes == ((void*)0) ? ((void*)0) : ((hdata
)->encoded.pos == (hdata)->encoded.len) ? ((void*)0) : (
hdata)->encoded.bytes + (hdata)->encoded.pos)
\
528 ((hdata)->encoded.bytes == NULL((void*)0) \
529 ? NULL((void*)0) \
530 : ((hdata)->encoded.pos == (hdata)->encoded.len) ? NULL((void*)0) : (hdata)->encoded.bytes + (hdata)->encoded.pos)
531
532#define HEADER_BLOCK_ENC_ITER_REMAINING(hdata)((hdata)->encoded.bytes == ((void*)0) ? 0 : ((hdata)->encoded
.len - (hdata)->encoded.pos))
\
533 ((hdata)->encoded.bytes == NULL((void*)0) ? 0 : ((hdata)->encoded.len - (hdata)->encoded.pos))
534
535#define HEADER_BLOCK_ENC_ITER_INC(hdata, nread)do { if ((hdata)) { (hdata)->encoded.pos += (nread); ((void
) (((hdata)->encoded.pos <= (hdata)->encoded.len) ? (
void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-http3.c", 535, "(hdata)->encoded.pos <= (hdata)->encoded.len"
)))) ; } } while (0)
\
536 do { \
537 if ((hdata)) { \
538 (hdata)->encoded.pos += (nread); \
539 DISSECTOR_ASSERT((hdata)->encoded.pos <= (hdata)->encoded.len)((void) (((hdata)->encoded.pos <= (hdata)->encoded.len
) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-http3.c", 539, "(hdata)->encoded.pos <= (hdata)->encoded.len"
))))
; \
540 } \
541 } while (0)
542
543#define HTTP3_HD_DECODER_BLOCKED0x1 0x1
544#define HTTP3_HD_DECODER_ERROR0x2 0x2
545/**
546 * HTTP3 header data block.
547 *
548 * The data block corresponds to contents of a single HTTP3 HEADERS frame.
549 * If a packet contains multiple HTTP3 HEADERS frames,
550 * the corresponding blocks will be chained using the `next'
551 * pointer. In this case, individual headers blocks
552 * will be identified by the `offset' field.
553 */
554typedef struct _http3_header_data {
555#if 0
556 /* XXX - This doesn't seem to be used. Would this be any different
557 * than encoded.len ? */
558 uint32_t len; /**< Length of the encoded headers block. */
559#endif
560 uint32_t offset; /**< Offset of the headers block in the pinfo TVB. */
561 int32_t ds_idx; /**< Index of the data source tvb in the pinfo. */
562 uint16_t state; /**< See HTTP3_HD_DECODER_XXX above */
563 int16_t error; /**< Decoding error code if any. */
564 wmem_array_t * header_fields; /**< List of header fields contained in the header block. */
565 header_block_encoded_iter_t encoded; /**< Used for dissection, not allocated. */
566 struct _http3_header_data * next; /**< Next pointer in the chain. */
567 bool_Bool header_size_exceeded; /**< True if decoding halted due to excessive size. */
568} http3_header_data_t;
569
570
571#ifdef HAVE_NGHTTP31
572/* HTTP/3 pseudo-header fields.
573 *
574 * This is a convenience structure that is used
575 * to collect the values of the HTTP/3 pseudo-headers
576 * while constructing the protocol tree,
577 * and to construct the column info afterwards.
578 * https://www.ietf.org/archive/id/draft-ietf-quic-http-34.html#name-pseudo-header-fields
579 */
580typedef struct _http3_pseudo_header_fields {
581 const char *authority;
582 const char *method;
583 const char *path;
584 const char *protocol;
585 const char *reason_phrase; /**< "pseudo" pseudo-header. */
586 const char *scheme;
587 const char *status;
588} http3_pseudo_header_fields_t;
589
590#define HTTP3_PSEUDO_HEADERS_INITIALIZER(http3_pseudo_header_fields_t){ .authority = ((void*)0), .method
= ((void*)0), .path = ((void*)0), .protocol = ((void*)0), .reason_phrase
= ((void*)0), .scheme = ((void*)0), .status = ((void*)0), }
(http3_pseudo_header_fields_t){ \
591 .authority = NULL((void*)0), \
592 .method = NULL((void*)0), \
593 .path = NULL((void*)0), \
594 .protocol = NULL((void*)0), \
595 .reason_phrase = NULL((void*)0), \
596 .scheme = NULL((void*)0), \
597 .status = NULL((void*)0), \
598}
599#endif /* HAVE_NGHTTP3 */
600
601/* HTTP3 QPACK encoder state
602 *
603 * Store information about how many entries a QPACK encoder stream
604 * has inserted into the decoder at a particular point in the capture
605 * file (both the number newly inserted in the portion of the stream
606 * contained in the current QUIC packet and the total up to that point.)
607 * If a capture frame contains multiple encoder stream segments, the
608 * corresponding blocks will be chained using the 'next' pointer. In this
609 * case, individual blocks will be identified by the data source index
610 * of the tvb within the capture frame and the offset in the ds_tvb.
611 * (Both are necessary for multiple QUIC packets coalesced in a single
612 * UDP datagram with multiple stream segments within a QUIC packet.)
613 */
614typedef struct _http3_qpack_encoder_state {
615 unsigned offset; /**< Offset of the headers block in the pinfo TVB. */
616 int32_t ds_idx; /**< Index of the data source tvb in the pinfo. */
617 uint32_t icnt_inc; /**< Number of insertions in this header segment. */
618 uint64_t icnt; /**< Total number of insertions up to this point. */
619 ptrdiff_t nread; /**< Number of bytes read; if negative, an error code. */
620 struct _http3_qpack_encoder_state * next; /**< Next pointer in the chain. */
621} http3_qpack_encoder_state_t;
622
623/**
624 * File-scoped context.
625 * This data structure is used to maintain file-scoped
626 * lookup tables. It is reset when the file-scoped
627 * allocator is exited.
628 */
629typedef struct _http3_file_local_ctx {
630 wmem_map_t *conn_info_map;
631#ifdef HAVE_NGHTTP31
632 wmem_map_t *hdr_cache_map;
633#endif
634} http3_file_local_ctx;
635
636/**
637 * @function http3_get_file_local_ctx
638 * @abstract Will create a new instance for the first time
639 * the file is visited.
640 * This function is not intended to be invoked directly,
641 * but should be used via the `HTTP3_CONN_INFO_MAP` et. al. below.
642 * @returns file-local context.
643 */
644static http3_file_local_ctx *http3_get_file_local_ctx(void);
645
646#define HTTP3_CONN_INFO_MAPhttp3_get_file_local_ctx()->conn_info_map http3_get_file_local_ctx()->conn_info_map
647
648#ifdef HAVE_NGHTTP31
649#define HTTP3_HEADER_CACHEhttp3_get_file_local_ctx()->hdr_cache_map http3_get_file_local_ctx()->hdr_cache_map
650#endif
651
652/**
653 * Check whether the argument represents a reserved code point,
654 * for Stream Type, Frame Type, Error Code, etc.
655 */
656static inline bool_Bool
657http3_is_reserved_code(uint64_t stream_type)
658{
659 return (stream_type - 0x21) % 0x1f == 0;
660}
661
662/**
663 * Attempt to parse QUIC-encoded variable integer.
664 */
665static bool_Bool
666try_get_quic_varint(tvbuff_t *tvb, int offset, uint64_t *value, int *lenvar)
667{
668 if (tvb_reported_length_remaining(tvb, offset) == 0) {
669 return false0;
670 }
671 unsigned len = 1 << (tvb_get_uint8(tvb, offset) >> 6);
672 if (tvb_reported_length_remaining(tvb, offset) < len) {
673 return false0;
674 }
675 *lenvar = len;
676 if (value) {
677 unsigned n = tvb_get_varint(tvb, offset, -1, value, ENC_VARINT_QUIC0x00000004);
678 DISSECTOR_ASSERT_CMPINT(n, ==, len)((void) ((n == len) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion "
"n" " " "==" " " "len" " (" "%" "l" "d" " " "==" " " "%" "l"
"d" ")", "epan/dissectors/packet-http3.c", 678, (int64_t)n, (
int64_t)len))))
;
679 }
680 return true1;
681}
682
683/**
684 * Return the size of entire HTTP/3 frame.
685 */
686static int
687get_http3_frame_size(tvbuff_t *tvb, int offset)
688{
689 int type_size, length_size;
690 uint64_t frame_length;
691
692 if (!try_get_quic_varint(tvb, offset, NULL((void*)0), &type_size)) {
693 return 0;
694 }
695 offset += type_size;
696
697 if (!try_get_quic_varint(tvb, offset, &frame_length, &length_size)) {
698 return 0;
699 }
700
701 uint64_t frame_size = type_size + length_size + frame_length;
702 if (frame_size > INT32_MAX(2147483647)) {
703 // We do not support such large frames.
704 return 0;
705 }
706 return (int)frame_size;
707}
708
709/**
710 * Check whether the pinfo contains at least one whole HTTP3 frame,
711 * and adjust the pinfo desegmentation settings for the lower
712 * layer (QUIC, generally) to continue the desegmentation process.
713 */
714static bool_Bool
715http3_check_frame_size(tvbuff_t *tvb, packet_info *pinfo, int offset)
716{
717 int frame_size = get_http3_frame_size(tvb, offset);
718 int remaining = tvb_reported_length_remaining(tvb, offset);
719 if (frame_size && frame_size <= remaining) {
720 return true1;
721 }
722
723 pinfo->desegment_offset = offset;
724 pinfo->desegment_len = frame_size ? (frame_size - remaining) : DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
725 return false0;
726}
727
728static inline http3_stream_dir
729http3_packet_get_direction(quic_stream_info *stream_info)
730{
731 return stream_info->from_server
732 ? FROM_SERVER_TO_CLIENT
733 : FROM_CLIENT_TO_SERVER;
734}
735
736/**
737 * Functions to support decompression of HTTP3 headers.
738 */
739#ifdef HAVE_NGHTTP31
740/**
741 * File-scoped callback to release resources allocated for the QPACK
742 * decoder.
743 */
744static bool_Bool
745qpack_decoder_del_cb(wmem_allocator_t *allocator _U___attribute__((unused)), wmem_cb_event_t event _U___attribute__((unused)), void *user_data)
746{
747 nghttp3_qpack_decoder_del((nghttp3_qpack_decoder *)user_data);
748 return false0;
749}
750
751/**
752 * Memory allocation callbacks for nghttp3_qpack functionality.
753 */
754static void *
755http3_nghttp3_malloc(size_t size, void *user_data _U___attribute__((unused)))
756{
757 return wmem_alloc0(wmem_file_scope(), size);
758}
759
760static void
761http3_nghttp3_free(void *ptr, void *user_data _U___attribute__((unused)))
762{
763 wmem_free(wmem_file_scope(), ptr);
764}
765
766static void *
767http3_nghttp3_calloc(size_t nmemb, size_t size, void *user_data _U___attribute__((unused)))
768{
769 return wmem_alloc0(wmem_file_scope(), nmemb * size);
770}
771
772static void *
773http3_nghttp3_realloc(void *ptr, size_t size, void *user_data _U___attribute__((unused)))
774{
775 return wmem_realloc(wmem_file_scope(), ptr, size);
776}
777
778static nghttp3_mem g_qpack_mem_allocator = {
779 .malloc = http3_nghttp3_malloc,
780 .free = http3_nghttp3_free,
781 .calloc = http3_nghttp3_calloc,
782 .realloc = http3_nghttp3_realloc,
783};
784
785static nghttp3_mem *
786qpack_mem_allocator(wmem_allocator_t *allocator _U___attribute__((unused)), int debug _U___attribute__((unused)))
787{
788 nghttp3_mem *mem;
789 mem = &g_qpack_mem_allocator;
790 return mem;
791}
792
793/**
794 * Initialization routine for the http3_session object.
795 * Invoked during the creation of the new http3_session.
796 */
797static void
798http3_initialize_qpack_decoders(http3_session_info_t *http3_session)
799{
800 for (int dir = 0; dir < 2; dir++) {
801 nghttp3_qpack_decoder **pdecoder = (nghttp3_qpack_decoder **)&(http3_session->qpack_decoder[dir]);
802 nghttp3_qpack_decoder_new(pdecoder, QPACK_MAX_DTABLE_SIZE65536, QPACK_MAX_BLOCKED512,
803 qpack_mem_allocator(wmem_file_scope(), 1));
804 nghttp3_qpack_decoder_set_max_dtable_capacity(*pdecoder, QPACK_MAX_DTABLE_SIZE65536);
805 wmem_register_callback(wmem_file_scope(), qpack_decoder_del_cb, *pdecoder);
806 }
807}
808
809static GHashTable *header_fields_hash;
810
811static const char *
812cid_to_string(const quic_cid_t *cid, wmem_allocator_t *scope)
813{
814 if (cid->len == 0) {
815 return "(none)";
816 }
817 char *str = (char *)wmem_alloc0(scope, 2 * cid->len + 1);
818 bytes_to_hexstr(str, cid->cid, cid->len);
819 return str;
820}
821
822static http3_header_data_t *
823http3_get_header_data(packet_info *pinfo, tvbuff_t *tvb, unsigned offset)
824{
825 http3_header_data_t *data, *prev = NULL((void*)0);
826
827 unsigned raw_offset = tvb_raw_offset(tvb) + offset;
828 /* The raw offset is relative to the original data source, which is
829 * the decrypted QUIC packet. There can be multiple decrypted QUIC
830 * packets in a single QUIC layer, so this guarantees the same raw
831 * offset from different decrypted data gives different keys.
832 */
833 int32_t ds_idx = get_data_source_index_by_tvb(pinfo, tvb_get_ds_tvb(tvb));
834 DISSECTOR_ASSERT(ds_idx >= 0)((void) ((ds_idx >= 0) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 834, "ds_idx >= 0"))))
;
835
836 data = (http3_header_data_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_http3, PROTO_DATA_KEY_HEADER0);
837
838 /*
839 * Attempt to find existing header data block.
840 * In most cases, data will be `NULL'
841 * and this loop won't be visited.
842 */
843 while (data != NULL((void*)0)) {
844 if (data->offset == raw_offset && data->ds_idx == ds_idx) {
845 /*
846 * We found the matching data. Return it.
847 */
848 return data;
849 }
850 prev = data;
851 data = data->next;
852 }
853
854 /*
855 * We did not find header data matching the offset.
856 * Allocate a new header data block, and initialize
857 * the offset marker.
858 */
859 data = wmem_new0(wmem_file_scope(), http3_header_data_t)((http3_header_data_t*)wmem_alloc0((wmem_file_scope()), sizeof
(http3_header_data_t)))
;
860 data->offset = raw_offset;
861 data->ds_idx = ds_idx;
862
863 /*
864 * Check whether the newly allocated data should be linked
865 * to the tail of existing header block chain, or whether
866 * it is the head of a new header block chain.
867 */
868 if (prev != NULL((void*)0)) {
869 prev->next = data;
870 } else {
871 p_add_proto_data(wmem_file_scope(), pinfo, proto_http3, PROTO_DATA_KEY_HEADER0, data);
872 }
873
874 return data;
875}
876
877static http3_qpack_encoder_state_t *
878http3_get_qpack_encoder_state(packet_info *pinfo, tvbuff_t *tvb, unsigned offset)
879{
880 http3_qpack_encoder_state_t *data, *prev = NULL((void*)0);
881
882 unsigned raw_offset = tvb_raw_offset(tvb) + offset;
883 /* The raw offset is relative to the original data source, which is
884 * the decrypted QUIC packet. There can be multiple decrypted QUIC
885 * packets in a single QUIC layer, so this guarantees the same raw
886 * offset from different decrypted data gives different keys.
887 */
888 int32_t ds_idx = get_data_source_index_by_tvb(pinfo, tvb_get_ds_tvb(tvb));
889 DISSECTOR_ASSERT(ds_idx >= 0)((void) ((ds_idx >= 0) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 889, "ds_idx >= 0"))))
;
890
891 data = (http3_qpack_encoder_state_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_http3, PROTO_DATA_KEY_QPACK1);
892
893 /*
894 * Attempt to find existing header data block.
895 * In most cases, data will be `NULL'
896 * and this loop won't be visited.
897 */
898 while (data != NULL((void*)0)) {
899 if (data->offset == raw_offset && data->ds_idx == ds_idx) {
900 /*
901 * We found the matching data. Return it.
902 */
903 return data;
904 }
905 prev = data;
906 data = data->next;
907 }
908
909 /*
910 * We did not find header data matching the offset.
911 * Allocate a new header data block, and initialize
912 * the offset marker.
913 */
914 data = wmem_new0(wmem_file_scope(), http3_qpack_encoder_state_t)((http3_qpack_encoder_state_t*)wmem_alloc0((wmem_file_scope()
), sizeof(http3_qpack_encoder_state_t)))
;
915 data->offset = raw_offset;
916 data->ds_idx = ds_idx;
917
918 /*
919 * Check whether the newly allocated data should be linked
920 * to the tail of existing header block chain, or whether
921 * it is the head of a new header block chain.
922 */
923 if (prev != NULL((void*)0)) {
924 prev->next = data;
925 } else {
926 p_add_proto_data(wmem_file_scope(), pinfo, proto_http3, PROTO_DATA_KEY_QPACK1, data);
927 }
928
929 return data;
930}
931
932static proto_item *
933try_add_named_header_field(proto_tree *tree, tvbuff_t *tvb, int offset, uint32_t length, const char *header_name,
934 const char *header_value)
935{
936 int hf_id;
937 header_field_info *hfi;
938 proto_item *ti = NULL((void*)0);
939
940 const int *entry = (const int *)g_hash_table_lookup(header_fields_hash, header_name);
941 if (entry == NULL((void*)0)) {
942 return NULL((void*)0);
943 }
944
945 hf_id = *entry;
946
947 hfi = proto_registrar_get_nth(hf_id);
948 DISSECTOR_ASSERT(hfi != NULL)((void) ((hfi != ((void*)0)) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 948, "hfi != ((void*)0)"))))
;
949
950 if (FT_IS_UINT32(hfi->type)((hfi->type) == FT_CHAR || (hfi->type) == FT_UINT8 || (
hfi->type) == FT_UINT16 || (hfi->type) == FT_UINT24 || (
hfi->type) == FT_UINT32 || (hfi->type) == FT_FRAMENUM)
) {
951 uint32_t value;
952 if (ws_strtou32(header_value, NULL((void*)0), &value)) {
953 ti = proto_tree_add_uint(tree, hf_id, tvb, offset, length, value);
954 }
955 } else if (FT_IS_UINT(hfi->type)(((hfi->type) == FT_CHAR || (hfi->type) == FT_UINT8 || (
hfi->type) == FT_UINT16 || (hfi->type) == FT_UINT24 || (
hfi->type) == FT_UINT32 || (hfi->type) == FT_FRAMENUM) ||
((hfi->type) == FT_UINT40 || (hfi->type) == FT_UINT48 ||
(hfi->type) == FT_UINT56 || (hfi->type) == FT_UINT64))
) {
956 uint64_t value;
957 if (ws_strtou64(header_value, NULL((void*)0), &value)) {
958 ti = proto_tree_add_uint64(tree, hf_id, tvb, offset, length, value);
959 }
960 } else {
961 ti = proto_tree_add_item(tree, hf_id, tvb, offset, length, ENC_BIG_ENDIAN0x00000000);
962 }
963 return ti;
964}
965
966static void
967get_header_field_pstr(wmem_allocator_t *scratch, nghttp3_qpack_nv *header_nv, const char **outp, uint32_t *outlen)
968{
969 char *pstr; /* The returned pstr, always from the cache. */
970 uint32_t pstr_len; /* The length of `pstr'. */
971 nghttp3_vec namev; /* Vector holding the bytes of the field's name. */
972 char *name; /* Typed pointer to field's name. */
973 uint32_t name_len; /* Field's name length. */
974 nghttp3_vec valuev; /* Vector holding the bytes of the field's value. */
975 char *value; /* Typed pointer to field's value. */
976 uint32_t value_len; /* Field's value length. */
977
978 uint8_t *scratch_buffer;
979
980 /* Extract the vectors from `header_nv'. */
981 namev = nghttp3_rcbuf_get_buf(header_nv->name);
982 name = (char *)namev.base;
983 name_len = (uint32_t)namev.len;
984 valuev = nghttp3_rcbuf_get_buf(header_nv->value);
985 value = (char *)valuev.base;
986 value_len = (uint32_t)valuev.len;
987
988 ws_debug("HTTP header: %.*s: %.*s", name_len, name, value_len, value)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 988, __func__, "HTTP header: %.*s: %.*s", name_len, name, value_len
, value); } } while (0)
;
989
990 /* Construct the pstr in the scratch buffer.
991 * The pstr format is described in the "Header caching scheme"
992 * comment above.
993 */
994 pstr_len = (4 + name_len) + (4 + value_len);
995 scratch_buffer = (uint8_t *)wmem_alloc(scratch, pstr_len);
996 phtonu32(&scratch_buffer[0], name_len);
997 memcpy(&scratch_buffer[4], name, name_len);
998 phtonu32(&scratch_buffer[4 + name_len], value_len);
999 memcpy(&scratch_buffer[4 + name_len + 4], value, value_len);
1000
1001 /* Check whether the pstr is already in the cache,
1002 * or allocate a new entry. */
1003 pstr = (char *)wmem_map_lookup(HTTP3_HEADER_CACHEhttp3_get_file_local_ctx()->hdr_cache_map, scratch_buffer);
1004 if (pstr == NULL((void*)0)) {
1005 pstr = (char *)wmem_memdup(wmem_file_scope(), scratch_buffer, pstr_len);
1006 wmem_map_insert(HTTP3_HEADER_CACHEhttp3_get_file_local_ctx()->hdr_cache_map, pstr, pstr);
1007 }
1008
1009 /* Decrement `nv' reference counts to avoid memory leaks. */
1010 nghttp3_rcbuf_decref(header_nv->name);
1011 nghttp3_rcbuf_decref(header_nv->value);
1012
1013 *outp = pstr;
1014 *outlen = pstr_len;
1015}
1016
1017static const char*
1018http3_get_header_value(packet_info *pinfo, const char* name, bool_Bool the_other_direction) {
1019 wmem_list_t *header_data_list;
1020 wmem_list_frame_t *frame;
1021 http3_header_data_t *header_data;
1022 http3_session_info_t *http3_session = http3_session_lookup_or_create(pinfo);
1023 http3_stream_info_t *http3_stream = http3_session->current_stream;
1024
1025 if (!http3_stream) {
1026 return NULL((void*)0);
1027 }
1028
1029 if ((http3_stream->direction && the_other_direction) || (!http3_stream->direction && !the_other_direction)) {
1030 header_data_list = http3_stream->request_header_data;
1031 } else {
1032 header_data_list = http3_stream->response_header_data;
1033 }
1034
1035 if (!header_data_list) {
1036 return NULL((void*)0);
1037 }
1038
1039 for (frame = wmem_list_head(header_data_list);
1040 frame;
1041 frame = wmem_list_frame_next(frame))
1042 {
1043 header_data = (http3_header_data_t*)wmem_list_frame_data(frame);
1044 if (!header_data) {
1045 continue;
1046 }
1047 for (unsigned i = 0; i < wmem_array_get_count(header_data->header_fields); ++i) {
1048 http3_header_field_t *in;
1049 uint32_t name_len;
1050 in = (http3_header_field_t *)wmem_array_index(header_data->header_fields, i);
1051 name_len = pntohu32(in->decoded.bytes);
1052 if (strlen(name) == name_len && strncmp(in->decoded.bytes + 4, name, name_len) == 0) {
1053 return (const char*)get_ascii_string(pinfo->pool,
1054 (uint8_t*)in->decoded.bytes + 4 + name_len + 4,
1055 pntohu32(in->decoded.bytes + 4 + name_len));
1056 }
1057 }
1058 }
1059 return NULL((void*)0);
1060}
1061
1062static int
1063dissect_http3_headers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned tvb_offset, unsigned offset,
1064 quic_stream_info *stream_info, http3_stream_info_t *http3_stream)
1065{
1066 http3_header_data_t *header_data; /* The decoded header data block; populated on the first pass. */
1067 http3_session_info_t *http3_session; /* The corresponding HTTP/3 session. */
1068 tvbuff_t *header_tvb; /* Composite TVB containing the decoded header fields. */
1069 unsigned header_len; /* Total length of the decoded header fields. */
1070 int hoffset; /* Offset of a decoded header in the decoded TVB */
1071 proto_item *ti; /* Temporary tree item; used in multiple ways when constructing proto trees. */
1072 http3_pseudo_header_fields_t pseudo_headers; /* Pseudo-header values; populated when building proto trees; used when creating column info. */
1073
1074 http3_session = http3_session_lookup_or_create(pinfo);
1075 header_data = http3_get_header_data(pinfo, tvb, offset);
1076
1077 ws_noisy("pdinfo visited=%d", PINFO_FD_VISITED(pinfo))do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 1077, __func__, "pdinfo visited=%d", ((pinfo)->fd->visited
)); } } while (0)
;
1078
1079 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1080 nghttp3_qpack_decoder *decoder;
1081 int length = 0;
1082 http3_stream_dir packet_direction;
1083
1084 /*
1085 * This packet has not been processed yet, which means this is
1086 * the first linear scan. We do header decompression only
1087 * once in linear scan and cache the result. If we don't
1088 * cache, already processed data will be fed into decompressor
1089 * again and again since dissector will be called randomly.
1090 * This makes context out-of-sync.
1091 */
1092
1093 length = tvb_reported_length_remaining(tvb, tvb_offset);
1094 packet_direction = http3_packet_get_direction(stream_info);
1095 decoder = http3_session->qpack_decoder[packet_direction];
1096
1097 DISSECTOR_ASSERT(decoder)((void) ((decoder) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-http3.c", 1097, "decoder"))))
;
1098 DISSECTOR_ASSERT(header_data)((void) ((header_data) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 1098, "header_data"))))
;
1099 DISSECTOR_ASSERT(header_data->encoded.bytes == NULL)((void) ((header_data->encoded.bytes == ((void*)0)) ? (void
)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-http3.c", 1099, "header_data->encoded.bytes == ((void*)0)"
))))
;
1100 DISSECTOR_ASSERT(header_data->encoded.len == 0)((void) ((header_data->encoded.len == 0) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 1100, "header_data->encoded.len == 0"))))
;
1101 DISSECTOR_ASSERT(header_data->header_fields == NULL)((void) ((header_data->header_fields == ((void*)0)) ? (void
)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-http3.c", 1101, "header_data->header_fields == ((void*)0)"
))))
;
1102
1103 header_data->encoded.bytes = tvb_memdup(wmem_file_scope(), tvb, tvb_offset, length);
1104 header_data->encoded.pos = 0;
1105 header_data->encoded.len = length;
1106
1107 nghttp3_qpack_stream_context *sctx = NULL((void*)0);
1108 nghttp3_qpack_stream_context_new(&sctx, http3_stream->id, nghttp3_mem_default());
1109
1110 ws_debug("Header data: %p %d %d", header_data->encoded.bytes, header_data->encoded.pos,do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 1111, __func__, "Header data: %p %d %d", header_data->encoded
.bytes, header_data->encoded.pos, header_data->encoded.
len); } } while (0)
1111 header_data->encoded.len)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 1111, __func__, "Header data: %p %d %d", header_data->encoded
.bytes, header_data->encoded.pos, header_data->encoded.
len); } } while (0)
;
1112
1113 header_len = 0;
1114
1115 /*
1116 * Attempt to decode headers.
1117 *
1118 * TODO: This may incorrectly put headers that were blocked
1119 * for packet k in the past to this packet n. We will deal with this later
1120 */
1121 while (HEADER_BLOCK_ENC_ITER_REMAINING(header_data)((header_data)->encoded.bytes == ((void*)0) ? 0 : ((header_data
)->encoded.len - (header_data)->encoded.pos))
) {
1122 nghttp3_qpack_nv nv;
1123 uint8_t flags;
1124
1125 if (header_len >= QPACK_MAX_HEADER_SIZE1048576) {
1126 header_data->header_size_exceeded = true1;
1127 break;
1128 }
1129
1130 ws_noisy("%p %p:%d decode decoder=%p sctx=%p", header_data->encoded.bytes,do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 1132, __func__, "%p %p:%d decode decoder=%p sctx=%p", header_data
->encoded.bytes, ((header_data)->encoded.bytes == ((void
*)0) ? ((void*)0) : ((header_data)->encoded.pos == (header_data
)->encoded.len) ? ((void*)0) : (header_data)->encoded.bytes
+ (header_data)->encoded.pos), ((header_data)->encoded
.bytes == ((void*)0) ? 0 : ((header_data)->encoded.len - (
header_data)->encoded.pos)), decoder, sctx); } } while (0)
1131 HEADER_BLOCK_ENC_ITER_PTR(header_data),do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 1132, __func__, "%p %p:%d decode decoder=%p sctx=%p", header_data
->encoded.bytes, ((header_data)->encoded.bytes == ((void
*)0) ? ((void*)0) : ((header_data)->encoded.pos == (header_data
)->encoded.len) ? ((void*)0) : (header_data)->encoded.bytes
+ (header_data)->encoded.pos), ((header_data)->encoded
.bytes == ((void*)0) ? 0 : ((header_data)->encoded.len - (
header_data)->encoded.pos)), decoder, sctx); } } while (0)
1132 HEADER_BLOCK_ENC_ITER_REMAINING(header_data), decoder, sctx)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 1132, __func__, "%p %p:%d decode decoder=%p sctx=%p", header_data
->encoded.bytes, ((header_data)->encoded.bytes == ((void
*)0) ? ((void*)0) : ((header_data)->encoded.pos == (header_data
)->encoded.len) ? ((void*)0) : (header_data)->encoded.bytes
+ (header_data)->encoded.pos), ((header_data)->encoded
.bytes == ((void*)0) ? 0 : ((header_data)->encoded.len - (
header_data)->encoded.pos)), decoder, sctx); } } while (0)
;
1133
1134 int32_t nread = (int32_t)nghttp3_qpack_decoder_read_request(decoder, sctx, &nv, &flags,
1135 HEADER_BLOCK_ENC_ITER_PTR(header_data)((header_data)->encoded.bytes == ((void*)0) ? ((void*)0) :
((header_data)->encoded.pos == (header_data)->encoded.
len) ? ((void*)0) : (header_data)->encoded.bytes + (header_data
)->encoded.pos)
,
1136 HEADER_BLOCK_ENC_ITER_REMAINING(header_data)((header_data)->encoded.bytes == ((void*)0) ? 0 : ((header_data
)->encoded.len - (header_data)->encoded.pos))
, 1);
1137 /*
1138 * Check for decoding errors.
1139 */
1140 if (nread < 0) {
1141 header_data->state = HTTP3_HD_DECODER_ERROR0x2;
1142 header_data->error = nread;
1143 ws_debug("Early return nread=%d err=%s", nread, nghttp3_strerror(nread))do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 1143, __func__, "Early return nread=%d err=%s", nread, nghttp3_strerror
(nread)); } } while (0)
;
1144 break;
1145 }
1146
1147 /*
1148 * Check whether the QPACK decoder is blocked on QPACK encoder stream.
1149 */
1150 if (flags & NGHTTP3_QPACK_DECODE_FLAG_BLOCKED0x04u) {
1151 uint64_t wicnt, ricnt;
1152
1153 header_data->state = HTTP3_HD_DECODER_BLOCKED0x1;
1154 ricnt = nghttp3_qpack_stream_context_get_ricnt(sctx);
1155 wicnt = nghttp3_qpack_decoder_get_icnt(decoder);
1156 ws_debug("Early return nread=%d blocked=%" PRIu8 " ricnt=%" PRIu64 " wicnt=%" PRIu64,do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 1157, __func__, "Early return nread=%d blocked=%" "hhu" " ricnt=%"
"l" "u" " wicnt=%" "l" "u", nread, flags, ricnt, wicnt); } }
while (0)
1157 nread, flags, ricnt, wicnt)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 1157, __func__, "Early return nread=%d blocked=%" "hhu" " ricnt=%"
"l" "u" " wicnt=%" "l" "u", nread, flags, ricnt, wicnt); } }
while (0)
;
1158 break;
1159 }
1160
1161 /*
1162 * Check whether the decoder has emitted header data.
1163 */
1164 if (flags & NGHTTP3_QPACK_DECODE_FLAG_EMIT0x01u) {
1165 http3_header_field_t *out;
1166
1167 ws_noisy("Emit nread=%d flags=%" PRIu8 "", nread, flags)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 1167, __func__, "Emit nread=%d flags=%" "hhu" "", nread, flags
); } } while (0)
;
1168
1169 /* Create an output field and add it to the headers array */
1170 out = wmem_new0(wmem_file_scope(), http3_header_field_t)((http3_header_field_t*)wmem_alloc0((wmem_file_scope()), sizeof
(http3_header_field_t)))
;
1171
1172 /* Populate the `encoded' portion. */
1173 out->encoded.len = nread;
1174 out->encoded.offset = header_data->encoded.pos;
1175
1176 /* Populate the `decoded' portion. */
1177 get_header_field_pstr(pinfo->pool, &nv, &out->decoded.bytes, &out->decoded.len);
1178
1179 /* Add the decoded header field to the header data. */
1180 if (header_data->header_fields == NULL((void*)0)) {
1181 header_data->header_fields = wmem_array_new(wmem_file_scope(), sizeof(http3_header_field_t));
1182 }
1183 wmem_array_append(header_data->header_fields, out, 1);
1184
1185 header_len += out->decoded.len;
1186
1187 } else {
1188 proto_tree_add_expert_format(tree, pinfo, &ei_http3_header_decoding_no_output, tvb, tvb_offset, 0,
1189 "QPACK - nothing emitted decoder %p ctx %p flags %" PRIu8"hhu" " error %d (%s)",
1190 decoder, sctx, flags, nread, nghttp3_strerror((int)nread));
1191 }
1192
1193 /*
1194 * Check whether the QPACK decoder has finished.
1195 */
1196 if (nread == 0 || (flags & NGHTTP3_QPACK_DECODE_FLAG_FINAL0x02u)) {
1197 break;
1198 }
1199
1200 HEADER_BLOCK_ENC_ITER_INC(header_data, nread)do { if ((header_data)) { (header_data)->encoded.pos += (nread
); ((void) (((header_data)->encoded.pos <= (header_data
)->encoded.len) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-http3.c", 1200, "(header_data)->encoded.pos <= (header_data)->encoded.len"
)))) ; } } while (0)
;
1201 }
1202 nghttp3_qpack_stream_context_del(sctx);
1203
1204 if (stream_info->from_server) {
1205 if (!http3_stream->response_header_data) {
1206 http3_stream->response_header_data = wmem_list_new(wmem_file_scope());
1207 }
1208 wmem_list_append(http3_stream->response_header_data, header_data);
1209 } else {
1210 if (!http3_stream->request_header_data) {
1211 http3_stream->request_header_data = wmem_list_new(wmem_file_scope());
1212 }
1213 wmem_list_append(http3_stream->request_header_data, header_data);
1214 }
1215 }
1216
1217 /* Check if any expert information fields have to be added.
1218 */
1219 if (header_data->state == HTTP3_HD_DECODER_ERROR0x2) {
1220 proto_tree_add_expert_format(tree, pinfo, &ei_http3_header_decoding_failed, tvb, tvb_offset, 0,
1221 "QPACK decoding error %d (%s)",
1222 header_data->error, nghttp3_strerror(header_data->error));
1223 } else if (header_data->state == HTTP3_HD_DECODER_BLOCKED0x1) {
1224 ti = proto_tree_add_boolean(tree, hf_http3_header_qpack_blocked, tvb, tvb_offset, 0, true1);
1225 proto_item_set_generated(ti);
1226 proto_tree_add_expert_format(tree, pinfo, &ei_http3_header_decoding_blocked, tvb, tvb_offset, 0,
1227 "QPACK decoding blocked");
1228 }
1229
1230 if (header_data->encoded.pos < tvb_offset && header_data->encoded.len != 0) {
1231 proto_tree_add_expert_format(tree, pinfo, &ei_http3_header_encoded_state, tvb, tvb_offset, 0,
1232 "HTTP3 encoded headers - bytes %p pos %d len %d", header_data->encoded.bytes,
1233 header_data->encoded.pos, header_data->encoded.len);
1234 }
1235
1236 if ((header_data->header_fields == NULL((void*)0)) || (wmem_array_get_count(header_data->header_fields) == 0)) {
1237 return tvb_offset;
1238 }
1239
1240 /* Header data contains decoded header values; start building the protocol trees. */
1241 header_tvb = tvb_new_composite();
1242 header_len = 0;
1243 hoffset = 0;
1244 pseudo_headers = HTTP3_PSEUDO_HEADERS_INITIALIZER(http3_pseudo_header_fields_t){ .authority = ((void*)0), .method
= ((void*)0), .path = ((void*)0), .protocol = ((void*)0), .reason_phrase
= ((void*)0), .scheme = ((void*)0), .status = ((void*)0), }
;
1245
1246 for (unsigned i = 0; i < wmem_array_get_count(header_data->header_fields); ++i) {
1247 http3_header_field_t *in;
1248 tvbuff_t *next_tvb;
1249
1250 in = (http3_header_field_t *)wmem_array_index(header_data->header_fields, i);
1251 header_len += in->decoded.len;
1252
1253 /* Now setup the tvb buffer to have the new data */
1254 next_tvb = tvb_new_child_real_data(tvb, (uint8_t*)in->decoded.bytes, in->decoded.len, in->decoded.len);
1255 tvb_composite_append(header_tvb, next_tvb);
1256 }
1257
1258 tvb_composite_finalize(header_tvb);
1259 add_new_data_source(pinfo, header_tvb, "Decompressed Header");
1260
1261 ti = proto_tree_add_uint(tree, hf_http3_headers_decoded_length, header_tvb, hoffset, 1, header_len);
1262 proto_item_set_generated(ti);
1263 if (header_data->header_size_exceeded) {
1264 expert_add_info(pinfo, ti, &ei_http3_header_size);
1265 }
1266
1267 ti = proto_tree_add_uint(tree, hf_http3_headers_count, header_tvb, hoffset, 1,
1268 wmem_array_get_count(header_data->header_fields));
1269 proto_item_set_generated(ti);
1270
1271 wmem_strbuf_t *headers_buf = wmem_strbuf_create(pinfo->pool)wmem_strbuf_new(pinfo->pool, "");
1272 wmem_strbuf_t *header_buf;
1273
1274 for (unsigned i = 0; i < wmem_array_get_count(header_data->header_fields); ++i) {
1275 http3_header_field_t *in;
1276 proto_item *ti_named_field;
1277 proto_item *header;
1278 proto_tree *header_tree;
1279 uint32_t header_name_length;
1280 const char *header_name;
1281 uint32_t header_value_length;
1282 const char *header_value;
1283
1284 in = (http3_header_field_t *)wmem_array_index(header_data->header_fields, i);
1285
1286 /* Populate tree with header name/value details. */
1287 /* Add 'Header' subtree with description. */
1288 header = proto_tree_add_item(tree, hf_http3_header, tvb, tvb_offset, in->encoded.len, ENC_NA0x00000000);
1289
1290 header_tree = proto_item_add_subtree(header, ett_http3_headers);
1291
1292 /* header value length */
1293 proto_tree_add_item_ret_uint(header_tree, hf_http3_header_name_length, header_tvb, hoffset, 4,
1294 ENC_BIG_ENDIAN0x00000000, &header_name_length);
1295 hoffset += 4;
1296
1297 /* Add header name. */
1298 proto_tree_add_item_ret_string(header_tree, hf_http3_header_name, header_tvb, hoffset, header_name_length,
1299 ENC_ASCII0x00000000 | ENC_NA0x00000000, pinfo->pool, (const uint8_t**)&header_name);
1300 hoffset += header_name_length;
1301
1302 /* header value length */
1303 proto_tree_add_item_ret_uint(header_tree, hf_http3_header_value_length, header_tvb, hoffset, 4,
1304 ENC_BIG_ENDIAN0x00000000, &header_value_length);
1305 hoffset += 4;
1306
1307 /* Add header value. */
1308 proto_tree_add_item_ret_string(header_tree, hf_http3_header_value, header_tvb, hoffset, header_value_length,
1309 ENC_ASCII0x00000000 | ENC_NA0x00000000, pinfo->pool, (const uint8_t**)&header_value);
1310
1311 ti_named_field = try_add_named_header_field(header_tree, header_tvb, hoffset, header_value_length, header_name,
1312 header_value);
1313
1314 hoffset += header_value_length;
1315
1316 /* Create a buffer of one header name and value per line to resemble
1317 * text-based HTTP for adding to Follow Stream. The header_tvb already
1318 * created has the string lengths and lacks newlines. */
1319 header_buf = wmem_strbuf_new(pinfo->pool, header_name);
1320 wmem_strbuf_append_printf(header_buf, ": %s", header_value);
1321 proto_item_append_text(header, ": %s", wmem_strbuf_get_str(header_buf));
1322 wmem_strbuf_append_printf(headers_buf, "%s\n", wmem_strbuf_finalize(header_buf));
1323
1324 /* Collect the pseudo-header values to be used later. */
1325 /* XXX - We could save other headers to possibly save parsing
1326 * later, see HTTP/2 populate_http_header_tracking */
1327 if (strcmp(header_name, HTTP3_HEADER_NAME_METHOD":method") == 0) {
1328 pseudo_headers.method = header_value;
1329 } else if (strcmp(header_name, HTTP3_HEADER_NAME_PROTOCOL":protocol") == 0) {
1330 pseudo_headers.protocol = header_value;
1331 } else if (strcmp(header_name, HTTP3_HEADER_NAME_PATH":path") == 0) {
1332 pseudo_headers.path = header_value;
1333 http_add_path_components_to_tree(header_tvb, pinfo, ti_named_field, hoffset - header_value_length,
1334 header_value_length);
1335 } else if (strcmp(header_name, HTTP3_HEADER_NAME_AUTHORITY":authority") == 0) {
1336 pseudo_headers.authority = header_value;
1337 } else if (strcmp(header_name, HTTP3_HEADER_NAME_SCHEME":scheme") == 0) {
1338 pseudo_headers.scheme = header_value;
1339 } else if (strcmp(header_name, HTTP3_HEADER_NAME_STATUS":status") == 0) {
1340 unsigned status_code;
1341
1342 status_code = (unsigned)strtoul(header_value, NULL((void*)0), 10);
1343 pseudo_headers.status = header_value;
1344 pseudo_headers.reason_phrase = val_to_str_const(status_code, vals_http_status_code, "Unknown");
1345 proto_item_append_text(header_tree, " %s", pseudo_headers.reason_phrase);
1346 proto_item_append_text(tree, ", %s %s", pseudo_headers.status, pseudo_headers.reason_phrase);
1347 } else if (strcmp(header_name, HTTP3_HEADER_NAME_TRANSFER_ENCODING"transfer-encoding") == 0) {
1348 /* The Transfer-Encoding header field MUST NOT be used.
1349 * https://www.rfc-editor.org/rfc/rfc9114.html#section-4.1-11 */
1350 expert_add_info(pinfo, header, &ei_http3_header_transfer_encoding);
1351 }
1352
1353 tvb_offset += in->encoded.len;
1354 }
1355
1356 if (have_tap_listener(http3_follow_tap)) {
1357 quic_follow_tap_data_t *follow_data = wmem_new0(pinfo->pool, quic_follow_tap_data_t)((quic_follow_tap_data_t*)wmem_alloc0((pinfo->pool), sizeof
(quic_follow_tap_data_t)))
;
1358
1359 wmem_strbuf_append(headers_buf, "\n");
1360 follow_data->tvb = tvb_new_child_real_data(header_tvb,
1361 (const uint8_t*)wmem_strbuf_get_str(headers_buf),
1362 (unsigned)wmem_strbuf_get_len(headers_buf),
1363 (unsigned)wmem_strbuf_get_len(headers_buf));
1364 follow_data->stream_id = http3_stream->id;
1365 follow_data->from_server = stream_info->from_server;
1366
1367 tap_queue_packet(http3_follow_tap, pinfo, follow_data);
1368 }
1369
1370 /* We have finished constructing the tree for the header fields.
1371 * Proceed to determine whether this is a variant of the CONNECT
1372 * method and to update the `hf_http3_header_request_full_uri'
1373 * and the info column display accordingly.
1374 */
1375 if (pseudo_headers.method != NULL((void*)0)) {
1376 proto_item *ti_url;
1377 char *uri;
1378 bool_Bool authority_contains_target = false0;
1379
1380 if (strcmp(pseudo_headers.method, "CONNECT") == 0) {
1381 /* This is a variant of CONNECT method.
1382 * Supported variants:
1383 * 1. "Plain CONNECT"
1384 * https://www.rfc-editor.org/rfc/rfc7231#section-4.3.6
1385 * 2. "Extended CONNECT"
1386 * https://www.rfc-editor.org/rfc/rfc9298.html#section-2
1387 * https://www.rfc-editor.org/rfc/rfc9298.html#section-3.4
1388 * https://www.rfc-editor.org/rfc/rfc8441.html#section-4
1389 *
1390 * "Plain CONNECT" utilizes the `:authority' pseudo-header as
1391 * the connection target.
1392 * The "Extended CONNECT" uses the pseudo-headers
1393 * in the same way as other HTTP methods.
1394 */
1395 http3_stream->is_connect = true1;
1396 if (pseudo_headers.protocol == NULL((void*)0)) {
1397 /* This is the plain CONNECT method
1398 * https://www.rfc-editor.org/rfc/rfc7231#section-4.3.6
1399 *
1400 * Pseudo-header semantics:
1401 * `:method' contains "CONNECT"
1402 * `:authority' contains the target host and port
1403 * `:scheme' and `:path' MUST be empty
1404 */
1405 authority_contains_target = true1;
1406 } else if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1407 http3_stream->protocol = wmem_strdup(wmem_file_scope(), pseudo_headers.protocol);
1408 http3_stream->next_handle = http_upgrade_dissector(http3_stream->protocol);
1409 http3_stream->upgrade_info = wmem_new0(wmem_file_scope(), http_upgrade_info_t)((http_upgrade_info_t*)wmem_alloc0((wmem_file_scope()), sizeof
(http_upgrade_info_t)))
;
1410 http3_stream->upgrade_info->server_port = pinfo->destport;
1411 http3_stream->upgrade_info->http_version = 3;
1412 http3_stream->upgrade_info->get_header_value = http3_get_header_value;
1413 }
1414 }
1415
1416 if (authority_contains_target) {
1417 /* Both plain CONNECT and CONNECT-UDP use only the `:authority' header.
1418 */
1419 uri = wmem_strdup(pinfo->pool, pseudo_headers.authority);
1420 } else {
1421 /* The Extended CONNECT uses the standard URL construction
1422 */
1423 uri = wmem_strdup_printf(pinfo->pool, "%s://%s%s",
1424 pseudo_headers.scheme, pseudo_headers.authority, pseudo_headers.path);
1425 }
1426
1427 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ": ", "%s %s",
1428 pseudo_headers.method, uri);
1429 ti_url = proto_tree_add_string(tree, hf_http3_header_request_full_uri, tvb, 0, 0, uri);
1430 proto_item_set_url(ti_url);
1431 proto_item_set_generated(ti_url);
1432 } else if (pseudo_headers.status != NULL((void*)0)) {
1433 DISSECTOR_ASSERT(pseudo_headers.reason_phrase)((void) ((pseudo_headers.reason_phrase) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 1433, "pseudo_headers.reason_phrase"))))
; /* Must be filled together with `:status' */
1434 /* append the status code and the reason phrase (for example, HEADERS: 200 OK) */
1435 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ": ", "%s %s",
1436 pseudo_headers.status, pseudo_headers.reason_phrase);
1437 }
1438
1439 return tvb_offset;
1440}
1441
1442#else /* HAVE_NGHTTP3 */
1443const char *
1444http3_get_header_value(packet_info *pinfo _U___attribute__((unused)), const char* name _U___attribute__((unused)), bool_Bool the_other_direction _U___attribute__((unused))) {
1445 return NULL((void*)0);
1446}
1447
1448#endif /* HAVE_NGHTTP3 */
1449
1450static http3_session_info_t *
1451http3_session_new(void)
1452{
1453 http3_session_info_t *http3_session;
1454
1455 http3_session = wmem_new0(wmem_file_scope(), http3_session_info_t)((http3_session_info_t*)wmem_alloc0((wmem_file_scope()), sizeof
(http3_session_info_t)))
;
1456
1457#ifdef HAVE_NGHTTP31
1458 http3_initialize_qpack_decoders(http3_session);
1459#endif
1460
1461 return http3_session;
1462}
1463
1464static http3_session_info_t *
1465http3_session_lookup_or_create(packet_info *pinfo)
1466{
1467 http3_session_info_t *http3_session;
1468
1469 /* First, try to look up the session by initial QUIC DCID */
1470 quic_cid_t initial_dcid = {0};
1471 if (quic_conn_data_get_conn_client_dcid_initial(pinfo, &initial_dcid)) {
1472 /* Look up the session data in the conn map */
1473 http3_session = (http3_session_info_t *)wmem_map_lookup(HTTP3_CONN_INFO_MAPhttp3_get_file_local_ctx()->conn_info_map, &initial_dcid);
1474 if (http3_session == NULL((void*)0)) {
1475 quic_cid_t *dcid_p = wmem_memdup(wmem_file_scope(), &initial_dcid, sizeof(initial_dcid));
1476 http3_session = http3_session_new();
1477 wmem_map_insert(HTTP3_CONN_INFO_MAPhttp3_get_file_local_ctx()->conn_info_map, dcid_p, http3_session);
1478 }
1479 } else {
1480 /* Initial DCID can not be found, use the 5-tuple for lookup */
1481 conversation_t *conversation = find_or_create_conversation(pinfo);
1482 http3_session = (http3_session_info_t *)conversation_get_proto_data(conversation, proto_http3);
1483
1484 if (http3_session == NULL((void*)0)) {
1485 http3_session = http3_session_new();
1486 conversation_add_proto_data(conversation, proto_http3, http3_session);
1487 }
1488 }
1489
1490 return http3_session;
1491}
1492
1493#ifdef HAVE_NGHTTP31
1494
1495static conversation_t *
1496http3_find_inner_conversation(packet_info *pinfo, quic_stream_info *stream_info, http3_stream_info_t *http3_stream, void **ctx)
1497{
1498 conversation_t *inner_conv = NULL((void*)0);
1499
1500 if (stream_info != NULL((void*)0)) {
1501 if (ctx) {
1502 *ctx = pinfo->conv_elements;
1503 }
1504
1505 wmem_array_t *conversation_elements = wmem_array_new(pinfo->pool, sizeof(conversation_element_t));
1506
1507 conversation_element_t h3_stream_addr = {
1508 .type = CE_ADDRESS,
1509 .addr_val = (pinfo->srcport < pinfo->destport) ? pinfo->src : pinfo->dst,
1510 };
1511 wmem_array_append_one(conversation_elements, h3_stream_addr)wmem_array_append((conversation_elements), &(h3_stream_addr
), 1)
;
1512
1513 conversation_element_t h3_stream_port = {
1514 .type = CE_PORT,
1515 .port_val = (pinfo->srcport < pinfo->destport) ? pinfo->srcport : pinfo->destport,
1516 };
1517 wmem_array_append_one(conversation_elements, h3_stream_port)wmem_array_append((conversation_elements), &(h3_stream_port
), 1)
;
1518
1519 conversation_element_t h3_stream_quic_stream = {
1520 .type = CE_UINT64,
1521 .uint64_val = http3_stream->id,
1522 };
1523 wmem_array_append_one(conversation_elements, h3_stream_quic_stream)wmem_array_append((conversation_elements), &(h3_stream_quic_stream
), 1)
;
1524
1525 conversation_element_t h3_stream_last = {
1526 .type = CE_CONVERSATION_TYPE,
1527 .conversation_type_val = CONVERSATION_LOG,
1528 };
1529 wmem_array_append_one(conversation_elements, h3_stream_last)wmem_array_append((conversation_elements), &(h3_stream_last
), 1)
;
1530
1531 pinfo->conv_elements = (conversation_element_t *)wmem_array_get_raw(conversation_elements);
1532 inner_conv = find_conversation_pinfo(pinfo, 0);
1533 if (!inner_conv) {
1534 inner_conv = conversation_new_full(pinfo->fd->num, pinfo->conv_elements);
1535 }
1536 }
1537
1538 return inner_conv;
1539}
1540
1541static void
1542http3_reset_inner_conversation(packet_info *pinfo, void *ctx)
1543{
1544 if (ctx) {
1545 struct conversation_element *conv_elements = (struct conversation_element *)ctx;
1546 pinfo->conv_elements = conv_elements;
1547 }
1548}
1549
1550enum body_decompression {
1551 BODY_DECOMPRESSION_NONE,
1552 BODY_DECOMPRESSION_ZLIB,
1553 BODY_DECOMPRESSION_BROTLI,
1554 BODY_DECOMPRESSION_ZSTD,
1555 BODY_DECOMPRESSION_FAIL
1556};
1557
1558static enum body_decompression
1559get_body_decompression_info(packet_info *pinfo)
1560{
1561 const char *content_encoding = http3_get_header_value(pinfo, HTTP3_HEADER_NAME_CONTENT_ENCODING"content-encoding", false0);
1562 const char *status = http3_get_header_value(pinfo, HTTP3_HEADER_NAME_STATUS":status", false0);
1563 if (content_encoding == NULL((void*)0)) {
1564 return BODY_DECOMPRESSION_NONE;
1565 }
1566 if (!http3_decompress_body || g_strcmp0(status, HTTP3_HEADER_STATUS_PARTIAL_CONTENT"206") == 0) {
1567 return BODY_DECOMPRESSION_FAIL;
1568 }
1569#ifdef USE_ZLIB_OR_ZLIBNG
1570 if (strncmp(content_encoding, "gzip", 4) == 0 || strncmp(content_encoding, "deflate", 7) == 0) {
1571 return BODY_DECOMPRESSION_ZLIB;
1572 }
1573#endif
1574#ifdef HAVE_BROTLI1
1575 if (strncmp(content_encoding, "br", 2) == 0) {
1576 return BODY_DECOMPRESSION_BROTLI;
1577 }
1578#endif
1579#ifdef HAVE_ZSTD1
1580 if (strncmp(content_encoding, "zstd", 4) == 0) {
1581 return BODY_DECOMPRESSION_ZSTD;
1582 }
1583#endif
1584
1585 return BODY_DECOMPRESSION_FAIL;
1586}
1587
1588static void
1589dissect_http3_body_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *body_tree, http3_stream_info_t *http3_stream, bool_Bool decompression_success)
1590{
1591 unsigned length = tvb_reported_length(tvb);
1592
1593 proto_tree_add_item(body_tree, hf_http3_data, tvb, 0, length, ENC_NA0x00000000);
1594
1595 if (have_tap_listener(http3_follow_tap)) {
1596 quic_follow_tap_data_t *follow_data = wmem_new0(pinfo->pool, quic_follow_tap_data_t)((quic_follow_tap_data_t*)wmem_alloc0((pinfo->pool), sizeof
(quic_follow_tap_data_t)))
;
1597
1598 follow_data->tvb = tvb;
1599 follow_data->stream_id = http3_stream->id;
1600 follow_data->from_server = http3_stream->direction;
1601
1602 tap_queue_packet(http3_follow_tap, pinfo, follow_data);
1603 }
1604
1605 /* If we couldn't, or wouldn't, decompress the data, stop here. */
1606 if (!decompression_success)
1607 return;
1608
1609 const char *content_type = http3_get_header_value(pinfo, HTTP3_HEADER_NAME_CONTENT_TYPE"content-type", false0);
1610 if (content_type != NULL((void*)0)) {
1611 const char *semicolon = ws_strchrnul(content_type, ';');
1612 char *media_type = wmem_ascii_strdown(pinfo->pool, content_type, semicolon - content_type);
1613 char *media_type_parameters = NULL((void*)0);
1614 while (*semicolon && *semicolon == ';' && g_ascii_isspace(*semicolon)((g_ascii_table[(guchar) (*semicolon)] & G_ASCII_SPACE) !=
0)
) {
1615 ++semicolon;
1616 }
1617 if (*semicolon) {
1618 media_type_parameters = wmem_strdup(pinfo->pool, semicolon);
1619 }
1620 media_content_info_t media_type_metadata = { MEDIA_CONTAINER_HTTP_OTHERS, media_type_parameters, NULL((void*)0), NULL((void*)0)};
1621 dissector_try_string_with_data(media_type_dissector_table, media_type,
1622 tvb, pinfo, proto_tree_get_root(body_tree), true1, &media_type_metadata);
1623 }
1624}
1625
1626static void
1627dissect_http3_data_full_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *http3_tree, http3_stream_info_t *http3_stream)
1628{
1629 unsigned datalen = tvb_reported_length(tvb);
1630 proto_tree *body_tree = http3_tree;
1631 tvbuff_t *next_tvb = tvb;
1632
1633 const char *content_encoding = http3_get_header_value(pinfo, HTTP3_HEADER_NAME_CONTENT_ENCODING"content-encoding", false0);
1634 enum body_decompression decompression = get_body_decompression_info(pinfo);
1635 bool_Bool decompression_success = true1;
1636
1637 if (decompression != BODY_DECOMPRESSION_NONE) {
1638 proto_item *compressed_ti = NULL((void*)0);
1639
1640 tvbuff_t *decompressed_tvb = NULL((void*)0);
1641 switch (decompression) {
1642 case BODY_DECOMPRESSION_ZLIB:
1643 decompressed_tvb = tvb_child_uncompress_zlib(tvb, tvb, 0, datalen);
1644 break;
1645 case BODY_DECOMPRESSION_BROTLI:
1646 decompressed_tvb = tvb_child_uncompress_brotli(tvb, tvb, 0, datalen);
1647 break;
1648 case BODY_DECOMPRESSION_ZSTD:
1649 decompressed_tvb = tvb_child_uncompress_zstd(tvb, tvb, 0, datalen);
1650 break;
1651 default:
1652 break;
1653 }
1654
1655 compressed_ti = proto_tree_add_none_format(http3_tree,
1656 hf_http3_encoded_entity, tvb, 0, datalen,
1657 "Content-encoded entity body (%s): %u bytes",
1658 content_encoding == NULL((void*)0) ? "unknown" : content_encoding, datalen);
1659
1660 if (decompressed_tvb) {
1661 unsigned decompressed_length = tvb_reported_length(decompressed_tvb);
1662 add_new_data_source(pinfo, decompressed_tvb, "Decompressed entity body");
1663
1664 proto_item_append_text(compressed_ti, " -> %u bytes", decompressed_length);
1665 body_tree = proto_item_add_subtree(compressed_ti, ett_http3_encoded_entity);
1666 next_tvb = decompressed_tvb;
1667 datalen = decompressed_length;
Value stored to 'datalen' is never read
1668 } else {
1669 expert_add_info(pinfo, compressed_ti, &ei_http3_body_decompression_failed);
1670 decompression_success = false0;
1671 }
1672 }
1673
1674 dissect_http3_body_data(next_tvb, pinfo, body_tree, http3_stream, decompression_success);
1675}
1676
1677static void
1678dissect_http3_data_partial_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *http3_tree, quic_stream_info *stream_info, http3_stream_info_t *http3_stream)
1679{
1680 unsigned length;
1681 void *saved_ctx = NULL((void*)0);
1682
1683 if (http3_stream->is_connect) {
1684 /* Part of a tunneled CONNECT method. */
1685 proto_item_append_text(http3_tree, " (tunneled data)");
1686 } else {
1687 /* Not part of CONNECT, frame that should be reassembled later. */
1688 proto_item_append_text(http3_tree, " (partial entity body)");
1689 }
1690
1691 length = tvb_reported_length(tvb);
1692 /* Adding this seems redundant with http3.frame_payload. */
1693 proto_tree_add_item(http3_tree, hf_http3_data, tvb, 0, length, ENC_NA0x00000000);
1694
1695 if (http3_stream->next_handle) {
1696 /* Extended CONNECT */
1697 /* inner_conv = */ http3_find_inner_conversation(pinfo, stream_info, http3_stream, &saved_ctx);
1698 http3_stream->upgrade_info->from_server = http3_stream->direction;
1699 call_dissector_only(http3_stream->next_handle, tvb, pinfo, proto_tree_get_root(http3_tree), http3_stream->upgrade_info);
1700 http3_reset_inner_conversation(pinfo, saved_ctx);
1701 }
1702}
1703
1704static bool_Bool
1705should_attempt_to_reassemble_data_content(http3_stream_info_t *http3_stream)
1706{
1707 /* If this data frame is part of a CONNECT tunnel, don't try to reassemble.
1708 * XXX - This is what HTTP/2 does, but perhaps CONNECT data should also
1709 * use the streaming reassembly mode, once that is implemented.
1710 */
1711 if (http3_stream->is_connect) {
1712 return false0;
1713 }
1714
1715 return true1;
1716}
1717
1718static tvbuff_t*
1719reassemble_http3_data_into_full_content(tvbuff_t *tvb, packet_info *pinfo, proto_tree *http3_tree, unsigned offset, quic_stream_info *stream_info, http3_stream_info_t *http3_stream, bool_Bool fin)
1720{
1721 if (!should_attempt_to_reassemble_data_content(http3_stream)) {
1722 return NULL((void*)0);
1723 }
1724
1725 fragment_head *head = NULL((void*)0);
1726 unsigned remaining = tvb_captured_length_remaining(tvb, offset);
1727 unsigned content_length;
1728 bool_Bool content_length_set = false0;
1729
1730 /* We can re-use the QUIC reassembly functions; we only have one body
1731 * reassembly per request/response (since we only reassemble at FIN
1732 * or when reaching the content-length), so the QUIC stream_info
1733 * has all the necessary information to make the reassembly unique. */
1734
1735 /* Are we starting the body defragmentation? */
1736 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && !fragment_get(&http3_body_reassembly_table, pinfo, 0, stream_info)) {
1737 /* If so, do we know the content length */
1738 const char *content_length_str = http3_get_header_value(pinfo, HTTP3_HEADER_NAME_CONTENT_LENGTH"content-length", false0);
1739 if (content_length_str && ws_strtou(content_length_str, NULL((void*)0), &content_length)) {
1740 content_length_set = true1;
1741 /* Is this DATA frame the entire content-length? */
1742 if (remaining == content_length) {
1743 /* Yes; there are no more DATA frames. If FIN isn't set, that
1744 * is because a later QUIC frame with no DATA will have FIN.
1745 * Let's go ahead and desegment now. The reassembly head isn't
1746 * created, so we can't use fragment_set_tot_len, which will
1747 * handle this in the other cases.
1748 *
1749 * XXX - Would it be simpler to have something like
1750 * fragment_start_seq_check?
1751 */
1752 fin = true1;
1753 }
1754 }
1755 }
1756
1757 /* We might want a fragment_add_next instead of fragment_add_check_next so
1758 * that we can get reassembly errors when the segment is too long instead
1759 * of creating a new reassembly. */
1760 head = fragment_add_check_next(&http3_body_reassembly_table, tvb, offset, pinfo, 0, stream_info, remaining, !fin);
1761 if (content_length_set) {
1762 fragment_set_tot_len(&http3_body_reassembly_table, pinfo, 0, stream_info, content_length);
1763 }
1764
1765 if (head) {
1766 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1767 /* XXX - Remember that we dissected via DATA frames so we don't need
1768 * to dissect at FIN in a non-DATA frame, e.g. HEADERS or GREASE. */
1769 }
1770 /* The Info column information is less useful when dissected in the
1771 * same capture file frame, even in a different HTTP/3 DATA frame. */
1772 if (pinfo->num != head->reassembled_in) {
1773 col_append_frame_number(pinfo, COL_INFO, " [HTTP/3 reassembled in #%u]",
1774 head->reassembled_in);
1775 }
1776 /* This should work now (layer numbers are more stable), but check
1777 * to see if we need to do what HTTP/2 does. */
1778 return process_reassembled_data(tvb, offset, pinfo, "Reassembled body",
1779 head, &http3_body_fragment_items, NULL((void*)0), http3_tree);
1780
1781#if 0
1782 proto_tree_add_uint(http3_tree, hf_http3_body_reassembled_in, tvb, 0,
1783 0, head->reassembled_in);
1784#endif
1785 }
1786
1787 return NULL((void*)0);
1788}
1789
1790static int
1791dissect_http3_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *http3_tree, unsigned offset _U___attribute__((unused)),
1792 quic_stream_info *stream_info, http3_stream_info_t *http3_stream, bool_Bool fin)
1793{
1794 /* Padding is not defined in HTTP/3 DATA Frames
1795 * https://www.rfc-editor.org/rfc/rfc9114.html#name-comparison-of-http-2-and-ht
1796 */
1797
1798 /* XXX - HTTP/2 supports fake headers for a stream here */
1799
1800 /* "Because some messages are large or unbounded, endpoints SHOULD begin
1801 * processing partial HTTP messages once enough of the message has been
1802 * received to make progress."
1803 * https://www.rfc-editor.org/rfc/rfc9114.html#section-4.1-14
1804 * Not all possible media type subdissectors support defragmentation via
1805 * setting desegment_offset and desegment_len in pinfo, and the necessary
1806 * hooks are not in this dissector. For now, just reassemble everything
1807 * into the full content.
1808 *
1809 * XXX - Cf. what the HTTP/2 dissector does for the streaming reassembly
1810 * mode.
1811 */
1812
1813 tvbuff_t *data_tvb = reassemble_http3_data_into_full_content(tvb, pinfo, http3_tree, offset, stream_info, http3_stream, fin);
1814 if (data_tvb) {
1815 dissect_http3_data_full_body(data_tvb, pinfo, http3_tree, http3_stream);
1816 } else {
1817 dissect_http3_data_partial_body(tvb, pinfo, http3_tree, stream_info, http3_stream);
1818 }
1819
1820 return tvb_reported_length(tvb);
1821}
1822#else
1823static int
1824dissect_http3_data(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *http3_tree, unsigned offset _U___attribute__((unused)),
1825 quic_stream_info *stream_info _U___attribute__((unused)), http3_stream_info_t *http3_stream _U___attribute__((unused)), bool_Bool fin _U___attribute__((unused)))
1826{
1827 unsigned length = tvb_reported_length(tvb);
1828 /* Adding this seems redundant with http3.frame_payload. */
1829 proto_tree_add_item(http3_tree, hf_http3_data, tvb, 0, length, ENC_NA0x00000000);
1830
1831 return length;
1832}
1833#endif /* HAVE_NGHTTP3 */
1834
1835/* Settings */
1836static int
1837dissect_http3_settings(tvbuff_t *tvb, packet_info *pinfo, proto_tree *http3_tree, unsigned offset)
1838{
1839 uint64_t settingsid, value;
1840 unsigned lenvar;
1841 proto_item *ti_settings, *pi;
1842 proto_tree *settings_tree;
1843
1844 while (tvb_reported_length_remaining(tvb, offset) > 0) {
1845 ti_settings = proto_tree_add_item(http3_tree, hf_http3_settings, tvb, offset, 2, ENC_NA0x00000000);
1846 settings_tree = proto_item_add_subtree(ti_settings, ett_http3_settings);
1847 pi = proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_identifier, tvb, offset, -1,
1848 ENC_VARINT_QUIC0x00000004, &settingsid, &lenvar);
1849 /* Check if it is a GREASE Settings ID */
1850 if (http3_is_reserved_code(settingsid)) {
1851 proto_item_set_text(pi, "Settings Identifier: Reserved (%#" PRIx64"l" "x" ")", settingsid);
1852 proto_item_append_text(ti_settings, " - Reserved (GREASE)");
1853 } else {
1854 proto_item_append_text(ti_settings, " - %s",
1855 val64_to_str_wmem(pinfo->pool, settingsid, http3_settings_vals, "Unknown (%#" PRIx64"l" "x" ")"));
1856 }
1857
1858 offset += lenvar;
1859 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_value, tvb, offset, -1, ENC_VARINT_QUIC0x00000004, NULL((void*)0),
1860 &lenvar);
1861
1862 switch (settingsid) {
1863 case HTTP3_QPACK_MAX_TABLE_CAPACITY0x01:
1864 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_qpack_max_table_capacity, tvb, offset, -1,
1865 ENC_VARINT_QUIC0x00000004, &value, &lenvar);
1866 proto_item_append_text(ti_settings, ": %" PRIu64"l" "u", value);
1867 break;
1868 case HTTP3_SETTINGS_MAX_FIELD_SECTION_SIZE0x06:
1869 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_max_field_section_size, tvb, offset, -1,
1870 ENC_VARINT_QUIC0x00000004, &value, &lenvar);
1871 proto_item_append_text(ti_settings, ": %" PRIu64"l" "u", value);
1872 break;
1873 case HTTP3_QPACK_BLOCKED_STREAMS0x07:
1874 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_qpack_blocked_streams, tvb, offset, -1,
1875 ENC_VARINT_QUIC0x00000004, &value, &lenvar);
1876 proto_item_append_text(ti_settings, ": %" PRIu64"l" "u", value);
1877 break;
1878 case HTTP3_EXTENDED_CONNECT0x08:
1879 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_extended_connect, tvb, offset, -1,
1880 ENC_VARINT_QUIC0x00000004, &value, &lenvar);
1881 proto_item_append_text(ti_settings, ": %" PRIu64"l" "u", value);
1882 break;
1883 case HTTP3_WEBTRANSPORT0x2b603742:
1884 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_webtransport, tvb, offset, -1,
1885 ENC_VARINT_QUIC0x00000004, &value, &lenvar);
1886 proto_item_append_text(ti_settings, ": %" PRIu64"l" "u", value);
1887 break;
1888 case HTTP3_H3_DATAGRAM0x33:
1889 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_h3_datagram, tvb, offset, -1,
1890 ENC_VARINT_QUIC0x00000004, &value, &lenvar);
1891 proto_item_append_text(ti_settings, ": %" PRIu64"l" "u", value);
1892 break;
1893 case HTTP3_H3_DATAGRAM_DRAFT040xffd277:
1894 proto_tree_add_item_ret_varint(settings_tree, hf_http3_settings_h3_datagram_draft04, tvb, offset, -1,
1895 ENC_VARINT_QUIC0x00000004, &value, &lenvar);
1896 proto_item_append_text(ti_settings, ": %" PRIu64"l" "u", value);
1897 break;
1898 default:
1899 /* No Default */
1900 break;
1901 }
1902 offset += lenvar;
1903 }
1904
1905 return offset;
1906}
1907
1908/**
1909 * Priority Update
1910 */
1911static int
1912dissect_http3_priority_update(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *http3_tree, unsigned offset,
1913 http3_stream_info_t *http3_stream)
1914{
1915 uint64_t element_id;
1916 unsigned priority_field_value_len;
1917 unsigned lenvar;
1918
1919 proto_tree_add_item_ret_varint(http3_tree, hf_http3_priority_update_element_id, tvb, offset, -1, ENC_VARINT_QUIC0x00000004,
1920 &element_id, &lenvar);
1921 offset += lenvar;
1922 priority_field_value_len = tvb_reported_length_remaining(tvb, offset);
1923
1924 proto_tree_add_item(http3_tree, hf_http3_priority_update_field_value, tvb, offset, priority_field_value_len,
1925 ENC_ASCII0x00000000);
1926
1927 if (have_tap_listener(http3_follow_tap)) {
1928 quic_follow_tap_data_t *follow_data = wmem_new0(pinfo->pool, quic_follow_tap_data_t)((quic_follow_tap_data_t*)wmem_alloc0((pinfo->pool), sizeof
(quic_follow_tap_data_t)))
;
1929
1930 wmem_strbuf_t *priority_buf = wmem_strbuf_new(pinfo->pool, "priority: ");
1931 tvbuff_t *priority_tvb = tvb_new_composite();
1932 tvb_composite_append(priority_tvb,
1933 tvb_new_child_real_data(tvb,
1934 (const uint8_t*)wmem_strbuf_get_str(priority_buf),
1935 (unsigned)wmem_strbuf_get_len(priority_buf),
1936 (unsigned)wmem_strbuf_get_len(priority_buf)));
1937 tvb_composite_append(priority_tvb, tvb_new_subset_length(tvb, offset, priority_field_value_len));
1938 priority_buf = wmem_strbuf_create(pinfo->pool)wmem_strbuf_new(pinfo->pool, "");
1939 wmem_strbuf_append_printf(priority_buf, " [Prioritized Element ID %" PRIu64"l" "u" "]\n", element_id);
1940 tvb_composite_append(priority_tvb,
1941 tvb_new_child_real_data(tvb,
1942 (const uint8_t*)wmem_strbuf_get_str(priority_buf),
1943 (unsigned)wmem_strbuf_get_len(priority_buf),
1944 (unsigned)wmem_strbuf_get_len(priority_buf)));
1945 tvb_composite_finalize(priority_tvb);
1946 follow_data->tvb = priority_tvb;
1947 follow_data->stream_id = http3_stream->id;
1948 follow_data->from_server = http3_stream->direction;
1949
1950 tap_queue_packet(http3_follow_tap, pinfo, follow_data);
1951 }
1952
1953 offset += priority_field_value_len;
1954
1955 return offset;
1956}
1957
1958static int
1959dissect_http3_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, quic_stream_info *stream_info, http3_stream_info_t *http3_stream)
1960{
1961 uint64_t frame_type, frame_length;
1962 unsigned type_length_size, lenvar, payload_length, total_length;
1963 proto_item *ti_ft, *ti_ft_type, *ti_streamid;
1964 proto_tree *ft_tree;
1965 const char *ft_display_name;
1966 bool_Bool use_follow_tap = false0;
1967 bool_Bool fin = false0;
1968
1969 ti_ft = proto_tree_add_item(tree, hf_http3_frame, tvb, offset, -1, ENC_NA0x00000000);
1970 ft_tree = proto_item_add_subtree(ti_ft, ett_http3_frame);
1971
1972 ti_streamid = proto_tree_add_uint64(ft_tree, hf_http3_frame_streamid, tvb, offset, 0, http3_stream->id);
1973 proto_item_set_generated(ti_streamid);
1974
1975 ti_ft_type = proto_tree_add_item_ret_varint(ft_tree, hf_http3_frame_type, tvb, offset, -1, ENC_VARINT_QUIC0x00000004, &frame_type,
1976 &lenvar);
1977 offset += lenvar;
1978 type_length_size = lenvar;
1979 if (http3_is_reserved_code(frame_type)) {
1980 proto_item_set_text(ti_ft_type, "Type: Reserved (%#" PRIx64"l" "x" ")", frame_type);
1981 ft_display_name = "Reserved (GREASE)";
1982 } else {
1983 ft_display_name = val64_to_str_wmem(pinfo->pool, frame_type, http3_frame_types, "Unknown (%#" PRIx64"l" "x" ")");
1984 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", ft_display_name);
1985 }
1986 proto_tree_add_item_ret_varint(ft_tree, hf_http3_frame_length, tvb, offset, -1, ENC_VARINT_QUIC0x00000004, &frame_length,
1987 &lenvar);
1988 proto_item_set_text(ti_ft, "%s len=%" PRId64"l" "d", ft_display_name, frame_length);
1989 offset += lenvar;
1990 type_length_size += lenvar;
1991
1992 if (ckd_add(&total_length, type_length_size, frame_length)__builtin_add_overflow((type_length_size), (frame_length), (&
total_length))
) {
1993 // There is no way for us to correctly handle these sizes. Most likely
1994 // it is garbage.
1995 return INT32_MAX(2147483647);
1996 }
1997
1998 proto_item_set_len(ti_ft, total_length);
1999 payload_length = (unsigned)frame_length;
2000 if (payload_length == 0) {
2001 return offset;
2002 }
2003
2004 if (stream_info->fin && tvb_reported_length_remaining(tvb, offset) == frame_length) {
2005 // If the QUIC stream is at FIN, then finish reassembly iff this
2006 // is the last HTTP/3 frame within the QUIC STREAM frame.
2007 fin = true1;
2008 }
2009 proto_tree_add_item(ft_tree, hf_http3_frame_payload, tvb, offset, payload_length, ENC_NA0x00000000);
2010
2011 switch (frame_type) {
2012 case HTTP3_DATA0x0: { /* TODO: dissect Data Frame */
2013 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, payload_length);
2014 dissect_http3_data(next_tvb, pinfo, ft_tree, 0, stream_info, http3_stream, fin);
2015 fin = false0;
2016 } break;
2017 case HTTP3_HEADERS0x1: {
2018#ifdef HAVE_NGHTTP31
2019 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, payload_length);
2020 dissect_http3_headers(next_tvb, pinfo, ft_tree, 0, offset, stream_info, http3_stream);
2021#else
2022 use_follow_tap = true1;
2023#endif /* HAVE_NGHTTP3 */
2024 } break;
2025 case HTTP3_CANCEL_PUSH0x3: /* TODO: dissect Cancel_Push Frame */
2026 break;
2027 case HTTP3_SETTINGS0x4: { /* Settings Frame */
2028 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, payload_length);
2029 dissect_http3_settings(next_tvb, pinfo, ft_tree, 0);
2030 } break;
2031 case HTTP3_PUSH_PROMISE0x5: /* TODO: dissect Push_Promise_Frame */
2032 break;
2033 case HTTP3_GOAWAY0x7: /* TODO: dissect Goaway Frame */
2034 break;
2035 case HTTP3_MAX_PUSH_ID0xD: /* TODO: dissect Max_Push_ID Frame */
2036 break;
2037 case HTTP3_PRIORITY_UPDATE_REQUEST_STREAM0xF0700:
2038 /* FALLTHROUGH */
2039 case HTTP3_PRIORITY_UPDATE_PUSH_STREAM0xF0701: { /* Priority_Update Frame */
2040 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, payload_length);
2041 dissect_http3_priority_update(next_tvb, pinfo, ft_tree, 0, http3_stream);
2042 } break;
2043 default: /* TODO: add expert advice (remember to treat GREASE differntly) */
2044 break;
2045 }
2046
2047#ifdef HAVE_NGHTTP31
2048 if (fin) {
2049 fragment_head *head = NULL((void*)0);
2050 head = fragment_end_seq_next(&http3_body_reassembly_table, pinfo, 0, stream_info);
2051
2052 if (head) {
2053 tvbuff_t *reassembled_data = process_reassembled_data(tvb, offset, pinfo, "Reassembled body",
2054 head, &http3_body_fragment_items, NULL((void*)0), ft_tree);
2055 if (reassembled_data)
2056 dissect_http3_data_full_body(reassembled_data, pinfo, ft_tree, http3_stream);
2057 }
2058 }
2059#endif
2060
2061 if (use_follow_tap && have_tap_listener(http3_follow_tap)) {
2062 quic_follow_tap_data_t *follow_data = wmem_new0(pinfo->pool, quic_follow_tap_data_t)((quic_follow_tap_data_t*)wmem_alloc0((pinfo->pool), sizeof
(quic_follow_tap_data_t)))
;
2063
2064 follow_data->tvb = tvb_new_subset_length(tvb, offset, payload_length);
2065 follow_data->stream_id = http3_stream->id;
2066 follow_data->from_server = stream_info->from_server;
2067
2068 tap_queue_packet(http3_follow_tap, pinfo, follow_data);
2069 }
2070
2071 offset += payload_length;
2072 return offset;
2073}
2074
2075static void
2076report_unknown_stream_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
2077 quic_stream_info *stream_info, http3_stream_info_t *http3_stream)
2078{
2079 /*
2080 * https://www.rfc-editor.org/rfc/rfc9114.html#name-unidirectional-streams
2081 *
2082 * "If the stream header indicates a stream type which is not supported by
2083 * the recipient, the remainder of the stream cannot be consumed as the
2084 * semantics are unknown."
2085 */
2086 proto_tree_add_expert_format(tree, pinfo, &ei_http3_unknown_stream_type, tvb, offset, 0,
2087 "Unknown stream type %#" PRIx64"l" "x" " on Stream ID %#" PRIx64"l" "x",
2088 http3_stream->uni_stream_type, stream_info->stream_id);
2089}
2090
2091/**
2092 * https://www.rfc-editor.org/rfc/rfc7541#section-5.1
2093 * via
2094 * https://www.rfc-editor.org/rfc/rfc9204.html#name-prefixed-integers
2095 *
2096 * Read a QPACK varint value, return number of consumed bytes, including the prefix byte.
2097 *
2098 * Optionally return the value of the one-bit flag that precedes the QPACK prefixed integer.
2099 *
2100 * Such flag is is interpreted differently, depending on the context:
2101 * - If the prefixed integer represents length of a string literal, the flag value
2102 * indicates that the following string literal is encoded using Huffman code.
2103 * See https://www.rfc-editor.org/rfc/rfc7541#section-5.2 for details.
2104 * - If the prefixed integer represents a name index, the flag value indicates
2105 * that the following name index belongs to the static/dynamic table.
2106 * See https://www.rfc-editor.org/rfc/rfc9204.html#name-insert-with-name-reference
2107 * for details.
2108 */
2109#define HTTP3_QPACK_MAX_SHIFT62 62
2110#define HTTP3_QPACK_MAX_INT((1ull << 62) - 1) ((1ull << HTTP3_QPACK_MAX_SHIFT62) - 1)
2111
2112static unsigned
2113read_qpack_prefixed_integer(tvbuff_t *tvb, unsigned offset, unsigned prefix,
2114 uint64_t *out_result, bool_Bool *out_flag)
2115{
2116 /*
2117 * This can throw a ReportedBoundError; in fact, we count on that
2118 * currently in order to detect QPACK fields split across packets.
2119 */
2120 uint64_t k = (uint8_t)((1 << prefix) - 1);
2121 uint64_t n = 0;
2122 uint64_t add = 0;
2123 uint64_t shift = 0;
2124 uint8_t byte;
2125 unsigned start_offset = offset;
2126
2127 byte = tvb_get_uint8(tvb, offset);
2128
2129 if (out_flag) {
2130 *out_flag = byte & (1 << prefix);
2131 }
2132
2133 if ((byte & k) != k) {
2134 *out_result = byte & k;
2135 return 1;
2136 }
2137
2138 n = k;
2139
2140 for (++offset; tvb_captured_length_remaining(tvb, offset); ++offset, shift += 7) {
2141 byte = tvb_get_uint8(tvb, offset);
2142 add = byte & 0x7f;
2143 if (shift > HTTP3_QPACK_MAX_SHIFT62) {
2144 return 0;
2145 }
2146 if ((HTTP3_QPACK_MAX_INT((1ull << 62) - 1) >> shift) < add) {
2147 return 0;
2148 }
2149 add <<= shift;
2150 if (HTTP3_QPACK_MAX_INT((1ull << 62) - 1) - add < n) {
2151 return 0;
2152 }
2153
2154 n += add;
2155
2156 if ((byte & (1 << 7)) == 0) {
2157 break;
2158 }
2159 }
2160
2161 *out_result = n;
2162
2163 /* Otherwise, consume extra byte and mark the fin output param */
2164 return offset - start_offset + 1;
2165}
2166
2167static int
2168dissect_http3_qpack_encoder_stream(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree,
2169 int start_offset, http3_stream_info_t *http3_stream, int *picnt)
2170{
2171 unsigned end_offset; /* Sentinel offset past the buffer. */
2172 tvbuff_t *decoded_tvb; /* TVB with the result of decoding the Huffman-encoding strings */
2173 volatile bool_Bool can_continue; /* Flag to indicate that we can parse the next QPACK instruction */
2174 volatile int icnt; /* Number of dissected QPACK instructions */
2175 volatile unsigned offset; /* Current parsing offset, relative to the start of the tvb */
2176
2177 can_continue = true1;
2178 icnt = 0;
2179 offset = start_offset;
2180 end_offset = start_offset + tvb_captured_length_remaining(tvb, start_offset);
2181 wmem_strbuf_t *follow_buf = wmem_strbuf_create(pinfo->pool)wmem_strbuf_new(pinfo->pool, "");
2182 wmem_strbuf_t *instr_buf;
2183
2184 while (offset < end_offset && can_continue) {
2185 int inst_offset; /* Starting offset of the currently parsed instruction in the tvb */
2186 int inst_len; /* Total length of the instruction */
2187 unsigned varint_len;
2188
2189 proto_item *opcode_ti = NULL((void*)0), *huffman_ti;
2190 proto_tree *opcode_tree;
2191
2192 inst_offset = offset;
2193
2194 TRY{ except_t *volatile exc; volatile int except_state = 0; static
const except_id_t catch_spec[] = { { 1, 0 } }; { struct except_stacknode
except_sn; struct except_catch except_ch; except_setup_try(&
except_sn, &except_ch, catch_spec, 1); if (_setjmp (except_ch
.except_jmp)) *(&exc) = &except_ch.except_obj; else *
(&exc) = 0; if(except_state & 1) except_state |= 2; except_state
&= ~1; if (except_state == 0 && exc == 0)
{
2195 uint8_t opcode; /* The instruction opcode */
2196
2197 opcode = tvb_get_uint8(tvb, inst_offset) & QPACK_OPCODE_MASK0xE0;
2198
2199 ws_noisy("Decoding opcode=%" PRIu8 " decoded=%d start=%d current=%d end=%d",do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 2200, __func__, "Decoding opcode=%" "hhu" " decoded=%d start=%d current=%d end=%d"
, opcode, (offset - start_offset), start_offset, offset, end_offset
); } } while (0)
2200 opcode, (offset - start_offset), start_offset, offset, end_offset)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 2200, __func__, "Decoding opcode=%" "hhu" " decoded=%d start=%d current=%d end=%d"
, opcode, (offset - start_offset), start_offset, offset, end_offset
); } } while (0)
;
2201
2202 if (opcode & QPACK_OPCODE_INSERT_INDEXED0x80) {
2203 unsigned name_idx_len = 0;
2204 uint64_t name_idx = 0;
2205 unsigned val_offset = 0;
2206 uint64_t val_len = 0;
2207 bool_Bool val_huffman = false0;
2208 const uint8_t *val_str = NULL((void*)0);
2209
2210 /* https://datatracker.ietf.org/doc/html/rfc9204#name-insert-with-name-reference
2211 *
2212 * 0 1 2 3 4 5 6 7
2213 * +---+---+---+---+---+---+---+---+
2214 * | 1 | T | Name Index (6+) |
2215 * +---+---+-----------------------+
2216 * | H | Value Length (7+) |
2217 * +---+---------------------------+
2218 * | Value String (Length bytes) |
2219 * +-------------------------------+
2220 */
2221
2222 /* Read the 6-encoded name index len */
2223 name_idx_len = read_qpack_prefixed_integer(tvb, offset, 6, &name_idx, NULL((void*)0));
2224 if (name_idx_len == 0) {
2225 THROW(ScsiBoundsError)except_throw(1, (7), ((void*)0));
2226 }
2227 offset += name_idx_len;
2228
2229 /* Read the 7-encoded value len and set the value offset for subsequent dissection */
2230 varint_len = read_qpack_prefixed_integer(tvb, offset, 7, &val_len, &val_huffman);
2231 if (varint_len == 0) {
2232 THROW(ScsiBoundsError)except_throw(1, (7), ((void*)0));
2233 }
2234 /* XXX - If val_len > UINT32_MAX, fail with expert info? */
2235 offset += varint_len;
2236 val_offset = offset;
2237 offset += (uint32_t)val_len;
2238
2239 /* Update the instruction length */
2240 inst_len = offset - inst_offset;
2241
2242 /* Add the protocol tree items */
2243 opcode_ti = proto_tree_add_item(tree, hf_http3_qpack_encoder_opcode_insert_indexed,
2244 tvb, inst_offset,inst_len, ENC_NA0x00000000);
2245 opcode_tree = proto_item_add_subtree(opcode_ti, ett_http3_qpack_opcode);
2246 proto_tree_add_uint64(opcode_tree, hf_http3_qpack_encoder_opcode_insert_indexed_ref,
2247 tvb, inst_offset, inst_len, name_idx);
2248
2249 if (val_huffman) {
2250 huffman_ti = proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_indexed_hval,
2251 tvb, val_offset, (uint32_t)val_len, ENC_NA0x00000000);
2252 decoded_tvb = tvb_child_uncompress_hpack_huff(tvb, val_offset, (unsigned)val_len);
2253 if (decoded_tvb) {
2254 add_new_data_source(pinfo, decoded_tvb, "Decoded QPACK Value");
2255 proto_tree_add_item_ret_string(opcode_tree, hf_http3_qpack_encoder_opcode_insert_indexed_val,
2256 decoded_tvb, 0, tvb_captured_length(decoded_tvb), ENC_NA0x00000000, pinfo->pool, &val_str);
2257 } else {
2258 expert_add_info(pinfo, huffman_ti, &ei_http3_huffman_failed);
2259 val_str = (const uint8_t*)"???";
2260 }
2261 } else {
2262 proto_tree_add_item_ret_string(opcode_tree, hf_http3_qpack_encoder_opcode_insert_indexed_val,
2263 tvb, val_offset, (uint32_t)val_len, ENC_NA0x00000000, pinfo->pool, &val_str);
2264 }
2265 instr_buf = wmem_strbuf_new(pinfo->pool, "INSERT_INDEXED");
2266 wmem_strbuf_append_printf(instr_buf, "[%" PRIu64"l" "u" "=%s]", name_idx, val_str);
2267 proto_item_set_text(opcode_ti, "%s", wmem_strbuf_get_str(instr_buf));
2268 wmem_strbuf_append_printf(follow_buf, "%s\n", wmem_strbuf_finalize(instr_buf));
2269 } else if (opcode & QPACK_OPCODE_INSERT0x40) {
2270 unsigned name_offset = 0;
2271 uint64_t name_len = 0;
2272 bool_Bool name_huffman = false0;
2273 const uint8_t *name_str = NULL((void*)0);
2274 bool_Bool val_huffman = false0;
2275 unsigned val_offset = 0;
2276 uint64_t val_len = 0;
2277 const uint8_t *val_str = NULL((void*)0);
2278
2279
2280 /* https://datatracker.ietf.org/doc/html/rfc9204#name-insert-with-literal-name
2281 *
2282 * 0 1 2 3 4 5 6 7
2283 * +---+---+---+---+---+---+---+---+
2284 * | 0 | 1 | H | Name Length (5+) |
2285 * +---+---+---+-------------------+
2286 * | Name String (Length bytes) |
2287 * +---+---------------------------+
2288 * | H | Value Length (7+) |
2289 * +---+---------------------------+
2290 * | Value String (Length bytes) |
2291 * +-------------------------------+
2292 */
2293
2294 /* Read the 5-encoded name length and set the name offset for subsequent dissection */
2295 varint_len = read_qpack_prefixed_integer(tvb, offset, 5, &name_len, &name_huffman);
2296 if (varint_len == 0) {
2297 THROW(ScsiBoundsError)except_throw(1, (7), ((void*)0));
2298 }
2299 /* XXX - If name_len > UINT32_MAX, fail with expert info? */
2300 offset += varint_len;
2301 name_offset = offset;
2302 offset += (uint32_t)name_len;
2303
2304 /* Read the 7-encoded value length and set the value offset for subsequent dissection */
2305 varint_len = read_qpack_prefixed_integer(tvb, offset, 7, &val_len, &val_huffman);
2306 if (varint_len == 0) {
2307 THROW(ScsiBoundsError)except_throw(1, (7), ((void*)0));
2308 }
2309 /* XXX - If val_len > UINT32_MAX, fail with expert info? */
2310 offset += varint_len;
2311 val_offset = offset;
2312 offset += (uint32_t)val_len;
2313
2314 /* Update the instruction length */
2315 inst_len = offset - inst_offset;
2316
2317 /* Add the protocol tree items */
2318 opcode_ti = proto_tree_add_item(tree, hf_http3_qpack_encoder_opcode_insert,
2319 tvb, inst_offset, inst_len, ENC_NA0x00000000);
2320 opcode_tree = proto_item_add_subtree(opcode_ti, ett_http3_qpack_opcode);
2321
2322 if (name_huffman) {
2323 huffman_ti = proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_hname,
2324 tvb, name_offset, (uint32_t)name_len, ENC_NA0x00000000);
2325 decoded_tvb = tvb_child_uncompress_hpack_huff(tvb, name_offset, (unsigned)name_len);
2326 if (decoded_tvb) {
2327 add_new_data_source(pinfo, decoded_tvb, "Decoded QPACK Name");
2328 proto_tree_add_item_ret_string(opcode_tree, hf_http3_qpack_encoder_opcode_insert_name,
2329 decoded_tvb, 0, tvb_captured_length(decoded_tvb), ENC_NA0x00000000, pinfo->pool, &name_str);
2330 } else {
2331 expert_add_info(pinfo, huffman_ti, &ei_http3_huffman_failed);
2332 name_str = (const uint8_t*)"???";
2333 }
2334 } else {
2335 proto_tree_add_item_ret_string(opcode_tree, hf_http3_qpack_encoder_opcode_insert_name,
2336 tvb, name_offset,(uint32_t)name_len, ENC_NA0x00000000, pinfo->pool, &name_str);
2337 }
2338
2339 if (val_huffman) {
2340 huffman_ti = proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_hval,
2341 tvb, val_offset,(uint32_t)val_len, ENC_NA0x00000000);
2342 decoded_tvb = tvb_child_uncompress_hpack_huff(tvb, val_offset, (unsigned)val_len);
2343 if (decoded_tvb) {
2344 add_new_data_source(pinfo, decoded_tvb, "Decoded QPACK Value");
2345 proto_tree_add_item_ret_string(opcode_tree, hf_http3_qpack_encoder_opcode_insert_val,
2346 decoded_tvb, 0, tvb_captured_length(decoded_tvb), ENC_NA0x00000000, pinfo->pool, &val_str);
2347 } else {
2348 expert_add_info(pinfo, huffman_ti, &ei_http3_huffman_failed);
2349 val_str = (const uint8_t*)"???";
2350 }
2351 } else {
2352 proto_tree_add_item_ret_string(opcode_tree, hf_http3_qpack_encoder_opcode_insert_val,
2353 tvb, val_offset,(uint32_t)val_len, ENC_NA0x00000000, pinfo->pool, &val_str);
2354 }
2355
2356 instr_buf = wmem_strbuf_new(pinfo->pool, "INSERT");
2357 wmem_strbuf_append_printf(instr_buf, "[%s=%s]", name_str, val_str);
2358 proto_item_set_text(opcode_ti, "%s", wmem_strbuf_get_str(instr_buf));
2359 wmem_strbuf_append_printf(follow_buf, "%s\n", wmem_strbuf_finalize(instr_buf));
2360 } else if (opcode & QPACK_OPCODE_SET_DTABLE_CAP0x20) {
2361 uint64_t dynamic_capacity = 0;
2362
2363 /* https://datatracker.ietf.org/doc/html/rfc9204#name-set-dynamic-table-capacity
2364 *
2365 * 0 1 2 3 4 5 6 7
2366 * +---+---+---+---+---+---+---+---+
2367 * | 0 | 0 | 1 | Capacity (5+) |
2368 * +---+---+---+-------------------+
2369 */
2370
2371 /* Read the 5-encoded table capacity */
2372 varint_len = read_qpack_prefixed_integer(tvb, offset, 5, &dynamic_capacity, NULL((void*)0));
2373 if (varint_len == 0) {
2374 THROW(ScsiBoundsError)except_throw(1, (7), ((void*)0));
2375 }
2376 offset += varint_len;
2377
2378 /* Update the instruction length */
2379 inst_len = offset - inst_offset;
2380
2381 /* Add the protocol tree items */
2382 opcode_ti = proto_tree_add_item(tree, hf_http3_qpack_encoder_opcode_dtable_cap,
2383 tvb, inst_offset,inst_len, ENC_NA0x00000000);
2384 opcode_tree = proto_item_add_subtree(opcode_ti, ett_http3_qpack_opcode);
2385 proto_tree_add_uint64(opcode_tree, hf_http3_qpack_encoder_opcode_dtable_cap_val,
2386 tvb, inst_offset, inst_len,dynamic_capacity);
2387
2388 instr_buf = wmem_strbuf_new(pinfo->pool, "DTABLE_CAP");
2389 wmem_strbuf_append_printf(instr_buf, "[%" PRIu64"l" "u" "]", dynamic_capacity);
2390 proto_item_set_text(opcode_ti, "%s", wmem_strbuf_get_str(instr_buf));
2391 wmem_strbuf_append_printf(follow_buf, "%s\n", wmem_strbuf_finalize(instr_buf));
2392 } else if (opcode == QPACK_OPCODE_DUPLICATE0x00) {
2393 uint64_t duplicate_of = 0;
2394
2395 /* https://datatracker.ietf.org/doc/html/rfc9204#name-duplicate
2396 *
2397 * 0 1 2 3 4 5 6 7
2398 * +---+---+---+---+---+---+---+---+
2399 * | 0 | 0 | 0 | Index (5+) |
2400 * +---+---+---+-------------------+
2401 */
2402
2403 /* Read the 5-encoded index of a duplicate instruction */
2404 varint_len = read_qpack_prefixed_integer(tvb, offset, 5, &duplicate_of, NULL((void*)0));
2405 if (varint_len == 0) {
2406 THROW(ScsiBoundsError)except_throw(1, (7), ((void*)0));
2407 }
2408 offset += varint_len;
2409
2410 /* Update the instruction length */
2411 inst_len = offset - inst_offset;
2412
2413 /* Add the protocol tree items */
2414 proto_tree_add_item(tree, hf_http3_qpack_encoder_opcode_duplicate,
2415 tvb, inst_offset, inst_len, ENC_NA0x00000000);
2416
2417 instr_buf = wmem_strbuf_new(pinfo->pool, "DUPLICATE");
2418 wmem_strbuf_append_printf(instr_buf, "[%" PRIu64"l" "u" "]", duplicate_of);
2419 proto_item_set_text(opcode_ti, "%s", wmem_strbuf_get_str(instr_buf));
2420 wmem_strbuf_append_printf(follow_buf, "%s\n", wmem_strbuf_finalize(instr_buf));
2421 } else {
2422 ws_debug("Opcode=%" PRIu8 ": UNKNOWN", opcode)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2422, __func__, "Opcode=%" "hhu" ": UNKNOWN", opcode); } } while
(0)
;
2423 can_continue = false0;
2424 }
2425 /* Increment the instruction count */
2426 icnt ++;
2427 }
2428 CATCH(ScsiBoundsError)if (except_state == 0 && exc != 0 && exc->
except_id.except_code == (7) && (except_state |= 1))
{
2429 /* This is obviously not SCSI, but we use a bounds type error
2430 * which the main API won't throw. This too large integer is
2431 * possibly a QUIC reassembly error or the payload not actually
2432 * being HTTP/3. */
2433 proto_tree_add_expert(tree, pinfo, &ei_http3_prefix_int_failed, tvb, offset, 1);
2434 /* Above won't throw an exception because we would have thrown
2435 * an error retrieving the first octet of the prefixed integer. */
2436 offset = end_offset;
2437 can_continue = false0;
2438 }
2439 CATCH(ReportedBoundsError)if (except_state == 0 && exc != 0 && exc->
except_id.except_code == (3) && (except_state |= 1))
{
2440 /* We could not parse the last instruction, hence update `decoded' accordingly. */
2441 ws_debug("%u: Could not parse last instruction, rolling back parsing offset from %d to %d",do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2442, __func__, "%u: Could not parse last instruction, rolling back parsing offset from %d to %d"
, pinfo->num, offset, inst_offset); } } while (0)
2442 pinfo->num, offset, inst_offset)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2442, __func__, "%u: Could not parse last instruction, rolling back parsing offset from %d to %d"
, pinfo->num, offset, inst_offset); } } while (0)
;
2443 offset = inst_offset;
2444 can_continue = false0;
2445 }
2446 ENDTRYif(!(except_state&1) && exc != 0) except_rethrow(
exc); except_free(except_ch.except_obj.except_dyndata); except_pop
(); };}
;
2447 }
2448
2449 if (icnt && have_tap_listener(http3_follow_tap)) {
2450 quic_follow_tap_data_t *follow_data = wmem_new0(pinfo->pool, quic_follow_tap_data_t)((quic_follow_tap_data_t*)wmem_alloc0((pinfo->pool), sizeof
(quic_follow_tap_data_t)))
;
2451
2452 follow_data->tvb = tvb_new_child_real_data(tvb,
2453 (const uint8_t*)wmem_strbuf_get_str(follow_buf),
2454 (unsigned)wmem_strbuf_get_len(follow_buf),
2455 (unsigned)wmem_strbuf_get_len(follow_buf));
2456 follow_data->stream_id = http3_stream->id;
2457 follow_data->from_server = http3_stream->direction;
2458
2459 tap_queue_packet(http3_follow_tap, pinfo, follow_data);
2460 }
2461
2462 *picnt = icnt;
2463 return offset - start_offset;
2464}
2465
2466static int
2467dissect_http3_qpack_enc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
2468 quic_stream_info *stream_info, http3_stream_info_t *http3_stream)
2469{
2470 int remaining;
2471 int remaining_captured;
2472 int retval;
2473
2474 remaining_captured = tvb_captured_length_remaining(tvb, offset);
2475 remaining = tvb_reported_length_remaining(tvb, offset);
2476 retval = remaining;
2477
2478 DISSECTOR_ASSERT(remaining_captured == remaining)((void) ((remaining_captured == remaining) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 2478, "remaining_captured == remaining"))))
;
2479
2480 if (remaining > 0) {
2481 http3_session_info_t *http3_session;
2482 proto_item *qpack_update;
2483 proto_tree *qpack_update_tree;
2484 int decoded;
2485 int icnt;
2486
2487 http3_session = http3_session_lookup_or_create(pinfo);
2488 DISSECTOR_ASSERT(http3_session)((void) ((http3_session) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 2488, "http3_session"))))
;
2489
2490 /*
2491 * Add a QPACK encoder tree item.
2492 */
2493 qpack_update = proto_tree_add_item(tree, hf_http3_qpack_encoder, tvb, offset, remaining, ENC_NA0x00000000);
2494 qpack_update_tree = proto_item_add_subtree(qpack_update, ett_http3_qpack_update);
2495 decoded = dissect_http3_qpack_encoder_stream(tvb, pinfo, qpack_update_tree, offset,
2496 http3_stream, &icnt);
2497
2498 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2499 ws_debug("decode encoder stream: Wireshark decoded=%u of %u", decoded, remaining)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2499, __func__, "decode encoder stream: Wireshark decoded=%u of %u"
, decoded, remaining); } } while (0)
;
2500 }
2501 if (decoded < remaining) {
2502 pinfo->desegment_offset = offset + decoded;
2503 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
2504 }
2505
2506 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "QPACK ENC[%d]", icnt);
2507
2508#ifdef HAVE_NGHTTP31
2509 http3_stream_dir packet_direction = http3_packet_get_direction(stream_info);
2510 nghttp3_qpack_decoder *decoder = http3_session->qpack_decoder[packet_direction];
2511 proto_item *ti = NULL((void*)0);
2512 http3_qpack_encoder_state_t *encoder_state = http3_get_qpack_encoder_state(pinfo, tvb, offset);
2513
2514 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2515 /*
2516 * Since we are now defragmenting, pass only the number of bytes
2517 * decoded to the nghttp3_qpack_decoder. Otherwise, we'll end up
2518 * sending the same bytes to the decoder again when the packet
2519 * is defragmented.
2520 */
2521 uint8_t *qpack_buf = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, decoded);
2522 int qpack_buf_len = decoded;
2523
2524 /*
2525 * Get the instr count prior to processing the data.
2526 */
2527 uint64_t icnt_before = nghttp3_qpack_decoder_get_icnt(decoder);
2528
2529 encoder_state->nread = nghttp3_qpack_decoder_read_encoder(decoder, qpack_buf, qpack_buf_len);
2530 encoder_state->icnt = nghttp3_qpack_decoder_get_icnt(decoder);
2531 encoder_state->icnt_inc = (uint32_t)(encoder_state->icnt - icnt_before);
2532
2533 ws_debug("decode encoder stream: decoder=%p nread=%td new insertions=%u total insertions=%" PRIu64,do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2534, __func__, "decode encoder stream: decoder=%p nread=%td new insertions=%u total insertions=%"
"l" "u", decoder, encoder_state->nread, encoder_state->
icnt_inc, encoder_state->icnt); } } while (0)
2534 decoder, encoder_state->nread, encoder_state->icnt_inc, encoder_state->icnt)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2534, __func__, "decode encoder stream: decoder=%p nread=%td new insertions=%u total insertions=%"
"l" "u", decoder, encoder_state->nread, encoder_state->
icnt_inc, encoder_state->icnt); } } while (0)
;
2535 }
2536
2537 /* nghttp3_qpack_decoder_read_encoder() returns a nghttp3_ssize
2538 * (ptrdiff_t), negative in the case of errors, but nghttp3_strerror()
2539 * accepts int instead.
2540 */
2541 if (encoder_state->nread < 0) {
2542 quic_cid_t quic_cid = {.len = 0};
2543 bool_Bool initial_cid_found = quic_conn_data_get_conn_client_dcid_initial(pinfo, &quic_cid);
2544 proto_tree_add_expert_format(tree, pinfo, &ei_http3_qpack_failed, tvb, offset, 0,
2545 "QPACK decoder %p DCID %s [found=%d] error %d (%s)",
2546 decoder, cid_to_string(&quic_cid, pinfo->pool), initial_cid_found,
2547 (int)encoder_state->nread, nghttp3_strerror((int)encoder_state->nread));
2548 }
2549
2550 proto_item_set_text(qpack_update, "QPACK encoder stream; %d instructions (%" PRIu64"l" "u" " total)",
2551 encoder_state->icnt_inc, encoder_state->icnt);
2552 ti = proto_tree_add_uint(qpack_update_tree, hf_http3_qpack_encoder_icnt_inc, tvb, offset, 0,
2553 encoder_state->icnt_inc);
2554 proto_item_set_generated(ti);
2555 ti = proto_tree_add_uint64(qpack_update_tree, hf_http3_qpack_encoder_icnt, tvb, offset, 0,
2556 encoder_state->icnt);
2557 proto_item_set_generated(ti);
2558#else
2559 (void)stream_info;
2560 (void)qpack_update;
2561 (void)decoded;
2562#endif /* HAVE_NGHTTP3 */
2563 }
2564
2565 return retval;
2566}
2567
2568static int
2569dissect_http3_qpack_decoder_stream(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree,
2570 int start_offset, http3_stream_info_t *http3_stream, int *picnt)
2571{
2572 unsigned end_offset; /* Sentinel offset past the buffer. */
2573 volatile bool_Bool can_continue; /* Flag to indicate that we can parse the next QPACK instruction */
2574 volatile int icnt; /* Number of dissected QPACK instructions */
2575 volatile unsigned offset; /* Current parsing offset, relative to the start of the tvb */
2576
2577 can_continue = true1;
2578 icnt = 0;
2579 offset = start_offset;
2580 end_offset = start_offset + tvb_captured_length_remaining(tvb, start_offset);
2581
2582 wmem_strbuf_t *follow_buf = wmem_strbuf_create(pinfo->pool)wmem_strbuf_new(pinfo->pool, "");
2583 wmem_strbuf_t *instr_buf;
2584
2585 while (offset < end_offset && can_continue) {
2586 int inst_offset; /* Starting offset of the currently parsed instruction in the tvb */
2587 int inst_len; /* Total length of the instruction */
2588 proto_item *opcode_ti;
2589 proto_tree *opcode_tree;
2590
2591 inst_offset = offset;
2592
2593 TRY{ except_t *volatile exc; volatile int except_state = 0; static
const except_id_t catch_spec[] = { { 1, 0 } }; { struct except_stacknode
except_sn; struct except_catch except_ch; except_setup_try(&
except_sn, &except_ch, catch_spec, 1); if (_setjmp (except_ch
.except_jmp)) *(&exc) = &except_ch.except_obj; else *
(&exc) = 0; if(except_state & 1) except_state |= 2; except_state
&= ~1; if (except_state == 0 && exc == 0)
{
2594 uint8_t opcode; /* The instruction opcode */
2595 unsigned varint_len;
2596
2597 opcode = tvb_get_uint8(tvb, inst_offset) & QPACK_OPCODE_MASK0xE0;
2598
2599 ws_noisy("Decoding opcode=%" PRIu8 " decoded=%d start=%d current=%d end=%d",do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 2600, __func__, "Decoding opcode=%" "hhu" " decoded=%d start=%d current=%d end=%d"
, opcode, (offset - start_offset), start_offset, offset, end_offset
); } } while (0)
2600 opcode, (offset - start_offset), start_offset, offset, end_offset)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 2600, __func__, "Decoding opcode=%" "hhu" " decoded=%d start=%d current=%d end=%d"
, opcode, (offset - start_offset), start_offset, offset, end_offset
); } } while (0)
;
2601
2602 if (opcode & QPACK_OPCODE_SECTION_ACK0x80) {
2603 uint64_t stream_id = 0;
2604
2605 /* https://datatracker.ietf.org/doc/html/rfc9204#section-4.4.1
2606 *
2607 * 0 1 2 3 4 5 6 7
2608 * +---+---+---+---+---+---+---+---+
2609 * | 1 | Stream ID (7+) |
2610 * +---+---------------------------+
2611 */
2612
2613 /* Read the 7-encoded name stream ID */
2614 varint_len = read_qpack_prefixed_integer(tvb, offset, 7, &stream_id, NULL((void*)0));
2615 if (varint_len == 0) {
2616 offset = end_offset;
2617 break;
2618 }
2619 offset += varint_len;
2620
2621 /* Update the instruction length */
2622 inst_len = offset - inst_offset;
2623
2624 /* Add the protocol tree items */
2625 opcode_ti = proto_tree_add_item(tree, hf_http3_qpack_decoder_opcode_section_ack,
2626 tvb, inst_offset, inst_len, ENC_NA0x00000000);
2627 opcode_tree = proto_item_add_subtree(opcode_ti, ett_http3_qpack_opcode);
2628 proto_tree_add_uint64(opcode_tree, hf_http3_qpack_decoder_opcode_section_ack_stream_id,
2629 tvb, inst_offset, inst_len, stream_id);
2630
2631 instr_buf = wmem_strbuf_new(pinfo->pool, "SECTION_ACK");
2632 wmem_strbuf_append_printf(instr_buf, "[id=%" PRIu64"l" "u" "]", stream_id);
2633 proto_item_set_text(opcode_ti, "%s", wmem_strbuf_get_str(instr_buf));
2634 wmem_strbuf_append_printf(follow_buf, "%s\n", wmem_strbuf_finalize(instr_buf));
2635 } else if (opcode & QPACK_OPCODE_STREAM_CANCEL0x40) {
2636 uint64_t stream_id = 0;
2637
2638 /* https://datatracker.ietf.org/doc/html/rfc9204#section-4.4.2
2639 *
2640 * 0 1 2 3 4 5 6 7
2641 * +---+---+---+---+---+---+---+---+
2642 * | 0 | 1 | Stream ID (6+) |
2643 * +---+---+---+-------------------+
2644 */
2645
2646 /* Read the 6-encoded name stream ID */
2647 varint_len = read_qpack_prefixed_integer(tvb, offset, 6, &stream_id, NULL((void*)0));
2648 if (varint_len == 0) {
2649 offset = end_offset;
2650 break;
2651 }
2652 offset += varint_len;
2653
2654 /* Update the instruction length */
2655 inst_len = offset - inst_offset;
2656
2657 /* Add the protocol tree items */
2658 opcode_ti = proto_tree_add_item(tree, hf_http3_qpack_decoder_opcode_cancel_stream,
2659 tvb, inst_offset, inst_len, ENC_NA0x00000000);
2660 opcode_tree = proto_item_add_subtree(opcode_ti, ett_http3_qpack_opcode);
2661 proto_tree_add_uint64(opcode_tree, hf_http3_qpack_decoder_opcode_cancel_stream_id,
2662 tvb, inst_offset, inst_len,stream_id);
2663
2664 instr_buf = wmem_strbuf_new(pinfo->pool, "STREAM_CANCEL");
2665 wmem_strbuf_append_printf(instr_buf, "[id=%" PRIu64"l" "u" "]", stream_id);
2666 proto_item_set_text(opcode_ti, "%s", wmem_strbuf_get_str(instr_buf));
2667 wmem_strbuf_append_printf(follow_buf, "%s\n", wmem_strbuf_finalize(instr_buf));
2668 } else if (opcode == QPACK_OPCODE_ICNT_INCREMENT0x00) {
2669 uint64_t icnt_inc = 0;
2670
2671 /* https://datatracker.ietf.org/doc/html/rfc9204#section-4.4.3
2672 *
2673 * 0 1 2 3 4 5 6 7
2674 * +---+---+---+---+---+---+---+---+
2675 * | 0 | 0 | Increment (6+) |
2676 * +---+---+-----------------------+
2677 */
2678
2679 /* Read the 6-encoded instruction count increment */
2680 varint_len = read_qpack_prefixed_integer(tvb, offset, 6, &icnt_inc, NULL((void*)0));
2681 if (varint_len == 0) {
2682 offset = end_offset;
2683 break;
2684 }
2685 offset += varint_len;
2686
2687 /* Update the instruction length */
2688 inst_len = offset - inst_offset;
2689 /* Add the protocol tree items */
2690
2691 opcode_ti = proto_tree_add_item(tree, hf_http3_qpack_decoder_opcode_icnt_increment,
2692 tvb, inst_offset, inst_len, ENC_NA0x00000000);
2693 opcode_tree = proto_item_add_subtree(opcode_ti, ett_http3_qpack_opcode);
2694 proto_tree_add_uint64(opcode_tree, hf_http3_qpack_decoder_opcode_icnt_increment_value,
2695 tvb, inst_offset, inst_len,icnt_inc);
2696
2697 instr_buf = wmem_strbuf_new(pinfo->pool, "ICNT_INC");
2698 wmem_strbuf_append_printf(instr_buf, "[%" PRIu64"l" "u" "]", icnt_inc);
2699 proto_item_set_text(opcode_ti, "%s", wmem_strbuf_get_str(instr_buf));
2700 wmem_strbuf_append_printf(follow_buf, "%s\n", wmem_strbuf_finalize(instr_buf));
2701 } else {
2702 ws_debug("Opcode=%" PRIu8 ": UNKNOWN", opcode)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2702, __func__, "Opcode=%" "hhu" ": UNKNOWN", opcode); } } while
(0)
;
2703 can_continue = false0;
2704 }
2705 /* Increment the instruction count */
2706 icnt ++;
2707 }
2708 CATCH(ReportedBoundsError)if (except_state == 0 && exc != 0 && exc->
except_id.except_code == (3) && (except_state |= 1))
{
2709 /* We could not parse the last instruction, hence roll back `parsing_offset' . */
2710 ws_noisy("Could not parse last instruction, rolling back parsing offset from %d to %d",do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 2711, __func__, "Could not parse last instruction, rolling back parsing offset from %d to %d"
, offset, inst_offset); } } while (0)
2711 offset, inst_offset)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_NOISY, "epan/dissectors/packet-http3.c"
, 2711, __func__, "Could not parse last instruction, rolling back parsing offset from %d to %d"
, offset, inst_offset); } } while (0)
;
2712 offset = inst_offset;
2713 can_continue = false0;
2714 }
2715 ENDTRYif(!(except_state&1) && exc != 0) except_rethrow(
exc); except_free(except_ch.except_obj.except_dyndata); except_pop
(); };}
;
2716 }
2717
2718 if (icnt && have_tap_listener(http3_follow_tap)) {
2719 quic_follow_tap_data_t *follow_data = wmem_new0(pinfo->pool, quic_follow_tap_data_t)((quic_follow_tap_data_t*)wmem_alloc0((pinfo->pool), sizeof
(quic_follow_tap_data_t)))
;
2720
2721 follow_data->tvb = tvb_new_child_real_data(tvb,
2722 (const uint8_t*)wmem_strbuf_get_str(follow_buf),
2723 (unsigned)wmem_strbuf_get_len(follow_buf),
2724 (unsigned)wmem_strbuf_get_len(follow_buf));
2725 follow_data->stream_id = http3_stream->id;
2726 follow_data->from_server = http3_stream->direction;
2727
2728 tap_queue_packet(http3_follow_tap, pinfo, follow_data);
2729 }
2730
2731 *picnt = icnt;
2732 return offset - start_offset;
2733}
2734
2735static int
2736dissect_http3_qpack_dec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
2737 quic_stream_info *stream_info _U___attribute__((unused)), http3_stream_info_t *http3_stream)
2738{
2739 int remaining;
2740 int remaining_captured;
2741 int retval;
2742
2743 remaining_captured = tvb_captured_length_remaining(tvb, offset);
2744 remaining = tvb_reported_length_remaining(tvb, offset);
2745 retval = remaining;
2746
2747 DISSECTOR_ASSERT(remaining_captured == remaining)((void) ((remaining_captured == remaining) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 2747, "remaining_captured == remaining"))))
;
2748
2749 if (remaining > 0) {
2750 http3_session_info_t *http3_session;
2751 proto_item *qpack_update;
2752 proto_tree *qpack_update_tree;
2753 int decoded;
2754 int icnt;
2755
2756 http3_session = http3_session_lookup_or_create(pinfo);
2757 DISSECTOR_ASSERT(http3_session)((void) ((http3_session) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-http3.c"
, 2757, "http3_session"))))
;
2758
2759 /*
2760 * Add a QPACK encoder tree item.
2761 */
2762 qpack_update = proto_tree_add_item(tree, hf_http3_qpack_decoder, tvb, offset, remaining, ENC_NA0x00000000);
2763 qpack_update_tree = proto_item_add_subtree(qpack_update, ett_http3_qpack_update);
2764 decoded = dissect_http3_qpack_decoder_stream(tvb, pinfo, qpack_update_tree, offset, http3_stream, &icnt);
2765
2766 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "QPACK DEC[%d]", icnt);
2767
2768 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2769 ws_debug("decode decoder stream: Wireshark decoded=%u of %u", decoded, remaining)do { if (1) { ws_log_full("HTTP3", LOG_LEVEL_DEBUG, "epan/dissectors/packet-http3.c"
, 2769, __func__, "decode decoder stream: Wireshark decoded=%u of %u"
, decoded, remaining); } } while (0)
;
2770 }
2771 if (decoded < remaining) {
2772 pinfo->desegment_offset = offset + decoded;
2773 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
2774 }
2775 retval = decoded;
2776 }
2777
2778 return retval;
2779}
2780
2781static int
2782dissect_http3_client_bidi_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
2783 quic_stream_info *stream_info, http3_stream_info_t *http3_stream)
2784{
2785 proto_item *ti_stream;
2786 proto_tree *stream_tree;
2787
2788 ti_stream = proto_tree_add_item(tree, hf_http3_stream_bidi, tvb, offset, 1, ENC_NA0x00000000);
2789 stream_tree = proto_item_add_subtree(ti_stream, ett_http3_stream_bidi);
2790
2791 while (tvb_reported_length_remaining(tvb, offset)) {
2792 if (!http3_check_frame_size(tvb, pinfo, offset)) {
2793 return tvb_captured_length(tvb);
2794 }
2795 offset = dissect_http3_frame(tvb, pinfo, stream_tree, offset, stream_info, http3_stream);
2796 }
2797
2798 return offset;
2799}
2800
2801static int
2802dissect_http3_uni_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, quic_stream_info *stream_info,
2803 http3_stream_info_t *http3_stream)
2804{
2805 uint64_t stream_type;
2806 unsigned lenvar;
2807 proto_item *ti_stream, *ti_stream_type;
2808 proto_tree *stream_tree;
2809 const char *stream_display_name;
2810
2811 ti_stream = proto_tree_add_item(tree, hf_http3_stream_uni, tvb, offset, -1, ENC_NA0x00000000);
2812 stream_tree = proto_item_add_subtree(ti_stream, ett_http3_stream_uni);
2813
2814 if (stream_info->offset == 0) {
2815 ti_stream_type = proto_tree_add_item_ret_varint(stream_tree, hf_http3_stream_uni_type, tvb, offset, -1, ENC_VARINT_QUIC0x00000004, &stream_type,
2816 &lenvar);
2817 offset += lenvar;
2818 http3_stream->uni_stream_type = stream_type;
2819 if (http3_is_reserved_code(stream_type)) {
2820 // Reserved to exercise requirement that unknown types are ignored.
2821 proto_item_set_text(ti_stream_type, "Stream Type: Reserved (%#" PRIx64"l" "x" ")", stream_type);
2822 stream_display_name = "Reserved (GREASE)";
2823 }
2824 else {
2825 stream_display_name = val64_to_str_wmem(pinfo->pool, stream_type, http3_stream_types, "Unknown (%#" PRIx64"l" "x" ")");
2826 }
2827 proto_item_set_text(ti_stream, "UNI STREAM: %s off=%" PRIu64"l" "u", stream_display_name, stream_info->stream_offset);
2828 } else {
2829 stream_type = http3_stream->uni_stream_type;
2830 /*ti_stream_type = proto_tree_add_item(stream_tree, hf_http3_stream_uni_type, tvb, offset, -1, ENC_BIG_ENDIAN);*/
2831 }
2832
2833 switch (stream_type) {
2834 case HTTP3_STREAM_TYPE_CONTROL:
2835 while (tvb_reported_length_remaining(tvb, offset)) {
2836 if (!http3_check_frame_size(tvb, pinfo, offset)) {
2837 return tvb_captured_length(tvb);
2838 }
2839 offset = dissect_http3_frame(tvb, pinfo, stream_tree, offset, stream_info, http3_stream);
2840 }
2841 break;
2842 case HTTP3_STREAM_TYPE_PUSH:
2843 // The remaining data of this stream consists of HTTP/3 frames.
2844 if (stream_info->offset == 0) {
2845 proto_tree_add_item_ret_varint(stream_tree, hf_http3_push_id, tvb, offset, -1, ENC_VARINT_QUIC0x00000004, NULL((void*)0), &lenvar);
2846 offset += lenvar;
2847 }
2848 break;
2849 case HTTP3_STREAM_TYPE_QPACK_ENCODER:
2850 offset = dissect_http3_qpack_enc(tvb, pinfo, stream_tree, offset, stream_info, http3_stream);
2851 break;
2852 case HTTP3_STREAM_TYPE_QPACK_DECODER:
2853 offset = dissect_http3_qpack_dec(tvb, pinfo, stream_tree, offset, stream_info, http3_stream);
2854 break;
2855 case HTTP3_STREAM_TYPE_WEBTRANSPORT:
2856 // TODO
2857 offset = tvb_captured_length(tvb);
2858 break;
2859 default:
2860 // Unknown or reserved stream type, consume everything.
2861 if (!http3_is_reserved_code(stream_type)) {
2862 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2863 http3_stream->broken_from_offset = stream_info->offset + offset;
2864 }
2865 report_unknown_stream_type(tvb, pinfo, stream_tree, offset, stream_info, http3_stream);
2866 }
2867 offset = tvb_captured_length(tvb);
2868 break;
2869 }
2870
2871 return offset;
2872}
2873
2874static proto_tree *
2875start_http3_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
2876 proto_item * ti;
2877
2878 col_set_str(pinfo->cinfo, COL_PROTOCOL, "HTTP3");
2879 // Only clear the columns if this is the first HTTP/3 STREAM in the packet.
2880 if (proto_get_layer_num(pinfo, proto_http3) == 1) {
2881 col_clear(pinfo->cinfo, COL_INFO);
2882 }
2883
2884 ti = proto_tree_add_item(tree, proto_http3, tvb, 0, -1, ENC_NA0x00000000);
2885 return proto_item_add_subtree(ti, ett_http3);
2886}
2887
2888static int
2889dissect_http3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2890{
2891 quic_stream_info * stream_info = (quic_stream_info *)data;
2892 proto_tree * http3_tree;
2893 int offset = 0;
2894 http3_stream_info_t *http3_stream;
2895 http3_session_info_t *http3_session;
2896 bool_Bool from_server;
2897
2898 if (!stream_info) {
2899 return 0;
2900 }
2901
2902 /* XXX - Handle implementations where QUIC signals FIN in a QUIC frame that
2903 * has no HTTP/3 frames, and we don't get a Content-Length header either?
2904 * Unlike HTTP/1.1, there might be nothing for QUIC itself to reassemble,
2905 * since each HTTP/3 frame has a TPKT-like header with its own length.
2906 * So tvb might be length 0 here. We also might want to handle the case
2907 * where FIN is set but the length is too short for a frame. In that
2908 * case, it is more likely that more DATA will be forthcoming, or would
2909 * the QUIC stream just abruptly stop like a RESET_STREAM? For that matter,
2910 * should we try to reassemble any leftover data on a RESET_STREAM? */
2911
2912 switch (QUIC_STREAM_TYPE(stream_info->stream_id)((stream_info->stream_id) & 3U)) {
2913 case QUIC_STREAM_CLIENT_BIDI0:
2914 /* Used for HTTP requests and responses. */
2915 if (!http3_check_frame_size(tvb, pinfo, offset)) {
2916 return tvb_captured_length(tvb);
2917 }
2918 break;
2919 case QUIC_STREAM_SERVER_BIDI1:
2920 /* "HTTP/3 does not use server-initiated bidirectional streams,
2921 * though an extension could define a use for these streams." */
2922 break;
2923 case QUIC_STREAM_CLIENT_UNI2:
2924 case QUIC_STREAM_SERVER_UNI3:
2925 break;
2926 }
2927
2928 http3_tree = start_http3_tree(tvb, pinfo, tree);
2929
2930 /* We need a single HTTP/3 stream for both directions */
2931 from_server = stream_info->from_server;
2932 if (QUIC_STREAM_TYPE(stream_info->stream_id)((stream_info->stream_id) & 3U) == QUIC_STREAM_CLIENT_BIDI0 && from_server) {
2933 stream_info->from_server = false0;
2934 }
2935 http3_stream = (http3_stream_info_t *)quic_stream_get_proto_data(pinfo, stream_info);
2936 if (!http3_stream) {
2937 http3_stream = wmem_new0(wmem_file_scope(), http3_stream_info_t)((http3_stream_info_t*)wmem_alloc0((wmem_file_scope()), sizeof
(http3_stream_info_t)))
;
2938 quic_stream_add_proto_data(pinfo, stream_info, http3_stream);
2939 http3_stream->id = stream_info->stream_id;
2940 }
2941 if (QUIC_STREAM_TYPE(stream_info->stream_id)((stream_info->stream_id) & 3U) == QUIC_STREAM_CLIENT_BIDI0 && from_server) {
2942 stream_info->from_server = true1;
2943 }
2944
2945 http3_session = http3_session_lookup_or_create(pinfo);
2946 http3_session->current_stream = http3_stream;
2947 http3_stream->direction = http3_packet_get_direction(stream_info);
2948
2949 // If a STREAM has unknown data, everything afterwards cannot be dissected.
2950 if (http3_stream->broken_from_offset && http3_stream->broken_from_offset <= stream_info->offset + offset) {
2951 report_unknown_stream_type(tvb, pinfo, tree, offset, stream_info, http3_stream);
2952 return tvb_captured_length(tvb);
2953 }
2954
2955 switch (QUIC_STREAM_TYPE(stream_info->stream_id)((stream_info->stream_id) & 3U)) {
2956 case QUIC_STREAM_CLIENT_BIDI0:
2957 /* Used for HTTP requests and responses. */
2958 dissect_http3_client_bidi_stream(tvb, pinfo, http3_tree, offset, stream_info, http3_stream);
2959 break;
2960
2961 case QUIC_STREAM_SERVER_BIDI1:
2962 /* "HTTP/3 does not use server-initiated bidirectional streams,
2963 * though an extension could define a use for these streams." */
2964 // XXX expert info?
2965 return tvb_captured_length(tvb);
2966
2967 case QUIC_STREAM_CLIENT_UNI2:
2968 case QUIC_STREAM_SERVER_UNI3:
2969 dissect_http3_uni_stream(tvb, pinfo, http3_tree, offset, stream_info, http3_stream);
2970 break;
2971 }
2972
2973 return tvb_captured_length(tvb);
2974}
2975
2976static int
2977dissect_http3_datagram(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
2978 quic_datagram_info * datagram_info = (quic_datagram_info *)data;
2979 uint64_t request_stream_id;
2980 proto_item * ti;
2981 proto_tree * http3_tree, * datragram_tree, * stream_id_tree;
2982 uint32_t lenvar;
2983 int offset = 0;
2984
2985 if (!datagram_info) {
2986 return 0;
2987 }
2988
2989 http3_tree = start_http3_tree(tvb, pinfo, tree);
2990 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "DATAGRAM");
2991
2992 ti = proto_tree_add_item(http3_tree, hf_http3_datagram, tvb, offset, -1, ENC_NA0x00000000);
2993 datragram_tree = proto_item_add_subtree(ti, ett_http3_datagram);
2994
2995 ti = proto_tree_add_item_ret_varint(datragram_tree, hf_http3_datagram_quarter_stream_id, tvb, offset, -1, ENC_VARINT_QUIC0x00000004, &request_stream_id, &lenvar);
2996 stream_id_tree = proto_item_add_subtree(ti, ett_http3_datagram_stream_id);
2997
2998 if (request_stream_id > ((1ULL << 60) - 1)) {
2999 proto_tree_add_expert_format(stream_id_tree, pinfo, &ei_http3_datagram_invalid_stream_id, tvb, offset, lenvar,
3000 "Quarter Stream ID is too big");
3001 return tvb_captured_length(tvb);
3002 }
3003
3004 request_stream_id = request_stream_id * 4;
3005 ti = proto_tree_add_uint64(stream_id_tree, hf_http3_datagram_request_stream_id, tvb, offset, lenvar, request_stream_id);
3006 proto_item_set_generated(ti);
3007 offset += lenvar;
3008
3009 proto_tree_add_item(datragram_tree, hf_http3_datagram_payload, tvb, offset, -1, ENC_NA0x00000000);
3010
3011 return tvb_captured_length(tvb);
3012}
3013
3014#ifdef HAVE_NGHTTP31
3015static void
3016register_static_headers(void)
3017{
3018 header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL((void*)0));
3019
3020 /*
3021 * Here hf[x].hfinfo.name is a header method which is used as key
3022 * for matching ids while processing http3 packets.
3023 */
3024 static hf_register_info hf[] = {
3025 { &hf_http3_headers_authority,
3026 { ":authority", "http3.headers.authority",
3027 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3028 "Authority portion of the target URI", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3029 },
3030 { &hf_http3_headers_status,
3031 { ":status", "http3.headers.status",
3032 FT_UINT16, BASE_DEC, NULL((void*)0), 0x0,
3033 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3034 },
3035 { &hf_http3_headers_path,
3036 { ":path", "http3.headers.path",
3037 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3038 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3039 },
3040 { &hf_http3_headers_protocol,
3041 { ":protocol", "http3.headers.protocol",
3042 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3043 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3044 },
3045 { &hf_http3_headers_method,
3046 { ":method", "http3.headers.method",
3047 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3048 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3049 },
3050 { &hf_http3_headers_scheme,
3051 { ":scheme", "http3.headers.scheme",
3052 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3053 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3054 },
3055 { &hf_http3_headers_accept,
3056 { "accept", "http3.headers.accept",
3057 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3058 "Media types that are acceptable to the user agent", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3059 },
3060 { &hf_http3_headers_accept_charset,
3061 { "accept-charset", "http3.headers.accept_charset",
3062 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3063 "Acceptable charsets in textual responses for the user agent", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3064 },
3065 { &hf_http3_headers_accept_encoding,
3066 { "accept-encoding", "http3.headers.accept_encoding",
3067 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3068 "Acceptable content codings (like compression) in responses for the user agent", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3069 },
3070 { &hf_http3_headers_accept_language,
3071 { "accept-language", "http3.headers.accept_language",
3072 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3073 "Preferred natural languages for the user agent", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3074 },
3075 { &hf_http3_headers_accept_ranges,
3076 { "accept-ranges", "http3.headers.accept_ranges",
3077 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3078 "Bytes range which server may use for partial data transfer", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3079 },
3080 { &hf_http3_headers_access_control_allow_origin,
3081 { "access-control-allow-origin", "http3.headers.access_control_allow_origin",
3082 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3083 "Origin control for cross-origin resource sharing", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3084 },
3085 { &hf_http3_headers_age,
3086 { "age", "http3.headers.age",
3087 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3088 "Time in seconds which was spent for transferring data through proxy", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3089 },
3090 { &hf_http3_headers_allow,
3091 { "allow", "http3.headers.allow",
3092 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3093 "List of allowed methods for request", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3094 },
3095 { &hf_http3_headers_authorization,
3096 { "authorization", "http3.headers.authorization",
3097 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3098 "Credentials for a server-side authorization", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3099 },
3100 { &hf_http3_headers_cache_control,
3101 { "cache-control", "http3.headers.cache_control",
3102 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3103 "Request or response directives for a cache control", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3104 },
3105 { &hf_http3_headers_content_disposition,
3106 { "content-disposition", "http3.headers.content_disposition",
3107 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3108 "Indicates that response will be displayed as page or downloaded with dialog box", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3109 },
3110 { &hf_http3_headers_content_encoding,
3111 { "content-encoding", "http3.headers.content_encoding",
3112 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3113 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3114 },
3115 { &hf_http3_headers_content_language,
3116 { "content-language", "http3.headers.content_language",
3117 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3118 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3119 },
3120 { &hf_http3_headers_content_length,
3121 { "content-length", "http3.headers.content_length",
3122 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3123 "Size of body in bytes", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3124 },
3125 { &hf_http3_headers_content_location,
3126 { "content-location", "http3.headers.content_location",
3127 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3128 "Alternative URL for a response data", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3129 },
3130 { &hf_http3_headers_content_range,
3131 { "content-range", "http3.headers.content_range",
3132 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3133 "Range of bytes which was sent by server for partial data transfer", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3134 },
3135 { &hf_http3_headers_content_type,
3136 { "content-type", "http3.headers.content_type",
3137 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3138 "MIME type of response", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3139 },
3140 { &hf_http3_headers_cookie,
3141 { "cookie", "http3.headers.cookie",
3142 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3143 "Stored cookies", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3144 },
3145 { &hf_http3_headers_date,
3146 { "date", "http3.headers.date",
3147 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3148 "Date and time at which the data was originated", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3149 },
3150 { &hf_http3_headers_etag,
3151 { "etag", "http3.headers.etag",
3152 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3153 "Directive for version indication of resource", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3154 },
3155 { &hf_http3_headers_expect,
3156 { "expect", "http3.headers.expect",
3157 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3158 "Expectations that need to be fulfilled for correct request", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3159 },
3160 { &hf_http3_headers_expires,
3161 { "expires", "http3.headers.expires",
3162 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3163 "Data after which resource will be stale", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3164 },
3165 { &hf_http3_headers_from,
3166 { "from", "http3.headers.from",
3167 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3168 "Email of a person who responsible for a requesting data", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3169 },
3170 { &hf_http3_headers_if_match,
3171 { "if-match", "http3.headers.if_match",
3172 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3173 "Mechanism for requesting data matched by a list of ETags", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3174 },
3175 { &hf_http3_headers_if_modified_since,
3176 { "if-modified-since", "http3.headers.if_modified_since",
3177 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3178 "Resource will be sent with status code 200 if it was modified otherwise with status code 304", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3179 },
3180 { &hf_http3_headers_if_none_match,
3181 { "if-none-match", "http3.headers.if_none_match",
3182 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3183 "Mechanism for requesting data not matched by a list of ETags", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3184 },
3185 { &hf_http3_headers_if_range,
3186 { "if-range", "http3.headers.if_range",
3187 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3188 "Mechanism for a range request which is used to check if a resource was modified", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3189 },
3190 { &hf_http3_headers_if_unmodified_since,
3191 { "if-unmodified-since", "http3.headers.if_unmodified_since",
3192 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3193 "Resource will be processed if it was not modified otherwise 412 error will be returned", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3194 },
3195 { &hf_http3_headers_last_modified,
3196 { "last-modified", "http3.headers.last_modified",
3197 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3198 "Date and time at which the origin server believes the resource was last modified", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3199 },
3200 { &hf_http3_headers_link,
3201 { "link", "http3.headers.link",
3202 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3203 "Mechanism for indicating that resource will be preloaded", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3204 },
3205 { &hf_http3_headers_location,
3206 { "location", "http3.headers.location",
3207 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3208 "Mechanism for indicating that client will be redirected", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3209 },
3210 { &hf_http3_headers_max_forwards,
3211 { "max-forwards", "http3.headers.max_forwards",
3212 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3213 "Mechanism for limiting the number of proxies", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3214 },
3215 { &hf_http3_headers_proxy_authenticate,
3216 { "proxy-authenticate", "http3.headers.proxy_authenticate",
3217 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3218 "Authentication method that should be used to gain access to a resource behind a proxy server", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3219 },
3220 { &hf_http3_headers_proxy_authorization,
3221 { "proxy-authorization", "http3.headers.proxy_authorization",
3222 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3223 "Credentials for a proxy-side authorization", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3224 },
3225 { &hf_http3_headers_range,
3226 { "range", "http3.headers.range",
3227 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3228 "Range of resource bytes that server should return", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3229 },
3230 { &hf_http3_headers_referer,
3231 { "referer", "http3.headers.referer",
3232 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3233 "Address of the previous web page", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3234 },
3235 { &hf_http3_headers_refresh,
3236 { "refresh", "http3.headers.refresh",
3237 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3238 "Time in seconds after which client will be redirected by given url", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3239 },
3240 { &hf_http3_headers_retry_after,
3241 { "retry-after", "http3.headers.retry_after",
3242 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3243 "Mechanism to indicate when resource expected to be available", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3244 },
3245 { &hf_http3_headers_server,
3246 { "server", "http3.headers.server",
3247 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3248 "Information about server software", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3249 },
3250 { &hf_http3_headers_set_cookie,
3251 { "set-cookie", "http3.headers.set_cookie",
3252 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3253 "Send a cookie to the client", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3254 },
3255 { &hf_http3_headers_strict_transport_security,
3256 { "strict-transport-security", "http3.headers.strict_transport_security",
3257 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3258 "HSTS indicates that resource should be accessed only using HTTPS", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3259 },
3260 { &hf_http3_headers_user_agent,
3261 { "user-agent", "http3.headers.user_agent",
3262 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3263 "Information about client software", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3264 },
3265 { &hf_http3_headers_vary,
3266 { "vary", "http3.headers.vary",
3267 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3268 "Mechanism for selecting which header will be used for content negotiation algorithm", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3269 },
3270 { &hf_http3_headers_via,
3271 { "via", "http3.headers.via",
3272 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3273 "Additional information for loop detection and protocol capabilities in proxy requests", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3274 },
3275 { &hf_http3_headers_www_authenticate,
3276 { "www-authenticate", "http3.headers.www_authenticate",
3277 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3278 "Authentication method that should be used to gain access to a resource", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3279 }
3280 };
3281
3282 char *header_name;
3283 for (unsigned i = 0; i < G_N_ELEMENTS(hf)(sizeof (hf) / sizeof ((hf)[0])); ++i) {
3284 header_name = g_strdup(hf[i].hfinfo.name)g_strdup_inline (hf[i].hfinfo.name);
3285
3286 g_hash_table_insert(header_fields_hash, header_name, &hf[i].hfinfo.id);
3287 }
3288 proto_register_field_array(proto_http3, hf, G_N_ELEMENTS(hf)(sizeof (hf) / sizeof ((hf)[0])));
3289}
3290#endif /* HAVE_NGHTTP3 */
3291
3292void
3293proto_register_http3(void)
3294{
3295 expert_module_t *expert_http3;
3296 module_t *module_http3 _U___attribute__((unused));
3297
3298 static hf_register_info hf[] = {
3299 { &hf_http3_stream_uni,
3300 { "Uni Stream", "http3.stream.uni",
3301 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3302 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3303 },
3304 { &hf_http3_stream_uni_type,
3305 { "Uni Stream Type", "http3.stream_uni_type",
3306 FT_UINT64, BASE_HEX|BASE_VAL64_STRING0x00000400, VALS64(http3_stream_types)((0 ? (const struct _val64_string*)0 : ((http3_stream_types))
))
, 0x0,
3307 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3308 },
3309 { &hf_http3_stream_bidi,
3310 { "Request Stream", "http3.stream",
3311 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3312 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3313 },
3314 { &hf_http3_push_id,
3315 { "Push ID", "http3.push_id",
3316 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3317 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3318 },
3319 { &hf_http3_frame,
3320 { "Frame", "http3.frame",
3321 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3322 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3323 },
3324 { &hf_http3_frame_type,
3325 { "Type", "http3.frame_type",
3326 FT_UINT64, BASE_HEX|BASE_VAL64_STRING0x00000400, VALS64(http3_frame_types)((0 ? (const struct _val64_string*)0 : ((http3_frame_types)))
)
, 0x0,
3327 "Frame Type", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3328 },
3329 { &hf_http3_frame_streamid,
3330 { "Stream ID", "http3.frame_streamid",
3331 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3332 "QUIC Stream id that this frame came in on", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3333 },
3334 { &hf_http3_frame_length,
3335 { "Length", "http3.frame_length",
3336 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3337 "Length of the Frame Payload", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3338 },
3339 { &hf_http3_frame_payload,
3340 { "Frame Payload", "http3.frame_payload",
3341 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3342 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3343 },
3344
3345 /* Data */
3346 { &hf_http3_data,
3347 { "Data", "http3.data",
3348 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3349 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3350 },
3351 { &hf_http3_encoded_entity,
3352 { "Content-encoded entity body", "http3.body.content_encoded",
3353 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3354 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3355 },
3356 /* Body fragments */
3357 { &hf_http3_body_fragments,
3358 { "Body fragments", "http3.body.fragments",
3359 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3360 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3361 },
3362 { &hf_http3_body_fragment,
3363 { "Body fragment", "http3.body.fragment",
3364 FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0,
3365 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3366 },
3367 { &hf_http3_body_fragment_overlap,
3368 { "Body fragment overlap", "http3.body.fragment.overlap",
3369 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
3370 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3371 },
3372 { &hf_http3_body_fragment_overlap_conflicts,
3373 { "Body fragment overlapping with conflicting data", "http3.body.fragment.overlap.conflicts",
3374 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
3375 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3376 },
3377 { &hf_http3_body_fragment_multiple_tails,
3378 { "Body has multiple tail fragments", "http3.body.fragment.multiple_tails",
3379 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
3380 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3381 },
3382 { &hf_http3_body_fragment_too_long_fragment,
3383 { "Body fragment too long", "http3.body.fragment.too_long_fragment",
3384 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
3385 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3386 },
3387 { &hf_http3_body_fragment_error,
3388 { "Body defragment error", "http3.body.fragment.error",
3389 FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0,
3390 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3391 },
3392 { &hf_http3_body_fragment_count,
3393 { "Body fragment count", "http3.body.fragment.count",
3394 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3395 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3396 },
3397 { &hf_http3_body_reassembled_in,
3398 { "Reassembled body in frame", "http3.body.reassembled.in",
3399 FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0,
3400 "Reassembled body in frame number", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3401 },
3402 { &hf_http3_body_reassembled_length,
3403 { "Reassembled body length", "http3.body.reassembled.length",
3404 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3405 "Reassembled body in frame number", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3406 },
3407 { &hf_http3_body_reassembled_data,
3408 { "Reassembled body data", "http3.body.reassembled.data",
3409 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3410 "Reassembled body data for multisegment PDU spanning across DATAs", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3411 },
3412
3413 /* Headers */
3414 { &hf_http3_headers_count,
3415 { "Headers Count", "http3.headers.count",
3416 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3417 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3418 },
3419 { &hf_http3_header,
3420 { "Header", "http3.headers.header",
3421 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3422 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3423 },
3424 { &hf_http3_headers_decoded_length,
3425 { "Decoded Headers Length", "http3.headers.decoded_length",
3426 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3427 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3428 },
3429 { &hf_http3_header_name_length,
3430 { "Name Length", "http3.headers.header.name.length",
3431 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3432 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3433 },
3434 { &hf_http3_header_name,
3435 { "Name", "http3.header.header.name",
3436 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3437 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3438 },
3439 { &hf_http3_header_value_length,
3440 { "Value Length", "http3.headers.header.value.length",
3441 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3442 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3443 },
3444 { &hf_http3_header_value,
3445 { "Value", "http3.headers.header.value",
3446 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3447 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3448 },
3449 { &hf_http3_header_request_full_uri,
3450 { "Full request URI", "http3.request.full_uri",
3451 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3452 "The full requested URI (including host name)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3453 },
3454
3455 /* QPACK */
3456 { &hf_http3_header_qpack_blocked,
3457 { "HEADERS head-of-line-blocked on QPACK encoder stream", "http3.header.qpack.blocked",
3458 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
3459 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3460 },
3461 { &hf_http3_header_qpack_blocked_stream_rcint,
3462 { "Required instruction count", "http3.header.qpack.blocked.rcint",
3463 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3464 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3465 },
3466 { &hf_http3_header_qpack_blocked_decoder_wicnt,
3467 { "Available instruction count", "http3.header.qpack.blocked.wcint",
3468 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3469 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3470 },
3471 { &hf_http3_qpack_encoder,
3472 { "QPACK encoder", "http3.qpack.encoder",
3473 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3474 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3475 },
3476 { &hf_http3_qpack_encoder_icnt,
3477 { "QPACK encoder instruction count", "http3.qpack.encoder.icnt",
3478 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3479 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3480 },
3481 { &hf_http3_qpack_encoder_icnt_inc,
3482 { "QPACK encoder instruction count increment", "http3.qpack.encoder.icnt.inc",
3483 FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
3484 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3485 },
3486 { &hf_http3_qpack_encoder_opcode_insert_indexed,
3487 { "Insert with Name Reference", "http3.qpack.encoder.opcode.insert_indexed",
3488 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3489 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3490 },
3491 { &hf_http3_qpack_encoder_opcode_insert_indexed_ref,
3492 { "Name Reference", "http3.qpack.encoder.opcode.insert_indexed.ref",
3493 FT_UINT64, BASE_HEX, NULL((void*)0), 0x0,
3494 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3495 },
3496 { &hf_http3_qpack_encoder_opcode_insert_indexed_val,
3497 { "Value", "http3.qpack.encoder.opcode.insert_indexed.val",
3498 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3499 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3500 },
3501 { &hf_http3_qpack_encoder_opcode_insert_indexed_hval,
3502 { "Value (Huffman)", "http3.qpack.encoder.opcode.insert_indexed.hval",
3503 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3504 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3505 },
3506 { &hf_http3_qpack_encoder_opcode_insert,
3507 { "Insert with Literal Name", "http3.qpack.encoder.opcode.insert",
3508 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3509 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3510 },
3511 { &hf_http3_qpack_encoder_opcode_insert_name,
3512 { "Literal Name", "http3.qpack.encoder.opcode.insert.name",
3513 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3514 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3515 },
3516 { &hf_http3_qpack_encoder_opcode_insert_hname,
3517 { "Literal Name (Huffman)", "http3.qpack.encoder.opcode.insert.hname",
3518 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3519 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3520 },
3521 { &hf_http3_qpack_encoder_opcode_insert_val,
3522 { "Value", "http3.qpack.encoder.opcode.insert.val",
3523 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3524 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3525 },
3526 { &hf_http3_qpack_encoder_opcode_insert_hval,
3527 { "Value (Huffman)", "http3.qpack.encoder.opcode.insert.hval",
3528 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3529 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3530 },
3531 { &hf_http3_qpack_encoder_opcode_duplicate,
3532 { "Duplicate", "http3.qpack.encoder.opcode.duplicate",
3533 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3534 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3535 },
3536 { &hf_http3_qpack_encoder_opcode_dtable_cap,
3537 { "Set Dynamic Table Capacity", "http3.qpack.encoder.opcode.dtable_cap",
3538 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3539 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3540 },
3541 { &hf_http3_qpack_encoder_opcode_dtable_cap_val,
3542 { "Capacity", "http3.qpack.encoder.opcode.dtable_cap.val",
3543 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3544 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3545 },
3546 { &hf_http3_qpack_decoder,
3547 { "QPACK decoder", "http3.qpack.decoder",
3548 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3549 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3550 },
3551 { &hf_http3_qpack_decoder_opcode_section_ack,
3552 { "Section ACK", "http3.qpack.decoder.opcode.section_ack",
3553 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3554 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3555 },
3556 { &hf_http3_qpack_decoder_opcode_section_ack_stream_id,
3557 { "Section ACK stream ID", "http3.qpack.decoder.opcode.section_ack.stream_id",
3558 FT_UINT64, BASE_HEX, NULL((void*)0), 0x0,
3559 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3560 },
3561 { &hf_http3_qpack_decoder_opcode_cancel_stream,
3562 { "Cancel stream", "http3.qpack.decoder.opcode.cancel_stream",
3563 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3564 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3565 },
3566 { &hf_http3_qpack_decoder_opcode_cancel_stream_id,
3567 { "Cancel stream stream ID", "http3.qpack.decoder.opcode.cancel_stream.id",
3568 FT_UINT64, BASE_HEX, NULL((void*)0), 0x0,
3569 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3570 },
3571 { &hf_http3_qpack_decoder_opcode_icnt_increment,
3572 { "Instruction count increment", "http3.qpack.decoder.opcode.icnt_inc",
3573 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3574 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3575 },
3576 { &hf_http3_qpack_decoder_opcode_icnt_increment_value,
3577 { "Instruction count increment value", "http3.qpack.decoder.opcode.icnt_inc.val",
3578 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3579 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3580 },
3581
3582 /* Settings */
3583 { &hf_http3_settings,
3584 { "Settings", "http3.settings",
3585 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3586 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3587 },
3588 { &hf_http3_settings_identifier,
3589 { "Settings Identifier", "http3.settings.id",
3590 FT_UINT64, BASE_HEX|BASE_VAL64_STRING0x00000400, VALS64(http3_settings_vals)((0 ? (const struct _val64_string*)0 : ((http3_settings_vals)
)))
, 0x0,
3591 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3592 },
3593 { &hf_http3_settings_value,
3594 { "Settings Value", "http3.settings.value",
3595 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3596 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3597 },
3598 { &hf_http3_settings_qpack_max_table_capacity,
3599 { "Max Table Capacity", "http3.settings.qpack.max_table_capacity",
3600 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3601 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3602 },
3603 { &hf_http3_settings_max_field_section_size,
3604 { "Max header list size", "http3.settings.max_field_section_size",
3605 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3606 "The default value is unlimited.", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3607 },
3608 { &hf_http3_settings_qpack_blocked_streams,
3609 { "Blocked Streams", "http3.settings.qpack.blocked_streams",
3610 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3611 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3612 },
3613 { &hf_http3_settings_extended_connect,
3614 { "Extended CONNECT", "http3.settings.extended_connect",
3615 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3616 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3617 },
3618 { &hf_http3_settings_webtransport,
3619 { "WebTransport", "http3.settings.webtransport",
3620 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3621 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3622 },
3623 { &hf_http3_settings_h3_datagram,
3624 { "H3 DATAGRAM", "http3.settings.h3_datagram",
3625 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3626 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3627 },
3628 { &hf_http3_settings_h3_datagram_draft04,
3629 { "H3 DATAGRAM Draft04", "http3.settings.h3_datagram_draft04",
3630 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3631 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3632 },
3633
3634 /* Priority Update */
3635 { &hf_http3_priority_update_element_id,
3636 { "Priority Update Element ID", "http3.priority_update_element_id",
3637 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3638 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3639 },
3640 { &hf_http3_priority_update_field_value,
3641 { "Priority Update Field Value", "http3.priority_update_field_value",
3642 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
3643 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3644 },
3645
3646 /* Datagram */
3647 { &hf_http3_datagram,
3648 { "Datagram", "http3.datagram",
3649 FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
3650 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3651 },
3652 { &hf_http3_datagram_quarter_stream_id,
3653 { "Quarter Stream ID", "http3.datagram.quarter_stream_id",
3654 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3655 "Request stream id divided by 4", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3656 },
3657 { &hf_http3_datagram_request_stream_id,
3658 { "Associated Request Stream ID", "http3.datagram.request_stream_id",
3659 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
3660 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3661 },
3662 { &hf_http3_datagram_payload,
3663 { "Datagram Payload", "http3.datagram.payload",
3664 FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
3665 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
3666 },
3667 };
3668
3669 static int *ett[] = {&ett_http3,
3670 &ett_http3_stream_uni,
3671 &ett_http3_stream_bidi,
3672 &ett_http3_frame,
3673 &ett_http3_body_fragment,
3674 &ett_http3_body_fragments,
3675 &ett_http3_encoded_entity,
3676 &ett_http3_settings,
3677 &ett_http3_headers,
3678 &ett_http3_headers_qpack_blocked,
3679 &ett_http3_qpack_update,
3680 &ett_http3_qpack_opcode,
3681 &ett_http3_datagram,
3682 &ett_http3_datagram_stream_id};
3683
3684 static ei_register_info ei[] = {
3685 { &ei_http3_unknown_stream_type,
3686 { "http3.unknown_stream_type", PI_UNDECODED0x05000000, PI_WARN0x00600000,
3687 "An unknown stream type was encountered", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3688 },
3689 { &ei_http3_qpack_failed,
3690 { "http3.qpack_enc_failed", PI_UNDECODED0x05000000, PI_NOTE0x00400000,
3691 "Error decoding QPACK buffer", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3692 },
3693 { &ei_http3_prefix_int_failed,
3694 { "http3.prefix_int.failed", PI_UNDECODED0x05000000, PI_WARN0x00600000,
3695 "Error decoding prefixed integer (too big)", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3696 },
3697 { &ei_http3_huffman_failed,
3698 { "http3.huffman.failed", PI_UNDECODED0x05000000, PI_WARN0x00600000,
3699 "Error in Huffman decoding", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3700 },
3701 { &ei_http3_header_encoded_state ,
3702 { "http3.expert.header.encoded_state", PI_DEBUG0x08000000, PI_NOTE0x00400000,
3703 "HTTP3 header encoded block", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3704 },
3705 { &ei_http3_header_decoding_failed ,
3706 { "http3.expert.header_decoding.failed", PI_UNDECODED0x05000000, PI_NOTE0x00400000,
3707 "Failed to decode HTTP3 header name/value", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3708 },
3709 { &ei_http3_header_decoding_blocked,
3710 { "http3.expert.header_decoding.blocked", PI_UNDECODED0x05000000, PI_NOTE0x00400000,
3711 "Failed to decode HTTP3 header name/value (blocked on QPACK)", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3712 },
3713 { &ei_http3_header_decoding_no_output,
3714 { "http3.expert.header_decoding.no_output", PI_UNDECODED0x05000000, PI_NOTE0x00400000,
3715 "Failed to decode HTTP3 header name/value (QPACK decoder no emission)", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3716 },
3717 /* Stopping due to excessive headers is possibly PI_SECURITY
3718 * (decompression bomb or other dangerous implemention). */
3719 { &ei_http3_header_size,
3720 { "http3.expert.header_decoding.header_size_exceeded", PI_UNDECODED0x05000000, PI_WARN0x00600000,
3721 "QPACK decompression stopped after " G_STRINGIFY(QPACK_MAX_HEADER_SIZE)"1048576" " bytes", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3722 },
3723 { &ei_http3_header_transfer_encoding,
3724 { "http3.header.transfer_encoding", PI_PROTOCOL0x09000000, PI_WARN0x00600000,
3725 "The Transfer-Encoding header field MUST NOT be used in HTTP/3", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3726 },
3727 { &ei_http3_body_decompression_failed,
3728 { "http3.body.content_encoded.failed", PI_UNDECODED0x05000000, PI_WARN0x00600000,
3729 "Unable to decompress content-encoded entity", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3730 },
3731 { &ei_http3_datagram_invalid_stream_id,
3732 { "http3.expert.datagram.invalid_stream_id", PI_UNDECODED0x05000000, PI_WARN0x00600000,
3733 "Failed to decode HTTP3 datagram stream id", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
3734 },
3735 };
3736
3737 proto_http3 = proto_register_protocol("Hypertext Transfer Protocol Version 3", "HTTP3", "http3");
3738
3739 proto_register_field_array(proto_http3, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
3740 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
3741
3742 module_http3 = prefs_register_protocol(proto_http3, NULL((void*)0));
3743
3744 expert_http3 = expert_register_protocol(proto_http3);
3745 expert_register_field_array(expert_http3, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
3746
3747 http3_handle = register_dissector("http3", dissect_http3, proto_http3);
3748 http3_datagram_handle = register_dissector("http3.datagram", dissect_http3_datagram, proto_http3);
3749#ifdef HAVE_NGHTTP31
3750 /* Fill hash table with static headers */
3751 register_static_headers();
3752
3753#if defined(HAVE_ZLIB1) || defined(HAVE_ZLIBNG) || defined(HAVE_BROTLI1) || defined(HAVE_ZSTD1)
3754 prefs_register_bool_preference(module_http3, "decompress_body",
3755 "Decompress entity bodies",
3756 "Whether to decompress entity bodies that are compressed "
3757 "using \"Content-Encoding: \"",
3758 &http3_decompress_body);
3759#else
3760 prefs_register_obsolete_preference(module_http3, "decompress_body");
3761#endif
3762
3763 reassembly_table_register(&http3_body_reassembly_table,
3764 &quic_reassembly_table_functions);
3765#endif
3766
3767 http3_follow_tap = register_tap("http3_follow");
3768
3769 /* Just use the QUIC functions for now, since the IDs are the same.
3770 * This may change once QUIC multipath is supported. */
3771 register_follow_stream(proto_http3, "http3_follow", quic_follow_conv_filter, quic_follow_index_filter, udp_follow_address_filter, udp_port_to_display, follow_quic_tap_listener, get_quic_connections_count, quic_get_sub_stream_id);
3772}
3773
3774void
3775proto_reg_handoff_http3(void)
3776{
3777#ifdef HAVE_NGHTTP31
3778 media_type_dissector_table = find_dissector_table("media_type");
3779#endif
3780
3781 dissector_add_string("quic.proto", "h3", http3_handle);
3782 dissector_add_string("quic.proto.datagram", "h3", http3_datagram_handle);
3783}
3784
3785/**
3786 * Implementation of helper functions.
3787 */
3788static http3_file_local_ctx *g_http3_file_local_ctx;
3789
3790static unsigned
3791http3_conn_info_hash(const void *key)
3792{
3793 uint8_t bkey[QUIC_MAX_CID_LENGTH20];
3794 const quic_cid_t *v;
3795 unsigned h = 0;
3796
3797 if (key) {
3798 v = (const quic_cid_t *)key;
3799 memset(&bkey[0], 0, QUIC_MAX_CID_LENGTH20);
3800 memcpy(&bkey[0], &v->cid[0], MIN(v->len, QUIC_MAX_CID_LENGTH)(((v->len) < (20)) ? (v->len) : (20)));
3801 h = wmem_strong_hash(&bkey[0], QUIC_MAX_CID_LENGTH20);
3802 }
3803 return h;
3804}
3805
3806static gboolean
3807http3_conn_info_equal(const void *lhs, const void *rhs)
3808{
3809 const quic_cid_t *a = (const quic_cid_t *)lhs;
3810 const quic_cid_t *b = (const quic_cid_t *)rhs;
3811 size_t alen = a->len;
3812 size_t blen = b->len;
3813
3814 return alen == blen && memcmp(&a->cid[0], &b->cid[0], alen) == 0;
3815}
3816
3817#ifdef HAVE_NGHTTP31
3818/* Due to QPACK compression, we may get lots of relatively large
3819 header decoded_header_fields (e.g., 4KiB). Allocating each of them requires lots
3820 of memory. The maximum compression is achieved in QPACK by
3821 referencing header field stored in dynamic table by one or two
3822 bytes. We reduce memory usage by caching header field in this
3823 wmem_map_t to reuse its memory region when we see the same header
3824 field next time. */
3825
3826static size_t
3827http3_hdrcache_length(const void *vv)
3828{
3829 const uint8_t *v = (const uint8_t *)vv;
3830 uint32_t namelen, valuelen;
3831
3832 namelen = pntohu32(v);
3833 valuelen = pntohu32(v + sizeof(namelen) + namelen);
3834
3835 return namelen + sizeof(namelen) + valuelen + sizeof(valuelen);
3836}
3837
3838static unsigned
3839http3_hdrcache_hash(const void *key)
3840{
3841 return wmem_strong_hash((const uint8_t *)key, http3_hdrcache_length(key));
3842}
3843
3844static gboolean
3845http3_hdrcache_equal(const void *lhs, const void *rhs)
3846{
3847 const uint8_t *a = (const uint8_t *)lhs;
3848 const uint8_t *b = (const uint8_t *)rhs;
3849 size_t alen = http3_hdrcache_length(a);
3850 size_t blen = http3_hdrcache_length(b);
3851
3852 return alen == blen && memcmp(a, b, alen) == 0;
3853}
3854#endif
3855
3856/* Deallocation callback */
3857static bool_Bool
3858http3_file_local_ctx_del_cb(wmem_allocator_t *allocator _U___attribute__((unused)), wmem_cb_event_t event _U___attribute__((unused)), void *user_data _U___attribute__((unused)))
3859{
3860 g_http3_file_local_ctx = NULL((void*)0);
3861 return false0;
3862}
3863
3864static http3_file_local_ctx *
3865http3_get_file_local_ctx(void)
3866{
3867 if (g_http3_file_local_ctx == NULL((void*)0)) {
3868 /*
3869 * The file-local context hasn't been initialized yet
3870 * for the current file.
3871 */
3872 g_http3_file_local_ctx = wmem_new(wmem_file_scope(), http3_file_local_ctx)((http3_file_local_ctx*)wmem_alloc((wmem_file_scope()), sizeof
(http3_file_local_ctx)))
;
3873 g_http3_file_local_ctx->conn_info_map =
3874 wmem_map_new(wmem_file_scope(), http3_conn_info_hash, http3_conn_info_equal);
3875#ifdef HAVE_NGHTTP31
3876 g_http3_file_local_ctx->hdr_cache_map =
3877 wmem_map_new(wmem_file_scope(), http3_hdrcache_hash, http3_hdrcache_equal);
3878#endif
3879 wmem_register_callback(wmem_file_scope(), http3_file_local_ctx_del_cb, NULL((void*)0));
3880 }
3881
3882 return g_http3_file_local_ctx;
3883}
3884
3885/*
3886 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3887 *
3888 * Local variables:
3889 * c-basic-offset: 4
3890 * tab-width: 8
3891 * indent-tabs-mode: nil
3892 * End:
3893 *
3894 * vi: set shiftwidth=4 tabstop=8 expandtab:
3895 * :indentSize=4:tabSize=8:noTabs=true:
3896 */