Bug Summary

File:builds/wireshark/wireshark/epan/dissectors/packet-http.c
Warning:line 2727, column 24
Dereference of null pointer (loaded from variable 'p')

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-http.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-11-07-100330-3663-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-http.c
1/* packet-http.c
2 * Routines for HTTP packet disassembly
3 * RFC 1945 (HTTP/1.0)
4 * RFC 2616 (HTTP/1.1)
5 *
6 * Guy Harris <guy@alum.mit.edu>
7 *
8 * Copyright 2017, Eugene Adell <eugene.adell@gmail.com>
9 * Copyright 2004, Jerry Talkington <jtalkington@users.sourceforge.net>
10 * Copyright 2002, Tim Potter <tpot@samba.org>
11 * Copyright 1999, Andrew Tridgell <tridge@samba.org>
12 *
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
16 *
17 * SPDX-License-Identifier: GPL-2.0-or-later
18 */
19
20#include "config.h"
21
22#include <errno(*__errno_location ()).h>
23
24#include <epan/packet.h>
25#include <epan/prefs.h>
26#include <epan/expert.h>
27#include <epan/follow.h>
28#include <epan/addr_resolv.h>
29#include <epan/uat.h>
30#include <epan/charsets.h>
31#include <epan/strutil.h>
32#include <epan/stats_tree.h>
33#include <epan/to_str.h>
34#include <epan/req_resp_hdrs.h>
35#include <epan/proto_data.h>
36#include <epan/export_object.h>
37#include <epan/exceptions.h>
38#include <epan/show_exception.h>
39#include <epan/unit_strings.h>
40#include <epan/credentials.h>
41#include <glib.h>
42#include "packet-http.h"
43#include "packet-http2.h"
44#include "packet-tcp.h"
45#include "packet-tls.h"
46#include "packet-acdr.h"
47#include "packet-media-type.h"
48
49void proto_register_http(void);
50void proto_reg_handoff_http(void);
51void proto_register_message_http(void);
52void proto_reg_handoff_message_http(void);
53
54static int http_tap;
55static int http_eo_tap;
56static int http_follow_tap;
57static int credentials_tap;
58
59static int proto_http;
60static int proto_http2;
61static int proto_ssdp;
62static int hf_http_notification;
63static int hf_http_response;
64static int hf_http_request;
65static int hf_http_response_line;
66static int hf_http_request_line;
67static int hf_http_basic;
68static int hf_http_citrix;
69static int hf_http_citrix_user;
70static int hf_http_citrix_domain;
71static int hf_http_citrix_passwd;
72static int hf_http_citrix_session;
73static int hf_http_request_method;
74static int hf_http_request_uri;
75static int hf_http_request_full_uri;
76static int hf_http_request_path;
77static int hf_http_request_path_segment;
78static int hf_http_request_query;
79static int hf_http_request_query_parameter;
80static int hf_http_request_version;
81static int hf_http_response_version;
82static int hf_http_response_code;
83static int hf_http_response_code_desc;
84static int hf_http_response_phrase;
85static int hf_http_authorization;
86static int hf_http_proxy_authenticate;
87static int hf_http_proxy_authorization;
88static int hf_http_proxy_connect_host;
89static int hf_http_proxy_connect_port;
90static int hf_http_www_authenticate;
91static int hf_http_content_type;
92static int hf_http_content_length_header;
93static int hf_http_content_length;
94static int hf_http_content_encoding;
95static int hf_http_transfer_encoding;
96static int hf_http_upgrade;
97static int hf_http_user_agent;
98static int hf_http_host;
99static int hf_http_range;
100static int hf_http_content_range;
101static int hf_http_connection;
102static int hf_http_cookie;
103static int hf_http_cookie_pair;
104static int hf_http_accept;
105static int hf_http_accept_query;
106static int hf_http_referer;
107static int hf_http_accept_language;
108static int hf_http_accept_encoding;
109static int hf_http_date;
110static int hf_http_cache_control;
111static int hf_http_server;
112static int hf_http_location;
113static int hf_http_sec_websocket_accept;
114static int hf_http_sec_websocket_extensions;
115static int hf_http_sec_websocket_key;
116static int hf_http_sec_websocket_protocol;
117static int hf_http_sec_websocket_version;
118static int hf_http_set_cookie;
119static int hf_http_last_modified;
120static int hf_http_x_forwarded_for;
121static int hf_http_http2_settings;
122static int hf_http_request_in;
123static int hf_http_response_in;
124/*static int hf_http_next_request_in;
125static int hf_http_next_response_in;
126static int hf_http_prev_request_in;
127static int hf_http_prev_response_in; */
128static int hf_http_time;
129static int hf_http_chunk_size;
130static int hf_http_chunk_data;
131static int hf_http_chunk_boundary;
132static int hf_http_chunked_trailer_part;
133static int hf_http_file_data;
134static int hf_http_unknown_header;
135static int hf_http_http2_settings_uri;
136
137static int ett_http;
138static int ett_http_ntlmssp;
139static int ett_http_kerberos;
140static int ett_http_request;
141static int ett_http_request_uri;
142static int ett_http_request_path;
143static int ett_http_request_query;
144static int ett_http_chunked_response;
145static int ett_http_chunk_data;
146static int ett_http_encoded_entity;
147static int ett_http_header_item;
148static int ett_http_http2_settings_item;
149
150static expert_field ei_http_te_and_length;
151static expert_field ei_http_tunnel_too_deep;
152static expert_field ei_http_te_unknown;
153static expert_field ei_http_subdissector_failed;
154static expert_field ei_http_tls_port;
155static expert_field ei_http_leading_crlf;
156static expert_field ei_http_excess_data;
157static expert_field ei_http_bad_header_name;
158static expert_field ei_http_header_name_trailing_ws;
159static expert_field ei_http_bad_header_value_nul;
160static expert_field ei_http_decompression_failed;
161static expert_field ei_http_decompression_disabled;
162static expert_field ei_http_response_code_invalid;
163static expert_field ei_http_request_uri_invalid;
164static expert_field ei_http_request_uri_whitespace;
165
166static dissector_handle_t http_handle;
167static dissector_handle_t http_tcp_handle;
168static dissector_handle_t http_tls_handle;
169static dissector_handle_t http_sctp_handle;
170
171static dissector_handle_t media_handle;
172static dissector_handle_t http2_handle;
173static dissector_handle_t sstp_handle;
174static dissector_handle_t ntlmssp_handle;
175static dissector_handle_t gssapi_handle;
176
177/* RFC 3986 Ch 2.2 Reserved characters*/
178/* patterns used for tvb_ws_mempbrk_pattern_uint8 */
179static ws_mempbrk_pattern pbrk_gen_delims;
180static ws_mempbrk_pattern pbrk_sub_delims;
181
182/* reassembly table for streaming chunk mode */
183static reassembly_table http_streaming_reassembly_table;
184
185REASSEMBLE_ITEMS_DEFINE(http_body, "HTTP Chunked Body")static int ett_http_body_fragment; static int ett_http_body_fragments
; static int hf_http_body_fragments; static int hf_http_body_fragment
; static int hf_http_body_fragment_overlap; static int hf_http_body_fragment_overlap_conflicts
; static int hf_http_body_fragment_multiple_tails; static int
hf_http_body_fragment_too_long_fragment; static int hf_http_body_fragment_error
; static int hf_http_body_fragment_count; static int hf_http_body_reassembled_in
; static int hf_http_body_reassembled_length; static int hf_http_body_reassembled_data
; static int hf_http_body_segment; static const fragment_items
http_body_fragment_items = { &ett_http_body_fragment, &
ett_http_body_fragments, &hf_http_body_fragments, &hf_http_body_fragment
, &hf_http_body_fragment_overlap, &hf_http_body_fragment_overlap_conflicts
, &hf_http_body_fragment_multiple_tails, &hf_http_body_fragment_too_long_fragment
, &hf_http_body_fragment_error, &hf_http_body_fragment_count
, &hf_http_body_reassembled_in, &hf_http_body_reassembled_length
, &hf_http_body_reassembled_data, "HTTP Chunked Body" " fragments"
}
;
186
187/* HTTP chunk virtual frame number (similar to HTTP2 frame num) */
188#define get_http_chunk_frame_numget_virtual_frame_num64 get_virtual_frame_num64
189
190/* Stuff for generation/handling of fields for custom HTTP headers */
191typedef struct _header_field_t {
192 char* header_name;
193 char* header_desc;
194} header_field_t;
195
196static header_field_t* header_fields;
197static unsigned num_header_fields;
198
199static GHashTable* header_fields_hash;
200static hf_register_info* dynamic_hf;
201static unsigned dynamic_hf_size;
202
203static bool_Bool
204header_fields_update_cb(void *r, char **err)
205{
206 header_field_t *rec = (header_field_t *)r;
207 char c;
208
209 if (rec->header_name == NULL((void*)0)) {
210 *err = g_strdup("Header name can't be empty")g_strdup_inline ("Header name can't be empty");
211 return false0;
212 }
213
214 g_strstrip(rec->header_name)g_strchomp (g_strchug (rec->header_name));
215 if (rec->header_name[0] == 0) {
216 *err = g_strdup("Header name can't be empty")g_strdup_inline ("Header name can't be empty");
217 return false0;
218 }
219
220 /* Check for invalid characters (to avoid asserting out when
221 * registering the field).
222 */
223 c = proto_check_field_name(rec->header_name);
224 if (c) {
225 *err = ws_strdup_printf("Header name can't contain '%c'", c)wmem_strdup_printf(((void*)0), "Header name can't contain '%c'"
, c)
;
226 return false0;
227 }
228
229 *err = NULL((void*)0);
230 return true1;
231}
232
233static void *
234header_fields_copy_cb(void* n, const void* o, size_t siz _U___attribute__((unused)))
235{
236 header_field_t* new_rec = (header_field_t*)n;
237 const header_field_t* old_rec = (const header_field_t*)o;
238
239 new_rec->header_name = g_strdup(old_rec->header_name)g_strdup_inline (old_rec->header_name);
240 new_rec->header_desc = g_strdup(old_rec->header_desc)g_strdup_inline (old_rec->header_desc);
241
242 return new_rec;
243}
244
245static void
246header_fields_free_cb(void*r)
247{
248 header_field_t* rec = (header_field_t*)r;
249
250 g_free(rec->header_name)(__builtin_object_size ((rec->header_name), 0) != ((size_t
) - 1)) ? g_free_sized (rec->header_name, __builtin_object_size
((rec->header_name), 0)) : (g_free) (rec->header_name)
;
251 g_free(rec->header_desc)(__builtin_object_size ((rec->header_desc), 0) != ((size_t
) - 1)) ? g_free_sized (rec->header_desc, __builtin_object_size
((rec->header_desc), 0)) : (g_free) (rec->header_desc)
;
252}
253
254UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t)static void header_fields_header_name_set_cb(void* rec, const
char* buf, unsigned len, const void* u1 __attribute__((unused
)), const void* u2 __attribute__((unused))) { char* new_buf =
g_strndup(buf,len); (__builtin_object_size (((((header_field_t
*)rec)->header_name)), 0) != ((size_t) - 1)) ? g_free_sized
((((header_field_t*)rec)->header_name), __builtin_object_size
(((((header_field_t*)rec)->header_name)), 0)) : (g_free) (
(((header_field_t*)rec)->header_name)); (((header_field_t*
)rec)->header_name) = new_buf; } static void header_fields_header_name_tostr_cb
(void* rec, char** out_ptr, unsigned* out_len, const void* u1
__attribute__((unused)), const void* u2 __attribute__((unused
))) { if (((header_field_t*)rec)->header_name ) { *out_ptr
= g_strdup_inline ((((header_field_t*)rec)->header_name))
; *out_len = (unsigned)strlen((((header_field_t*)rec)->header_name
)); } else { *out_ptr = g_strdup_inline (""); *out_len = 0; }
}
255UAT_CSTRING_CB_DEF(header_fields, header_desc, header_field_t)static void header_fields_header_desc_set_cb(void* rec, const
char* buf, unsigned len, const void* u1 __attribute__((unused
)), const void* u2 __attribute__((unused))) { char* new_buf =
g_strndup(buf,len); (__builtin_object_size (((((header_field_t
*)rec)->header_desc)), 0) != ((size_t) - 1)) ? g_free_sized
((((header_field_t*)rec)->header_desc), __builtin_object_size
(((((header_field_t*)rec)->header_desc)), 0)) : (g_free) (
(((header_field_t*)rec)->header_desc)); (((header_field_t*
)rec)->header_desc) = new_buf; } static void header_fields_header_desc_tostr_cb
(void* rec, char** out_ptr, unsigned* out_len, const void* u1
__attribute__((unused)), const void* u2 __attribute__((unused
))) { if (((header_field_t*)rec)->header_desc ) { *out_ptr
= g_strdup_inline ((((header_field_t*)rec)->header_desc))
; *out_len = (unsigned)strlen((((header_field_t*)rec)->header_desc
)); } else { *out_ptr = g_strdup_inline (""); *out_len = 0; }
}
256
257/*
258 * desegmentation of HTTP headers
259 * (when we are over TCP or another protocol providing the desegmentation API)
260 */
261static bool_Bool http_desegment_headers = true1;
262
263/*
264 * desegmentation of HTTP bodies
265 * (when we are over TCP or another protocol providing the desegmentation API)
266 * TODO let the user filter on content-type the bodies he wants desegmented
267 */
268static bool_Bool http_desegment_body = true1;
269
270/*
271 * De-chunking of content-encoding: chunk entity bodies.
272 */
273static bool_Bool http_dechunk_body = true1;
274
275/*
276 * Decompression of compressed content-encoded entities.
277 */
278static bool_Bool http_decompress_body = true1;
279
280/*
281 * Extra checks for valid ASCII data in HTTP headers.
282 */
283static bool_Bool http_check_ascii_headers = false0;
284
285/*
286 * Try heuristic sub-dissectors for HTTP message bodies before
287 * sub-dissectors registered to the Content-Type, aka "MIME sniffing".
288 * Disabled by default, per RFC 9110.
289 */
290static bool_Bool http_try_heuristic_first;
291
292/* Simple Service Discovery Protocol
293 * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
294 * SSDP is the discovery protocol of Universal Plug and Play
295 * UPnP http://www.upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
296 */
297#define TCP_PORT_SSDP1900 1900
298#define UDP_PORT_SSDP1900 1900
299
300/*
301 * TCP and TLS ports
302 *
303 * 2710 is the XBT BitTorrent tracker
304 */
305
306#define TCP_DEFAULT_RANGE"80,3128,3132,5985,8080,8088,11371,1900,2869,2710" "80,3128,3132,5985,8080,8088,11371,1900,2869,2710"
307#define SCTP_DEFAULT_RANGE"80" "80"
308#define TLS_DEFAULT_RANGE"443" "443"
309
310static range_t *global_http_tls_range;
311
312static range_t *http_tcp_range;
313static range_t *http_sctp_range;
314static range_t *http_tls_range;
315
316typedef void (*ReqRespDissector)(packet_info*, tvbuff_t*, proto_tree*, unsigned, const unsigned char*,
317 const unsigned char*, http_conv_t *, http_req_res_t *);
318
319/**
320 * Transfer codings from
321 * https://www.iana.org/assignments/http-parameters/http-parameters.xhtml#transfer-coding
322 * Note: chunked encoding is handled separately.
323 */
324typedef enum _http_transfer_coding {
325 HTTP_TE_NONE, /* Dummy value for header which is not set */
326 /* HTTP_TE_CHUNKED, */
327 HTTP_TE_COMPRESS,
328 HTTP_TE_DEFLATE,
329 HTTP_TE_GZIP,
330 HTTP_TE_IDENTITY,
331 HTTP_TE_UNKNOWN, /* Header was set, but no valid name was found */
332} http_transfer_coding;
333
334/*
335 * Structure holding information from headers needed by main
336 * HTTP dissector code.
337 */
338typedef struct {
339 char *content_type;
340 char *content_type_parameters;
341 int64_t content_length;
342 char *content_encoding;
343 char *upgrade;
344 http_transfer_coding transfer_encoding;
345 bool_Bool have_content_length;
346 bool_Bool transfer_encoding_chunked;
347} headers_t;
348
349/* request or response streaming reassembly data */
350typedef struct {
351 /* reassembly information only for request or response with chunked and streaming data */
352 streaming_reassembly_info_t* streaming_reassembly_info;
353 /* subdissector handler for request or response with chunked and streaming data */
354 dissector_handle_t streaming_handle;
355 /* message being passed to subdissector if the request or response has chunked and streaming data */
356 media_content_info_t* content_info;
357 headers_t* main_headers;
358} http_streaming_reassembly_data_t;
359
360/* http request or response private data */
361typedef struct {
362 /* direction of request message */
363 int req_fwd_flow;
364 /* request or response streaming reassembly data */
365 http_streaming_reassembly_data_t* req_streaming_reassembly_data;
366 http_streaming_reassembly_data_t* res_streaming_reassembly_data;
367 /* request and response headers */
368 wmem_map_t *request_headers;
369 wmem_map_t *response_headers;
370} http_req_res_private_data_t;
371
372 typedef struct _request_trans_t {
373 uint64_t first_range_num;
374 nstime_t abs_time;
375 char *request_uri;
376 uint32_t req_frame;
377} request_trans_t;
378
379 typedef struct _match_trans_t {
380 uint32_t req_frame;
381 uint32_t resp_frame;
382 nstime_t delta_time;
383 char *request_uri;
384 char *http_host;
385} match_trans_t;
386
387static int parse_http_status_code(const unsigned char *line, const unsigned char *lineend);
388static int is_http_request_or_reply(packet_info *pinfo, const char *data, unsigned linelen,
389 media_container_type_t *type, ReqRespDissector
390 *reqresp_dissector, http_conv_t *conv_data);
391static unsigned chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
392 proto_tree *tree, unsigned offset);
393static bool_Bool valid_header_name(const unsigned char *line, unsigned header_len);
394static bool_Bool invalid_header_value_char(uint8_t c);
395static bool_Bool process_header(tvbuff_t *tvb, unsigned offset, unsigned next_offset,
396 const unsigned char *line, unsigned linelen, unsigned colon_offset,
397 packet_info *pinfo, proto_tree *tree,
398 headers_t *eh_ptr, http_conv_t *conv_data,
399 media_container_type_t http_type, wmem_map_t *header_value_map,
400 wmem_allocator_t *header_value_map_allocator, bool_Bool streaming_chunk_mode);
401static int find_header_hf_value(tvbuff_t *tvb, unsigned offset, unsigned header_len);
402static bool_Bool check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb,
403 packet_info *pinfo, char *value);
404static bool_Bool check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb,
405 packet_info *pinfo, char *value);
406static bool_Bool check_auth_digest(proto_item* hdr_item, tvbuff_t* tvb, packet_info* pinfo _U___attribute__((unused)), char* value, unsigned offset, unsigned len);
407static bool_Bool check_auth_citrixbasic(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo,
408 char *value, unsigned offset);
409static bool_Bool check_auth_kerberos(proto_item *hdr_item, tvbuff_t *tvb,
410 packet_info *pinfo, const char *value);
411
412static dissector_table_t port_subdissector_table;
413static dissector_table_t media_type_subdissector_table;
414static dissector_table_t streaming_content_type_dissector_table;
415static dissector_table_t upgrade_subdissector_table;
416static heur_dissector_list_t heur_subdissector_list;
417
418static tap_packet_status
419http_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U___attribute__((unused)), const void *data, tap_flags_t flags _U___attribute__((unused)))
420{
421 export_object_list_t *object_list = (export_object_list_t *)tapdata;
422 const http_eo_t *eo_info = (const http_eo_t *)data;
423 export_object_entry_t *entry;
424
425 if(eo_info) { /* We have data waiting for us */
426 /* These values will be freed when the Export Object window
427 * is closed. */
428 entry = g_new(export_object_entry_t, 1)((export_object_entry_t *) g_malloc_n ((1), sizeof (export_object_entry_t
)))
;
429
430 entry->pkt_num = pinfo->num;
431 /* XXX: Should this remove the port, if any? It's only
432 * for display, so probably not. */
433 entry->hostname = g_strdup(eo_info->hostname)g_strdup_inline (eo_info->hostname);
434 entry->content_type = g_strdup(eo_info->content_type)g_strdup_inline (eo_info->content_type);
435 /* XXX: Should this remove the query portion, if any, from
436 * the path? (Or should that be done in the dissector?) */
437 entry->filename = eo_info->filename ? g_path_get_basename(eo_info->filename) : NULL((void*)0);
438 entry->payload_len = tvb_captured_length(eo_info->payload);
439 entry->payload_data = (uint8_t *)tvb_memdup(NULL((void*)0), eo_info->payload, 0, entry->payload_len);
440
441 object_list->add_entry(object_list->gui_data, entry);
442
443 return TAP_PACKET_REDRAW; /* State changed - window should be redrawn */
444 } else {
445 return TAP_PACKET_DONT_REDRAW; /* State unchanged - no window updates needed */
446 }
447}
448
449/* --- HTTP Status Codes */
450/* Note: The reference for uncommented entries is RFC 2616 */
451const value_string vals_http_status_code[] = {
452 { 100, "Continue" },
453 { 101, "Switching Protocols" },
454 { 102, "Processing" }, /* RFC 2518 */
455 { 103, "Early Hints" }, /* RFC-ietf-httpbis-early-hints-05 */
456 { 199, "Informational - Others" },
457
458 { 200, "OK"},
459 { 201, "Created"},
460 { 202, "Accepted"},
461 { 203, "Non-authoritative Information"},
462 { 204, "No Content"},
463 { 205, "Reset Content"},
464 { 206, "Partial Content"},
465 { 207, "Multi-Status"}, /* RFC 4918 */
466 { 208, "Already Reported"}, /* RFC 5842 */
467 { 226, "IM Used"}, /* RFC 3229 */
468 { 299, "Success - Others"},
469
470 { 300, "Multiple Choices"},
471 { 301, "Moved Permanently"},
472 { 302, "Found"},
473 { 303, "See Other"},
474 { 304, "Not Modified"},
475 { 305, "Use Proxy"},
476 { 307, "Temporary Redirect"},
477 { 308, "Permanent Redirect"}, /* RFC 7538 */
478 { 399, "Redirection - Others"},
479
480 { 400, "Bad Request"},
481 { 401, "Unauthorized"},
482 { 402, "Payment Required"},
483 { 403, "Forbidden"},
484 { 404, "Not Found"},
485 { 405, "Method Not Allowed"},
486 { 406, "Not Acceptable"},
487 { 407, "Proxy Authentication Required"},
488 { 408, "Request Time-out"},
489 { 409, "Conflict"},
490 { 410, "Gone"},
491 { 411, "Length Required"},
492 { 412, "Precondition Failed"},
493 { 413, "Request Entity Too Large"},
494 { 414, "Request-URI Too Long"},
495 { 415, "Unsupported Media Type"},
496 { 416, "Requested Range Not Satisfiable"},
497 { 417, "Expectation Failed"},
498 { 418, "I'm a teapot"}, /* RFC 2324 */
499 { 421, "Misdirected Request"}, /* RFC 7540 */
500 { 422, "Unprocessable Entity"}, /* RFC 4918 */
501 { 423, "Locked"}, /* RFC 4918 */
502 { 424, "Failed Dependency"}, /* RFC 4918 */
503 { 425, "Too Early"}, /* RFC 8470 */
504 { 426, "Upgrade Required"}, /* RFC 2817 */
505 { 428, "Precondition Required"}, /* RFC 6585 */
506 { 429, "Too Many Requests"}, /* RFC 6585 */
507 { 431, "Request Header Fields Too Large"}, /* RFC 6585 */
508 { 451, "Unavailable For Legal Reasons"}, /* RFC 7725 */
509 { 499, "Client Error - Others"},
510
511 { 500, "Internal Server Error"},
512 { 501, "Not Implemented"},
513 { 502, "Bad Gateway"},
514 { 503, "Service Unavailable"},
515 { 504, "Gateway Time-out"},
516 { 505, "HTTP Version not supported"},
517 { 506, "Variant Also Negotiates"}, /* RFC 2295 */
518 { 507, "Insufficient Storage"}, /* RFC 4918 */
519 { 508, "Loop Detected"}, /* RFC 5842 */
520 { 510, "Not Extended"}, /* RFC 2774 */
521 { 511, "Network Authentication Required"}, /* RFC 6585 */
522 { 599, "Server Error - Others"},
523
524 { 0, NULL((void*)0)}
525};
526
527static const char* st_str_reqs = "HTTP Requests by Server";
528static const char* st_str_reqs_by_srv_addr = "HTTP Requests by Server Address";
529static const char* st_str_reqs_by_http_host = "HTTP Requests by HTTP Host";
530static const char* st_str_resps_by_srv_addr = "HTTP Responses by Server Address";
531
532static int st_node_reqs = -1;
533static int st_node_reqs_by_srv_addr = -1;
534static int st_node_reqs_by_http_host = -1;
535static int st_node_resps_by_srv_addr = -1;
536
537/* Parse HTTP path sub components RFC3986 Ch 3.3, 3.4 */
538void
539http_add_path_components_to_tree(tvbuff_t* tvb, packet_info* pinfo, proto_item* item, unsigned offset, unsigned length)
540{
541 proto_item* ti;
542 proto_tree* uri_tree;
543 unsigned end_offset, end_path_offset, query_offset, path_len, query_len, parameter_offset;
544 bool_Bool q_off_found, par_off_found;
545 end_offset = offset + length;
546 /* The Content-Location (and Referer) headers in HTTP 1.1, and the
547 * :path header in HTTP/2 can be an absolute-URI or a partial-URI;
548 * i.e. that they can include a path and a query, but not a fragment.
549 * RFC 7230 2.7 Uniform Request Identifiers, RFC 7231 Appendices C and D,
550 * RFC 7540 8.1.2.3. Request Pseudo-Header Fields
551 * Look for a ? to mark a query.
552 */
553 q_off_found = tvb_find_uint8_length(tvb, offset, length, '?', &query_offset);
554 end_path_offset = (q_off_found == false0) ? end_offset : query_offset;
555 par_off_found = tvb_ws_mempbrk_uint8_length(tvb, offset + 1, end_path_offset - offset - 1, &pbrk_sub_delims, &parameter_offset, NULL((void*)0));
556 if (q_off_found == false0 && par_off_found == false0) {
557 /* Nothing interesting, no need to split. */
558 return;
559 }
560 uri_tree = proto_item_add_subtree(item, ett_http_request_uri);
561 path_len = end_path_offset - offset;
562 proto_tree_add_item(uri_tree, hf_http_request_path, tvb, offset, path_len, ENC_ASCII0x00000000);
563 if (!tvb_ws_mempbrk_uint8_length(tvb, offset + 1, end_path_offset - offset - 1, &pbrk_sub_delims, &parameter_offset, NULL((void*)0))) {
564 proto_tree* path_tree = proto_item_add_subtree(item, ett_http_request_path);
565 while (offset < end_path_offset) {
566 if (!tvb_ws_mempbrk_uint8_length(tvb, offset + 1, end_path_offset - offset - 1, &pbrk_sub_delims, &parameter_offset, NULL((void*)0))) {
567 parameter_offset = end_path_offset;
568 }
569 proto_tree_add_item(path_tree, hf_http_request_path_segment, tvb, offset, parameter_offset - offset, ENC_ASCII0x00000000);
570 offset = parameter_offset + 1;
571 }
572 }
573 if (q_off_found == false0) {
574 return;
575 }
576 /* Skip past the delimiter. */
577 query_offset++;
578 query_len = end_offset - query_offset;
579 offset = query_offset;
580 ti = proto_tree_add_item(uri_tree, hf_http_request_query, tvb, query_offset, query_len, ENC_ASCII0x00000000);
581 proto_tree *query_tree = proto_item_add_subtree(ti, ett_http_request_query);
582 while (offset < end_offset) {
583 if (!tvb_ws_mempbrk_uint8_length(tvb, offset + 1, end_offset - offset - 1, &pbrk_sub_delims, &parameter_offset, NULL((void*)0))) {
584 parameter_offset = end_offset;
585 }
586 proto_tree_add_item(query_tree, hf_http_request_query_parameter, tvb, offset, parameter_offset - offset, ENC_ASCII0x00000000);
587
588 // RFC 8484 - DNS Queries over HTTPS (DoH)
589 if (!tvb_strneql(tvb, offset, "dns=", 4)) {
590 unsigned parameter_value_length = parameter_offset - offset - 4;
591 // The Base64 decode functions just silently skip over
592 // invalid bytes, so we check the length. (It might be
593 // nice for those functions to do the checking.)
594 // Padding is expressely omitted
595 // https://www.rfc-editor.org/info/rfc8484/#section-6
596 // as allowed by base64url
597 // https://www.rfc-editor.org/info/rfc4648/#section-5
598 // https://www.rfc-editor.org/info/rfc4648/#section-3.2
599 // which makes the expected length calculation a bit
600 // tedious.
601 // https://www.rfc-editor.org/info/rfc4648/#section-4
602 unsigned expected_dns_tvb_length = (parameter_value_length / 4) * 3;
603 // parameter_value_length % 4 == 1 should perhaps just
604 // be rejected, it's not valid encoding output.
605 expected_dns_tvb_length += ((parameter_value_length % 4) + 1) / 2;
606 tvbuff_t *dns_tvb = base64uri_tvb_to_new_tvb(tvb, offset + 4, parameter_value_length);
607 if (tvb_reported_length(dns_tvb) == expected_dns_tvb_length &&
608 expected_dns_tvb_length >= 30) { // Check if parameter value was likely base64uri encoded DNS query
609 add_new_data_source(pinfo, dns_tvb, "DNS query");
610 const char *save_match_string = pinfo->match_string;
611 pinfo->match_string = "application/dns-message"; // The DNS dissector needs this for DOH
612 dissector_try_string_with_data(media_type_subdissector_table, "application/dns-message",
613 dns_tvb, pinfo, query_tree, true1, NULL((void*)0));
614 pinfo->match_string = save_match_string;
615 }
616 }
617
618 offset = parameter_offset + 1;
619 }
620}
621
622/* HTTP/Load Distribution stats init function */
623static void
624http_reqs_stats_tree_init(stats_tree* st)
625{
626 st_node_reqs = stats_tree_create_node(st, st_str_reqs, 0, STAT_DT_INT, true1);
627 st_node_reqs_by_srv_addr = stats_tree_create_node(st, st_str_reqs_by_srv_addr, st_node_reqs, STAT_DT_INT, true1);
628 st_node_reqs_by_http_host = stats_tree_create_node(st, st_str_reqs_by_http_host, st_node_reqs, STAT_DT_INT, true1);
629 st_node_resps_by_srv_addr = stats_tree_create_node(st, st_str_resps_by_srv_addr, 0, STAT_DT_INT, true1);
630}
631
632/* HTTP/Load Distribution stats packet function */
633static tap_packet_status
634http_reqs_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U___attribute__((unused)), const void* p, tap_flags_t flags _U___attribute__((unused)))
635{
636 const http_info_value_t* v = (const http_info_value_t*)p;
637 int reqs_by_this_host;
638 int reqs_by_this_addr;
639 int resps_by_this_addr;
640 int i = v->response_code;
641 char *ip_str;
642
643
644 if (v->request_method) {
645 ip_str = address_to_str(NULL((void*)0), &pinfo->dst);
646
647 tick_stat_node(st, st_str_reqs, 0, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_reqs),(0)
,(0),1))
;
648 tick_stat_node(st, st_str_reqs_by_srv_addr, st_node_reqs, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_reqs_by_srv_addr
),(st_node_reqs),(1),1))
;
649 tick_stat_node(st, st_str_reqs_by_http_host, st_node_reqs, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_reqs_by_http_host
),(st_node_reqs),(1),1))
;
650 reqs_by_this_addr = tick_stat_node(st, ip_str, st_node_reqs_by_srv_addr, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(ip_str),(st_node_reqs_by_srv_addr
),(1),1))
;
651
652 if (v->http_host) {
653 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_reqs_by_http_host, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(v->http_host)
,(st_node_reqs_by_http_host),(1),1))
;
654 tick_stat_node(st, ip_str, reqs_by_this_host, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(ip_str),(reqs_by_this_host
),(0),1))
;
655
656 tick_stat_node(st, v->http_host, reqs_by_this_addr, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(v->http_host)
,(reqs_by_this_addr),(0),1))
;
657 }
658
659 wmem_free(NULL((void*)0), ip_str);
660
661 return TAP_PACKET_REDRAW;
662
663 } else if (i != 0) {
664 ip_str = address_to_str(NULL((void*)0), &pinfo->src);
665
666 tick_stat_node(st, st_str_resps_by_srv_addr, 0, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_resps_by_srv_addr
),(0),(0),1))
;
667 resps_by_this_addr = tick_stat_node(st, ip_str, st_node_resps_by_srv_addr, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(ip_str),(st_node_resps_by_srv_addr
),(1),1))
;
668
669 if ( (i>=100)&&(i<400) ) {
670 tick_stat_node(st, "OK", resps_by_this_addr, false)(stats_tree_manip_node_int(MN_INCREASE,(st),("OK"),(resps_by_this_addr
),(0),1))
;
671 } else {
672 tick_stat_node(st, "Error", resps_by_this_addr, false)(stats_tree_manip_node_int(MN_INCREASE,(st),("Error"),(resps_by_this_addr
),(0),1))
;
673 }
674
675 wmem_free(NULL((void*)0), ip_str);
676
677 return TAP_PACKET_REDRAW;
678 }
679
680 return TAP_PACKET_DONT_REDRAW;
681}
682
683
684static int st_node_requests_by_host = -1;
685static const char *st_str_requests_by_host = "HTTP Requests by HTTP Host";
686
687/* HTTP/Requests stats init function */
688static void
689http_req_stats_tree_init(stats_tree* st)
690{
691 st_node_requests_by_host = stats_tree_create_node(st, st_str_requests_by_host, 0, STAT_DT_INT, true1);
692}
693
694/* HTTP/Requests stats packet function */
695static tap_packet_status
696http_req_stats_tree_packet(stats_tree* st, packet_info* pinfo _U___attribute__((unused)), epan_dissect_t* edt _U___attribute__((unused)), const void* p, tap_flags_t flags _U___attribute__((unused)))
697{
698 const http_info_value_t* v = (const http_info_value_t*)p;
699 int reqs_by_this_host;
700
701 if (v->request_method) {
702 tick_stat_node(st, st_str_requests_by_host, 0, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_requests_by_host
),(0),(0),1))
;
703
704 if (v->http_host) {
705 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_requests_by_host, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(v->http_host)
,(st_node_requests_by_host),(1),1))
;
706
707 if (v->request_uri) {
708 tick_stat_node(st, v->request_uri, reqs_by_this_host, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(v->request_uri
),(reqs_by_this_host),(1),1))
;
709 }
710 }
711
712 return TAP_PACKET_REDRAW;
713 }
714
715 return TAP_PACKET_DONT_REDRAW;
716}
717
718static const char *st_str_packets = "Total HTTP Packets";
719static const char *st_str_requests = "HTTP Request Packets";
720static const char *st_str_responses = "HTTP Response Packets";
721static const char *st_str_resp_broken = "???: broken";
722static const char *st_str_resp_100 = "1xx: Informational";
723static const char *st_str_resp_200 = "2xx: Success";
724static const char *st_str_resp_300 = "3xx: Redirection";
725static const char *st_str_resp_400 = "4xx: Client Error";
726static const char *st_str_resp_500 = "5xx: Server Error";
727static const char *st_str_other = "Other HTTP Packets";
728
729static int st_node_packets = -1;
730static int st_node_requests = -1;
731static int st_node_responses = -1;
732static int st_node_resp_broken = -1;
733static int st_node_resp_100 = -1;
734static int st_node_resp_200 = -1;
735static int st_node_resp_300 = -1;
736static int st_node_resp_400 = -1;
737static int st_node_resp_500 = -1;
738static int st_node_other = -1;
739
740
741/* HTTP/Packet Counter stats init function */
742static void
743http_stats_tree_init(stats_tree* st)
744{
745 st_node_packets = stats_tree_create_node(st, st_str_packets, 0, STAT_DT_INT, true1);
746 st_node_requests = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
747 st_node_responses = stats_tree_create_node(st, st_str_responses, st_node_packets, STAT_DT_INT, true1);
748 st_node_resp_broken = stats_tree_create_node(st, st_str_resp_broken, st_node_responses, STAT_DT_INT, true1);
749 st_node_resp_100 = stats_tree_create_node(st, st_str_resp_100, st_node_responses, STAT_DT_INT, true1);
750 st_node_resp_200 = stats_tree_create_node(st, st_str_resp_200, st_node_responses, STAT_DT_INT, true1);
751 st_node_resp_300 = stats_tree_create_node(st, st_str_resp_300, st_node_responses, STAT_DT_INT, true1);
752 st_node_resp_400 = stats_tree_create_node(st, st_str_resp_400, st_node_responses, STAT_DT_INT, true1);
753 st_node_resp_500 = stats_tree_create_node(st, st_str_resp_500, st_node_responses, STAT_DT_INT, true1);
754 st_node_other = stats_tree_create_node(st, st_str_other, st_node_packets, STAT_DT_INT, false0);
755}
756
757/* HTTP/Packet Counter stats packet function */
758static tap_packet_status
759http_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U___attribute__((unused)), const void* p, tap_flags_t flags _U___attribute__((unused)))
760{
761 const http_info_value_t* v = (const http_info_value_t*)p;
762 unsigned i = v->response_code;
763 int resp_grp;
764 const char *resp_str;
765 char* str;
766
767 tick_stat_node(st, st_str_packets, 0, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_packets),
(0),(0),1))
;
768
769 if (i) {
770 tick_stat_node(st, st_str_responses, st_node_packets, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_responses
),(st_node_packets),(0),1))
;
771
772 if ( (i<100)||(i>=600) ) {
773 resp_grp = st_node_resp_broken;
774 resp_str = st_str_resp_broken;
775 } else if (i<200) {
776 resp_grp = st_node_resp_100;
777 resp_str = st_str_resp_100;
778 } else if (i<300) {
779 resp_grp = st_node_resp_200;
780 resp_str = st_str_resp_200;
781 } else if (i<400) {
782 resp_grp = st_node_resp_300;
783 resp_str = st_str_resp_300;
784 } else if (i<500) {
785 resp_grp = st_node_resp_400;
786 resp_str = st_str_resp_400;
787 } else {
788 resp_grp = st_node_resp_500;
789 resp_str = st_str_resp_500;
790 }
791
792 tick_stat_node(st, resp_str, st_node_responses, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(resp_str),(st_node_responses
),(0),1))
;
793
794 str = wmem_strdup_printf(pinfo->pool, "%u %s", i,
795 val_to_str(pinfo->pool, i, vals_http_status_code, "Unknown (%d)"));
796 tick_stat_node(st, str, resp_grp, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(str),(resp_grp),
(0),1))
;
797 } else if (v->request_method) {
798 stats_tree_tick_pivot(st,st_node_requests,v->request_method);
799 } else {
800 tick_stat_node(st, st_str_other, st_node_packets, false)(stats_tree_manip_node_int(MN_INCREASE,(st),(st_str_other),(st_node_packets
),(0),1))
;
801 }
802
803 return TAP_PACKET_REDRAW;
804}
805
806/*
807Generates a referer tree - a best-effort representation of which web request led to which.
808
809Some challenges:
810A user can be forwarded to a single sites from multiple sources. For example,
811google.com -> foo.com and bing.com -> foo.com. A URI alone is not unique.
812
813Additionally, if a user has a subsequent request to foo.com -> bar.com, the
814full chain could either be:
815 google.com -> foo.com -> bar.com, or
816 bing.com -> foo.com -> bar.com,
817
818This indicates that a URI and its referer are not unique. Only a URI and its
819full referer chain are unique. However, HTTP requests only contain the URI
820and the immediate referer. This means that any attempt at generating a
821referer tree is inherently going to be a best-effort approach.
822
823This code assumes that the referer in a request is from the most-recent request
824to that referer.
825
826* To maintain readability of the statistics, whenever a site is visited, all
827prior referers are 'ticked' as well, so that one can easily see the breakdown.
828*/
829
830/* Root node for all referer statistics */
831static int st_node_requests_by_referer = -1;
832/* Referer statistics root node's text */
833static const char *st_str_request_sequences = "HTTP Request Sequences";
834
835/* Mapping of URIs to the most-recently seen node id */
836static wmem_map_t* refstats_uri_to_node_id_hash;
837/* Mapping of node ids to the node's URI ('name' value) */
838static wmem_map_t* refstats_node_id_to_uri_hash;
839/* Mapping of node ids to the parent node id */
840static wmem_map_t* refstats_node_id_to_parent_node_id_hash;
841
842
843/* HTTP/Request Sequences stats init function */
844static void
845http_seq_stats_tree_init(stats_tree* st)
846{
847 int root_node_id = 0;
848 void *root_node_id_p = GINT_TO_POINTER(root_node_id)((gpointer) (glong) (root_node_id));
849 void *node_id_p = NULL((void*)0);
850 char *uri = NULL((void*)0);
851
852 refstats_node_id_to_parent_node_id_hash = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
853 refstats_node_id_to_uri_hash = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
854 refstats_uri_to_node_id_hash = wmem_map_new(wmem_file_scope(), wmem_str_hash, g_str_equal);
855
856 /* Add the root node and its mappings */
857 st_node_requests_by_referer = stats_tree_create_node(st, st_str_request_sequences, root_node_id, STAT_DT_INT, true1);
858 node_id_p = GINT_TO_POINTER(st_node_requests_by_referer)((gpointer) (glong) (st_node_requests_by_referer));
859 uri = wmem_strdup(wmem_file_scope(), st_str_request_sequences);
860
861 wmem_map_insert(refstats_uri_to_node_id_hash, uri, node_id_p);
862 wmem_map_insert(refstats_node_id_to_uri_hash, node_id_p, uri);
863 wmem_map_insert(refstats_node_id_to_parent_node_id_hash, node_id_p, root_node_id_p);
864}
865
866static int
867http_seq_stats_tick_referer(stats_tree* st, const char* arg_referer_uri)
868{
869 int root_node_id = st_node_requests_by_referer;
870 void *root_node_id_p = GINT_TO_POINTER(st_node_requests_by_referer)((gpointer) (glong) (st_node_requests_by_referer));
871 int referer_node_id;
872 void *referer_node_id_p;
873 int referer_parent_node_id;
874 void *referer_parent_node_id_p;
875 char *referer_uri;
876
877 /* Tick the referer's URI */
878 /* Does the node exist? */
879 if (!wmem_map_lookup_extended(refstats_uri_to_node_id_hash, arg_referer_uri, NULL((void*)0), &referer_node_id_p)) {
880 /* The node for the referer didn't already exist, create the mappings */
881 referer_node_id = tick_stat_node(st, arg_referer_uri, root_node_id, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(arg_referer_uri)
,(root_node_id),(1),1))
;
882 referer_node_id_p = GINT_TO_POINTER(referer_node_id)((gpointer) (glong) (referer_node_id));
883 referer_parent_node_id_p = root_node_id_p;
884
885 referer_uri = wmem_strdup(wmem_file_scope(), arg_referer_uri);
886 wmem_map_insert(refstats_uri_to_node_id_hash, referer_uri, referer_node_id_p);
887 wmem_map_insert(refstats_node_id_to_uri_hash, referer_node_id_p, referer_uri);
888 wmem_map_insert(refstats_node_id_to_parent_node_id_hash, referer_node_id_p, referer_parent_node_id_p);
889 } else {
890 /* The node for the referer already exists, tick it */
891 referer_parent_node_id_p = wmem_map_lookup(refstats_node_id_to_parent_node_id_hash, referer_node_id_p);
892 referer_parent_node_id = GPOINTER_TO_INT(referer_parent_node_id_p)((gint) (glong) (referer_parent_node_id_p));
893 referer_node_id = tick_stat_node(st, arg_referer_uri, referer_parent_node_id, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(arg_referer_uri)
,(referer_parent_node_id),(1),1))
;
894 }
895 return referer_node_id;
896}
897
898static void
899http_seq_stats_tick_request(stats_tree* st, const char* arg_full_uri, int referer_node_id)
900{
901 void *referer_node_id_p = GINT_TO_POINTER(referer_node_id)((gpointer) (glong) (referer_node_id));
902 int node_id;
903 void *node_id_p;
904 char *uri;
905
906 /* A request whose referer is itself would only create a chain of nodes. */
907 uri = (char *) wmem_map_lookup(refstats_node_id_to_uri_hash, referer_node_id_p);
908 if (uri && strcmp(uri, arg_full_uri) == 0)
909 return;
910
911 node_id = tick_stat_node(st, arg_full_uri, referer_node_id, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(arg_full_uri),(referer_node_id
),(1),1))
;
912 node_id_p = GINT_TO_POINTER(node_id)((gpointer) (glong) (node_id));
913
914 /* Update the mappings. Even if the URI was already seen, the URI->node mapping may need to be updated */
915
916 /* Is this a new node? */
917 uri = (char *) wmem_map_lookup(refstats_node_id_to_uri_hash, node_id_p);
918 if (!uri) {
919 /* node not found, add mappings for the node and uri */
920 uri = wmem_strdup(wmem_file_scope(), arg_full_uri);
921
922 wmem_map_insert(refstats_uri_to_node_id_hash, uri, node_id_p);
923 wmem_map_insert(refstats_node_id_to_uri_hash, node_id_p, uri);
924 wmem_map_insert(refstats_node_id_to_parent_node_id_hash, node_id_p, referer_node_id_p);
925 } else {
926 /* We've seen the node id before. Update the URI mapping refer to this node id*/
927 wmem_map_insert(refstats_uri_to_node_id_hash, uri, node_id_p);
928 }
929}
930
931char*
932determine_http_location_target(wmem_allocator_t *scope, const char *base_url, const char * location_url)
933{
934 /* Resolving a base URI + relative URI to an absolute URI ("Relative Resolution")
935 is complicated. Because of that, we take shortcuts that may result in
936 inaccurate results, but is also significantly simpler.
937 It would be best to use an external library to do this for us.
938 For reference, the RFC is located at https://tools.ietf.org/html/rfc3986#section-5.4
939
940 Returns NULL if the resolution fails
941 */
942 char *final_target;
943
944 /* base_url must be an absolute URL.*/
945 if (strstr(base_url, "://") == NULL((void*)0)){
946 return NULL((void*)0);
947 }
948
949 /* Empty Location */
950 if (location_url[0] == '\0') {
951 final_target = wmem_strdup(scope, base_url);
952 return final_target;
953 }
954 /* Protocol Relative */
955 else if (g_str_has_prefix(location_url, "//")(__builtin_constant_p ("//")? __extension__ ({ const char * const
__str = (location_url); const char * const __prefix = ("//")
; gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (location_url, "//") )
) {
956 char *base_scheme = g_uri_parse_scheme(base_url);
957 if (base_scheme == NULL((void*)0)) {
958 return NULL((void*)0);
959 }
960 final_target = wmem_strdup_printf(scope, "%s:%s", base_scheme, location_url);
961 g_free(base_scheme)(__builtin_object_size ((base_scheme), 0) != ((size_t) - 1)) ?
g_free_sized (base_scheme, __builtin_object_size ((base_scheme
), 0)) : (g_free) (base_scheme)
;
962 return final_target;
963 }
964 /* Absolute URL*/
965 else if (strstr(location_url, "://") != NULL((void*)0)) {
966 final_target = wmem_strdup(scope, location_url);
967 return final_target;
968 }
969 /* Relative */
970 else {
971 char *start_fragment = strstr(base_url, "#");
972 char *start_query = NULL((void*)0);
973 char *base_url_no_fragment = NULL((void*)0);
974 char *base_url_no_query = NULL((void*)0);
975
976 /* Strip off the fragment (which should never be present)*/
977 if (start_fragment == NULL((void*)0)) {
978 base_url_no_fragment = wmem_strdup(scope, base_url);
979 }
980 else {
981 base_url_no_fragment = wmem_strndup(scope, base_url, start_fragment - base_url);
982 }
983
984 /* Strip off the query (Queries are stripped from all relative URIs) */
985 start_query = strstr(base_url_no_fragment, "?");
986 if (start_query == NULL((void*)0)) {
987 base_url_no_query = wmem_strdup(scope, base_url_no_fragment);
988 }
989 else {
990 base_url_no_query = wmem_strndup(scope, base_url_no_fragment, start_query - base_url_no_fragment);
991 }
992
993 /* A leading question mark (?) means to replace the old query with the new*/
994 if (g_str_has_prefix(location_url, "?")(__builtin_constant_p ("?")? __extension__ ({ const char * const
__str = (location_url); const char * const __prefix = ("?");
gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (location_url, "?") )
) {
995 final_target = wmem_strdup_printf(scope, "%s%s", base_url_no_query, location_url);
996 return final_target;
997 }
998 else {
999 /* We have already tested strstr(base_url) above */
1000 char *scheme_end;
1001 scheme_end = strstr(base_url_no_query, "://");
1002 if (!(scheme_end)) {
1003 return NULL((void*)0);
1004 }
1005 scheme_end += strlen("://");
1006 /* A leading slash means to put the location after the netloc */
1007 if (g_str_has_prefix(location_url, "/")(__builtin_constant_p ("/")? __extension__ ({ const char * const
__str = (location_url); const char * const __prefix = ("/");
gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (location_url, "/") )
) {
1008 char *netloc_end;
1009 int netloc_length;
1010
1011 netloc_end = strstr(scheme_end, "/");
1012 if (!(netloc_end)) {
1013 return NULL((void*)0);
1014 }
1015 netloc_length = (int) (netloc_end - base_url_no_query);
1016 final_target = wmem_strdup_printf(scope, "%.*s%s", netloc_length, base_url_no_query, location_url);
1017 return final_target;
1018 }
1019 /* Otherwise, it replaces the last element in the URI */
1020 else {
1021 const char *end_of_path = g_strrstr(scheme_end, "/");
1022
1023 if (end_of_path != NULL((void*)0)) {
1024 int base_through_path = (int) (end_of_path - base_url_no_query);
1025 final_target = wmem_strdup_printf(scope, "%.*s/%s", base_through_path, base_url_no_query, location_url);
1026 }
1027 else {
1028 final_target = wmem_strdup_printf(scope, "%s/%s", base_url_no_query, location_url);
1029 }
1030 return final_target;
1031 }
1032 }
1033 }
1034 return NULL((void*)0);
1035}
1036
1037/* HTTP/Request Sequences stats packet function */
1038static tap_packet_status
1039http_seq_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U___attribute__((unused)), const void* p, tap_flags_t flags _U___attribute__((unused)))
1040{
1041 const http_info_value_t* v = (const http_info_value_t*)p;
1042
1043 /* Track HTTP Redirects */
1044 if (v->location_target && v->location_base_uri) {
1045 int referer_node_id;
1046 int parent_node_id;
1047 void *parent_node_id_p;
1048 void *current_node_id_p;
1049 char *uri = NULL((void*)0);
1050
1051 char *absolute_target = determine_http_location_target(pinfo->pool, v->location_base_uri, v->location_target);
1052 /* absolute_target is NULL if the resolution fails */
1053 if (absolute_target != NULL((void*)0)) {
1054 /* We assume the user makes the request to the absolute_target */
1055 /* Tick the base URI */
1056 referer_node_id = http_seq_stats_tick_referer(st, v->location_base_uri);
1057
1058 /* Tick the location header's resolved URI */
1059 http_seq_stats_tick_request(st, absolute_target, referer_node_id);
1060
1061 /* Tick all stats nodes above the location */
1062 current_node_id_p = GINT_TO_POINTER(referer_node_id)((gpointer) (glong) (referer_node_id));
1063 unsigned depth = 0;
1064 while (depth++ < 64 && wmem_map_lookup_extended(refstats_node_id_to_parent_node_id_hash, current_node_id_p, NULL((void*)0), &parent_node_id_p)) {
1065 parent_node_id = GPOINTER_TO_INT(parent_node_id_p)((gint) (glong) (parent_node_id_p));
1066 uri = (char *) wmem_map_lookup(refstats_node_id_to_uri_hash, current_node_id_p);
1067 tick_stat_node(st, uri, parent_node_id, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(uri),(parent_node_id
),(1),1))
;
1068 current_node_id_p = parent_node_id_p;
1069 }
1070 }
1071 }
1072
1073 /* Track HTTP Requests/Referers */
1074 if (v->request_method && v->referer_uri && v->full_uri) {
1075 int referer_node_id;
1076 int parent_node_id;
1077 void *parent_node_id_p;
1078 void *current_node_id_p;
1079 char *uri = NULL((void*)0);
1080 /* Tick the referer's URI */
1081 referer_node_id = http_seq_stats_tick_referer(st, v->referer_uri);
1082
1083 /* Tick the request's URI */
1084 http_seq_stats_tick_request(st, v->full_uri, referer_node_id);
1085
1086 /* Tick all stats nodes above the referer */
1087 current_node_id_p = GINT_TO_POINTER(referer_node_id)((gpointer) (glong) (referer_node_id));
1088 unsigned depth = 0;
1089 while (depth++ < 64 && wmem_map_lookup_extended(refstats_node_id_to_parent_node_id_hash, current_node_id_p, NULL((void*)0), &parent_node_id_p)) {
1090 parent_node_id = GPOINTER_TO_INT(parent_node_id_p)((gint) (glong) (parent_node_id_p));
1091 uri = (char *) wmem_map_lookup(refstats_node_id_to_uri_hash, current_node_id_p);
1092 tick_stat_node(st, uri, parent_node_id, true)(stats_tree_manip_node_int(MN_INCREASE,(st),(uri),(parent_node_id
),(1),1))
;
1093 current_node_id_p = parent_node_id_p;
1094 }
1095 }
1096 return TAP_PACKET_DONT_REDRAW;
1097}
1098
1099
1100static void
1101dissect_http_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1102 const char *line)
1103{
1104 tvbuff_t *ntlmssp_tvb;
1105
1106 ntlmssp_tvb = base64_to_tvb(tvb, line);
1107 add_new_data_source(pinfo, ntlmssp_tvb, "NTLMSSP / GSSAPI Data");
1108 if (tvb_strneql(ntlmssp_tvb, 0, "NTLMSSP", 7) == 0)
1109 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo, tree);
1110 else
1111 call_dissector(gssapi_handle, ntlmssp_tvb, pinfo, tree);
1112}
1113
1114static void
1115dissect_http_kerberos(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1116 const char *line)
1117{
1118 tvbuff_t *kerberos_tvb;
1119
1120 kerberos_tvb = base64_to_tvb(tvb, line + 9); /* skip 'Kerberos ' which is 9 chars */
1121 add_new_data_source(pinfo, kerberos_tvb, "Kerberos Data");
1122 call_dissector(gssapi_handle, kerberos_tvb, pinfo, tree);
1123
1124}
1125
1126
1127static http_conv_t *
1128get_http_conversation_data(packet_info *pinfo, conversation_t **conversation)
1129{
1130 http_conv_t *conv_data;
1131
1132 *conversation = find_or_create_conversation(pinfo);
1133
1134 /* Retrieve information from conversation
1135 * or add it if it isn't there yet
1136 */
1137 conv_data = (http_conv_t *)conversation_get_proto_data(*conversation, proto_http);
1138 if(!conv_data) {
1139 /* Setup the conversation structure itself */
1140 conv_data = wmem_new0(wmem_file_scope(), http_conv_t)((http_conv_t*)wmem_alloc0((wmem_file_scope()), sizeof(http_conv_t
)))
;
1141 conv_data->chunk_offsets_fwd = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
1142 conv_data->chunk_offsets_rev = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
1143 conv_data->req_list = wmem_list_new(wmem_file_scope());
1144 conv_data->matches_table = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
1145
1146 conversation_add_proto_data(*conversation, proto_http,
1147 conv_data);
1148 }
1149
1150 return conv_data;
1151}
1152
1153/**
1154 * create a new http_req_res_t and add it to the conversation.
1155 * @return the new allocated object which is already added to the linked list
1156 */
1157static http_req_res_t*
1158push_req_res(http_conv_t *conv_data)
1159{
1160 http_req_res_t *req_res = wmem_new0(wmem_file_scope(), http_req_res_t)((http_req_res_t*)wmem_alloc0((wmem_file_scope()), sizeof(http_req_res_t
)))
;
1161
1162 nstime_set_unset(&(req_res->req_ts));
1163 conv_data->req_res_tail = req_res;
1164 req_res->private_data = wmem_new0(wmem_file_scope(), http_req_res_private_data_t)((http_req_res_private_data_t*)wmem_alloc0((wmem_file_scope()
), sizeof(http_req_res_private_data_t)))
;
1165
1166 return req_res;
1167}
1168
1169/**
1170 * push a request frame number and its time stamp to the conversation data.
1171 */
1172static http_req_res_t*
1173push_req(http_conv_t *conv_data, packet_info *pinfo)
1174{
1175 /* a request will always create a new http_req_res_t object */
1176 http_req_res_t *req_res = push_req_res(conv_data);
1177
1178 req_res->req_framenum = pinfo->num;
1179 req_res->req_ts = pinfo->abs_ts;
1180
1181 /* XXX: Using the same proto key for the frame doesn't work well
1182 * with HTTP 1.1 pipelining, or other situations where more
1183 * than one request can appear in a frame.
1184 */
1185 p_add_proto_data(wmem_file_scope(), pinfo, proto_http, HTTP_PROTO_DATA_REQRES0, req_res);
1186
1187 return req_res;
1188}
1189
1190/**
1191 * push a response frame number to the conversation data.
1192 */
1193static http_req_res_t*
1194push_res(http_conv_t *conv_data, packet_info *pinfo)
1195{
1196 /* a response will create a new http_req_res_t object: if no
1197 object exists, or if the most recent one is already for
1198 a different response. (Exception: If the previous response
1199 code was in the Informational 1xx category, then it was
1200 an interim response, and this response could be for the same
1201 request.) In both cases the corresponding request was not
1202 detected/included in the conversation. In all other cases
1203 the http_req_res_t object created by the request is
1204 used. */
1205 /* XXX: This finds the only most recent request and doesn't support
1206 * HTTP 1.1 pipelining. This limitation has been addressed for
1207 * HTTP GETS if Range Requests are supported.
1208 */
1209 http_req_res_t *req_res = conv_data->req_res_tail;
1210 if (!req_res || (req_res->res_framenum > 0 && req_res->response_code >= 200)) {
1211 req_res = push_req_res(conv_data);
1212 }
1213 req_res->res_framenum = pinfo->num;
1214 /* XXX: Using the same proto key for the frame doesn't work well
1215 * with HTTP 1.1 pipelining, or other situations where more
1216 * than one request can appear in a frame and multiple outstanding
1217 * GET requests. The latter has been addressed with matches_table."
1218 */
1219 p_add_proto_data(wmem_file_scope(), pinfo, proto_http, HTTP_PROTO_DATA_REQRES0, req_res);
1220
1221 return req_res;
1222}
1223
1224dissector_handle_t
1225http_upgrade_dissector(const char *protocol) {
1226 return dissector_get_string_handle(upgrade_subdissector_table, protocol);
1227}
1228
1229static const char *
1230http_get_header_value(packet_info* pinfo, const char *name, bool_Bool the_other_direction) {
1231 conversation_t* conv = find_or_create_conversation(pinfo);
1232 const http_conv_t *conv_data = (http_conv_t *)conversation_get_proto_data(conv, proto_http);
1233 if (conv_data) {
1234 const http_req_res_t *req_res = conv_data->req_res_tail;
1235 if (req_res && req_res->private_data) {
1236 const http_req_res_private_data_t *private_data = (http_req_res_private_data_t *)req_res->private_data;
1237 wmem_map_t *headers = (conv_data->server_port == pinfo->destport && the_other_direction) || (
1238 conv_data->server_port == pinfo->srcport && !the_other_direction)
1239 ? private_data->response_headers
1240 : private_data->request_headers;
1241 if (headers) {
1242 return wmem_map_lookup(headers, name);
1243 }
1244 }
1245 }
1246 return NULL((void*)0);
1247}
1248
1249static int
1250dissect_http_message(tvbuff_t *tvb, unsigned offset, packet_info *pinfo,
1251 proto_tree *tree, http_conv_t *conv_data,
1252 const char* proto_tag, int proto, bool_Bool end_of_stream,
1253 const uint32_t* const seq)
1254{
1255 proto_tree *http_tree = NULL((void*)0);
1256 proto_item *ti = NULL((void*)0);
1257 proto_item *hidden_item;
1258 const unsigned char *line, *firstline;
1259 unsigned next_offset;
1260 const unsigned char *linep, *lineend;
1261 unsigned orig_offset = offset;
1262 unsigned first_linelen, linelen;
1263 bool_Bool is_request_or_reply, is_tls = false0;
1264 bool_Bool saw_req_resp_or_header;
1265 media_container_type_t http_type;
1266 proto_item *hdr_item = NULL((void*)0);
1267 ReqRespDissector reqresp_dissector;
1268 proto_tree *req_tree;
1269 unsigned colon_offset;
1270 headers_t *headers = NULL((void*)0);
1271 unsigned datalen;
1272 int reported_datalen = -1;
1273 dissector_handle_t handle = NULL((void*)0);
1274 bool_Bool dissected = false0;
1275 bool_Bool first_loop = true1;
1276 bool_Bool have_seen_http = false0;
1277 /*unsigned i;*/
1278 /*http_info_value_t *si;*/
1279 http_eo_t *eo_info;
1280 heur_dtbl_entry_t *hdtbl_entry;
1281 int reported_length;
1282 uint16_t word;
1283 bool_Bool leading_crlf = false0;
1284 bool_Bool excess_data = false0;
1285 media_content_info_t* content_info = NULL((void*)0);
1286 wmem_map_t* header_value_map = NULL((void*)0);
1287 int chunk_offset = 0;
1288 wmem_map_t *chunk_map = NULL((void*)0);
1289 wmem_allocator_t *header_value_map_allocator = NULL((void*)0);
1290
1291 /*
1292 * Originally this dissector only saved the header information (both in
1293 * headers and header_value_map) in pinfo->pool scoped data, passing it
1294 * to the (reassembled, if necessary) body contained in the message.
1295 *
1296 * Some protocols use the chunked transfer method to streaming data;
1297 * the headers are not repeated before each chunk but some dissectors
1298 * want the headers when dissecting each chunk (instead of saving the
1299 * headers themselves when called for the first chunk.) So in that
1300 * case the headers are saved in file scoped memory.
1301 *
1302 * Other protocols use the HTTP Upgrade mechanism; at least the first
1303 * frame for the upgrade protocol (which is likely after the response
1304 * that confirms the upgrade) will need a copy of the headers (likely
1305 * the response header and probably the request as well.) In that case
1306 * we also need to save the headers in file scoped memory.
1307 *
1308 * The current implementation saves the headers in file scoped memory
1309 * for all request/response pairs (but not for stray headers outside
1310 * of a request/response pair, often in fuzzed data.) It probably only
1311 * needs to do so for the above two cases, which could mean initially
1312 * allocating a map in pinfo->pool scope and then copying its contents
1313 * to file scope after an Upgrade header is found in order to prevent
1314 * memory consumption from growing over time for captures with HTTP
1315 * that does *not* use Upgrade or streaming chunked transfer method.
1316 * (For HTTP Upgrade both the request and response should have Upgrade
1317 * headers.)
1318 */
1319
1320 /*
1321 * For supporting dissecting chunked data in streaming reassembly mode.
1322 *
1323 * If a HTTP request or response is chunked encoding (the transfer-encoding
1324 * header is 'chunked') and its content-type matching a subdissector in
1325 * "streaming_content_type" dissector table, then we switch to dissect in
1326 * streaming chunk mode. In streaming chunk mode, we dissect the data as soon
1327 * as possible, unlike normal mode, we don't start reassembling until the end
1328 * of the request or response message or at the end of the TCP stream. In
1329 * streaming chunk mode, the first reassembled PDU contains HTTP headers
1330 * and at least one completed chunk of this request or response message. And
1331 * subsequent PDUs consist of one or more chunks:
1332 *
1333 * ----- +-- Reassembled Streaming Content PDU(s) --+-- Reassembled Streaming Content PDU(s) --+--- Reassembled ...
1334 * HLProtos | 1*high-proto-pdu | 1*high-proto-pdu | 1*high-proto-pdu
1335 * ----- +-------------------------------------+----+--------------------------------+---------+-------------------
1336 * | de-chunked-data | de-chunked-data | de-chunked-data
1337 * HTTP +-------- First Reassembled HTTP PDU -----------+--- Second Reassembled HTTP PDU -----+- Third PDU -+ +- Fourth ---
1338 * | headers and 1*chunk | 1*chunk | 1*chunk | | 1*chunk ...
1339 * ----- +--------- TCP segment ---------+ +-----------TCP segment -----------+ +---- TCP segment ---------+ +------------
1340 * TCP | headers | *chunk | part-chunk | | part-chunk | *chunk | part-chunk | | part-chunk | 1*chunk | | 1*chunk ...
1341 * ----- +---------+--------+------------+ +------------+--------+------------+ +------------+-------------+ +------------
1342 *
1343 * Notation:
1344 * - headers HTTP headers of a request or response message.
1345 * - part-chunk The front or rear part of a HTTP chunk.
1346 * - *chunk Zero or more completed HTTP chunks of a HTTP message.
1347 * - 1*chunk One or more completed HTTP chunks of a HTTP message.
1348 * - de-chunked-data De-chunked HTTP body data based on one or more completed chunks.
1349 * - 1*high-proto-pdu One or more high level protocol (on top of HTTP) PDUs.
1350 * - HLProtos High Level Protocols like GRPC-Web.
1351 *
1352 * The headers and content_info of the req_res are allocated in file scope that
1353 * helps to provide information for dissecting subsequent PDUs which only
1354 * contains chunks without headers.
1355 */
1356 bool_Bool streaming_chunk_mode = false0;
1357 bool_Bool begin_with_chunk = false0;
1358 http_streaming_reassembly_data_t* streaming_reassembly_data = NULL((void*)0);
1359
1360 http_req_res_t *curr = (http_req_res_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_http, HTTP_PROTO_DATA_REQRES0);
1361 http_info_value_t *stat_info = NULL((void*)0);
1362 http_req_res_private_data_t* prv_data = curr ? (http_req_res_private_data_t*)curr->private_data : NULL((void*)0);
1363 http_req_res_private_data_t* tail_prv_data = NULL((void*)0);
1364
1365 /* Determine the direction as in the TCP dissector, but don't call
1366 * get_tcp_conversation_data because we don't want to create a new
1367 * TCP stream if it doesn't exist (e.g., SSDP over UDP.)
1368 */
1369 int direction = cmp_address(&pinfo->src, &pinfo->dst);
1370 /* if the addresses are equal, match the ports instead */
1371 if (direction == 0) {
1372 direction = (pinfo->srcport > pinfo->destport) ? 1 : -1;
1373 }
1374 if (direction >= 0) {
1375 chunk_map = conv_data->chunk_offsets_fwd;
1376 } else {
1377 chunk_map = conv_data->chunk_offsets_rev;
1378 }
1379
1380 if (seq && chunk_map) {
1381 chunk_offset = GPOINTER_TO_INT(wmem_map_lookup(chunk_map, GUINT_TO_POINTER(*seq)))((gint) (glong) (wmem_map_lookup(chunk_map, ((gpointer) (gulong
) (*seq)))))
;
1382 /* Returns 0 when there is no entry in the map, as we want. */
1383 }
1384
1385 reported_length = tvb_reported_length_remaining(tvb, offset);
1386 if (reported_length < 1) {
1387 return -1;
1388 }
1389
1390 /* RFC 2616
1391 * In the interest of robustness, servers SHOULD ignore any empty
1392 * line(s) received where a Request-Line is expected. In other words, if
1393 * the server is reading the protocol stream at the beginning of a
1394 * message and receives a CRLF first, it should ignore the CRLF.
1395 */
1396 if (reported_length > 3) {
1397 word = tvb_get_ntohs(tvb,offset);
1398 if (word == 0x0d0a) {
1399 leading_crlf = true1;
1400 offset += 2;
1401 }
1402 }
1403
1404 /*
1405 * If we previously dissected an HTTP request in this conversation then
1406 * we should be pretty sure that whatever we got in this TVB is
1407 * actually HTTP (even if what we have here is part of a file being
1408 * transferred over HTTP).
1409 */
1410 if (conv_data->req_res_tail)
1411 have_seen_http = true1;
1412
1413 /*
1414 * If this is binary data then there's no point in doing all the string
1415 * operations below: they'll just be slow on this data.
1416 */
1417 if (!g_ascii_isprint(tvb_get_uint8(tvb, offset))((g_ascii_table[(guchar) (tvb_get_uint8(tvb, offset))] & G_ASCII_PRINT
) != 0)
) {
1418 /*
1419 * But, if we've seen some real HTTP then we're sure this is
1420 * an HTTP conversation, and this is binary file data.
1421 * Mark it as such.
1422 */
1423 if (have_seen_http) {
1424 tvbuff_t *next_tvb;
1425 int data_len;
1426
1427 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
1428 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1429 ti = proto_tree_add_item(tree, proto, tvb, offset, -1, ENC_NA0x00000000);
1430 http_tree = proto_item_add_subtree(ti, ett_http);
1431
1432 next_tvb = tvb_new_subset_remaining(tvb, orig_offset);
1433 /* If orig_offset > 0, this isn't the first message
1434 * dissected in this TCP segment, which means we had
1435 * a Content-Length, but more data after that body.
1436 */
1437 if (orig_offset > 0) {
1438 proto_tree_add_expert(http_tree, pinfo, &ei_http_excess_data, next_tvb, 0, tvb_captured_length(next_tvb));
1439 }
1440 /* Send it to Follow HTTP Stream and mark as file data */
1441 if(have_tap_listener(http_follow_tap)) {
1442 tap_queue_packet(http_follow_tap, pinfo, next_tvb);
1443 }
1444 data_len = tvb_captured_length(next_tvb);
1445 proto_tree_add_bytes_format_value(http_tree, hf_http_file_data,
1446 next_tvb, 0, data_len, NULL((void*)0), "%u byte%s", data_len, plurality(data_len, "", "s")((data_len) == 1 ? ("") : ("s")));
1447 call_data_dissector(next_tvb, pinfo, http_tree);
1448 }
1449 return -1;
1450 }
1451
1452 /*
1453 * Is this a request or response?
1454 *
1455 * Note that "tvb_find_line_end_length()" will return a value that
1456 * is not longer than what's in the buffer, so the
1457 * "tvb_get_ptr()" call won't throw an exception.
1458 */
1459 bool_Bool lind_end_found = tvb_find_line_end_length(tvb, offset,
1460 tvb_ensure_captured_length_remaining(tvb, offset), &first_linelen , &next_offset);
1461
1462 if (!lind_end_found) {
1463 /* No complete line was found in this segment, do
1464 * desegmentation if we're told to.
1465 */
1466 if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
1467 http_desegment_headers, http_desegment_body, false0, &chunk_offset,
1468 streaming_content_type_dissector_table, &handle)) {
1469 /*
1470 * More data needed for desegmentation.
1471 */
1472 return -1;
1473 }
1474 }
1475
1476 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && conv_data->req_res_tail && conv_data->req_res_tail->private_data) {
1477 tail_prv_data = (http_req_res_private_data_t*) conv_data->req_res_tail->private_data;
1478 }
1479
1480 /* Check whether the first line is the beginning of a chunk. If it is the beginning
1481 * of a chunk, the headers and at least one chunk of HTTP request or response should
1482 * be dissected in the previous packets, and now we are processing subsequent chunks.
1483 */
1484 if (http_desegment_body && http_dechunk_body) {
1485 begin_with_chunk = starts_with_chunk_size(tvb, offset, pinfo);
1486
1487 if (begin_with_chunk &&
1488 ((prv_data && ( /* This packet has been parsed */
1489 /* and now we are in a HTTP request chunk stream */
1490 (prv_data->req_fwd_flow == direction && prv_data->req_streaming_reassembly_data) ||
1491 /* and now we are in a HTTP response chunk stream */
1492 (prv_data->req_fwd_flow != direction && prv_data->res_streaming_reassembly_data)))
1493 ||
1494 (tail_prv_data && ( /* This packet has not been parsed and headers info in conv_data->req_res_tail */
1495 /* and now we are in a HTTP request chunk stream */
1496 (tail_prv_data->req_fwd_flow == direction && tail_prv_data->req_streaming_reassembly_data) ||
1497 /* and now we are in a HTTP response chunk stream */
1498 (tail_prv_data->req_fwd_flow != direction && tail_prv_data->res_streaming_reassembly_data)))))
1499 {
1500 streaming_chunk_mode = true1;
1501 }
1502 }
1503
1504 /*
1505 * Is the first line a request or response?
1506 * Note that "tvb_find_line_end_length()" will return a value that
1507 * is not longer than what's in the buffer, so the
1508 * "tvb_get_ptr()" call won't throw an exception.
1509 */
1510 firstline = tvb_get_ptr(tvb, offset, first_linelen);
1511 http_type = MEDIA_CONTAINER_HTTP_OTHERS; /* type not known yet */
1512 is_request_or_reply = is_http_request_or_reply(pinfo, (const char *)firstline,
1513 first_linelen, &http_type, NULL((void*)0), conv_data);
1514 if (is_request_or_reply || streaming_chunk_mode) {
1515 bool_Bool try_desegment_body;
1516
1517 if (streaming_chunk_mode && begin_with_chunk) {
1518 col_set_str(pinfo->cinfo, COL_INFO, "Chunk Stream ");
1519 } else {
1520 /*
1521 * Yes, it's a request or response.
1522 * Put the first line from the buffer into the summary
1523 * (but leave out the line terminator).
1524 */
1525 col_add_fstr(pinfo->cinfo, COL_INFO, "%s ", format_text(pinfo->pool, (char*)firstline, first_linelen));
1526 }
1527
1528 /*
1529 * Do header desegmentation if we've been told to,
1530 * and do body desegmentation if we've been told to and
1531 * we find a Content-Length header in requests.
1532 *
1533 * The following cases (from RFC 7230, Section 3.3) never have a
1534 * response body, so do not attempt to desegment the body for:
1535 * * Responses to HEAD requests.
1536 * * 2xx responses to CONNECT requests.
1537 * * 1xx, 204 No Content, 304 Not Modified responses.
1538 *
1539 * Additionally if we are at the end of stream, no more segments
1540 * will be added so disable body segmentation too in that case.
1541 */
1542 try_desegment_body = (http_desegment_body && !end_of_stream);
1543 if (try_desegment_body && http_type == MEDIA_CONTAINER_HTTP_RESPONSE && !streaming_chunk_mode) {
1544 /*
1545 * The response_code is not yet set, so extract
1546 * the response code from the current line.
1547 */
1548 int response_code = parse_http_status_code(firstline, firstline + first_linelen);
1549 /*
1550 * On a second pass, we should have already associated
1551 * the response with the request. On a first sequential
1552 * pass, we haven't done so yet (as we don't know if we
1553 * need more data), so get the request method from the
1554 * most recent request, if it exists.
1555 */
1556 char* request_method = NULL((void*)0);
1557 if (curr) {
1558 request_method = curr->request_method;
1559 } else if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && conv_data->req_res_tail) {
1560 request_method = conv_data->req_res_tail->request_method;
1561 }
1562 if ((g_strcmp0(request_method, "HEAD") == 0 ||
1563 (response_code / 100 == 2 &&
1564 (g_strcmp0(request_method, "CONNECT") == 0 ||
1565 g_strcmp0(request_method, "SSTP_DUPLEX_POST") == 0)) ||
1566 response_code / 100 == 1 ||
1567 response_code == 204 ||
1568 response_code == 304)) {
1569 /* No response body is present. */
1570 try_desegment_body = false0;
1571 }
1572 }
1573 if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
1574 http_desegment_headers, try_desegment_body, http_type == MEDIA_CONTAINER_HTTP_RESPONSE, &chunk_offset,
1575 streaming_content_type_dissector_table, &handle)) {
1576 /*
1577 * More data needed for desegmentation.
1578 */
1579 if (seq && chunk_map && chunk_offset) {
1580 wmem_map_insert(chunk_map, GUINT_TO_POINTER(*seq)((gpointer) (gulong) (*seq)), GINT_TO_POINTER(chunk_offset)((gpointer) (glong) (chunk_offset)));
1581 }
1582 return -1;
1583 }
1584
1585 if (handle && http_desegment_body && http_dechunk_body) {
1586 /* This handle is set because there is a header 'Transfer-Encoding: chunked', and
1587 * a streaming mode reassembly supported subdissector is found according to the
1588 * header of Content-Type.
1589 */
1590 streaming_chunk_mode = true1;
1591 }
1592 } else if (have_seen_http) {
1593 /*
1594 * If we know this is HTTP then call it continuation.
1595 */
1596 /* If orig_offset > 0, this isn't the first message dissected
1597 * in this segment, which means we had a Content-Length, but
1598 * more data after the body. If this isn't a request or reply,
1599 * that's bogus, and probably means the Content-Length was
1600 * wrong.
1601 */
1602 if (orig_offset > 0) {
1603 excess_data = true1;
1604 }
1605 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1606 }
1607
1608 if (is_request_or_reply || have_seen_http || streaming_chunk_mode) {
1609 /*
1610 * Now set COL_PROTOCOL and create the http tree for the
1611 * cases where we set COL_INFO above.
1612 */
1613 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
1614 ti = proto_tree_add_item(tree, proto, tvb, offset, -1, ENC_NA0x00000000);
1615 http_tree = proto_item_add_subtree(ti, ett_http);
1616
1617 if (leading_crlf) {
1618 proto_tree_add_expert(http_tree, pinfo, &ei_http_leading_crlf, tvb, offset-2, 2);
1619 }
1620 if (excess_data) {
1621 proto_tree_add_expert(http_tree, pinfo, &ei_http_excess_data, tvb, offset, tvb_captured_length_remaining(tvb, offset));
1622 }
1623 }
1624
1625 is_tls = proto_is_frame_protocol(pinfo->layers, "tls");
1626
1627 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && begin_with_chunk
1628 && streaming_chunk_mode && conv_data->req_res_tail) {
1629 /* point this packet beginning with a chunk to req_res info created in previous packet. */
1630 curr = conv_data->req_res_tail;
1631 prv_data = (http_req_res_private_data_t*)curr->private_data;
1632 p_set_proto_data(wmem_file_scope(), pinfo, proto_http, HTTP_PROTO_DATA_REQRES0, curr);
1633 }
1634
1635 if (prv_data) {
1636 if (prv_data->req_fwd_flow == direction && prv_data->req_streaming_reassembly_data) {
1637 /* in request flow */
1638 streaming_reassembly_data = prv_data->req_streaming_reassembly_data;
1639 } else if (prv_data->req_fwd_flow != direction && prv_data->res_streaming_reassembly_data) {
1640 /* in response flow */
1641 streaming_reassembly_data = prv_data->res_streaming_reassembly_data;
1642 }
1643
1644 if (streaming_reassembly_data) {
1645 streaming_chunk_mode = true1;
1646 headers = streaming_reassembly_data->main_headers;
1647 handle = streaming_reassembly_data->streaming_handle;
1648 content_info = streaming_reassembly_data->content_info;
1649 header_value_map = (wmem_map_t*) content_info->data;
1650 header_value_map_allocator = wmem_file_scope();
1651 }
1652 }
1653
1654 // Ensure headers is valid before the `goto dissecting_body` below.
1655 if (headers == NULL((void*)0)) {
1656 if (PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && streaming_chunk_mode) {
1657 /* No streaming state was kept for this frame (can happen
1658 * with pipelined messages); dissect it without it. */
1659 streaming_chunk_mode = false0;
1660 begin_with_chunk = false0;
1661 }
1662 header_value_map = NULL((void*)0);
1663
1664 headers = wmem_new0((streaming_chunk_mode ? wmem_file_scope() : pinfo->pool), headers_t)((headers_t*)wmem_alloc0(((streaming_chunk_mode ? wmem_file_scope
() : pinfo->pool)), sizeof(headers_t)))
;
1665 if (streaming_chunk_mode) {
1666 header_value_map_allocator = wmem_file_scope();
1667 header_value_map = wmem_map_new(header_value_map_allocator, g_str_hash, g_str_equal);
1668 }
1669 }
1670
1671 if (streaming_chunk_mode && begin_with_chunk) {
1672 datalen = reported_length;
1673 goto dissecting_body;
1674 }
1675
1676 stat_info = wmem_new(pinfo->pool, http_info_value_t)((http_info_value_t*)wmem_alloc((pinfo->pool), sizeof(http_info_value_t
)))
;
1677 stat_info->framenum = pinfo->num;
1678 stat_info->response_code = 0;
1679 stat_info->request_method = NULL((void*)0);
1680 stat_info->request_uri = NULL((void*)0);
1681 stat_info->referer_uri = NULL((void*)0);
1682 stat_info->http_host = NULL((void*)0);
1683 stat_info->full_uri = NULL((void*)0);
1684 stat_info->location_target = NULL((void*)0);
1685 stat_info->location_base_uri = NULL((void*)0);
1686 p_set_proto_data(pinfo->pool, pinfo, proto_http, HTTP_PROTO_DATA_INFO1, (void *)stat_info);
1687
1688 /*
1689 * Process the packet data, a line at a time.
1690 */
1691 http_type = MEDIA_CONTAINER_HTTP_OTHERS; /* type not known yet */
1692
1693 saw_req_resp_or_header = false0; /* haven't seen anything yet */
1694 while (tvb_offset_exists(tvb, offset)) {
1695 /*
1696 * Find the end of the line.
1697 * XXX - what if we don't find it because the packet
1698 * is cut short by a snapshot length or the header is
1699 * split across TCP segments? How much dissection should
1700 * we do on it?
1701 */
1702 bool_Bool linelen_found = tvb_find_line_end_length(tvb, offset,
1703 tvb_ensure_captured_length_remaining(tvb, offset), &linelen ,&next_offset);
1704 if (!linelen_found)
1705 return -1;
1706
1707 /*
1708 * Get a buffer that refers to the line.
1709 *
1710 * Note that "tvb_find_line_end_length()" will return a value that
1711 * is not longer than what's in the buffer, so the
1712 * "tvb_get_ptr()" call won't throw an exception.
1713 */
1714 line = tvb_get_ptr(tvb, offset, linelen);
1715 lineend = line + linelen;
1716 colon_offset = -1;
1717
1718 /*
1719 * OK, does it look like an HTTP request or response?
1720 */
1721 reqresp_dissector = NULL((void*)0);
1722 is_request_or_reply =
1723 is_http_request_or_reply(pinfo, (const char *)line,
1724 linelen, &http_type, &reqresp_dissector, conv_data);
1725 if (is_request_or_reply)
1726 goto is_http;
1727
1728 /*
1729 * No. Does it look like a blank line (as would appear
1730 * at the end of an HTTP request)?
1731 */
1732 if (linelen == 0)
1733 goto is_http; /* Yes. */
1734
1735 /*
1736 * No. Does it look like a header?
1737 */
1738 colon_offset = offset;
1739
1740 linep = (const unsigned char *)memchr(line, ':', linelen);
1741 if (linep) {
1742 /*
1743 * Colon found, assume it is a header if we've seen a
1744 * valid line before. Check a little more if not.
1745 */
1746 if (saw_req_resp_or_header || valid_header_name(line, (int)(linep - line))) {
1747 colon_offset += (int)(linep - line);
1748 if (http_check_ascii_headers) {
1749 unsigned i;
1750 for (i = 0; i < linelen; i++) {
1751 if (line[i] & 0x80) {
1752 /*
1753 * Non-ASCII! Return -2 for invalid
1754 * HTTP, distinct from -1 for possible
1755 * reassembly required.
1756 */
1757 return -2;
1758 }
1759 }
1760 }
1761 goto is_http;
1762 }
1763 }
1764
1765 /*
1766 * We haven't seen the colon yet.
1767 *
1768 * If we've already seen an HTTP request or response
1769 * line, or a header line, and we're at the end of
1770 * the tvbuff, we assume this is an incomplete header
1771 * line. (We quit this loop after seeing a blank line,
1772 * so if we've seen a request or response line, or a
1773 * header line, this is probably more of the request
1774 * or response we're presumably seeing. There is some
1775 * risk of false positives, but the same applies for
1776 * full request or response lines or header lines,
1777 * although that's less likely.)
1778 *
1779 * We throw an exception in that case, by checking for
1780 * the existence of the next byte after the last one
1781 * in the line. If it exists, "tvb_ensure_bytes_exist()"
1782 * throws no exception, and we fall through to the
1783 * "not HTTP" case. If it doesn't exist,
1784 * "tvb_ensure_bytes_exist()" will throw the appropriate
1785 * exception.
1786 */
1787 if (saw_req_resp_or_header)
1788 tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
1789
1790 /*
1791 * We don't consider this part of an HTTP request or
1792 * reply, so we don't display it.
1793 * (Yeah, that means we don't display, say, a text/http
1794 * page, but you can get that from the data pane.)
1795 */
1796 break;
1797
1798 is_http:
1799 if ((tree) && (http_tree == NULL((void*)0))) {
1800 ti = proto_tree_add_item(tree, proto, tvb, orig_offset, -1, ENC_NA0x00000000);
1801 http_tree = proto_item_add_subtree(ti, ett_http);
1802 if (leading_crlf) {
1803 proto_tree_add_expert(http_tree, pinfo, &ei_http_leading_crlf, tvb, orig_offset-2, 2);
1804 }
1805 }
1806
1807 if (first_loop && !is_tls && pinfo->ptype == PT_TCP &&
1808 (pinfo->srcport == 443 || pinfo->destport == 443)) {
1809 expert_add_info(pinfo, ti, &ei_http_tls_port);
1810 }
1811
1812 first_loop = false0;
1813
1814 /*
1815 * Process this line.
1816 */
1817
1818 if (linelen == 0) {
1819 /*
1820 * This is a blank line, which means that
1821 * whatever follows it isn't part of this
1822 * request or reply.
1823 */
1824 proto_tree_add_format_text(http_tree, tvb, offset, next_offset - offset);
1825 offset = next_offset;
1826 break;
1827 }
1828
1829 /*
1830 * Not a blank line - either a request, a reply, or a header
1831 * line.
1832 */
1833 saw_req_resp_or_header = true1;
1834 if (is_request_or_reply) {
1835 char *text = tvb_format_text(pinfo->pool, tvb, offset, next_offset - offset);
1836
1837 req_tree = proto_tree_add_subtree(http_tree, tvb,
1838 offset, next_offset - offset, ett_http_request, &hdr_item, text);
1839
1840 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1841 if (header_value_map_allocator != wmem_file_scope()) {
1842 /*
1843 * If we already have a header_value_map allocated
1844 * with pinfo->pool scope, that means we saw a
1845 * field-line followed by a start line in the same
1846 * message; that's bogus, so we shouldn't need to
1847 * worry about passing the previous "headers" to a
1848 * next dissector, so it's okay to drop the map.
1849 */
1850 header_value_map_allocator = wmem_file_scope();
1851 header_value_map = wmem_map_new(header_value_map_allocator, g_str_hash, g_str_equal);
1852 }
1853 if (http_type == MEDIA_CONTAINER_HTTP_REQUEST) {
1854 curr = push_req(conv_data, pinfo);
1855 curr->request_method = wmem_strdup(wmem_file_scope(), stat_info->request_method);
1856 prv_data = curr->private_data;
1857 prv_data->req_fwd_flow = direction;
1858 prv_data->request_headers = header_value_map;
1859 } else if (http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
1860 curr = push_res(conv_data, pinfo);
1861 prv_data = curr->private_data;
1862 prv_data->req_fwd_flow = -direction;
1863 prv_data->response_headers = header_value_map;
1864 }
1865 }
1866 if (reqresp_dissector) {
1867 reqresp_dissector(pinfo, tvb, req_tree, offset, line,
1868 lineend, conv_data, curr);
1869 }
1870 } else {
1871 /*
1872 * Header.
1873 */
1874 if (header_value_map == NULL((void*)0) && conv_data->req_res_tail) {
1875 prv_data = (http_req_res_private_data_t*)conv_data->req_res_tail->private_data;
1876 if (prv_data) {
1877 header_value_map_allocator = wmem_file_scope();
1878 if (prv_data->req_fwd_flow == direction) {
1879 header_value_map = prv_data->request_headers;
1880 } else {
1881 header_value_map = prv_data->response_headers;
1882 }
1883 }
1884 }
1885 if (header_value_map == NULL((void*)0)) {
1886 /*
1887 * We are seeing a header but have not tracked request or response, so we don't know
1888 * direction of this header, so not going to keep track of it
1889 */
1890 header_value_map_allocator = pinfo->pool;
1891 header_value_map = wmem_map_new(header_value_map_allocator, g_str_hash, g_str_equal);
1892 }
1893 bool_Bool good_header = process_header(tvb, offset, next_offset, line, linelen,
1894 colon_offset, pinfo, http_tree, headers, conv_data, http_type, header_value_map,
1895 header_value_map_allocator, streaming_chunk_mode);
1896 if (http_check_ascii_headers && !good_header) {
1897 /*
1898 * Line is not a good HTTP header.
1899 * Return -2 to mark as invalid HTTP;
1900 * this is distinct from returning -1 when
1901 * it may be HTTP but in need of reassembly.
1902 */
1903 return -2;
1904 }
1905 }
1906 offset = next_offset;
1907 }
1908 if (stat_info->http_host && stat_info->request_uri) {
1909 char *uri;
1910
1911 if ((g_ascii_strncasecmp(stat_info->request_uri, "http://", 7) == 0) ||
1912 (g_ascii_strncasecmp(stat_info->request_uri, "https://", 8) == 0) ||
1913 (g_ascii_strncasecmp(stat_info->request_method, "CONNECT", 7) == 0)) {
1914 uri = wmem_strdup(pinfo->pool, stat_info->request_uri);
1915 }
1916 else {
1917 uri = wmem_strdup_printf(pinfo->pool, "%s://%s%s",
1918 is_tls ? "https" : "http",
1919 g_strstrip(wmem_strdup(pinfo->pool, stat_info->http_host))g_strchomp (g_strchug (wmem_strdup(pinfo->pool, stat_info->
http_host)))
, stat_info->request_uri);
1920 }
1921 stat_info->full_uri = wmem_strdup(pinfo->pool, uri);
1922 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && curr) {
1923 curr->full_uri = wmem_strdup(wmem_file_scope(), uri);
1924 }
1925 }
1926 else {
1927 /* If the request has a range, this is, or potentially is, asynchronous I/O thus
1928 * full_uri must be reinitialized because it is set to that of the last request. */
1929 if (curr && curr->req_has_range)
1930 curr->full_uri = NULL((void*)0);
1931 }
1932 if (tree) {
1933 proto_item *pi;
1934
1935 switch (http_type) {
1936
1937 case MEDIA_CONTAINER_HTTP_NOTIFICATION:
1938 hidden_item = proto_tree_add_boolean(http_tree,
1939 hf_http_notification, tvb, 0, 0, 1);
1940 proto_item_set_hidden(hidden_item);
1941 break;
1942
1943 case MEDIA_CONTAINER_HTTP_RESPONSE:
1944 hidden_item = proto_tree_add_boolean(http_tree,
1945 hf_http_response, tvb, 0, 0, 1);
1946 proto_item_set_hidden(hidden_item);
1947
1948 match_trans_t *match_trans = NULL((void*)0);
1949
1950 if (curr && curr->response_code == 206 && curr->resp_has_range) {
1951 /* The conv_data->matches_table is only used for GET requests with ranges and
1952 * response_codes of 206 (Partial Content). (Note: only GETs use ranges.)
1953 */
1954 match_trans = (match_trans_t *)wmem_map_lookup(conv_data->matches_table,
1955 GUINT_TO_POINTER(pinfo->num)((gpointer) (gulong) (pinfo->num)));
1956 if (match_trans) {
1957 pi = proto_tree_add_uint(http_tree, hf_http_request_in, tvb, 0, 0,
1958 match_trans->req_frame);
1959 proto_item_set_generated(pi);
1960
1961 pi = proto_tree_add_time(http_tree, hf_http_time, tvb, 0, 0,
1962 &match_trans->delta_time);
1963 proto_item_set_generated(pi);
1964
1965 pi = proto_tree_add_string(http_tree, hf_http_request_uri, tvb, 0, 0,
1966 match_trans->request_uri);
1967 proto_item_set_generated(pi);
1968 {
1969 char *uri;
1970 uri = wmem_strdup_printf(pinfo->pool, "%s://%s%s",
1971 is_tls ? "https" : "http",
1972 g_strstrip(wmem_strdup(pinfo->pool, match_trans->http_host))g_strchomp (g_strchug (wmem_strdup(pinfo->pool, match_trans
->http_host)))
, match_trans->request_uri);
1973
1974 pi = proto_tree_add_string(http_tree, hf_http_request_full_uri, tvb, 0, 0,
1975 uri);
1976 proto_item_set_url(pi);
1977 proto_item_set_generated(pi);
1978 }
1979 }
1980 }
1981
1982 /* If responses don't have a range, the I/O is synchronous in which case a request is
1983 * matched with the following response. If a request or response is missing from the
1984 * capture file, correct matching resumes at the next request. */
1985 if(!match_trans
1986 && curr
1987 && !curr->resp_has_range
1988 && curr->req_framenum) {
1989 pi = proto_tree_add_uint(http_tree, hf_http_request_in, tvb, 0, 0, curr->req_framenum);
1990 proto_item_set_generated(pi);
1991
1992 if (! nstime_is_unset(&(curr->req_ts))) {
1993 nstime_t delta;
1994
1995 nstime_delta(&delta, &pinfo->abs_ts, &(curr->req_ts));
1996 pi = proto_tree_add_time(http_tree, hf_http_time, tvb, 0, 0, &delta);
1997 proto_item_set_generated(pi);
1998 }
1999 if (curr->request_uri) {
2000 pi = proto_tree_add_string(http_tree, hf_http_request_uri, tvb, 0, 0,
2001 curr->request_uri);
2002 proto_item_set_generated(pi);
2003 }
2004 if (curr->full_uri) {
2005 pi = proto_tree_add_string(http_tree, hf_http_request_full_uri, tvb, 0, 0,
2006 curr->full_uri);
2007 proto_item_set_url(pi);
2008 proto_item_set_generated(pi);
2009 }
2010 }
2011 break;
2012 case MEDIA_CONTAINER_HTTP_REQUEST:
2013 {
2014 int size = wmem_map_size(conv_data->matches_table);
2015
2016 hidden_item = proto_tree_add_boolean(http_tree, hf_http_request, tvb, 0, 0, 1);
2017 proto_item_set_hidden(hidden_item);
2018
2019 match_trans = NULL((void*)0);
2020 if (curr) {
2021 if (size > 0 && curr->req_has_range) {
2022 match_trans = (match_trans_t *)wmem_map_lookup(conv_data->matches_table,
2023 GUINT_TO_POINTER(pinfo->num)((gpointer) (gulong) (pinfo->num)));
2024 if (match_trans) {
2025 pi = proto_tree_add_uint(http_tree, hf_http_response_in,
2026 tvb, 0, 0, match_trans->resp_frame);
2027 proto_item_set_generated(pi);
2028 }
2029 }
2030 else {
2031 if(!match_trans
2032 && !curr->resp_has_range
2033 && curr->res_framenum) {
2034 pi = proto_tree_add_uint(http_tree, hf_http_response_in, tvb, 0, 0, curr->res_framenum);
2035 proto_item_set_generated(pi);
2036
2037 }
2038 }
2039
2040 if (curr->full_uri) {
2041 pi = proto_tree_add_string(http_tree, hf_http_request_full_uri, tvb, 0, 0,
2042 curr->full_uri);
2043 proto_item_set_url(pi);
2044 proto_item_set_generated(pi);
2045 }
2046 else if (stat_info->full_uri){
2047 pi = proto_tree_add_string(http_tree, hf_http_request_full_uri, tvb, 0, 0,
2048 stat_info->full_uri);
2049 proto_item_set_url(pi);
2050 proto_item_set_generated(pi);
2051 }
2052 }
2053 }
2054 break;
2055
2056 case MEDIA_CONTAINER_HTTP_OTHERS:
2057 default:
2058 break;
2059 }
2060 }
2061
2062 /* Give the follow tap what we've currently dissected */
2063 if(have_tap_listener(http_follow_tap)) {
2064 tap_queue_packet(http_follow_tap, pinfo, tvb_new_subset_length(tvb, orig_offset, offset-orig_offset));
2065 }
2066
2067 reported_datalen = tvb_reported_length_remaining(tvb, offset);
2068 datalen = tvb_captured_length_remaining(tvb, offset);
2069
2070 /*
2071 * If a content length was supplied, the amount of data to be
2072 * processed as HTTP payload is the minimum of the content
2073 * length and the amount of data remaining in the frame.
2074 *
2075 * If a message is received with both a Transfer-Encoding
2076 * header field and a Content-Length header field, the latter
2077 * MUST be ignored.
2078 *
2079 * If no content length was supplied (or if a bad content length
2080 * was supplied), the amount of data to be processed is the amount
2081 * of data remaining in the frame.
2082 *
2083 * If there was no Content-Length entity header, we should
2084 * accumulate all data until the end of the connection.
2085 * That'd require that the TCP dissector call subdissectors
2086 * for all frames with FIN, even if they contain no data,
2087 * which would require subdissectors to deal intelligently
2088 * with empty segments.
2089 *
2090 * According to RFC 2616, however, 1xx responses, 204 responses,
2091 * and 304 responses MUST NOT include a message body; if no
2092 * content length is specified for them, we don't attempt to
2093 * dissect the body.
2094 *
2095 * XXX - it says the same about responses to HEAD requests;
2096 * unless there's a way to determine from the response
2097 * whether it's a response to a HEAD request, we have to
2098 * keep information about the request and associate that with
2099 * the response in order to handle that.
2100 */
2101 if (headers->have_content_length &&
2102 headers->transfer_encoding == HTTP_TE_NONE) {
2103 if (datalen > headers->content_length)
2104 datalen = (int)headers->content_length;
2105
2106 /*
2107 * XXX - limit the reported length in the tvbuff we'll
2108 * hand to a subdissector to be no greater than the
2109 * content length.
2110 *
2111 * We really need both unreassembled and "how long it'd
2112 * be if it were reassembled" lengths for tvbuffs, so
2113 * that we throw the appropriate exceptions for
2114 * "not enough data captured" (running past the length),
2115 * "packet needed reassembly" (within the length but
2116 * running past the unreassembled length), and
2117 * "packet is malformed" (running past the reassembled
2118 * length).
2119 */
2120 if (reported_datalen > headers->content_length)
2121 reported_datalen = (int)headers->content_length;
2122 } else {
2123 switch (http_type) {
2124
2125 case MEDIA_CONTAINER_HTTP_REQUEST:
2126 /*
2127 * Requests have no content if there's no
2128 * Content-Length header and no Transfer-Encoding
2129 * header.
2130 */
2131 if (headers->transfer_encoding == HTTP_TE_NONE)
2132 datalen = 0;
2133 else
2134 reported_datalen = -1;
2135 break;
2136
2137 case MEDIA_CONTAINER_HTTP_RESPONSE:
2138 if ((stat_info->response_code/100) == 1 ||
2139 stat_info->response_code == 204 ||
2140 stat_info->response_code == 304)
2141 datalen = 0; /* no content! */
2142 else {
2143 /*
2144 * XXX - responses to HEAD requests,
2145 * and possibly other responses,
2146 * "MUST NOT" include a
2147 * message-body.
2148 */
2149 reported_datalen = -1;
2150 }
2151 break;
2152
2153 default:
2154 /*
2155 * XXX - what about MEDIA_CONTAINER_HTTP_NOTIFICATION?
2156 */
2157 reported_datalen = -1;
2158 break;
2159 }
2160 }
2161
2162 bool_Bool create_streaming_data = !PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && streaming_chunk_mode && streaming_reassembly_data == NULL((void*)0);
2163 if (create_streaming_data && !(!begin_with_chunk && handle && http_dechunk_body && http_desegment_body
2164 && headers->content_type && header_value_map && prv_data)) {
2165 /* Inconsistent streaming state (e.g. pipelined messages); dissect without it. */
2166 streaming_chunk_mode = false0;
2167 create_streaming_data = false0;
2168 }
2169 if (create_streaming_data) {
2170
2171 content_info = wmem_new0(wmem_file_scope(), media_content_info_t)((media_content_info_t*)wmem_alloc0((wmem_file_scope()), sizeof
(media_content_info_t)))
;
2172 content_info->media_str = headers->content_type_parameters;
2173 content_info->type = http_type;
2174 content_info->data = header_value_map;
2175
2176 streaming_reassembly_data = wmem_new0(wmem_file_scope(), http_streaming_reassembly_data_t)((http_streaming_reassembly_data_t*)wmem_alloc0((wmem_file_scope
()), sizeof(http_streaming_reassembly_data_t)))
;
2177 streaming_reassembly_data->streaming_handle = handle;
2178 streaming_reassembly_data->streaming_reassembly_info = streaming_reassembly_info_new();
2179 streaming_reassembly_data->content_info = content_info;
2180 streaming_reassembly_data->main_headers = headers;
2181
2182 if (prv_data->req_fwd_flow == direction) {
2183 prv_data->req_streaming_reassembly_data = streaming_reassembly_data;
2184 } else {
2185 prv_data->res_streaming_reassembly_data = streaming_reassembly_data;
2186 }
2187 }
2188
2189 if (content_info == NULL((void*)0)) {
2190 content_info = wmem_new0(pinfo->pool, media_content_info_t)((media_content_info_t*)wmem_alloc0((pinfo->pool), sizeof(
media_content_info_t)))
;
2191 content_info->media_str = headers->content_type_parameters;
2192 content_info->type = http_type;
2193 if (header_value_map == NULL((void*)0)) {
2194 header_value_map = wmem_map_new(pinfo->pool, g_str_hash, g_str_equal);
2195 }
2196 content_info->data = header_value_map;
2197 }
2198
2199dissecting_body:
2200
2201 if (datalen > 0) {
2202 /*
2203 * There's stuff left over; process it.
2204 */
2205 tvbuff_t *next_tvb;
2206 unsigned chunked_datalen = 0;
2207 int data_len;
2208
2209 /*
2210 * Create a tvbuff for the payload.
2211 *
2212 * The amount of data to be processed that's
2213 * available in the tvbuff is "datalen", which
2214 * is the minimum of the amount of data left in
2215 * the tvbuff and any specified content length.
2216 *
2217 * The amount of data to be processed that's in
2218 * this frame, regardless of whether it was
2219 * captured or not, is "reported_datalen",
2220 * which, if no content length was specified,
2221 * is -1, i.e. "to the end of the frame.
2222 */
2223 if (reported_datalen == -1) {
2224 next_tvb = tvb_new_subset_remaining(tvb, offset);
2225 } else {
2226 next_tvb = tvb_new_subset_length(tvb, offset, reported_datalen);
2227 }
2228
2229 /*
2230 * Handle *transfer* encodings.
2231 */
2232 if (headers->transfer_encoding_chunked) {
2233 if (!http_dechunk_body) {
2234 /* Chunking disabled, cannot dissect further. */
2235 /* XXX: Should this be sent to the follow tap? */
2236 call_data_dissector(next_tvb, pinfo, http_tree);
2237 goto body_dissected;
2238 }
2239
2240 chunked_datalen = chunked_encoding_dissector(
2241 &next_tvb, pinfo, http_tree, 0);
2242
2243 if (chunked_datalen == 0) {
2244 /*
2245 * The chunks weren't reassembled,
2246 * or there was a single zero
2247 * length chunk.
2248 */
2249 goto body_dissected;
2250 } else {
2251 /*
2252 * Add a new data source for the
2253 * de-chunked data.
2254 */
2255 add_new_data_source(pinfo, next_tvb,
2256 "De-chunked entity body");
2257 /* chunked-body might be smaller than
2258 * datalen. */
2259 datalen = chunked_datalen;
2260 }
2261 }
2262 /* Handle other transfer codings after de-chunking. */
2263 switch (headers->transfer_encoding) {
2264 case HTTP_TE_COMPRESS:
2265 case HTTP_TE_DEFLATE:
2266 case HTTP_TE_GZIP:
2267 /*
2268 * We currently can't handle, for example, "gzip",
2269 * "compress", or "deflate" as *transfer* encodings;
2270 * just handle them as data for now.
2271 * XXX: Should this be sent to the follow tap?
2272 */
2273 call_data_dissector(next_tvb, pinfo, http_tree);
2274 goto body_dissected;
2275 default:
2276 /* Nothing to do for "identity" or when header is
2277 * missing or invalid. */
2278 break;
2279 }
2280 /*
2281 * At this point, any chunked *transfer* coding has been removed
2282 * (the entity body has been dechunked) so it can be presented
2283 * for the following operation (*content* encoding), or it has
2284 * been handed off to the data dissector.
2285 *
2286 * Handle *content* encodings other than "identity" (which
2287 * shouldn't appear in a Content-Encoding header, but
2288 * we handle it in any case).
2289 */
2290 if (headers->content_encoding != NULL((void*)0) &&
2291 g_ascii_strcasecmp(headers->content_encoding, "identity") != 0) {
2292 /*
2293 * We currently don't handle, for example, "compress";
2294 * just handle them as data for now.
2295 *
2296 * After July 7, 2004 the LZW patent expired, so
2297 * support could be added. However, I don't think
2298 * that anybody ever really implemented "compress",
2299 * due to the aforementioned patent.
2300 */
2301 tvbuff_t *uncomp_tvb = NULL((void*)0);
2302 proto_item *e_ti = NULL((void*)0);
2303 proto_tree *e_tree = NULL((void*)0);
2304
2305#if defined(HAVE_ZLIB1) || defined(HAVE_ZLIBNG)
2306 if (http_decompress_body &&
2307 (g_ascii_strcasecmp(headers->content_encoding, "gzip") == 0 ||
2308 g_ascii_strcasecmp(headers->content_encoding, "deflate") == 0 ||
2309 g_ascii_strcasecmp(headers->content_encoding, "x-gzip") == 0 ||
2310 g_ascii_strcasecmp(headers->content_encoding, "x-deflate") == 0))
2311 {
2312 uncomp_tvb = tvb_child_uncompress_zlib(tvb, next_tvb, 0,
2313 tvb_captured_length(next_tvb));
2314 }
2315#endif
2316
2317#ifdef HAVE_BROTLI1
2318 if (http_decompress_body &&
2319 g_ascii_strcasecmp(headers->content_encoding, "br") == 0)
2320 {
2321 uncomp_tvb = tvb_child_uncompress_brotli(tvb, next_tvb, 0,
2322 tvb_captured_length(next_tvb));
2323 }
2324#endif
2325
2326#ifdef HAVE_SNAPPY1
2327 if (http_decompress_body &&
2328 g_ascii_strcasecmp(headers->content_encoding, "snappy") == 0)
2329 {
2330 uncomp_tvb = tvb_child_uncompress_snappy(tvb, next_tvb, 0,
2331 tvb_captured_length(next_tvb));
2332 }
2333#endif
2334
2335#ifdef HAVE_ZSTD1
2336 if (http_decompress_body &&
2337 g_ascii_strcasecmp(headers->content_encoding, "zstd") == 0)
2338 {
2339 uncomp_tvb = tvb_child_uncompress_zstd(tvb, next_tvb, 0,
2340 tvb_captured_length(next_tvb));
2341 }
2342#endif
2343
2344 if (http_decompress_body &&
2345 g_ascii_strcasecmp(headers->content_encoding, "xpress") == 0)
2346 {
2347 /*
2348 * [MS-WUSP] 2.1.1 Xpress Compression
2349 * Segmented into a series of blocks and compressed with the
2350 * Plain LZ77 variant of [MS-XCA] Xpress Compression Algorithm.
2351 *
2352 * XXX - Does Microsoft use any other variants of [MS-XCA]
2353 * for Content-Encoding: xpress in any other situations
2354 * besides Windows Update Services?
2355 */
2356 int comp_offset = 0;
2357 int compressed_len;
2358 tvbuff_t *block_tvb;
2359 while (tvb_captured_length_remaining(next_tvb, comp_offset) >= 8) {
2360 comp_offset += 4; // original length
2361 compressed_len = tvb_get_int32(next_tvb, comp_offset, ENC_LITTLE_ENDIAN0x80000000);
2362 /*
2363 * "The compressed size of each block MUST NOT be greater
2364 * than 65535 bytes."
2365 */
2366 if (compressed_len <= 0 || compressed_len > 65535) {
2367 break;
2368 }
2369 if (!tvb_bytes_exist(next_tvb, comp_offset, compressed_len)) {
2370 break;
2371 }
2372 comp_offset += 4;
2373 block_tvb = tvb_child_uncompress_lz77(tvb,
2374 tvb_new_subset_length(next_tvb, comp_offset, compressed_len),
2375 0, compressed_len);
2376 if (block_tvb) {
2377 if (uncomp_tvb == NULL((void*)0)) {
2378 uncomp_tvb = tvb_new_composite();
2379 }
2380 tvb_composite_append(uncomp_tvb, block_tvb);
2381 } else {
2382 break;
2383 }
2384 comp_offset += compressed_len;
2385 }
2386 if (uncomp_tvb != NULL((void*)0)) {
2387 /*
2388 * XXX - Should we add an expert info for partial
2389 * decompression if we didn't finish? I.e., if
2390 * tvb_captured_length_remaining(next_tvb, comp_offset) > 0
2391 */
2392 tvb_composite_finalize(uncomp_tvb);
2393 }
2394 }
2395
2396 /*
2397 * Add the encoded entity to the protocol tree
2398 */
2399 e_tree = proto_tree_add_subtree_format(http_tree, next_tvb,
2400 0, tvb_captured_length(next_tvb), ett_http_encoded_entity, &e_ti,
2401 "Content-encoded entity body (%s): %u bytes",
2402 headers->content_encoding,
2403 tvb_captured_length(next_tvb));
2404
2405 if (uncomp_tvb != NULL((void*)0)) {
2406 /*
2407 * Decompression worked
2408 */
2409
2410 /* XXX - Don't free this, since it's possible
2411 * that the data was only partially
2412 * decompressed, such as when desegmentation
2413 * isn't enabled.
2414 *
2415 tvb_free(next_tvb);
2416 */
2417 proto_item_append_text(e_ti, " -> %u bytes", tvb_captured_length(uncomp_tvb));
2418 next_tvb = uncomp_tvb;
2419 add_new_data_source(pinfo, next_tvb,
2420 "Uncompressed entity body");
2421 } else {
2422 if (http_decompress_body) {
2423 /* XXX - We should distinguish between "failed", "unsupported
2424 * only because support wasn't compiled in", and "unsupported
2425 * by Wireshark", to indicate whether the problem is with
2426 * the capture file, the build, or Wireshark.
2427 */
2428 expert_add_info(pinfo, e_ti, &ei_http_decompression_failed);
2429 }
2430 else {
2431 expert_add_info(pinfo, e_ti, &ei_http_decompression_disabled);
2432 }
2433 /* XXX: Should this be sent to the follow tap? */
2434 call_data_dissector(next_tvb, pinfo, e_tree);
2435
2436 goto body_dissected;
2437 }
2438 }
2439 /*
2440 * Note that a new data source is added for the entity body
2441 * only if it was content-encoded and/or transfer-encoded.
2442 */
2443
2444 /* Save values for the Export Object GUI feature if we have
2445 * an active listener to process it (which happens when
2446 * the export object window is open). */
2447 /* XXX: Do we really want to send it to Export Object if we didn't
2448 * get the headers, so that this is just a fragment of Continuation
2449 * Data and not a complete object?
2450 */
2451 if(have_tap_listener(http_eo_tap)) {
2452 eo_info = wmem_new0(pinfo->pool, http_eo_t)((http_eo_t*)wmem_alloc0((pinfo->pool), sizeof(http_eo_t))
)
;
2453
2454 if (curr) {
2455 eo_info->hostname = curr->http_host;
2456 eo_info->filename = curr->request_uri;
2457 }
2458 eo_info->content_type = headers->content_type;
2459 eo_info->payload = next_tvb;
2460
2461 tap_queue_packet(http_eo_tap, pinfo, eo_info);
2462 }
2463
2464 /* Send it to Follow HTTP Stream and mark as file data */
2465 if(have_tap_listener(http_follow_tap)) {
2466 tap_queue_packet(http_follow_tap, pinfo, next_tvb);
2467 }
2468 data_len = tvb_captured_length(next_tvb);
2469 proto_tree_add_bytes_format_value(http_tree, hf_http_file_data,
2470 next_tvb, 0, data_len, NULL((void*)0), "%u byte%s", data_len, plurality(data_len, "", "s")((data_len) == 1 ? ("") : ("s")));
2471
2472 if (tvb_captured_length(next_tvb) == 0)
2473 goto body_dissected;
2474
2475 /*
2476 * Do subdissector checks.
2477 */
2478
2479 /*
2480 * Is MIME sniffing enabled?
2481 */
2482 if (http_try_heuristic_first) {
2483 /*
2484 * Try the heuristic subdissectors.
2485 */
2486 uint16_t save_can_desegment = pinfo->can_desegment;
2487 if (!(is_request_or_reply || streaming_chunk_mode)) {
2488 /* If this isn't a request or reply, and we're not
2489 * in streaming chunk mode, then we didn't try to
2490 * desegment the body. (We think this is file data
2491 * in the middle of a connection.) Allow the heuristic
2492 * dissectors to desegment, if possible.
2493 */
2494 pinfo->can_desegment = pinfo->saved_can_desegment;
2495 }
2496 dissected = dissector_try_heuristic(heur_subdissector_list,
2497 next_tvb, pinfo, tree, &hdtbl_entry, content_info);
2498 pinfo->can_desegment = save_can_desegment;
2499
2500 if (dissected) {
2501 /*
2502 * The subdissector dissected the body.
2503 * Fix up the top-level item so that it doesn't
2504 * include the stuff for that protocol.
2505 */
2506 if (ti != NULL((void*)0))
2507 proto_item_set_len(ti, offset);
2508 goto body_dissected;
2509 }
2510 }
2511
2512 /* First, if we have a Content-Type value, check whether
2513 * there's a subdissector for that media type.
2514 */
2515 if (headers->content_type != NULL((void*)0) && handle == NULL((void*)0)) {
2516 /*
2517 * We have a Content-Type value. Is there any subdissector
2518 * for that content type?
2519 */
2520
2521 /*
2522 * Calling the string handle for the media type
2523 * dissector table will set pinfo->match_string
2524 * to headers->content_type for us.
2525 */
2526 pinfo->match_string = headers->content_type;
2527 handle = dissector_get_string_handle(
2528 media_type_subdissector_table,
2529 headers->content_type);
2530 if (handle == NULL((void*)0) &&
2531 strncmp(headers->content_type, "multipart/", sizeof("multipart/")-1) == 0) {
2532 /* Try to decode the unknown multipart subtype anyway */
2533 handle = dissector_get_string_handle(
2534 media_type_subdissector_table,
2535 "multipart/");
2536 }
2537 }
2538
2539 /*
2540 * Now, if we didn't find such a subdissector, check
2541 * whether some subdissector asked that they be called
2542 * if HTTP traffic was on some particular port. This
2543 * handles protocols that use HTTP syntax but don't have
2544 * a media type and instead use a specified port.
2545 */
2546 if (handle == NULL((void*)0)) {
2547 /* If the HTTP dissector was called heuristically
2548 * (or the HTTP dissector was called from the TLS
2549 * dissector, which was called heuristically), then
2550 * match_uint doesn't get set (or is likely set to
2551 * 6 for IP_PROTO_TCP.) Some protocols (e.g., IPP)
2552 * use the same specified port for both HTTP and
2553 * HTTP over TLS, and one will be a heuristic match.
2554 * In those cases, look at the src or dest port.
2555 */
2556 if (pinfo->match_uint == pinfo->srcport || pinfo->match_uint == pinfo->destport) {
2557 handle = dissector_get_uint_handle(port_subdissector_table,
2558 pinfo->match_uint);
2559 } else if (http_type == MEDIA_CONTAINER_HTTP_REQUEST) {
2560 handle = dissector_get_uint_handle(port_subdissector_table,
2561 pinfo->destport);
2562 } else if (http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
2563 handle = dissector_get_uint_handle(port_subdissector_table,
2564 pinfo->srcport);
2565 }
2566 }
2567
2568 if (handle != NULL((void*)0)) {
2569 /*
2570 * We have a subdissector - call it.
2571 */
2572 if (streaming_chunk_mode) {
2573 pinfo->match_string = headers->content_type;
2574 /* reassemble and call subdissector */
2575 dissected = (bool_Bool)reassemble_streaming_data_and_call_subdissector(next_tvb, pinfo, 0,
2576 tvb_reported_length_remaining(next_tvb, 0), http_tree, proto_tree_get_parent_tree(tree),
2577 http_streaming_reassembly_table, streaming_reassembly_data->streaming_reassembly_info,
2578 get_http_chunk_frame_numget_virtual_frame_num64(tvb, pinfo, offset), handle,
2579 proto_tree_get_parent_tree(tree), content_info,
2580 "HTTP", &http_body_fragment_items, hf_http_body_segment);
2581 } else {
2582 dissected = (bool_Bool)call_dissector_only(handle, next_tvb, pinfo, tree, content_info);
2583 }
2584 if (!dissected)
2585 expert_add_info(pinfo, http_tree, &ei_http_subdissector_failed);
2586 }
2587
2588 if (!dissected && !http_try_heuristic_first) {
2589 /*
2590 * We don't have a subdissector or we have one and it did not
2591 * dissect the payload - try the heuristic subdissectors.
2592 */
2593 uint16_t save_can_desegment = pinfo->can_desegment;
2594 if (!(is_request_or_reply || streaming_chunk_mode)) {
2595 /* If this isn't a request or reply, and we're not
2596 * in streaming chunk mode, then we didn't try to
2597 * desegment the body. (We think this is file data
2598 * in the middle of a connection.) Allow the heuristic
2599 * dissectors to desegment, if possible.
2600 */
2601 pinfo->can_desegment = pinfo->saved_can_desegment;
2602 }
2603 dissected = dissector_try_heuristic(heur_subdissector_list,
2604 next_tvb, pinfo, tree, &hdtbl_entry, content_info);
2605 pinfo->can_desegment = save_can_desegment;
2606 }
2607
2608 if (dissected) {
2609 /*
2610 * The subdissector dissected the body.
2611 * Fix up the top-level item so that it doesn't
2612 * include the stuff for that protocol.
2613 */
2614 if (ti != NULL((void*)0))
2615 proto_item_set_len(ti, offset);
2616 } else {
2617 if (headers->content_type != NULL((void*)0)) {
2618 /*
2619 * Calling the default media handle if there is a content-type that
2620 * wasn't handled above.
2621 */
2622 call_dissector_with_data(media_handle, next_tvb, pinfo, tree, content_info);
2623 } else {
2624 /* Call the default data dissector */
2625 call_data_dissector(next_tvb, pinfo, http_tree);
2626 }
2627 }
2628
2629 body_dissected:
2630 /*
2631 * We've processed "datalen" bytes worth of data
2632 * (which may be no data at all); advance the
2633 * offset past whatever data we've processed.
2634 */
2635 offset += datalen;
2636 }
2637
2638 /* Detect protocol changes after receiving full response headers. */
2639 if (http_type == MEDIA_CONTAINER_HTTP_RESPONSE && curr && pinfo->desegment_offset <= 0 && pinfo->desegment_len == 0) {
2640 dissector_handle_t next_handle = NULL((void*)0);
2641 bool_Bool server_acked = false0;
2642
2643 /*
2644 * SSTP uses a special request method (instead of the Upgrade
2645 * header) and expects a 200 response to set up the session.
2646 */
2647 if (g_strcmp0(curr->request_method, "SSTP_DUPLEX_POST") == 0 && curr->response_code == 200) {
2648 next_handle = sstp_handle;
2649 server_acked = true1;
2650 }
2651
2652 /*
2653 * An HTTP/1.1 upgrade only proceeds if the server responds
2654 * with 101 Switching Protocols. See RFC 7230 Section 6.7.
2655 */
2656 if (headers->upgrade && curr->response_code == 101) {
2657 next_handle = http_upgrade_dissector(headers->upgrade);
2658 server_acked = true1;
2659 }
2660
2661 if (server_acked && !PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2662 conv_data->startframe = pinfo->num;
2663 conv_data->startoffset = offset;
2664 conv_data->next_handle = next_handle;
2665 copy_address_wmem(wmem_file_scope(), &conv_data->server_addr, &pinfo->src);
2666 conv_data->server_port = pinfo->srcport;
2667 /* Prepare structure for upgrade protocol data */
2668 conv_data->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)))
;
2669 conv_data->upgrade_info->server_port = pinfo->srcport;
2670 conv_data->upgrade_info->http_version = 1;
2671 conv_data->upgrade_info->get_header_value = http_get_header_value;
2672 }
2673 }
2674
2675 if (stat_info)
2676 tap_queue_packet(http_tap, pinfo, stat_info);
2677
2678 return offset - orig_offset;
2679}
2680
2681/* This can be used to dissect an HTTP request until such time
2682 * that a more complete dissector is written for that HTTP request.
2683 * This simple dissector only puts the request method, URI, and
2684 * protocol version into a sub-tree.
2685 */
2686static void
2687basic_request_dissector(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
2688 unsigned offset, const unsigned char *line, const unsigned char *lineend,
2689 http_conv_t *conv_data _U___attribute__((unused)), http_req_res_t *curr)
2690{
2691 const unsigned char *next_token;
2692 const char *request_uri;
2693 unsigned tokenlen;
2694 proto_item* ti;
2695 http_info_value_t *stat_info = p_get_proto_data(pinfo->pool, pinfo, proto_http, HTTP_PROTO_DATA_INFO1);
2696
2697 /* The first token is the method. */
2698 tokenlen = get_token_len(line, lineend, &next_token);
2699 if (tokenlen == 0)
1
Assuming 'tokenlen' is not equal to 0
2
Taking false branch
2700 return;
2701 proto_tree_add_item(tree, hf_http_request_method, tvb, offset, tokenlen,
2702 ENC_ASCII0x00000000);
2703 if ((next_token - line) > 2 && next_token[-1] == ' ' && next_token[-2] == ' ') {
3
Assuming the condition is false
2704 /* Two spaces in a now indicates empty URI, so roll back one here */
2705 next_token--;
2706 }
2707 offset += (unsigned) (next_token - line);
2708 line = next_token;
2709
2710 /* The next token is the URI. */
2711 tokenlen = get_token_len(line, lineend, &next_token);
2712
2713 /* Save the request URI for various later uses */
2714 request_uri = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, tokenlen, ENC_ASCII0x00000000);
4
Value assigned to 'request_uri'
2715
2716 if (request_uri == NULL((void*)0) && curr)
5
Assuming 'request_uri' is equal to NULL
6
Assuming 'curr' is null
7
Taking false branch
2717 request_uri = curr->request_uri;
2718
2719 stat_info->request_uri = wmem_strdup(pinfo->pool, request_uri);
2720 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && curr) {
8
Assuming field 'visited' is not equal to 0
2721 curr->request_uri = wmem_strdup(wmem_file_scope(), request_uri);
2722 }
2723 ti = proto_tree_add_string(tree, hf_http_request_uri, tvb, offset, tokenlen, request_uri);
2724 const char *p;
2725
2726 /* RFC 9112 §3.2: No whitespace is allowed in the request-target. */
2727 for (p = request_uri; *p != '\0'; p++) {
9
Null pointer value stored to 'p'
10
Dereference of null pointer (loaded from variable 'p')
2728 if (*p == ' ' || *p == '\t') {
2729 expert_add_info(pinfo, ti, &ei_http_request_uri_whitespace);
2730 break;
2731 }
2732 }
2733 http_add_path_components_to_tree(tvb, pinfo, ti, offset, tokenlen);
2734 offset += (unsigned) (next_token - line);
2735 line = next_token;
2736
2737 /* Everything to the end of the line is the version. */
2738 tokenlen = (int) (lineend - line);
2739 proto_tree_add_item(tree, hf_http_request_version, tvb, offset, tokenlen,
2740 ENC_ASCII0x00000000);
2741}
2742
2743static int
2744parse_http_status_code(const unsigned char *line, const unsigned char *lineend)
2745{
2746 const unsigned char *next_token;
2747 unsigned tokenlen;
2748 char response_code_chars[4];
2749 int32_t status_code = 0;
2750
2751 /*
2752 * The first token is the HTTP Version.
2753 */
2754 tokenlen = get_token_len(line, lineend, &next_token);
2755 if (tokenlen == 0)
2756 return 0;
2757 line = next_token;
2758
2759 /*
2760 * The second token is the Status Code.
2761 */
2762 tokenlen = get_token_len(line, lineend, &next_token);
2763 if (tokenlen != 3)
2764 return 0;
2765
2766 memcpy(response_code_chars, line, 3);
2767 response_code_chars[3] = '\0';
2768 if (!ws_strtoi32(response_code_chars, NULL((void*)0), &status_code))
2769 return 0;
2770
2771 return status_code;
2772}
2773
2774static void
2775basic_response_dissector(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
2776 unsigned offset, const unsigned char *line, const unsigned char *lineend,
2777 http_conv_t *conv_data _U___attribute__((unused)), http_req_res_t *curr)
2778{
2779 const unsigned char *next_token;
2780 const unsigned char *status_code_token;
2781 unsigned tokenlen;
2782 unsigned i;
2783 unsigned expert_len;
2784 bool_Bool invalid_status_code_token = false0;
2785 int status_code_offset;
2786 proto_item *ti;
2787 proto_item *r_ti;
2788 http_info_value_t *stat_info = p_get_proto_data(pinfo->pool, pinfo, proto_http, HTTP_PROTO_DATA_INFO1);
2789
2790 /*
2791 * The first token is the HTTP Version.
2792 */
2793 tokenlen = get_token_len(line, lineend, &next_token);
2794 if (tokenlen == 0)
2795 return;
2796 proto_tree_add_item(tree, hf_http_response_version, tvb, offset, tokenlen,
2797 ENC_ASCII0x00000000);
2798 /* Advance to the start of the next token. */
2799 offset += (int) (next_token - line);
2800
2801 /*
2802 * The second token is the Status Code.
2803 */
2804 status_code_token = next_token;
2805 status_code_offset = offset;
2806 tokenlen = get_token_len(status_code_token, lineend, &next_token);
2807
2808 /* Validate status code token */
2809 if (tokenlen != 3) {
2810 invalid_status_code_token = true1;
2811 } else {
2812 for (i = 0; i < tokenlen; i++) {
2813 if (!g_ascii_isdigit(status_code_token[i])((g_ascii_table[(guchar) (status_code_token[i])] & G_ASCII_DIGIT
) != 0)
) {
2814 invalid_status_code_token = true1;
2815 break;
2816 }
2817 }
2818 }
2819
2820 expert_len = tokenlen;
2821 if (expert_len == 0 && tvb_reported_length_remaining(tvb, status_code_offset) > 0)
2822 expert_len = 1;
2823
2824 if (tokenlen >= 3) {
2825 ws_buftou32(status_code_token, 3, NULL((void*)0), &stat_info->response_code);
2826 if (curr) {
2827 curr->response_code = stat_info->response_code;
2828 }
2829 }
2830
2831 ti = proto_tree_add_uint(tree, hf_http_response_code, tvb, status_code_offset,
2832 tokenlen < 3 ? expert_len : 3,
2833 stat_info->response_code);
2834 if (expert_len > 3)
2835 proto_item_set_len(ti, expert_len);
2836
2837 if (invalid_status_code_token) {
2838 expert_add_info_format(pinfo, ti, &ei_http_response_code_invalid,
2839 "Invalid HTTP response status code token: \"%s\" (expected exactly 3 digits)",
2840 format_text(pinfo->pool, (const char *)status_code_token, tokenlen));
2841 }
2842 if (tokenlen < 3)
2843 return;
2844
2845 r_ti = proto_tree_add_string(tree, hf_http_response_code_desc,
2846 tvb, status_code_offset, 3, val_to_str(pinfo->pool, stat_info->response_code,
2847 vals_http_status_code, "Unknown (%d)"));
2848
2849 proto_item_set_generated(r_ti);
2850
2851 /* Advance to the start of the next token. */
2852 offset += (int) (next_token - status_code_token);
2853 line = next_token;
2854
2855 /*
2856 * The remaining tokens in the line comprise the Reason Phrase.
2857 */
2858 tokenlen = (int) (lineend - line);
2859 if (tokenlen >= 1) {
2860 proto_tree_add_item(tree, hf_http_response_phrase, tvb, offset,
2861 tokenlen, ENC_ASCII0x00000000);
2862 }
2863}
2864
2865/*
2866 * Dissect the http data chunks and add them to the tree.
2867 */
2868static unsigned
2869chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
2870 proto_tree *tree, unsigned offset)
2871{
2872 tvbuff_t *tvb;
2873 uint32_t datalen;
2874 uint32_t orig_datalen;
2875 unsigned chunked_data_size;
2876 proto_tree *subtree;
2877 proto_item *pi_chunked = NULL((void*)0);
2878 uint8_t *raw_data;
2879 unsigned raw_len;
2880 unsigned chunk_counter = 0;
2881 int last_chunk_id = -1;
2882
2883 if ((tvb_ptr == NULL((void*)0)) || (*tvb_ptr == NULL((void*)0))) {
2884 return 0;
2885 }
2886
2887 tvb = *tvb_ptr;
2888
2889 datalen = tvb_reported_length_remaining(tvb, offset);
2890
2891 subtree = proto_tree_add_subtree(tree, tvb, offset, datalen,
2892 ett_http_chunked_response, &pi_chunked,
2893 "HTTP chunked response");
2894
2895 /* Dechunk the "chunked response" to a new memory buffer */
2896 /* XXX: Composite tvbuffers do work now, so we should probably
2897 * use that to avoid the memcpys unless necessary.
2898 */
2899 orig_datalen = datalen;
2900 raw_data = (uint8_t *)wmem_alloc(pinfo->pool, datalen);
2901 raw_len = 0;
2902 chunked_data_size = 0;
2903
2904 while (datalen > 0) {
2905 uint32_t chunk_size;
2906 unsigned chunk_offset;
2907 unsigned linelen;
2908 unsigned endoff;
2909 bool_Bool found;
2910
2911 found = tvb_find_line_end_remaining(tvb, offset, &linelen , &chunk_offset);
2912
2913 if (linelen == 0 || found == false0) {
2914 /* Can't get the chunk size line */
2915 break;
2916 }
2917
2918 tvb_get_string_uint(tvb, offset, linelen, ENC_STR_HEX0x02000000, &chunk_size, &endoff);
2919
2920 if (chunk_size > datalen) {
2921 /*
2922 * The chunk size is more than what's in the tvbuff,
2923 * so either the user hasn't enabled decoding, or all
2924 * of the segments weren't captured.
2925 */
2926 chunk_size = datalen;
2927 }
2928
2929 chunked_data_size += chunk_size;
2930
2931 DISSECTOR_ASSERT((raw_len+chunk_size) <= orig_datalen)((void) (((raw_len+chunk_size) <= orig_datalen) ? (void)0 :
(proto_report_dissector_bug("%s:%u: failed assertion \"%s\""
, "epan/dissectors/packet-http.c", 2931, "(raw_len+chunk_size) <= orig_datalen"
))))
;
2932 tvb_memcpy(tvb, (uint8_t *)(raw_data + raw_len), chunk_offset, chunk_size);
2933 raw_len += chunk_size;
2934
2935 ++chunk_counter;
2936
2937 if (subtree) {
2938 proto_tree *chunk_subtree;
2939 proto_item *chunk_size_item;
2940
2941 if(chunk_size == 0) {
2942 chunk_subtree = proto_tree_add_subtree(subtree, tvb,
2943 offset,
2944 chunk_offset - offset + chunk_size + 2,
2945 ett_http_chunk_data, NULL((void*)0),
2946 "End of chunked encoding");
2947 last_chunk_id = chunk_counter - 1;
2948 } else {
2949 chunk_subtree = proto_tree_add_subtree_format(subtree, tvb,
2950 offset,
2951 chunk_offset - offset + chunk_size + 2,
2952 ett_http_chunk_data, NULL((void*)0),
2953 "Data chunk (%u octets)", chunk_size);
2954 }
2955
2956 chunk_size_item = proto_tree_add_uint(chunk_subtree, hf_http_chunk_size, tvb, offset,
2957 1, chunk_size);
2958 proto_item_set_len(chunk_size_item, chunk_offset - offset);
2959
2960 /* last-chunk does not have chunk-data CRLF. */
2961 if (chunk_size > 0) {
2962 /*
2963 * Adding the chunk as FT_BYTES means that, in
2964 * TShark, you get the entire chunk dumped
2965 * out in hex, in addition to whatever
2966 * dissection is done on the reassembled data.
2967 */
2968 proto_tree_add_item(chunk_subtree, hf_http_chunk_data, tvb, chunk_offset, chunk_size, ENC_NA0x00000000);
2969 proto_tree_add_item(chunk_subtree, hf_http_chunk_boundary, tvb,
2970 chunk_offset + chunk_size, 2, ENC_NA0x00000000);
2971 }
2972 }
2973
2974 offset = chunk_offset + chunk_size; /* beginning of next chunk */
2975 if (chunk_size > 0) offset += 2; /* CRLF of chunk */
2976 datalen = tvb_reported_length_remaining(tvb, offset);
2977
2978 /* This is the last chunk */
2979 if (chunk_size == 0) {
2980 /* Check for: trailer-part CRLF.
2981 * trailer-part = *( header-field CRLF ) */
2982 unsigned trailer_offset = offset, trailer_len;
2983 unsigned header_field_len;
2984 bool_Bool header_field_len_found;
2985 /* Skip all header-fields. */
2986 do {
2987 trailer_len = trailer_offset - offset;
2988 header_field_len_found = tvb_find_line_end_length(tvb,
2989 trailer_offset,
2990 datalen - trailer_len,
2991 &header_field_len,
2992 &trailer_offset);
2993 } while (header_field_len_found && header_field_len > 0);
2994 if (trailer_len > 0) {
2995 proto_tree_add_item(subtree,
2996 hf_http_chunked_trailer_part,
2997 tvb, offset, trailer_len, ENC_ASCII0x00000000);
2998 offset += trailer_len;
2999 datalen -= trailer_len;
3000 }
3001
3002 /* last CRLF of chunked-body is found. */
3003 if (header_field_len == 0) {
3004 proto_tree_add_format_text(subtree, tvb, offset,
3005 trailer_offset - offset);
3006 datalen -= trailer_offset - offset;
3007 }
3008 break;
3009 }
3010 }
3011
3012 /* datalen is the remaining bytes that are available for consumption. If
3013 * smaller than orig_datalen, then bytes were consumed. */
3014 if (datalen < orig_datalen) {
3015 tvbuff_t *new_tvb;
3016 proto_item_set_len(pi_chunked, orig_datalen - datalen);
3017 new_tvb = tvb_new_child_real_data(tvb, raw_data, chunked_data_size, chunked_data_size);
3018 *tvb_ptr = new_tvb;
3019 }
3020
3021 if (chunk_counter > 0) {
3022 proto_item* ti_http = proto_tree_get_parent(tree);
3023 proto_item_append_text(ti_http, ", has %d chunk%s%s",
3024 chunk_counter, plurality(chunk_counter, "", "s")((chunk_counter) == 1 ? ("") : ("s")),
3025 (last_chunk_id < 0 ? "" : " (including last chunk)"));
3026
3027 if (last_chunk_id == 0) {
3028 /* only append text to column while starting with last chunk */
3029 col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[Last Chunk]");
3030 }
3031 }
3032
3033 /* Size of chunked-body or 0 if none was found. */
3034 return orig_datalen - datalen;
3035}
3036
3037static bool_Bool
3038http_conversation_is_connect(conversation_t *conv, uint32_t frame_num)
3039{
3040 if (!conv) {
3041 return false0;
3042 }
3043
3044 http_conv_t *conv_data = (http_conv_t *)conversation_get_proto_data(conv, proto_http);
3045 if (conv_data) {
3046 http_req_res_t *curr_req_res = conv_data->req_res_tail;
3047 /* Any 2xx (Successful) response indicates the sender will
3048 * switch to tunnel mode immediately after the response header
3049 * section. */
3050 if(frame_num >= conv_data->startframe &&
3051 curr_req_res &&
3052 curr_req_res->response_code >= 200 &&
3053 curr_req_res->response_code < 300 &&
3054 curr_req_res->request_method &&
3055 strncmp(curr_req_res->request_method, "CONNECT", 7) == 0 &&
3056 curr_req_res->request_uri) {
3057
3058 return true1;
3059 }
3060 }
3061
3062 return false0;
3063}
3064
3065/* Call a subdissector to handle HTTP CONNECT's traffic */
3066static void
3067http_payload_subdissector(tvbuff_t *tvb, proto_tree *tree,
3068 packet_info *pinfo, http_conv_t *conv_data, struct tcpinfo *tcpinfo)
3069{
3070 uint32_t *ptr = NULL((void*)0);
3071 uint32_t uri_port, saved_port, srcport, destport;
3072 address uri_addr, saved_addr;
3073 address *addrp;
3074 char **strings; /* An array for splitting the request URI into hostname and port */
3075 proto_item *item;
3076 proto_tree *proxy_tree;
3077 conversation_t *conv;
3078 bool_Bool from_server = pinfo->srcport == conv_data->server_port &&
3079 addresses_equal(&conv_data->server_addr, &pinfo->src);
3080
3081 /* Grab the destination port number from the request URI to find the right subdissector */
3082 strings = wmem_strsplit(pinfo->pool, conv_data->req_res_tail->request_uri, ":", 2);
3083
3084 if(strings[0] != NULL((void*)0) && strings[1] != NULL((void*)0)) {
3085 /*
3086 * The string was successfully split in two
3087 * Create a proxy-connect subtree
3088 */
3089 item = proto_tree_add_item(tree, proto_http, tvb, 0, -1, ENC_NA0x00000000);
3090 proxy_tree = proto_item_add_subtree(item, ett_http);
3091
3092 item = proto_tree_add_string(proxy_tree, hf_http_proxy_connect_host,
3093 tvb, 0, 0, strings[0]);
3094 proto_item_set_generated(item);
3095
3096 if (!ws_strtou32(strings[1], NULL((void*)0), &uri_port)) {
3097 proto_tree_add_expert_format(proxy_tree, pinfo, &ei_http_request_uri_invalid,
3098 tvb, 0, 0, "Invalid target port number (%s)", strings[1]);
3099 return;
3100 }
3101
3102 item = proto_tree_add_uint(proxy_tree, hf_http_proxy_connect_port,
3103 tvb, 0, 0, uri_port);
3104 proto_item_set_generated(item);
3105
3106 /* Set the port and address to the proxied ones so that
3107 * decode_tcp_ports doesn't call the current conversation
3108 * dissector (we must set the address if the URI port is the
3109 * same), and other functions that retrieve conversation data
3110 * or set the conversation dissector don't affect the original
3111 * conversation but the proxied one.
3112 */
3113
3114 /* Just use the string as a string address. */
3115 set_address(&uri_addr, AT_STRINGZ, (int)strlen(strings[0]) + 1, strings[0]);
3116 /* We may get stuck in a recursion loop if we let decode_tcp_ports() call us.
3117 * So, if the conversation that would be called also is CONNECT,
3118 * call the data dissector directly instead. The CONNECT method
3119 * is blind forwarding of data and consumes no payload itself
3120 * here, so infinite loops are possible. (Strictly, to avoid a
3121 * loop we must only assure that the same 5-tuple isn't reused,
3122 * which would take more work to check.)
3123 */
3124 if (!from_server) {
3125 srcport = pinfo->srcport;
3126 destport = uri_port;
3127 conv = find_conversation(pinfo->num, &pinfo->src, &uri_addr, CONVERSATION_TCP, srcport, destport, 0);
3128 } else {
3129 srcport = uri_port;
3130 destport = pinfo->destport;
3131 conv = find_conversation(pinfo->num, &uri_addr, &pinfo->dst, CONVERSATION_TCP, srcport, destport, 0);
3132 }
3133
3134 if (http_conversation_is_connect(conv, pinfo->num)) {
3135 call_data_dissector(tvb, pinfo, tree);
3136 } else if (wmem_list_count(pinfo->layers) + 16 >= prefs.gui_max_tree_depth) {
3137 /* Tunnels inside tunnels (for example two CONNECTs to the
3138 * same target) would recurse until the layer limit. */
3139 proto_tree_add_expert(tree, pinfo, &ei_http_tunnel_too_deep, tvb, 0, 0);
3140 call_data_dissector(tvb, pinfo, tree);
3141 } else {
3142 /* set pinfo->{src/dst port} and call the TCP sub-dissector lookup */
3143 if (!from_server) {
3144 ptr = &pinfo->destport;
3145 addrp = &pinfo->src;
3146 } else {
3147 ptr = &pinfo->srcport;
3148 addrp = &pinfo->dst;
3149 }
3150
3151 /* Increase pinfo->can_desegment because we are traversing
3152 * http and want to preserve desegmentation functionality for
3153 * the proxied protocol
3154 */
3155 if( pinfo->can_desegment>0 )
3156 pinfo->can_desegment++;
3157
3158 copy_address_shallow(&saved_addr, addrp);
3159 copy_address_shallow(addrp, &uri_addr);
3160 saved_port = *ptr;
3161 *ptr = uri_port;
3162 increment_dissection_depth(pinfo);
3163 decode_tcp_ports(tvb, 0, pinfo, tree,
3164 pinfo->srcport, pinfo->destport, NULL((void*)0),
3165 tcpinfo);
3166 decrement_dissection_depth(pinfo);
3167 *ptr = saved_port;
3168 copy_address_shallow(addrp, &saved_addr);
3169 }
3170 }
3171}
3172
3173
3174
3175/*
3176 * XXX - this won't handle HTTP 0.9 replies, but they're all data
3177 * anyway.
3178 */
3179static int
3180is_http_request_or_reply(packet_info *pinfo, const char *data, unsigned linelen, media_container_type_t *type,
3181 ReqRespDissector *reqresp_dissector,
3182 http_conv_t *conv_data _U___attribute__((unused)))
3183{
3184 http_info_value_t *stat_info = p_get_proto_data(pinfo->pool, pinfo, proto_http, HTTP_PROTO_DATA_INFO1);
3185 int isHttpRequestOrReply = false0;
3186
3187 /*
3188 * From RFC 2774 - An HTTP Extension Framework
3189 *
3190 * Support the command prefix that identifies the presence of
3191 * a "mandatory" header.
3192 */
3193 if (linelen >= 2 && strncmp(data, "M-", 2) == 0) {
3194 data += 2;
3195 linelen -= 2;
3196 }
3197
3198 /*
3199 * From draft-cohen-gena-client-01.txt, available from the uPnP forum:
3200 * NOTIFY, SUBSCRIBE, UNSUBSCRIBE
3201 *
3202 * From draft-ietf-dasl-protocol-00.txt, a now vanished Microsoft draft:
3203 * SEARCH
3204 */
3205 if ((linelen >= 5 && strncmp(data, "HTTP/", 5) == 0) ||
3206 (linelen >= 3 && strncmp(data, "ICY", 3) == 0)) {
3207 *type = MEDIA_CONTAINER_HTTP_RESPONSE;
3208 isHttpRequestOrReply = true1; /* response */
3209 if (reqresp_dissector)
3210 *reqresp_dissector = basic_response_dissector;
3211 } else {
3212 const unsigned char * ptr = (const unsigned char *)data;
3213 unsigned indx = 0;
3214
3215 /* Look for the space following the Method */
3216 while (indx < linelen) {
3217 if (*ptr == ' ')
3218 break;
3219 else {
3220 ptr++;
3221 indx++;
3222 }
3223 }
3224
3225 /* Check the methods that have same length */
3226 switch (indx) {
3227
3228 case 3:
3229 if (strncmp(data, "GET", indx) == 0 ||
3230 strncmp(data, "PUT", indx) == 0) {
3231 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3232 isHttpRequestOrReply = true1;
3233 }
3234 break;
3235
3236 case 4:
3237 if (strncmp(data, "COPY", indx) == 0 ||
3238 strncmp(data, "HEAD", indx) == 0 ||
3239 strncmp(data, "LOCK", indx) == 0 ||
3240 strncmp(data, "MOVE", indx) == 0 ||
3241 strncmp(data, "POLL", indx) == 0 ||
3242 strncmp(data, "POST", indx) == 0) {
3243 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3244 isHttpRequestOrReply = true1;
3245 }
3246 break;
3247
3248 case 5:
3249 if (strncmp(data, "BCOPY", indx) == 0 ||
3250 strncmp(data, "BMOVE", indx) == 0 ||
3251 strncmp(data, "MKCOL", indx) == 0 ||
3252 strncmp(data, "TRACE", indx) == 0 ||
3253 strncmp(data, "PATCH", indx) == 0 || /* RFC 5789 */
3254 strncmp(data, "LABEL", indx) == 0 || /* RFC 3253 8.2 */
3255 strncmp(data, "MERGE", indx) == 0 || /* RFC 3253 11.2 */
3256 strncmp(data, "QUERY", indx) == 0) { /* RFC 10008 */
3257 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3258 isHttpRequestOrReply = true1;
3259 }
3260 break;
3261
3262 case 6:
3263 if (strncmp(data, "DELETE", indx) == 0 ||
3264 strncmp(data, "SEARCH", indx) == 0 ||
3265 strncmp(data, "UNLOCK", indx) == 0 ||
3266 strncmp(data, "REPORT", indx) == 0 || /* RFC 3253 3.6 */
3267 strncmp(data, "UPDATE", indx) == 0) { /* RFC 3253 7.1 */
3268 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3269 isHttpRequestOrReply = true1;
3270 }
3271 else if (strncmp(data, "NOTIFY", indx) == 0) {
3272 *type = MEDIA_CONTAINER_HTTP_NOTIFICATION;
3273 isHttpRequestOrReply = true1;
3274 }
3275 break;
3276
3277 case 7:
3278 if (strncmp(data, "BDELETE", indx) == 0 ||
3279 strncmp(data, "CONNECT", indx) == 0 ||
3280 strncmp(data, "OPTIONS", indx) == 0 ||
3281 strncmp(data, "CHECKIN", indx) == 0) { /* RFC 3253 4.4, 9.4 */
3282 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3283 isHttpRequestOrReply = true1;
3284 }
3285 break;
3286
3287 case 8:
3288 if (strncmp(data, "PROPFIND", indx) == 0 ||
3289 strncmp(data, "CHECKOUT", indx) == 0 || /* RFC 3253 4.3, 9.3 */
3290 strncmp(data, "CCM_POST", indx) == 0) {
3291 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3292 isHttpRequestOrReply = true1;
3293 }
3294 break;
3295
3296 case 9:
3297 if (strncmp(data, "SUBSCRIBE", indx) == 0) {
3298 *type = MEDIA_CONTAINER_HTTP_NOTIFICATION;
3299 isHttpRequestOrReply = true1;
3300 } else if (strncmp(data, "PROPPATCH", indx) == 0 ||
3301 strncmp(data, "BPROPFIND", indx) == 0) {
3302 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3303 isHttpRequestOrReply = true1;
3304 }
3305 break;
3306
3307 case 10:
3308 if (strncmp(data, "BPROPPATCH", indx) == 0 ||
3309 strncmp(data, "UNCHECKOUT", indx) == 0 || /* RFC 3253 4.5 */
3310 strncmp(data, "MKACTIVITY", indx) == 0) { /* RFC 3253 13.5 */
3311 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3312 isHttpRequestOrReply = true1;
3313 }
3314 break;
3315
3316 case 11:
3317 if (strncmp(data, "MKWORKSPACE", indx) == 0 || /* RFC 3253 6.3 */
3318 strncmp(data, "RPC_CONNECT", indx) == 0 || /* [MS-RPCH] 2.1.1.1.1 */
3319 strncmp(data, "RPC_IN_DATA", indx) == 0) { /* [MS-RPCH] 2.1.2.1.1 */
3320 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3321 isHttpRequestOrReply = true1;
3322 } else if (strncmp(data, "UNSUBSCRIBE", indx) == 0) {
3323 *type = MEDIA_CONTAINER_HTTP_NOTIFICATION;
3324 isHttpRequestOrReply = true1;
3325 }
3326 break;
3327
3328 case 12:
3329 if (strncmp(data, "RPC_OUT_DATA", indx) == 0) { /* [MS-RPCH] 2.1.2.1.2 */
3330 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3331 isHttpRequestOrReply = true1;
3332 }
3333 break;
3334
3335 case 15:
3336 if (strncmp(data, "VERSION-CONTROL", indx) == 0) { /* RFC 3253 3.5 */
3337 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3338 isHttpRequestOrReply = true1;
3339 }
3340 break;
3341
3342 case 16:
3343 if (strncmp(data, "BASELINE-CONTROL", indx) == 0) { /* RFC 3253 12.6 */
3344 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3345 isHttpRequestOrReply = true1;
3346 } else if (strncmp(data, "SSTP_DUPLEX_POST", indx) == 0) { /* MS SSTP */
3347 *type = MEDIA_CONTAINER_HTTP_REQUEST;
3348 isHttpRequestOrReply = true1;
3349 }
3350 break;
3351
3352 default:
3353 break;
3354 }
3355
3356 if (isHttpRequestOrReply && reqresp_dissector) {
3357 *reqresp_dissector = basic_request_dissector;
3358
3359 stat_info->request_method = wmem_strndup(pinfo->pool, data, indx);
3360 }
3361
3362
3363
3364 }
3365
3366 return isHttpRequestOrReply;
3367}
3368
3369/*
3370 * Process headers.
3371 */
3372typedef struct {
3373 const char *name;
3374 int *hf;
3375 int special;
3376} header_info;
3377
3378#define HDR_NO_SPECIAL0 0
3379#define HDR_AUTHORIZATION1 1
3380#define HDR_AUTHENTICATE2 2
3381#define HDR_CONTENT_TYPE3 3
3382#define HDR_CONTENT_LENGTH4 4
3383#define HDR_CONTENT_ENCODING5 5
3384#define HDR_TRANSFER_ENCODING6 6
3385#define HDR_HOST7 7
3386#define HDR_UPGRADE8 8
3387#define HDR_COOKIE9 9
3388#define HDR_WEBSOCKET_PROTOCOL10 10
3389#define HDR_WEBSOCKET_EXTENSIONS11 11
3390#define HDR_REFERER12 12
3391#define HDR_LOCATION13 13
3392#define HDR_HTTP2_SETTINGS14 14
3393#define HDR_RANGE15 15
3394#define HDR_CONTENT_RANGE16 16
3395
3396static const header_info headers[] = {
3397 { "Authorization", &hf_http_authorization, HDR_AUTHORIZATION1 },
3398 { "Proxy-Authorization", &hf_http_proxy_authorization, HDR_AUTHORIZATION1 },
3399 { "Proxy-Authenticate", &hf_http_proxy_authenticate, HDR_AUTHENTICATE2 },
3400 { "WWW-Authenticate", &hf_http_www_authenticate, HDR_AUTHENTICATE2 },
3401 { "Content-Type", &hf_http_content_type, HDR_CONTENT_TYPE3 },
3402 { "Content-Length", &hf_http_content_length_header, HDR_CONTENT_LENGTH4 },
3403 { "Content-Encoding", &hf_http_content_encoding, HDR_CONTENT_ENCODING5 },
3404 { "Transfer-Encoding", &hf_http_transfer_encoding, HDR_TRANSFER_ENCODING6 },
3405 { "Upgrade", &hf_http_upgrade, HDR_UPGRADE8 },
3406 { "User-Agent", &hf_http_user_agent, HDR_NO_SPECIAL0 },
3407 { "Host", &hf_http_host, HDR_HOST7 },
3408 { "Range", &hf_http_range, HDR_RANGE15 },
3409 { "Content-Range", &hf_http_content_range, HDR_CONTENT_RANGE16 },
3410 { "Connection", &hf_http_connection, HDR_NO_SPECIAL0 },
3411 { "Cookie", &hf_http_cookie, HDR_COOKIE9 },
3412 { "Accept", &hf_http_accept, HDR_NO_SPECIAL0 },
3413 { "Accept-Query", &hf_http_accept_query, HDR_NO_SPECIAL0 },
3414 { "Referer", &hf_http_referer, HDR_REFERER12 },
3415 { "Accept-Language", &hf_http_accept_language, HDR_NO_SPECIAL0 },
3416 { "Accept-Encoding", &hf_http_accept_encoding, HDR_NO_SPECIAL0 },
3417 { "Date", &hf_http_date, HDR_NO_SPECIAL0 },
3418 { "Cache-Control", &hf_http_cache_control, HDR_NO_SPECIAL0 },
3419 { "Server", &hf_http_server, HDR_NO_SPECIAL0 },
3420 { "Location", &hf_http_location, HDR_LOCATION13 },
3421 { "Sec-WebSocket-Accept", &hf_http_sec_websocket_accept, HDR_NO_SPECIAL0 },
3422 { "Sec-WebSocket-Extensions", &hf_http_sec_websocket_extensions, HDR_WEBSOCKET_EXTENSIONS11 },
3423 { "Sec-WebSocket-Key", &hf_http_sec_websocket_key, HDR_NO_SPECIAL0 },
3424 { "Sec-WebSocket-Protocol", &hf_http_sec_websocket_protocol, HDR_WEBSOCKET_PROTOCOL10 },
3425 { "Sec-WebSocket-Version", &hf_http_sec_websocket_version, HDR_NO_SPECIAL0 },
3426 { "Set-Cookie", &hf_http_set_cookie, HDR_NO_SPECIAL0 },
3427 { "Last-Modified", &hf_http_last_modified, HDR_NO_SPECIAL0 },
3428 { "X-Forwarded-For", &hf_http_x_forwarded_for, HDR_NO_SPECIAL0 },
3429 { "HTTP2-Settings", &hf_http_http2_settings, HDR_HTTP2_SETTINGS14 },
3430};
3431
3432/*
3433 * Look up a header name (assume lower-case header_name).
3434 */
3435static int*
3436get_hf_for_header(char* header_name)
3437{
3438 int* hf_id = NULL((void*)0);
3439
3440 if (header_fields_hash && header_name) {
3441 hf_id = (int*) g_hash_table_lookup(header_fields_hash, header_name);
3442 } else {
3443 hf_id = NULL((void*)0);
3444 }
3445
3446 return hf_id;
3447}
3448
3449/*
3450 *
3451 */
3452static void
3453deregister_header_fields(void)
3454{
3455 if (dynamic_hf) {
3456 /* Deregister all fields */
3457 for (unsigned i = 0; i < dynamic_hf_size; i++) {
3458 proto_deregister_field (proto_http, *(dynamic_hf[i].p_id));
3459 g_free (dynamic_hf[i].p_id)(__builtin_object_size ((dynamic_hf[i].p_id), 0) != ((size_t)
- 1)) ? g_free_sized (dynamic_hf[i].p_id, __builtin_object_size
((dynamic_hf[i].p_id), 0)) : (g_free) (dynamic_hf[i].p_id)
;
3460 }
3461
3462 proto_add_deregistered_data (dynamic_hf);
3463 dynamic_hf = NULL((void*)0);
3464 dynamic_hf_size = 0;
3465 }
3466
3467 if (header_fields_hash) {
3468 g_hash_table_destroy (header_fields_hash);
3469 header_fields_hash = NULL((void*)0);
3470 }
3471}
3472
3473static void
3474header_fields_post_update_cb(void)
3475{
3476 int* hf_id;
3477 char* header_name;
3478 char* header_name_key;
3479
3480 deregister_header_fields();
3481
3482 if (num_header_fields) {
3483 header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL((void*)0));
3484 dynamic_hf = g_new0(hf_register_info, num_header_fields)((hf_register_info *) g_malloc0_n ((num_header_fields), sizeof
(hf_register_info)))
;
3485 dynamic_hf_size = num_header_fields;
3486
3487 for (unsigned i = 0; i < dynamic_hf_size; i++) {
3488 hf_id = g_new(int,1)((int *) g_malloc_n ((1), sizeof (int)));
3489 *hf_id = -1;
3490 header_name = g_strdup(header_fields[i].header_name)g_strdup_inline (header_fields[i].header_name);
3491 header_name_key = g_ascii_strdown(header_name, -1);
3492
3493 dynamic_hf[i].p_id = hf_id;
3494 dynamic_hf[i].hfinfo.name = header_name;
3495 dynamic_hf[i].hfinfo.abbrev = ws_strdup_printf("http.header.%s", header_name)wmem_strdup_printf(((void*)0), "http.header.%s", header_name);
3496 dynamic_hf[i].hfinfo.type = FT_STRING;
3497 dynamic_hf[i].hfinfo.display = BASE_NONE;
3498 dynamic_hf[i].hfinfo.strings = NULL((void*)0);
3499 dynamic_hf[i].hfinfo.bitmask = 0;
3500 dynamic_hf[i].hfinfo.blurb = g_strdup(header_fields[i].header_desc)g_strdup_inline (header_fields[i].header_desc);
3501 HFILL_INIT(dynamic_hf[i])(dynamic_hf[i]).hfinfo.id = -1; (dynamic_hf[i]).hfinfo.parent
= 0; (dynamic_hf[i]).hfinfo.ref_type = HF_REF_TYPE_NONE; (dynamic_hf
[i]).hfinfo.same_name_prev_id = -1; (dynamic_hf[i]).hfinfo.same_name_next
= ((void*)0);
;
3502
3503 g_hash_table_insert(header_fields_hash, header_name_key, hf_id);
3504 }
3505
3506 proto_register_field_array(proto_http, dynamic_hf, dynamic_hf_size);
3507 }
3508}
3509
3510static void
3511header_fields_reset_cb(void)
3512{
3513 deregister_header_fields();
3514}
3515
3516/**
3517 * Parses the transfer-coding, returning true if everything was fully understood
3518 * or false when unknown names were encountered.
3519 */
3520static bool_Bool
3521http_parse_transfer_coding(const char *value, headers_t *eh_ptr)
3522{
3523 bool_Bool is_fully_parsed = true1;
3524
3525 /* Mark header as set, but with unknown encoding. */
3526 eh_ptr->transfer_encoding = HTTP_TE_UNKNOWN;
3527
3528 while (*value) {
3529 /* skip OWS (SP / HTAB) and commas; stop at the end. */
3530 while (*value == ' ' || *value == '\t' || *value == ',')
3531 value++;
3532 if (!*value)
3533 break;
3534
3535 if (g_str_has_prefix(value, "chunked")(__builtin_constant_p ("chunked")? __extension__ ({ const char
* const __str = (value); const char * const __prefix = ("chunked"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "chunked") )
) {
3536 eh_ptr->transfer_encoding_chunked = true1;
3537 value += sizeof("chunked") - 1;
3538 continue;
3539 }
3540
3541 /* For now assume that chunked can only combined with exactly
3542 * one other (compression) encoding. Anything else is
3543 * unsupported. */
3544 if (eh_ptr->transfer_encoding != HTTP_TE_UNKNOWN) {
3545 /* No more transfer codings are expected. */
3546 is_fully_parsed = false0;
3547 break;
3548 }
3549
3550 if (g_str_has_prefix(value, "compress")(__builtin_constant_p ("compress")? __extension__ ({ const char
* const __str = (value); const char * const __prefix = ("compress"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "compress") )
) {
3551 eh_ptr->transfer_encoding = HTTP_TE_COMPRESS;
3552 value += sizeof("compress") - 1;
3553 } else if (g_str_has_prefix(value, "deflate")(__builtin_constant_p ("deflate")? __extension__ ({ const char
* const __str = (value); const char * const __prefix = ("deflate"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "deflate") )
) {
3554 eh_ptr->transfer_encoding = HTTP_TE_DEFLATE;
3555 value += sizeof("deflate") - 1;
3556 } else if (g_str_has_prefix(value, "gzip")(__builtin_constant_p ("gzip")? __extension__ ({ const char *
const __str = (value); const char * const __prefix = ("gzip"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "gzip") )
) {
3557 eh_ptr->transfer_encoding = HTTP_TE_GZIP;
3558 value += sizeof("gzip") - 1;
3559 } else if (g_str_has_prefix(value, "identity")(__builtin_constant_p ("identity")? __extension__ ({ const char
* const __str = (value); const char * const __prefix = ("identity"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "identity") )
) {
3560 eh_ptr->transfer_encoding = HTTP_TE_IDENTITY;
3561 value += sizeof("identity") - 1;
3562 } else if (g_str_has_prefix(value, "x-compress")(__builtin_constant_p ("x-compress")? __extension__ ({ const char
* const __str = (value); const char * const __prefix = ("x-compress"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "x-compress") )
) {
3563 eh_ptr->transfer_encoding = HTTP_TE_COMPRESS;
3564 value += sizeof("x-compress") - 1;
3565 } else if (g_str_has_prefix(value, "x-gzip")(__builtin_constant_p ("x-gzip")? __extension__ ({ const char
* const __str = (value); const char * const __prefix = ("x-gzip"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "x-gzip") )
) {
3566 eh_ptr->transfer_encoding = HTTP_TE_GZIP;
3567 value += sizeof("x-gzip") - 1;
3568 } else {
3569 /* Unknown transfer encoding, skip until next comma.
3570 * Stop when no more names are found. */
3571 is_fully_parsed = false0;
3572 value = strchr(value, ',');
3573 if (!value)
3574 break;
3575 }
3576 }
3577
3578 return is_fully_parsed;
3579}
3580
3581static bool_Bool
3582is_token_char(char c)
3583{
3584 /* tchar according to https://tools.ietf.org/html/rfc7230#section-3.2.6 */
3585 return strchr("!#$%&\\:*+-.^_`|~", c) || g_ascii_isalnum(c)((g_ascii_table[(guchar) (c)] & G_ASCII_ALNUM) != 0);
3586}
3587
3588static bool_Bool
3589valid_header_name(const unsigned char *line, unsigned header_len)
3590{
3591
3592 /*
3593 * Validate the header name. This allows no space between the field name
3594 * and colon (RFC 7230, Section. 3.2.4).
3595 */
3596 if (header_len == 0) {
3597 return false0;
3598 }
3599 for (unsigned i = 0; i < header_len; i++) {
3600 /*
3601 * NUL is not a valid character; treat it specially
3602 * due to C's notion that strings are NUL-terminated.
3603 */
3604 if (line[i] == '\0') {
3605 return false0;
3606 }
3607 if (!is_token_char(line[i])) {
3608 return false0;
3609 }
3610 }
3611 return true1;
3612}
3613
3614static bool_Bool
3615invalid_header_value_char(uint8_t c)
3616{
3617 /* NUL is not allowed in field values. */
3618 return c == '\0';
3619}
3620
3621static bool_Bool
3622process_header(tvbuff_t *tvb, unsigned offset, unsigned next_offset,
3623 const unsigned char *line, unsigned linelen, unsigned colon_offset,
3624 packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr,
3625 http_conv_t *conv_data, media_container_type_t http_type, wmem_map_t *header_value_map,
3626 wmem_allocator_t *header_value_map_allocator, bool_Bool streaming_chunk_mode)
3627{
3628 unsigned len;
3629 unsigned line_end_offset;
3630 unsigned header_len;
3631 int hf_index;
3632 unsigned char c;
3633 unsigned value_offset;
3634 unsigned value_len, value_bytes_len;
3635 uint8_t *value_bytes;
3636 char *value;
3637 char *header_name;
3638 char *p;
3639 unsigned char *up;
3640 proto_item *hdr_item = NULL((void*)0), *it;
3641 unsigned f;
3642 bool_Bool header_name_trailing_ws;
3643 bool_Bool header_value_bad_char;
3644 int* hf_id;
3645 tap_credential_t* auth;
3646 http_req_res_t *curr_req_res = (http_req_res_t *)p_get_proto_data(wmem_file_scope(), pinfo,
3647 proto_http, HTTP_PROTO_DATA_REQRES0);
3648 http_info_value_t *stat_info = p_get_proto_data(pinfo->pool, pinfo, proto_http, HTTP_PROTO_DATA_INFO1);
3649 wmem_allocator_t *scope = (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && streaming_chunk_mode) ? wmem_file_scope() :
3650 ((PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && streaming_chunk_mode) ? NULL((void*)0) : pinfo->pool);
3651
3652 len = next_offset - offset;
3653 line_end_offset = offset + linelen;
3654 header_len = colon_offset - offset;
3655 header_name_trailing_ws = header_len > 0 &&
3656 (line[header_len - 1] == ' ' || line[header_len - 1] == '\t');
3657 header_value_bad_char = false0;
3658
3659 /**
3660 * Not a valid header name? Just add a line plus expert info.
3661 */
3662 if (!valid_header_name(line, header_len)) {
3663 if (http_check_ascii_headers) {
3664 /* If we're offering the chance for other dissectors to parse,
3665 * we shouldn't add any tree items ourselves.
3666 */
3667 return false0;
3668 }
3669 if (http_type == MEDIA_CONTAINER_HTTP_REQUEST) {
3670 hf_index = hf_http_request_line;
3671 } else if (http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
3672 hf_index = hf_http_response_line;
3673 } else {
3674 hf_index = hf_http_unknown_header;
3675 }
3676 it = proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_NA0x00000000|ENC_ASCII0x00000000);
3677 proto_item_set_text(it, "%s", format_text(pinfo->pool, (char*)line, len));
3678 expert_add_info(pinfo, it, &ei_http_bad_header_name);
3679 if (header_name_trailing_ws) {
3680 expert_add_info(pinfo, it, &ei_http_header_name_trailing_ws);
3681 }
3682 return false0;
3683 }
3684
3685 /*
3686 * Make a null-terminated, all-lower-case version of the header
3687 * name.
3688 */
3689 header_name = wmem_ascii_strdown(pinfo->pool, (const char*)&line[0], header_len);
3690
3691 hf_index = find_header_hf_value(tvb, offset, header_len);
3692
3693 /*
3694 * Skip whitespace after the colon.
3695 */
3696 value_offset = colon_offset + 1;
3697 while (value_offset < line_end_offset
3698 && ((c = line[value_offset - offset]) == ' ' || c == '\t'))
3699 value_offset++;
3700
3701 /*
3702 * Fetch the value.
3703 *
3704 * XXX - RFC 9110 5.5 "Specification for newly defined fields
3705 * SHOULD limit their values to visible US-ASCII octets (VCHAR),
3706 * SP, and HTAB. A recipient SHOULD treat other allowed octets in
3707 * field content (i.e., obs-text [%x80-FF]) as opaque data...
3708 * Field values containing CR, LF, or NUL characters are invalid
3709 * and dangerous." (Up to RFC 7230, an obsolete "line-folding"
3710 * mechanism that included CRLF was allowed.)
3711 *
3712 * So NUL is not allowed, and we should have one or more
3713 * expert infos if the field value has anything other than
3714 * ASCII printable + TAB. (Possibly different severities
3715 * depending on whether it contains obsolete characters
3716 * like \x80-\xFF vs characters never allowed like NUL.)
3717 * All known field types respect this (using Base64, etc.)
3718 * Unknown field types (possibly including those registered
3719 * through the UAT) should be treated like FT_BYTES with
3720 * BASE_SHOW_ASCII_PRINTABLE instead of FT_STRING, but it's
3721 * more difficult to do that with the custom formatting
3722 * that uses the header name.
3723 *
3724 * Instead, for now for display purposes we will treat strings
3725 * as ASCII and pass the raw value to subdissectors via the
3726 * header_value_map. For the latter, we allocate a buffer that's
3727 * value_bytes_len+1 bytes long, copy value_bytes_len bytes, and
3728 * stick in a NUL terminator, so that the buffer for value actually
3729 * has value_bytes_len bytes in it.
3730 */
3731 value_bytes_len = line_end_offset - value_offset;
3732 value_bytes = (uint8_t *)wmem_alloc(PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) ? pinfo->pool : header_value_map_allocator, value_bytes_len+1);
3733 memcpy(value_bytes, &line[value_offset - offset], value_bytes_len);
3734 value_bytes[value_bytes_len] = '\0';
3735 for (f = 0; f < value_bytes_len; f++) {
3736 if (invalid_header_value_char(value_bytes[f])) {
3737 header_value_bad_char = true1;
3738 break;
3739 }
3740 }
3741 value = (char*)tvb_get_string_enc(pinfo->pool, tvb, value_offset, value_bytes_len, ENC_ASCII0x00000000);
3742 /* The length of the value might change after UTF-8 sanitization */
3743 value_len = (int)strlen(value);
3744
3745 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { /* Record header if packet was not visited yet */
3746 wmem_map_insert(header_value_map, wmem_strdup(header_value_map_allocator, header_name), value_bytes);
3747 }
3748
3749 if (hf_index == -1) {
3750 /*
3751 * Not a header we know anything about.
3752 * Check if a HF generated from UAT information exists.
3753 */
3754 hf_id = get_hf_for_header(header_name);
3755
3756 if (tree) {
3757 if (!hf_id) {
3758 if (http_type == MEDIA_CONTAINER_HTTP_REQUEST ||
3759 http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
3760 hdr_item = proto_tree_add_item(tree,
3761 http_type == MEDIA_CONTAINER_HTTP_RESPONSE ?
3762 hf_http_response_line :
3763 hf_http_request_line,
3764 tvb, offset, len,
3765 ENC_NA0x00000000|ENC_ASCII0x00000000);
3766 proto_item_set_text(hdr_item, "%s",
3767 format_text(pinfo->pool, (char*)line, len));
3768 } else {
3769 char* str = format_text(pinfo->pool, (char*)line, len);
3770 hdr_item = proto_tree_add_string_format(tree, hf_http_unknown_header, tvb, offset,
3771 len, str, "%s", str);
3772 }
3773
3774 } else {
3775 hdr_item = proto_tree_add_string_format(tree,
3776 *hf_id, tvb, offset, len, value,
3777 "%s", format_text(pinfo->pool, (char*)line, len));
3778 if (http_type == MEDIA_CONTAINER_HTTP_REQUEST ||
3779 http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
3780 it = proto_tree_add_item(tree,
3781 http_type == MEDIA_CONTAINER_HTTP_RESPONSE ?
3782 hf_http_response_line :
3783 hf_http_request_line,
3784 tvb, offset, len,
3785 ENC_NA0x00000000|ENC_ASCII0x00000000);
3786 proto_item_set_text(it, "%s",
3787 format_text(pinfo->pool, (char*)line, len));
3788 proto_item_set_hidden(it);
3789 }
3790 }
3791 if (header_value_bad_char && hdr_item) {
3792 expert_add_info(pinfo, hdr_item, &ei_http_bad_header_value_nul);
3793 }
3794 }
3795 } else {
3796 /*
3797 * Add it to the protocol tree as a particular field,
3798 * but display the line as is.
3799 */
3800 if (tree) {
3801 header_field_info *hfinfo;
3802 uint32_t tmp;
3803
3804 hfinfo = proto_registrar_get_nth(*headers[hf_index].hf);
3805 switch(hfinfo->type){
3806 case FT_UINT8:
3807 case FT_UINT16:
3808 case FT_UINT24:
3809 case FT_UINT32:
3810 case FT_INT8:
3811 case FT_INT16:
3812 case FT_INT24:
3813 case FT_INT32:
3814 tmp=(uint32_t)strtol(value, NULL((void*)0), 10);
3815 hdr_item = proto_tree_add_uint(tree, *headers[hf_index].hf, tvb, offset, len, tmp);
3816 if (http_type == MEDIA_CONTAINER_HTTP_REQUEST ||
3817 http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
3818 it = proto_tree_add_item(tree,
3819 http_type == MEDIA_CONTAINER_HTTP_RESPONSE ?
3820 hf_http_response_line :
3821 hf_http_request_line,
3822 tvb, offset, len,
3823 ENC_NA0x00000000|ENC_ASCII0x00000000);
3824 proto_item_set_text(it, "%d", tmp);
3825 proto_item_set_hidden(it);
3826 }
3827 break;
3828 default:
3829 hdr_item = proto_tree_add_string_format(tree,
3830 *headers[hf_index].hf, tvb, offset, len,
3831 value,
3832 "%s", format_text(pinfo->pool, (char*)line, len));
3833 if (http_type == MEDIA_CONTAINER_HTTP_REQUEST ||
3834 http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
3835 it = proto_tree_add_item(tree,
3836 http_type == MEDIA_CONTAINER_HTTP_RESPONSE ?
3837 hf_http_response_line :
3838 hf_http_request_line,
3839 tvb, offset, len,
3840 ENC_NA0x00000000|ENC_ASCII0x00000000);
3841 proto_item_set_text(it, "%s",
3842 format_text(pinfo->pool, (char*)line, len));
3843 proto_item_set_hidden(it);
3844 }
3845 }
3846 } else
3847 hdr_item = NULL((void*)0);
3848
3849 if (header_value_bad_char && hdr_item) {
3850 expert_add_info(pinfo, hdr_item, &ei_http_bad_header_value_nul);
3851 }
3852
3853 /*
3854 * Do any special processing that particular headers
3855 * require.
3856 */
3857 switch (headers[hf_index].special) {
3858
3859 case HDR_AUTHORIZATION1:
3860 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
3861 break; /* dissected NTLMSSP */
3862 if (check_auth_basic(hdr_item, tvb, pinfo, value))
3863 break; /* dissected basic auth */
3864 if (check_auth_citrixbasic(hdr_item, tvb, pinfo, value, offset))
3865 break; /* dissected citrix basic auth */
3866 if (check_auth_kerberos(hdr_item, tvb, pinfo, value))
3867 break;
3868 if (check_auth_digest(hdr_item, tvb, pinfo, value, offset, value_len))
3869 break;/* dissected digest basic auth */
3870 auth = wmem_new0(pinfo->pool, tap_credential_t)((tap_credential_t*)wmem_alloc0((pinfo->pool), sizeof(tap_credential_t
)))
;
3871 auth->num = pinfo->num;
3872 auth->password_hf_id = *headers[hf_index].hf;
3873 auth->proto = "HTTP header auth";
3874 auth->username = wmem_strdup(pinfo->pool, CREDENTIALS_PLACEHOLDER"n.a.");
3875 tap_queue_packet(credentials_tap, pinfo, auth);
3876 break;
3877
3878 case HDR_AUTHENTICATE2:
3879 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
3880 break; /* dissected NTLMSSP */
3881 check_auth_kerberos(hdr_item, tvb, pinfo, value);
3882 break;
3883
3884 case HDR_CONTENT_TYPE3:
3885 if (scope == NULL((void*)0)) { /* identical to (PINFO_FD_VISITED(pinfo) && streaming_chunk_mode) */
3886 break; /* eh_ptr->content_type[_parameters] must have been set during first scan */
3887 }
3888 eh_ptr->content_type = wmem_strdup(scope, value);
3889
3890 for (f = 0; f < value_len; f++) {
3891 c = value[f];
3892 if (c == ';' || g_ascii_isspace(c)((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0)) {
3893 /*
3894 * End of subtype - either
3895 * white space or a ";"
3896 * separating the subtype from
3897 * a parameter.
3898 */
3899 break;
3900 }
3901
3902 /*
3903 * Map the character to lower case;
3904 * content types are case-insensitive.
3905 */
3906 eh_ptr->content_type[f] = g_ascii_tolower(eh_ptr->content_type[f]);
3907 }
3908 eh_ptr->content_type[f] = '\0';
3909 /*
3910 * Now find the start of the optional parameters;
3911 * skip the optional white space and the semicolon
3912 * if this has not been done before.
3913 */
3914 f++;
3915 while (f < value_len) {
3916 c = eh_ptr->content_type[f];
3917 if (c == ';' || g_ascii_isspace(c)((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0))
3918 /* Skip till start of parameters */
3919 f++;
3920 else
3921 break;
3922 }
3923 if (f < value_len)
3924 eh_ptr->content_type_parameters = eh_ptr->content_type + f;
3925 else
3926 eh_ptr->content_type_parameters = NULL((void*)0);
3927 break;
3928
3929 case HDR_CONTENT_LENGTH4:
3930 if (streaming_chunk_mode) {
3931 /* Transfer-Encoding overrides Content-Length (RFC 9112 6.3). */
3932 expert_add_info(pinfo, hdr_item, &ei_http_te_and_length);
3933 break;
3934 }
3935 errno(*__errno_location ()) = 0;
3936 eh_ptr->content_length = g_ascii_strtoll(value, &p, 10);
3937 up = (unsigned char *)p;
3938 if (eh_ptr->content_length < 0 ||
3939 p == value ||
3940 errno(*__errno_location ()) == ERANGE34 ||
3941 (*up != '\0' && !g_ascii_isspace(*up)((g_ascii_table[(guchar) (*up)] & G_ASCII_SPACE) != 0))) {
3942 /*
3943 * Content length not valid; pretend
3944 * we don't have it.
3945 */
3946 eh_ptr->have_content_length = false0;
3947 } else {
3948 proto_tree *header_tree;
3949 proto_item *tree_item;
3950 /*
3951 * We do have a valid content length.
3952 */
3953 eh_ptr->have_content_length = true1;
3954 header_tree = proto_item_add_subtree(hdr_item, ett_http_header_item);
3955 tree_item = proto_tree_add_uint64(header_tree, hf_http_content_length,
3956 tvb, offset, len, eh_ptr->content_length);
3957 proto_item_set_generated(tree_item);
3958 if (eh_ptr->transfer_encoding != HTTP_TE_NONE) {
3959 expert_add_info(pinfo, hdr_item, &ei_http_te_and_length);
3960 }
3961 }
3962 break;
3963
3964 case HDR_CONTENT_ENCODING5:
3965 if (scope == NULL((void*)0)) { /* identical to (PINFO_FD_VISITED(pinfo) && streaming_chunk_mode) */
3966 break; /* eh_ptr->content_encoding must have been set during first scan */
3967 }
3968 eh_ptr->content_encoding = wmem_strndup(scope, value, value_len);
3969 break;
3970
3971 case HDR_TRANSFER_ENCODING6:
3972 if (eh_ptr->have_content_length) {
3973 expert_add_info(pinfo, hdr_item, &ei_http_te_and_length);
3974 }
3975 if (!http_parse_transfer_coding(value, eh_ptr)) {
3976 expert_add_info(pinfo, hdr_item, &ei_http_te_unknown);
3977 }
3978 break;
3979
3980 case HDR_HOST7:
3981 stat_info->http_host = wmem_strndup(pinfo->pool, value, value_len);
3982 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) && curr_req_res) {
3983 curr_req_res->http_host = wmem_strndup(wmem_file_scope(), value, value_len);
3984 }
3985 break;
3986
3987 case HDR_UPGRADE8:
3988 if (scope == NULL((void*)0)) { /* identical to (PINFO_FD_VISITED(pinfo) && streaming_chunk_mode) */
3989 break;
3990 }
3991 eh_ptr->upgrade = wmem_ascii_strdown(scope, value, value_len);
3992 break;
3993
3994 case HDR_COOKIE9:
3995 if (hdr_item) {
3996 proto_tree *cookie_tree;
3997 char *part, *part_end;
3998 int part_len;
3999
4000 cookie_tree = proto_item_add_subtree(hdr_item, ett_http_header_item);
4001 for (f = 0; f < value_len; ) {
4002 /* skip whitespace and ';' (terminates at '\0' or earlier) */
4003 c = value[f];
4004 while (c == ';' || g_ascii_isspace(c)((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0))
4005 c = value[++f];
4006
4007 if (f >= value_len)
4008 break;
4009
4010 /* find "cookie=foo " in "cookie=foo ; bar" */
4011 part = value + f;
4012 part_end = (char *)memchr(part, ';', value_len - f);
4013 if (part_end)
4014 part_len =(int)(part_end - part);
4015 else
4016 part_len = value_len - f;
4017
4018 /* finally add cookie to tree */
4019 proto_tree_add_item(cookie_tree, hf_http_cookie_pair,
4020 tvb, value_offset + f, part_len, ENC_ASCII0x00000000);
4021 f += part_len;
4022 }
4023 }
4024 break;
4025
4026 case HDR_REFERER12:
4027 stat_info->referer_uri = wmem_strndup(pinfo->pool, value, value_len);
4028 break;
4029
4030 case HDR_LOCATION13:
4031 if (curr_req_res && curr_req_res->request_uri){
4032 stat_info->location_target = wmem_strndup(pinfo->pool, value, value_len);
4033 stat_info->location_base_uri = wmem_strdup(pinfo->pool, curr_req_res->full_uri);
4034 }
4035 break;
4036 case HDR_HTTP2_SETTINGS14:
4037 {
4038 proto_tree* settings_tree = proto_item_add_subtree(hdr_item, ett_http_http2_settings_item);
4039 tvbuff_t* new_tvb = base64uri_tvb_to_new_tvb(tvb, value_offset, value_bytes_len);
4040 add_new_data_source(pinfo, new_tvb, "Base64uri decoded");
4041 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)
{
4042 dissect_http2_settings_ext(new_tvb, pinfo, settings_tree, 0);
4043 } CATCH_ALLif (except_state == 0 && exc != 0 && (except_state
|=1))
{
4044 show_exception(tvb, pinfo, settings_tree, EXCEPT_CODE((exc)->except_id.except_code), GET_MESSAGE((exc)->except_message));
4045 }
4046 ENDTRYif(!(except_state&1) && exc != 0) except_rethrow(
exc); except_free(except_ch.except_obj.except_dyndata); except_pop
(); };}
;
4047
4048 break;
4049 }
4050 case HDR_RANGE15:
4051 {
4052 /* THIS IS A GET REQUEST
4053 * Note: GET is the only method that employs ranges.
4054 * (Unless the data has errors or is noncompliant.)
4055 */
4056 if (curr_req_res && !pinfo->fd->visited) {
4057 /*
4058 * Unlike protocols such as NFS and SMB, the HTTP protocol (RFC 9110) does not
4059 * provide an identifier with which to match requests and responses. Instead,
4060 * matching is solely based upon the order in which responses are received.
4061 * HTTP I/O is 'asynchronously ordered' such that, for example, the first of four
4062 * GET responses are matched with the first outstanding request, the next
4063 * response with the second oldest outstanding request and so on (FIFO).
4064 * The previous method instead matched responses with the last of several
4065 * async requests rather than the first (LIFO), and did not handle requests
4066 * with no responses such as the case where one or more HTTP packets were
4067 * not captured. Whenever there were multiple outstanding requests, the SRT
4068 * (RTT) stats were incorrect, in some cases massively so.
4069 *
4070 * While RFC 9110 expressly prohibits matching via byte ranges because, among
4071 * other things, the server may return fewer bytes than requested,
4072 * the first number of the range does not change. Unlike HTTP implementations,
4073 * Wireshark has the problem of requests/responses missing from the capture
4074 * file. In such cases resumption of correct matching was virtually impossible.
4075 * In addition, all matching was incorrect from that point on.
4076 *
4077 * The method of matching used herein is able to recover from packet loss,
4078 * any number of missing frames, and duplicate range requests. The
4079 * method used is explained within the comments.
4080 */
4081 /* https://www.rfc-editor.org/rfc/rfc9110.html#name-range-requests
4082 * Note that RFC 9110 16.5 defines a registry for
4083 * range units, but only bytes are registered.
4084 * ABNF:
4085 * Range = ranges-specifier
4086 * ranges-specifier = range-unit "=" range-set
4087 * range-set = 1#range-spec
4088 * range-spec = int-range / suffix-range / other-range
4089 * 1# is an ABNF extension defined in RFC 9110 5.6.1
4090 * which covers comma separated list with optional
4091 * white space:
4092 * 1#element => element *( OWS "," OWS element )
4093 * We don't care about other-range, but will try to
4094 * handle int-range and suffix-range.
4095 * This ignores any entries past the first in a list,
4096 * though responses to such would be multipart.
4097 * As mentioned above, this breaks down if the
4098 * response does not include all requested ranges
4099 * fully in one response.
4100 */
4101 const char *pos = strchr(value, '=');
4102 if (pos == NULL((void*)0)) {
4103 break;
4104 }
4105 pos++;
4106 uint64_t first_range_num = 0;
4107 /* Get the first range number */
4108 ws_strtou64(pos, &pos, &first_range_num);
4109 /* If the first number of the range is missing or '0',
4110 * use the second number in the range instead if we can.
4111 * XXX - Unlike strtoul, we can check the return value
4112 * of ws_strtou64() to distinguish between "converted
4113 * successfully as 0" and "failed conversion."
4114 * Note that strtoul allows an unsigned integer to
4115 * begin with a negative sign and applies unsigned
4116 * integer wraparound rules.
4117 * ws_strtouXX rejects an initial hyphen-minus, which
4118 * is good, as we want to properly handle:
4119 * suffix-range = "-" suffix-length
4120 */
4121 if (first_range_num == 0 && *pos == '-') {
4122 pos++;
4123 /* Pass in an end pointer to convert
4124 * a list of ranges, the first of which is
4125 * a suffix-range.
4126 */
4127 ws_strtou64(pos, &pos, &first_range_num);
4128 }
4129 /* req_list is used for req/resp matching and the deletion (and freeing) of matching
4130 * requests and any orphans that precede them. A GSList is used instead of a wmem map
4131 * because there are rarely more than 10 requests in the list."
4132 */
4133 if (first_range_num > 0) {
4134 request_trans_t* req_trans = wmem_new(wmem_file_scope(), request_trans_t)((request_trans_t*)wmem_alloc((wmem_file_scope()), sizeof(request_trans_t
)))
;
4135 req_trans->first_range_num = first_range_num;
4136 req_trans->req_frame = pinfo->num;
4137 req_trans->abs_time = pinfo->fd->abs_ts;
4138 req_trans->request_uri = curr_req_res->request_uri;
4139
4140 wmem_list_append(conv_data->req_list, req_trans);
4141 curr_req_res->req_has_range = true1;
4142 }
4143 }
4144
4145 break;
4146 }
4147 case HDR_CONTENT_RANGE16:
4148 /*
4149 * THIS IS A GET RESPONSE
4150 * GET is the only method that employs ranges.
4151 * XXX - Except that RFC 9110 14.4 & 14.5 note that by
4152 * private agreement it can be included in a request
4153 * to request a partial PUT.
4154 * ABNF:
4155 * Content-Range = range-unit SP ( range-resp / unsatisfied-range )
4156 * range-resp = incl-range "/" ( complete-length / "*" )
4157 * We do not attempt to handle unsatisfied-range.
4158 * Note that only one range can be included; multiple
4159 * ranges are transmitted with the media type of
4160 * "multipart/byteranges" and each body part contains
4161 * its own Content-Type and Content-Range fields.
4162 * The multipart dissector does not handle this nor
4163 * access the request list.
4164 */
4165 if (curr_req_res && !pinfo->fd->visited) {
4166 request_trans_t *req_trans;
4167 match_trans_t *match_trans = NULL((void*)0);
4168 nstime_t ns;
4169 wmem_list_frame_t *frame;
4170
4171 /* Note SP instead of '=' in ABNF. */
4172 const char *pos = strchr(value, ' ');
4173 if (pos == NULL((void*)0)) {
4174 break;
4175 }
4176 pos++;
4177 uint64_t first_crange_num = 0;
4178 /* Get the first content range number */
4179 ws_strtou64(pos, &pos, &first_crange_num);
4180
4181 if (first_crange_num == 0 && *pos == '-') {
4182 pos++;
4183 ws_strtou64(pos, &pos, &first_crange_num);
4184 }
4185
4186 /* Get the position of the matching request if any in the reqs_table.
4187 * This is used to remove and free the matching request, and the unmatched
4188 * requests (orphans) that precede it.
4189 * XXX - There is *NO* guarantee that there is
4190 * a perfectly matching request, see 15.3.7:
4191 * "However, a server might want to send only a
4192 * subset of the data requested for reasons of
4193 * its own... A client MUST inspect a 206
4194 * response's Content-Type and Content-Range
4195 * field(s) to determine what parts are enclosed
4196 * and whether additional requests are needed."
4197 * Also 15.3.7.2 Multiple Parts, noting that
4198 * the response may be sent in a Content-Type
4199 * multipart/byteranges, also "When multiple
4200 * ranges are requested, a server MAY coalesce
4201 * any of the ranges that overlap, or that are
4202 * separated by a gap that is smaller than the
4203 * overhead of sending multiple parts, regardless
4204 * of the order in which the corresponding range-
4205 * spec appeared in the received Range header
4206 * field." and 15.3.7.3 Combining Parts.
4207 * However, as mentioned above, the LIFO method
4208 * had issues with that as well. Truly proper
4209 * handling of such edge cases is more difficult.
4210 */
4211 req_trans = NULL((void*)0);
4212 for (frame = wmem_list_head(conv_data->req_list);
4213 frame; frame = wmem_list_frame_next(frame)) {
4214
4215 request_trans_t* frame_req_trans = wmem_list_frame_data(frame);
4216 if (frame_req_trans->first_range_num == first_crange_num) {
4217 req_trans = frame_req_trans;
4218 break;
4219 }
4220 }
4221
4222 if (first_crange_num != 0 && req_trans) {
4223 match_trans = wmem_new(wmem_file_scope(), match_trans_t)((match_trans_t*)wmem_alloc((wmem_file_scope()), sizeof(match_trans_t
)))
;
4224 match_trans->req_frame = req_trans->req_frame;
4225 match_trans->resp_frame = pinfo->num;
4226 nstime_delta(&ns, &pinfo->fd->abs_ts, &req_trans->abs_time);
4227 match_trans->delta_time = ns;
4228 match_trans->request_uri = req_trans->request_uri;
4229 match_trans->http_host = curr_req_res->http_host;
4230
4231 wmem_map_insert(conv_data->matches_table,
4232 GUINT_TO_POINTER(match_trans->req_frame)((gpointer) (gulong) (match_trans->req_frame)), (void *)match_trans);
4233 wmem_map_insert(conv_data->matches_table,
4234 GUINT_TO_POINTER(match_trans->resp_frame)((gpointer) (gulong) (match_trans->resp_frame)), (void *)match_trans);
4235
4236 /* Remove and free all of the list entries up to and including the
4237 * matching one from req_list. */
4238 while ((frame = wmem_list_head(conv_data->req_list))) {
4239
4240 if (wmem_list_frame_data(frame) == req_trans) {
4241 wmem_list_remove_frame(conv_data->req_list, frame);
4242 break;
4243 }
4244 wmem_list_remove_frame(conv_data->req_list, frame);
4245 }
4246 }
4247 }
4248 if (curr_req_res)
4249 curr_req_res->resp_has_range = true1;
4250 break;
4251 }
4252 }
4253 return true1;
4254}
4255
4256/* Returns index of header tag in headers */
4257static int
4258find_header_hf_value(tvbuff_t *tvb, unsigned offset, unsigned header_len)
4259{
4260 unsigned i;
4261
4262 for (i = 0; i < array_length(headers)(sizeof (headers) / sizeof (headers)[0]); i++) {
4263 if (header_len == strlen(headers[i].name) &&
4264 tvb_strncaseeql(tvb, offset,
4265 headers[i].name, header_len) == 0)
4266 return i;
4267 }
4268
4269 return -1;
4270}
4271
4272/*
4273 * Dissect Microsoft's abomination called NTLMSSP over HTTP.
4274 */
4275static bool_Bool
4276check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, char *value)
4277{
4278 static const char *ntlm_headers[] = {
4279 "NTLM ",
4280 "Negotiate ",
4281 NULL((void*)0)
4282 };
4283 const char **header;
4284 size_t hdrlen;
4285 proto_tree *hdr_tree;
4286
4287 /*
4288 * Check for NTLM credentials and challenge; those can
4289 * occur with WWW-Authenticate.
4290 */
4291 for (header = &ntlm_headers[0]; *header != NULL((void*)0); header++) {
4292 hdrlen = strlen(*header);
4293 if (strncmp(value, *header, hdrlen) == 0) {
4294 hdr_tree = proto_item_add_subtree(hdr_item,
4295 ett_http_ntlmssp);
4296 value += hdrlen;
4297 dissect_http_ntlmssp(tvb, pinfo, hdr_tree, value);
4298 return true1;
4299 }
4300 }
4301 return false0;
4302}
4303
4304static tap_credential_t*
4305basic_auth_credentials(wmem_allocator_t *scope, const char* str)
4306{
4307 char **tokens = g_strsplit(str, ":", -1);
4308
4309 if (!tokens || !tokens[0] || !tokens[1]) {
4310 g_strfreev(tokens);
4311 return NULL((void*)0);
4312 }
4313
4314 tap_credential_t* auth = wmem_new0(scope, tap_credential_t)((tap_credential_t*)wmem_alloc0((scope), sizeof(tap_credential_t
)))
;
4315
4316 auth->username = wmem_strdup(scope, tokens[0]);
4317 auth->proto = "HTTP basic auth";
4318
4319 g_strfreev(tokens);
4320
4321 return auth;
4322}
4323
4324/*
4325 * Dissect HTTP Basic authorization.
4326 */
4327static bool_Bool
4328check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, char *value)
4329{
4330 static const char *basic_headers[] = {
4331 "Basic ",
4332 NULL((void*)0)
4333 };
4334 const char **header;
4335 size_t hdrlen;
4336 const char *decoded_value;
4337 proto_tree *hdr_tree;
4338 tvbuff_t *auth_tvb;
4339
4340 for (header = &basic_headers[0]; *header != NULL((void*)0); header++) {
4341 hdrlen = strlen(*header);
4342 if (strncmp(value, *header, hdrlen) == 0) {
4343 hdr_tree = proto_item_add_subtree(hdr_item,
4344 ett_http_ntlmssp);
4345 value += hdrlen;
4346
4347 auth_tvb = base64_to_tvb(tvb, value);
4348 add_new_data_source(pinfo, auth_tvb, "Basic Credentials");
4349 /* RFC 7617 says that the character encoding is only
4350 * known to be UTF-8 if the 'charset' parameter was
4351 * used. Otherwise, after Base64 decoding it could be
4352 * any character encoding.
4353 * XXX: Perhaps the field should be a FT_BYTES with
4354 * BASE_SHOW_UTF_8_PRINTABLE?
4355 */
4356 proto_tree_add_item_ret_string(hdr_tree, hf_http_basic, auth_tvb, 0, tvb_reported_length(auth_tvb), ENC_UTF_80x00000002, pinfo->pool, (const uint8_t**)&decoded_value);
4357 tap_credential_t* auth = basic_auth_credentials(pinfo->pool, decoded_value);
4358 if (auth) {
4359 auth->num = auth->username_num = pinfo->num;
4360 auth->password_hf_id = hf_http_basic;
4361 tap_queue_packet(credentials_tap, pinfo, auth);
4362 }
4363
4364 return true1;
4365 }
4366 }
4367 return false0;
4368}
4369
4370/*
4371 * Dissect HTTP Digest authorization.
4372 */
4373static bool_Bool
4374check_auth_digest(proto_item* hdr_item, tvbuff_t* tvb, packet_info* pinfo _U___attribute__((unused)), char* value, unsigned offset, unsigned len)
4375{
4376 proto_tree* hdr_tree;
4377 unsigned queried_offset;
4378
4379 if (strncmp(value, "Digest", 6) == 0) {
4380 hdr_tree = proto_item_add_subtree(hdr_item, ett_http_ntlmssp);
4381 tvbuff_t *digest_tvb = tvb_new_subset_length(tvb, offset, len);
4382 offset = 21; // strlen("Authorization: Digest");
4383 while (tvb_captured_length_remaining(digest_tvb, offset)) {
4384 /* Find comma/end of line */
4385 tvb_find_uint8_remaining(digest_tvb, offset, ',', &queried_offset);
4386 proto_tree_add_format_text(hdr_tree, digest_tvb, offset, queried_offset - offset);
4387 offset = queried_offset + 1;
4388 }
4389 return true1;
4390 } else {
4391 return false0;
4392 }
4393}
4394/*
4395 * Dissect HTTP CitrixAGBasic authorization.
4396 */
4397static bool_Bool
4398check_auth_citrixbasic(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, char *value, unsigned offset)
4399{
4400 static const char *basic_headers[] = {
4401 "CitrixAGBasic ",
4402 NULL((void*)0)
4403 };
4404 const char **header;
4405 size_t hdrlen;
4406 proto_tree *hdr_tree;
4407 char *ch_ptr;
4408 unsigned data_len;
4409 tvbuff_t *data_tvb;
4410 proto_item *hidden_item;
4411 proto_item *pi;
4412 const uint8_t *user = NULL((void*)0), *passwd = NULL((void*)0);
4413
4414 for (header = &basic_headers[0]; *header != NULL((void*)0); header++) {
4415 hdrlen = strlen(*header);
4416 if (strncmp(value, *header, hdrlen) == 0) {
4417 hdr_tree = proto_item_add_subtree(hdr_item,
4418 ett_http_ntlmssp);
4419 value += hdrlen;
4420 offset += (unsigned)hdrlen + 15;
4421 hidden_item = proto_tree_add_boolean(hdr_tree,
4422 hf_http_citrix, tvb, 0, 0, 1);
4423 proto_item_set_hidden(hidden_item);
4424
4425 if(strncmp(value, "username=\"", 10) == 0) {
4426 value += 10;
4427 offset += 10;
4428 ch_ptr = strchr(value, '"');
4429 if ( ch_ptr != NULL((void*)0) ) {
4430 data_len = (unsigned)(ch_ptr - value);
4431 if (data_len) {
4432 data_tvb = base64_tvb_to_new_tvb(tvb, offset, data_len);
4433 add_new_data_source(pinfo, data_tvb, "Username");
4434 /* XXX: We don't know for certain the string encoding here. */
4435 pi = proto_tree_add_item_ret_string(hdr_tree, hf_http_citrix_user, data_tvb, 0, tvb_reported_length(data_tvb), ENC_UTF_80x00000002, pinfo->pool, &user);
4436 } else {
4437 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_user, tvb, offset, 0, "");
4438 }
4439 proto_item_set_generated(pi);
4440 value += data_len + 1;
4441 offset += data_len + 1;
4442 }
4443 }
4444 if(strncmp(value, "; domain=\"", 10) == 0) {
4445 value += 10;
4446 offset += 10;
4447 ch_ptr = strchr(value, '"');
4448 if ( ch_ptr != NULL((void*)0) ) {
4449 data_len = (unsigned)(ch_ptr - value);
4450 if (data_len) {
4451 data_tvb = base64_tvb_to_new_tvb(tvb, offset, data_len);
4452 add_new_data_source(pinfo, data_tvb, "Domain");
4453 pi = proto_tree_add_item(hdr_tree, hf_http_citrix_domain, data_tvb, 0, tvb_reported_length(data_tvb), ENC_UTF_80x00000002);
4454 } else {
4455 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_domain, tvb, offset, 0, "");
4456 }
4457 proto_item_set_generated(pi);
4458 value += data_len + 1;
4459 offset += data_len + 1;
4460 }
4461 }
4462 if(strncmp(value, "; password=\"", 12) == 0) {
4463 value += 12;
4464 offset += 12;
4465 ch_ptr = strchr(value, '"');
4466 if ( ch_ptr != NULL((void*)0) ) {
4467 data_len = (unsigned)(ch_ptr - value);
4468 if (data_len) {
4469 data_tvb = base64_tvb_to_new_tvb(tvb, offset, data_len);
4470 add_new_data_source(pinfo, data_tvb, "Password");
4471 pi = proto_tree_add_item_ret_string(hdr_tree, hf_http_citrix_passwd, data_tvb, 0, tvb_reported_length(data_tvb), ENC_UTF_80x00000002, pinfo->pool, &passwd);
4472 } else {
4473 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_passwd, tvb, offset, 0, "");
4474 }
4475 proto_item_set_generated(pi);
4476 value += data_len + 1;
4477 offset += data_len + 1;
4478 }
4479 }
4480 if(strncmp(value, "; AGESessionId=\"", 16) == 0) {
4481 value += 16;
4482 offset += 16;
4483 ch_ptr = strchr(value, '"');
4484 if ( ch_ptr != NULL((void*)0) ) {
4485 data_len = (unsigned)(ch_ptr - value);
4486 if (data_len) {
4487 data_tvb = base64_tvb_to_new_tvb(tvb, offset, data_len);
4488 add_new_data_source(pinfo, data_tvb, "Session ID");
4489 pi = proto_tree_add_item(hdr_tree, hf_http_citrix_session, data_tvb, 0, tvb_reported_length(data_tvb), ENC_UTF_80x00000002);
4490 } else {
4491 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_session, tvb,
4492 offset, 0, "");
4493 }
4494 proto_item_set_generated(pi);
4495 }
4496 }
4497 if (user != NULL((void*)0) && passwd != NULL((void*)0)) {
4498
4499 tap_credential_t* auth = wmem_new0(pinfo->pool, tap_credential_t)((tap_credential_t*)wmem_alloc0((pinfo->pool), sizeof(tap_credential_t
)))
;
4500
4501 auth->username = wmem_strdup(pinfo->pool, (char*)user);
4502 auth->proto = "HTTP CitrixAGBasic auth";
4503 auth->num = auth->username_num = pinfo->num;
4504 auth->password_hf_id = hf_http_citrix_passwd;
4505 tap_queue_packet(credentials_tap, pinfo, auth);
4506 }
4507 return true1;
4508 }
4509 }
4510 return false0;
4511}
4512
4513static bool_Bool
4514check_auth_kerberos(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, const char *value)
4515{
4516 proto_tree *hdr_tree;
4517
4518 if (strncmp(value, "Kerberos ", 9) == 0) {
4519 hdr_tree = proto_item_add_subtree(hdr_item, ett_http_kerberos);
4520 dissect_http_kerberos(tvb, pinfo, hdr_tree, value);
4521 return true1;
4522 }
4523 return false0;
4524}
4525
4526static int
4527dissect_http_on_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
4528 http_conv_t *conv_data, bool_Bool end_of_stream, const uint32_t *seq)
4529{
4530 unsigned offset = 0;
4531 int len = 0;
4532
4533 while (tvb_reported_length_remaining(tvb, offset) > 0) {
4534 /* Switch protocol if the data starts after response headers. */
4535 if (conv_data->startframe &&
4536 (pinfo->num > conv_data->startframe ||
4537 (pinfo->num == conv_data->startframe && offset >= conv_data->startoffset))) {
4538 /* Increase pinfo->can_desegment because we are traversing
4539 * http and want to preserve desegmentation functionality for
4540 * the proxied protocol
4541 */
4542 if (pinfo->can_desegment > 0)
4543 pinfo->can_desegment++;
4544 if (conv_data->next_handle) {
4545 conv_data->upgrade_info->from_server = pinfo->srcport == conv_data->server_port && addresses_equal(
4546 &pinfo->src, &conv_data->server_addr);
4547 call_dissector_only(conv_data->next_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, conv_data->upgrade_info);
4548 } else {
4549 call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
4550 }
4551 /*
4552 * If a subdissector requests reassembly, be sure not to
4553 * include the preceding HTTP headers.
4554 */
4555 if (pinfo->desegment_len) {
4556 pinfo->desegment_offset += offset;
4557 }
4558 break;
4559 }
4560 len = dissect_http_message(tvb, offset, pinfo, tree, conv_data, "HTTP", proto_http, end_of_stream, seq);
4561 if (len < 0)
4562 break;
4563 offset += len;
4564
4565 /*
4566 * OK, we've set the Protocol and Info columns for the
4567 * first HTTP message; set a fence so that subsequent
4568 * HTTP messages don't overwrite the Info column.
4569 */
4570 col_set_fence(pinfo->cinfo, COL_INFO);
4571 }
4572 /* dissect_http_message() returns -2 if message is not valid HTTP */
4573 return (len == -2)
4574 ? 0
4575 : (int)tvb_captured_length(tvb);
4576}
4577
4578static int
4579dissect_http_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
4580{
4581 struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
4582 conversation_t *conversation;
4583 http_conv_t *conv_data;
4584 bool_Bool end_of_stream;
4585
4586 conv_data = get_http_conversation_data(pinfo, &conversation);
4587
4588 /* Call HTTP2 dissector directly when detected via heuristics, but not
4589 * when it was upgraded (the conversation started with HTTP). */
4590 if (conversation_get_proto_data(conversation, proto_http2) &&
4591 !conv_data->startframe) {
4592 if (pinfo->can_desegment > 0)
4593 pinfo->can_desegment++;
4594 return call_dissector_only(http2_handle, tvb, pinfo, tree, data);
4595 }
4596
4597 /*
4598 * Check if this is proxied connection and if so, hand of dissection to the
4599 * payload-dissector.
4600 * Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */
4601 if(http_conversation_is_connect(conversation, pinfo->num)) {
4602 if (conv_data->startframe == 0 && !PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
4603 conv_data->startframe = pinfo->num;
4604 conv_data->startoffset = 0;
4605 copy_address_wmem(wmem_file_scope(), &conv_data->server_addr, &pinfo->dst);
4606 conv_data->server_port = pinfo->destport;
4607 }
4608 http_payload_subdissector(tvb, tree, pinfo, conv_data, tcpinfo);
4609
4610 return tvb_captured_length(tvb);
4611 }
4612
4613 /* XXX - how to detect end-of-stream without tcpinfo */
4614 end_of_stream = (tcpinfo && IS_TH_FIN(tcpinfo->flags)(tcpinfo->flags & 0x001));
4615 return dissect_http_on_stream(tvb, pinfo, tree, conv_data, end_of_stream, tcpinfo ? &tcpinfo->seq : NULL((void*)0));
4616}
4617
4618static bool_Bool
4619dissect_http_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
4620{
4621 unsigned offset = 0, next_offset, linelen;
4622 bool_Bool found;
4623 conversation_t *conversation;
4624
4625
4626 /* Check if we have a line terminated by CRLF
4627 * Return the length of the line (not counting the line terminator at
4628 * the end), or, if we don't find a line terminator:
4629 *
4630 * if "deseg" is true, return -1;
4631 */
4632 found = tvb_find_line_end_remaining(tvb, offset, &linelen , &next_offset);
4633 if((found == false0)||(linelen == 8)){
4634 return false0;
4635 }
4636
4637 /* Check if the line start or ends with the HTTP token */
4638 if((tvb_strncaseeql(tvb, linelen-8, "HTTP/1.", 7) == 0)||(tvb_strncaseeql(tvb, 0, "HTTP/1.", 7) == 0)){
4639 conversation = find_or_create_conversation(pinfo);
4640 conversation_set_dissector_from_frame_number(conversation, pinfo->num, http_tcp_handle);
4641 dissect_http_tcp(tvb, pinfo, tree, data);
4642 return true1;
4643 }
4644
4645 return false0;
4646}
4647
4648static int
4649dissect_http_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
4650{
4651 conversation_t *conversation;
4652 http_conv_t *conv_data;
4653 bool_Bool end_of_stream;
4654
4655 conv_data = get_http_conversation_data(pinfo, &conversation);
4656
4657 struct tlsinfo *tlsinfo = (struct tlsinfo *)data;
4658 end_of_stream = (tlsinfo && tlsinfo->end_of_stream);
4659 return dissect_http_on_stream(tvb, pinfo, tree, conv_data, end_of_stream, tlsinfo ? &tlsinfo->seq : NULL((void*)0));
4660}
4661
4662static bool_Bool
4663dissect_http_heur_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
4664{
4665 unsigned offset = 0, next_offset, linelen;
4666 struct tlsinfo *tlsinfo = (struct tlsinfo *)data;
4667
4668 /* Check if we have a line terminated by CRLF
4669 * Return the length of the line (not counting the line terminator at
4670 * the end), or, if we don't find a line terminator:
4671 *
4672 * if "deseg" is true, return -1;
4673 */
4674 bool_Bool found = tvb_find_line_end_remaining(tvb, offset, &linelen, &next_offset);
4675 if((found == false0)||(linelen == 8)){
4676 return false0;
4677 }
4678
4679 /* Check if the line start or ends with the HTTP token */
4680 if((tvb_strncaseeql(tvb, linelen-8, "HTTP/1.", 7) != 0) && (tvb_strncaseeql(tvb, 0, "HTTP/1.", 7) != 0)) {
4681 /* we couldn't find the Magic Hello HTTP/1.X. */
4682 return false0;
4683 }
4684
4685 *(tlsinfo->app_handle) = http_tls_handle;
4686 dissect_http_tls(tvb, pinfo, tree, data);
4687 return true1;
4688}
4689
4690static int
4691dissect_http_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused)))
4692{
4693 conversation_t *conversation;
4694 http_conv_t *conv_data;
4695
4696 conv_data = get_http_conversation_data(pinfo, &conversation);
4697
4698 /*
4699 * XXX - we need to provide an end-of-stream indication.
4700 */
4701 return dissect_http_on_stream(tvb, pinfo, tree, conv_data, false0, NULL((void*)0));
4702}
4703
4704static int
4705dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused)))
4706{
4707 conversation_t *conversation;
4708 http_conv_t *conv_data;
4709
4710 conv_data = get_http_conversation_data(pinfo, &conversation);
4711
4712 /*
4713 * XXX - what should be done about reassembly, pipelining, etc.
4714 * here?
4715 */
4716 return dissect_http_on_stream(tvb, pinfo, tree, conv_data, false0, NULL((void*)0));
4717}
4718
4719static int
4720dissect_ssdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused)))
4721{
4722 conversation_t *conversation;
4723 http_conv_t *conv_data;
4724
4725 conv_data = get_http_conversation_data(pinfo, &conversation);
4726 dissect_http_message(tvb, 0, pinfo, tree, conv_data, "SSDP", proto_ssdp, false0, NULL((void*)0));
4727 return tvb_captured_length(tvb);
4728}
4729
4730static void
4731range_delete_http_tls_callback(uint32_t port, void *ptr _U___attribute__((unused))) {
4732 ssl_dissector_delete(port, http_tls_handle);
4733}
4734
4735static void
4736range_add_http_tls_callback(uint32_t port, void *ptr _U___attribute__((unused))) {
4737 ssl_dissector_add(port, http_tls_handle);
4738}
4739
4740static void reinit_http(void) {
4741 http_tcp_range = prefs_get_range_value("http", "tcp.port");
4742
4743 http_sctp_range = prefs_get_range_value("http", "sctp.port");
4744
4745 range_foreach(http_tls_range, range_delete_http_tls_callback, NULL((void*)0));
4746 wmem_free(wmem_epan_scope(), http_tls_range);
4747 http_tls_range = range_copy(wmem_epan_scope(), global_http_tls_range);
4748 range_foreach(http_tls_range, range_add_http_tls_callback, NULL((void*)0));
4749}
4750
4751void
4752proto_register_http(void)
4753{
4754 static hf_register_info hf[] = {
4755 { &hf_http_notification,
4756 { "Notification", "http.notification",
4757 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
4758 "true if HTTP notification", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4759 { &hf_http_response,
4760 { "Response", "http.response",
4761 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
4762 "true if HTTP response", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4763 { &hf_http_request,
4764 { "Request", "http.request",
4765 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
4766 "true if HTTP request", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4767 { &hf_http_basic,
4768 { "Credentials", "http.authbasic",
4769 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4770 { &hf_http_citrix,
4771 { "Citrix AG Auth", "http.authcitrix",
4772 FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
4773 "true if CitrixAGBasic Auth", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4774 { &hf_http_citrix_user,
4775 { "Citrix AG Username", "http.authcitrix.user",
4776 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4777 { &hf_http_citrix_domain,
4778 { "Citrix AG Domain", "http.authcitrix.domain",
4779 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4780 { &hf_http_citrix_passwd,
4781 { "Citrix AG Password", "http.authcitrix.password",
4782 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4783 { &hf_http_citrix_session,
4784 { "Citrix AG Session ID", "http.authcitrix.session",
4785 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4786 { &hf_http_response_line,
4787 { "Response line", "http.response.line",
4788 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4789 { &hf_http_request_line,
4790 { "Request line", "http.request.line",
4791 FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4792 { &hf_http_request_method,
4793 { "Request Method", "http.request.method",
4794 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4795 "HTTP Request Method", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4796 { &hf_http_request_uri,
4797 { "Request URI", "http.request.uri",
4798 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4799 "HTTP Request-URI", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4800 { &hf_http_request_path,
4801 { "Request URI Path", "http.request.uri.path",
4802 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4803 "HTTP Request-URI Path", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4804 { &hf_http_request_path_segment,
4805 { "Request URI Path Segment", "http.request.uri.path.segment",
4806 FT_STRING, BASE_NONE, NULL((void*)0), 0,
4807 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
4808 { &hf_http_request_query,
4809 { "Request URI Query", "http.request.uri.query",
4810 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4811 "HTTP Request-URI Query", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4812 { &hf_http_request_query_parameter,
4813 { "Request URI Query Parameter", "http.request.uri.query.parameter",
4814 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4815 "HTTP Request-URI Query Parameter", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4816 { &hf_http_request_version,
4817 { "Request Version", "http.request.version",
4818 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4819 "HTTP Request HTTP-Version", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4820 { &hf_http_response_version,
4821 { "Response Version", "http.response.version",
4822 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4823 "HTTP Response HTTP-Version", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4824 { &hf_http_request_full_uri,
4825 { "Full request URI", "http.request.full_uri",
4826 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4827 "The full requested URI (including host name)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4828 { &hf_http_response_code,
4829 { "Status Code", "http.response.code",
4830 FT_UINT24, BASE_DEC, NULL((void*)0), 0x0,
4831 "HTTP Response Status Code", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4832 { &hf_http_response_code_desc,
4833 { "Status Code Description", "http.response.code.desc",
4834 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4835 "HTTP Response Status Code Description", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4836 { &hf_http_response_phrase,
4837 { "Response Phrase", "http.response.phrase",
4838 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4839 "HTTP Response Reason Phrase", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4840 { &hf_http_authorization,
4841 { "Authorization", "http.authorization",
4842 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4843 "HTTP Authorization header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4844 { &hf_http_proxy_authenticate,
4845 { "Proxy-Authenticate", "http.proxy_authenticate",
4846 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4847 "HTTP Proxy-Authenticate header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4848 { &hf_http_proxy_authorization,
4849 { "Proxy-Authorization", "http.proxy_authorization",
4850 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4851 "HTTP Proxy-Authorization header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4852 { &hf_http_proxy_connect_host,
4853 { "Proxy-Connect-Hostname", "http.proxy_connect_host",
4854 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4855 "HTTP Proxy Connect Hostname", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4856 { &hf_http_proxy_connect_port,
4857 { "Proxy-Connect-Port", "http.proxy_connect_port",
4858 FT_UINT16, BASE_DEC, NULL((void*)0), 0x0,
4859 "HTTP Proxy Connect Port", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4860 { &hf_http_www_authenticate,
4861 { "WWW-Authenticate", "http.www_authenticate",
4862 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4863 "HTTP WWW-Authenticate header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4864 { &hf_http_content_type,
4865 { "Content-Type", "http.content_type",
4866 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4867 "HTTP Content-Type header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4868 { &hf_http_content_length_header,
4869 { "Content-Length", "http.content_length_header",
4870 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4871 "HTTP Content-Length header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4872 { &hf_http_content_length,
4873 { "Content length", "http.content_length",
4874 FT_UINT64, BASE_DEC, NULL((void*)0), 0x0,
4875 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4876 { &hf_http_content_encoding,
4877 { "Content-Encoding", "http.content_encoding",
4878 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4879 "HTTP Content-Encoding header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4880 { &hf_http_transfer_encoding,
4881 { "Transfer-Encoding", "http.transfer_encoding",
4882 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4883 "HTTP Transfer-Encoding header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4884 { &hf_http_upgrade,
4885 { "Upgrade", "http.upgrade",
4886 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4887 "HTTP Upgrade header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4888 { &hf_http_user_agent,
4889 { "User-Agent", "http.user_agent",
4890 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4891 "HTTP User-Agent header", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4892 { &hf_http_host,
4893 { "Host", "http.host",
4894 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4895 "HTTP Host", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4896 { &hf_http_range,
4897 { "Range", "http.range",
4898 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4899 "HTTP Range", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4900 { &hf_http_content_range,
4901 { "Content-Range", "http.content_range",
4902 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4903 "HTTP Content-Range", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4904 { &hf_http_connection,
4905 { "Connection", "http.connection",
4906 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4907 "HTTP Connection", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4908 { &hf_http_cookie,
4909 { "Cookie", "http.cookie",
4910 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4911 "HTTP Cookie", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4912 { &hf_http_cookie_pair,
4913 { "Cookie pair", "http.cookie_pair",
4914 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4915 "A name/value HTTP cookie pair", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4916 { &hf_http_accept,
4917 { "Accept", "http.accept",
4918 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4919 "HTTP Accept", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4920 { &hf_http_accept_query,
4921 { "Accept-Query", "http.accept_query",
4922 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4923 "HTTP Accept-Query", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4924 { &hf_http_referer,
4925 { "Referer", "http.referer",
4926 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4927 "HTTP Referer", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4928 { &hf_http_accept_language,
4929 { "Accept-Language", "http.accept_language",
4930 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4931 "HTTP Accept Language", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4932 { &hf_http_accept_encoding,
4933 { "Accept Encoding", "http.accept_encoding",
4934 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4935 "HTTP Accept Encoding", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4936 { &hf_http_date,
4937 { "Date", "http.date",
4938 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4939 "HTTP Date", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4940 { &hf_http_cache_control,
4941 { "Cache-Control", "http.cache_control",
4942 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4943 "HTTP Cache Control", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4944 { &hf_http_server,
4945 { "Server", "http.server",
4946 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4947 "HTTP Server", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4948 { &hf_http_location,
4949 { "Location", "http.location",
4950 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4951 "HTTP Location", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4952 { &hf_http_sec_websocket_accept,
4953 { "Sec-WebSocket-Accept", "http.sec_websocket_accept",
4954 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4955 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4956 { &hf_http_sec_websocket_extensions,
4957 { "Sec-WebSocket-Extensions", "http.sec_websocket_extensions",
4958 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4959 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4960 { &hf_http_sec_websocket_key,
4961 { "Sec-WebSocket-Key", "http.sec_websocket_key",
4962 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4963 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4964 { &hf_http_sec_websocket_protocol,
4965 { "Sec-WebSocket-Protocol", "http.sec_websocket_protocol",
4966 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4967 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4968 { &hf_http_sec_websocket_version,
4969 { "Sec-WebSocket-Version", "http.sec_websocket_version",
4970 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4971 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4972 { &hf_http_set_cookie,
4973 { "Set-Cookie", "http.set_cookie",
4974 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4975 "HTTP Set Cookie", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4976 { &hf_http_last_modified,
4977 { "Last-Modified", "http.last_modified",
4978 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4979 "HTTP Last Modified", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4980 { &hf_http_x_forwarded_for,
4981 { "X-Forwarded-For", "http.x_forwarded_for",
4982 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4983 "HTTP X-Forwarded-For", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4984 { &hf_http_http2_settings,
4985 { "HTTP2-Settings", "http.http2_settings",
4986 FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
4987 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4988 { &hf_http_request_in,
4989 { "Request in frame", "http.request_in",
4990 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST)((gpointer) (glong) (FT_FRAMENUM_REQUEST)), 0,
4991 "This packet is a response to the packet with this number", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4992 { &hf_http_response_in,
4993 { "Response in frame", "http.response_in",
4994 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE)((gpointer) (glong) (FT_FRAMENUM_RESPONSE)), 0,
4995 "This packet will be responded in the packet with this number", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
4996 { &hf_http_time,
4997 { "Time since request", "http.time",
4998 FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0,
4999 "Time since the request was sent", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5000 { &hf_http_chunked_trailer_part,
5001 { "trailer-part", "http.chunked_trailer_part",
5002 FT_STRING, BASE_NONE, NULL((void*)0), 0,
5003 "Optional trailer in a chunked body", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5004 { &hf_http_chunk_boundary,
5005 { "Chunk boundary", "http.chunk_boundary",
5006 FT_BYTES, BASE_NONE, NULL((void*)0), 0,
5007 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5008 { &hf_http_chunk_size,
5009 { "Chunk size", "http.chunk_size",
5010 FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_octet_octets)((0 ? (const struct unit_name_string*)0 : ((&units_octet_octets
))))
, 0,
5011 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5012 { &hf_http_chunk_data,
5013 { "Chunk data", "http.chunk_data",
5014 FT_BYTES, BASE_NONE, NULL((void*)0), 0,
5015 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5016 { &hf_http_file_data,
5017 { "File Data", "http.file_data",
5018 FT_BYTES, BASE_NONE, NULL((void*)0), 0,
5019 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5020 { &hf_http_unknown_header,
5021 { "Unknown header", "http.unknown_header",
5022 FT_STRING, BASE_NONE, NULL((void*)0), 0,
5023 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5024 { &hf_http_http2_settings_uri,
5025 { "HTTP2 Settings URI", "http.http2_settings_uri",
5026 FT_BYTES, BASE_NONE, NULL((void*)0), 0,
5027 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
5028
5029 /* Body fragments */
5030 REASSEMBLE_INIT_HF_ITEMS(http_body, "HTTP Chunked Body", "http.body"){ &hf_http_body_fragments, { "Reassembled " "HTTP Chunked Body"
" fragments", "http.body" ".fragments", FT_NONE, BASE_NONE, (
(void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void
*)0) } }, { &hf_http_body_fragment, { "HTTP Chunked Body"
" fragment", "http.body" ".fragment", FT_FRAMENUM, BASE_NONE
, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, (
(void*)0) } }, { &hf_http_body_fragment_overlap, { "HTTP Chunked Body"
" fragment overlap", "http.body" ".fragment.overlap", FT_BOOLEAN
, BASE_NONE, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0) } }, { &hf_http_body_fragment_overlap_conflicts
, { "HTTP Chunked Body" " fragment overlapping with conflicting data"
, "http.body" ".fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE
, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, (
(void*)0) } }, { &hf_http_body_fragment_multiple_tails, {
"HTTP Chunked Body" " has multiple tail fragments", "http.body"
".fragment.multiple_tails", FT_BOOLEAN, BASE_NONE, ((void*)0
), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
}, { &hf_http_body_fragment_too_long_fragment, { "HTTP Chunked Body"
" fragment too long", "http.body" ".fragment.too_long_fragment"
, FT_BOOLEAN, BASE_NONE, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0) } }, { &hf_http_body_fragment_error, { "HTTP Chunked Body"
" defragment error", "http.body" ".fragment.error", FT_FRAMENUM
, BASE_NONE, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0) } }, { &hf_http_body_fragment_count, { "HTTP Chunked Body"
" fragment count", "http.body" ".fragment.count", FT_UINT32,
BASE_DEC, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0) } }, { &hf_http_body_reassembled_in, { "Reassembled in"
, "http.body" ".reassembled.in", FT_FRAMENUM, BASE_NONE, ((void
*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0
) } }, { &hf_http_body_reassembled_length, { "Reassembled length"
, "http.body" ".reassembled.length", FT_UINT32, BASE_DEC, ((void
*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0
) } }, { &hf_http_body_reassembled_data, { "Reassembled data"
, "http.body" ".reassembled.data", FT_BYTES, BASE_NONE, ((void
*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0
) } }, { &hf_http_body_segment, { "HTTP Chunked Body" " segment"
, "http.body" ".segment", FT_BYTES, BASE_NONE, ((void*)0), 0x0
, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }
,
5031 };
5032 static int *ett[] = {
5033 &ett_http,
5034 &ett_http_ntlmssp,
5035 &ett_http_kerberos,
5036 &ett_http_request,
5037 &ett_http_request_uri,
5038 &ett_http_request_path,
5039 &ett_http_request_query,
5040 &ett_http_chunked_response,
5041 &ett_http_chunk_data,
5042 &ett_http_encoded_entity,
5043 &ett_http_header_item,
5044 &ett_http_http2_settings_item,
5045 REASSEMBLE_INIT_ETT_ITEMS(http_body)&ett_http_body_fragment, &ett_http_body_fragments,
5046 };
5047
5048 static ei_register_info ei[] = {
5049 { &ei_http_te_and_length, { "http.te_and_length", PI_MALFORMED0x07000000, PI_WARN0x00600000, "The Content-Length and Transfer-Encoding header must not be set together", 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)}}
}},
5050 { &ei_http_tunnel_too_deep, { "http.tunnel_too_deep", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "Tunnels nested too deep, not dissecting the tunnelled data", 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)}}
}},
5051 { &ei_http_te_unknown, { "http.te_unknown", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Unknown transfer coding name in Transfer-Encoding header", 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)}}
}},
5052 { &ei_http_subdissector_failed, { "http.subdissector_failed", PI_MALFORMED0x07000000, PI_NOTE0x00400000, "HTTP body subdissector failed, trying heuristic subdissector", 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)}}
}},
5053 { &ei_http_tls_port, { "http.tls_port", PI_SECURITY0x0a000000, PI_WARN0x00600000, "Unencrypted HTTP protocol detected over encrypted port, could indicate a dangerous misconfiguration.", 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)}}
}},
5054 { &ei_http_excess_data, { "http.excess_data", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Excess data after a body (not a new request/response), previous Content-Length bogus?", 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)}}
}},
5055 { &ei_http_leading_crlf, { "http.leading_crlf", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "Leading CRLF previous message in the stream may have extra CRLF", 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)}}
}},
5056 { &ei_http_bad_header_name, { "http.bad_header_name", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Illegal characters found in header name", 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)}}
}},
5057 { &ei_http_header_name_trailing_ws, { "http.header_name.trailing_whitespace", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Whitespace before header colon", 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)}}
}},
5058 { &ei_http_bad_header_value_nul, { "http.header_value.invalid_nul_char", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Invalid NUL byte in HTTP header 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)}}
}},
5059 { &ei_http_decompression_failed, { "http.decompression_failed", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Decompression failed", 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)}}
}},
5060 { &ei_http_decompression_disabled, { "http.decompression_disabled", PI_UNDECODED0x05000000, PI_CHAT0x00200000, "Decompression disabled", 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)}}
}},
5061 { &ei_http_response_code_invalid, { "http.response.code.invalid", PI_MALFORMED0x07000000, PI_WARN0x00600000, "Invalid HTTP response status code token", 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)}}
}},
5062 { &ei_http_request_uri_invalid, { "http.request.uri.invalid", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "Invalid request target", 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)}}
}},
5063 { &ei_http_request_uri_whitespace, { "http.request.uri.whitespace", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Request target contains whitespace", 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)}}
}},
5064
5065 };
5066
5067 /* UAT for header fields */
5068 static uat_field_t custom_header_uat_fields[] = {
5069 UAT_FLD_CSTRING(header_fields, header_name, "Header name", "HTTP header name"){"header_name", "Header name", PT_TXTMOD_STRING,{uat_fld_chk_str
,header_fields_header_name_set_cb,header_fields_header_name_tostr_cb
},{0,0,0},0,"HTTP header name",((void*)0)}
,
5070 UAT_FLD_CSTRING(header_fields, header_desc, "Field desc", "Description of the value contained in the header"){"header_desc", "Field desc", PT_TXTMOD_STRING,{uat_fld_chk_str
,header_fields_header_desc_set_cb,header_fields_header_desc_tostr_cb
},{0,0,0},0,"Description of the value contained in the header"
,((void*)0)}
,
5071 UAT_END_FIELDS{((void*)0),((void*)0),PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,((void
*)0)}
5072 };
5073
5074 module_t *http_module;
5075 expert_module_t* expert_http;
5076 uat_t* headers_uat;
5077
5078 proto_http = proto_register_protocol("Hypertext Transfer Protocol", "HTTP", "http");
5079 proto_ssdp = proto_register_protocol("Simple Service Discovery Protocol", "SSDP", "ssdp");
5080
5081 proto_register_field_array(proto_http, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
5082 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
5083 expert_http = expert_register_protocol(proto_http);
5084 expert_register_field_array(expert_http, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
5085
5086 http_handle = register_dissector("http", dissect_http, proto_http);
5087 http_tcp_handle = register_dissector("http-over-tcp", dissect_http_tcp, proto_http);
5088 http_tls_handle = register_dissector("http-over-tls", dissect_http_tls, proto_http); /* RFC 2818 */
5089 http_sctp_handle = register_dissector("http-over-sctp", dissect_http_sctp, proto_http);
5090
5091 reassembly_table_register(&http_streaming_reassembly_table, &addresses_ports_reassembly_table_functions);
5092
5093 http_module = prefs_register_protocol(proto_http, reinit_http);
5094 prefs_register_bool_preference(http_module, "desegment_headers",
5095 "Reassemble HTTP headers spanning multiple TCP segments",
5096 "Whether the HTTP dissector should reassemble headers "
5097 "of a request spanning multiple TCP segments. "
5098 "To use this option, you must also enable "
5099 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5100 &http_desegment_headers);
5101 prefs_register_bool_preference(http_module, "desegment_body",
5102 "Reassemble HTTP bodies spanning multiple TCP segments",
5103 "Whether the HTTP dissector should use the "
5104 "\"Content-length:\" value, if present, to reassemble "
5105 "the body of a request spanning multiple TCP segments, "
5106 "and reassemble chunked data spanning multiple TCP segments. "
5107 "To use this option, you must also enable "
5108 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5109 &http_desegment_body);
5110 prefs_register_bool_preference(http_module, "dechunk_body",
5111 "Reassemble chunked transfer-coded bodies",
5112 "Whether to reassemble bodies of entities that are transferred "
5113 "using the \"Transfer-Encoding: chunked\" method",
5114 &http_dechunk_body);
5115 prefs_register_bool_preference(http_module, "decompress_body",
5116 "Uncompress entity bodies",
5117 "Whether to uncompress entity bodies that are compressed "
5118 "using \"Content-Encoding: \"",
5119 &http_decompress_body);
5120 prefs_register_bool_preference(http_module, "check_ascii_headers",
5121 "Reject non-ASCII headers as invalid HTTP",
5122 "Whether to treat non-ASCII in headers as non-HTTP data "
5123 "and allow other dissectors to process it",
5124 &http_check_ascii_headers);
5125 prefs_register_bool_preference(http_module, "try_heuristic_first",
5126 "Try heuristic sub-dissectors first",
5127 "Try to decode HTTP bodies using heuristic sub-dissector "
5128 "(aka MIME sniffing) before using a sub-dissector registered "
5129 "to the Content-Type header or a specific port",
5130 &http_try_heuristic_first);
5131 prefs_register_obsolete_preference(http_module, "tcp_alternate_port");
5132
5133 range_convert_str(wmem_epan_scope(), &global_http_tls_range, TLS_DEFAULT_RANGE"443", 65535);
5134 prefs_register_range_preference(http_module, "tls.port", "SSL/TLS Ports",
5135 "SSL/TLS Ports range",
5136 &global_http_tls_range, 65535);
5137 prefs_register_obsolete_preference(http_module, "ssl.port");
5138 /* UAT */
5139 headers_uat = uat_new("Custom HTTP Header Fields",
5140 sizeof(header_field_t),
5141 "custom_http_header_fields",
5142 true1,
5143 &header_fields,
5144 &num_header_fields,
5145 /* specifies named fields, so affects dissection
5146 and the set of named fields */
5147 UAT_AFFECTS_DISSECTION0x00000001|UAT_AFFECTS_FIELDS0x00000002,
5148 NULL((void*)0),
5149 header_fields_copy_cb,
5150 header_fields_update_cb,
5151 header_fields_free_cb,
5152 header_fields_post_update_cb,
5153 header_fields_reset_cb,
5154 custom_header_uat_fields
5155 );
5156
5157 prefs_register_uat_preference(http_module, "custom_http_header_fields", "Custom HTTP header fields",
5158 "A table to define custom HTTP header for which fields can be setup and used for filtering/data extraction etc.",
5159 headers_uat);
5160
5161 /*
5162 * Dissectors shouldn't register themselves in this table;
5163 * instead, they should call "http_tcp_dissector_add()", and
5164 * we'll register the port number they specify as a port
5165 * for HTTP, and register them in our subdissector table.
5166 *
5167 * This only works for protocols such as IPP that run over
5168 * HTTP on a specific non-HTTP port.
5169 */
5170 port_subdissector_table = register_dissector_table("http.port",
5171 "TCP port for protocols using HTTP", proto_http, FT_UINT16, BASE_DEC);
5172
5173 /*
5174 * Maps the Upgrade header value.
5175 * https://datatracker.ietf.org/doc/html/rfc9110#section-16.7
5176 * "A protocol-name token is case-insensitive and registered with the
5177 * preferred case to be generated by senders."
5178 */
5179 upgrade_subdissector_table = register_dissector_table("http.upgrade", "HTTP Upgrade", proto_http, FT_STRING, STRING_CASE_INSENSITIVE1);
5180
5181 /*
5182 * Heuristic dissectors SHOULD register themselves in
5183 * this table using the standard heur_dissector_add()
5184 * function.
5185 */
5186 heur_subdissector_list = register_heur_dissector_list_with_description("http", "HTTP payload fallback", proto_http);
5187
5188 /*
5189 * Register for tapping
5190 */
5191 http_tap = register_tap("http"); /* HTTP statistics tap */
5192 http_follow_tap = register_tap("http_follow"); /* HTTP Follow tap */
5193 credentials_tap = register_tap("credentials"); /* credentials tap */
5194
5195 register_follow_stream(proto_http, "http_follow", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
5196 tcp_port_to_display, follow_tvb_tap_listener,
5197 get_tcp_stream_count, NULL((void*)0));
5198 http_eo_tap = register_export_object(proto_http, http_eo_packet, NULL((void*)0));
5199
5200 /* compile patterns, excluding "/" */
5201 ws_mempbrk_compile(&pbrk_gen_delims, ":?#[]@");
5202 /* exclude "=", separating key and value should be done separately */
5203 ws_mempbrk_compile(&pbrk_sub_delims, "!$&'()*+,;");
5204
5205 register_external_value_string("vals_http_status_code", vals_http_status_code);
5206}
5207
5208/*
5209 * Called by dissectors for protocols that run atop HTTP/TCP.
5210 */
5211void
5212http_tcp_dissector_add(uint32_t port, dissector_handle_t handle)
5213{
5214 /*
5215 * Register ourselves as the handler for that port number
5216 * over TCP. "Auto-preference" not needed
5217 */
5218 dissector_add_uint("tcp.port", port, http_tcp_handle);
5219
5220 /*
5221 * And register them in *our* table for that port.
5222 */
5223 dissector_add_uint("http.port", port, handle);
5224}
5225
5226WS_DLL_PUBLIC__attribute__ ((visibility ("default"))) extern
5227void http_tcp_dissector_delete(uint32_t port)
5228{
5229 /*
5230 * Unregister ourselves as the handler for that port number
5231 * over TCP. "Auto-preference" not needed
5232 */
5233 dissector_delete_uint("tcp.port", port, NULL((void*)0));
5234
5235 /*
5236 * And unregister them in *our* table for that port.
5237 */
5238 dissector_delete_uint("http.port", port, NULL((void*)0));
5239}
5240
5241void
5242http_tcp_port_add(uint32_t port)
5243{
5244 /*
5245 * Register ourselves as the handler for that port number
5246 * over TCP. We rely on our caller having registered
5247 * themselves for the appropriate media type.
5248 * No "auto-preference" used.
5249 */
5250 dissector_add_uint("tcp.port", port, http_tcp_handle);
5251}
5252
5253void
5254proto_reg_handoff_http(void)
5255{
5256 dissector_handle_t ssdp_handle;
5257
5258 media_handle = find_dissector_add_dependency("media", proto_http);
5259 http2_handle = find_dissector("http2");
5260 /*
5261 * XXX - is there anything to dissect in the body of an SSDP
5262 * request or reply? I.e., should there be an SSDP dissector?
5263 */
5264 ssdp_handle = create_dissector_handle(dissect_ssdp, proto_ssdp);
5265 dissector_add_uint_with_preference("udp.port", UDP_PORT_SSDP1900, ssdp_handle);
5266
5267 /*
5268 * TLS Application-Layer Protocol Negotiation (ALPN) protocol ID.
5269 */
5270 dissector_add_string("tls.alpn", "http/1.1", http_tls_handle);
5271
5272 ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_http);
5273 gssapi_handle = find_dissector_add_dependency("gssapi", proto_http);
5274 sstp_handle = find_dissector_add_dependency("sstp", proto_http);
5275
5276 stats_tree_cfg *st_config;
5277 st_config = stats_tree_register("http", "http", "HTTP" STATS_TREE_MENU_SEPARATOR"//" "Packet Counter", 0, http_stats_tree_packet, http_stats_tree_init, NULL((void*)0) );
5278 stats_tree_set_first_column_name(st_config, "Packet Type");
5279 st_config = stats_tree_register("http", "http_req", "HTTP" STATS_TREE_MENU_SEPARATOR"//" "Requests", 0, http_req_stats_tree_packet, http_req_stats_tree_init, NULL((void*)0) );
5280 stats_tree_set_first_column_name(st_config, "Request Type");
5281 st_config = stats_tree_register("http", "http_srv", "HTTP" STATS_TREE_MENU_SEPARATOR"//" "Load Distribution",0, http_reqs_stats_tree_packet, http_reqs_stats_tree_init, NULL((void*)0) );
5282 stats_tree_set_first_column_name(st_config, "Packet Type");
5283 st_config = stats_tree_register("http", "http_seq", "HTTP" STATS_TREE_MENU_SEPARATOR"//" "Request Sequences",0, http_seq_stats_tree_packet, http_seq_stats_tree_init, NULL((void*)0) );
5284 stats_tree_set_first_column_name(st_config, "Sequence Type");
5285
5286 dissector_add_uint("acdr.tls_application_port", 443, http_handle);
5287 dissector_add_uint("acdr.tls_application", TLS_APP_HTTP, http_handle);
5288 dissector_add_uint("acdr.tls_application", TLS_APP_TR069, http_handle);
5289 dissector_add_uint("ippusb", 0, http_tcp_handle);
5290}
5291
5292/*
5293 * Content-Type: message/http
5294 */
5295
5296static int proto_message_http;
5297static int ett_message_http;
5298
5299static int
5300dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused)))
5301{
5302 proto_tree *subtree;
5303 proto_item *ti;
5304 unsigned offset = 0, next_offset;
5305 unsigned len;
5306 bool_Bool len_found;
5307
5308 col_append_str(pinfo->cinfo, COL_INFO, " (message/http)");
5309 if (tree) {
5310 ti = proto_tree_add_item(tree, proto_message_http,
5311 tvb, 0, -1, ENC_NA0x00000000);
5312 subtree = proto_item_add_subtree(ti, ett_message_http);
5313 while (tvb_offset_exists(tvb, offset)) {
5314 len_found = tvb_find_line_end_length(tvb, offset,
5315 tvb_ensure_captured_length_remaining(tvb, offset),
5316 &len, &next_offset);
5317 if (len_found == false0)
5318 break;
5319 proto_tree_add_format_text(subtree, tvb, offset, len);
5320 offset = next_offset;
5321 }
5322 }
5323 return tvb_captured_length(tvb);
5324}
5325
5326void
5327proto_register_message_http(void)
5328{
5329 static int *ett[] = {
5330 &ett_message_http,
5331 };
5332
5333 proto_message_http = proto_register_protocol("Media Type: message/http", "message/http", "message-http");
5334 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
5335}
5336
5337void
5338proto_reg_handoff_message_http(void)
5339{
5340 dissector_handle_t message_http_handle;
5341
5342 message_http_handle = create_dissector_handle(dissect_message_http,
5343 proto_message_http);
5344
5345 dissector_add_string("media_type", "message/http", message_http_handle);
5346
5347 heur_dissector_add("tcp", dissect_http_heur_tcp, "HTTP over TCP", "http_tcp", proto_http, HEURISTIC_ENABLE);
5348 heur_dissector_add("tls", dissect_http_heur_tls, "HTTP over TLS", "http_tls", proto_http, HEURISTIC_ENABLE);
5349
5350 proto_http2 = proto_get_id_by_filter_name("http2");
5351
5352 dissector_add_uint_range_with_preference("tcp.port", TCP_DEFAULT_RANGE"80,3128,3132,5985,8080,8088,11371,1900,2869,2710", http_tcp_handle);
5353 dissector_add_uint_range_with_preference("sctp.port", SCTP_DEFAULT_RANGE"80", http_sctp_handle);
5354
5355 /*
5356 * Get the content type and Internet media type table
5357 */
5358 media_type_subdissector_table = find_dissector_table("media_type");
5359
5360 streaming_content_type_dissector_table = find_dissector_table("streaming_content_type");
5361
5362 reinit_http();
5363}
5364
5365/*
5366 * Editor modelines - https://www.wireshark.org/tools/modelines.html
5367 *
5368 * Local variables:
5369 * c-basic-offset: 8
5370 * tab-width: 8
5371 * indent-tabs-mode: t
5372 * End:
5373 *
5374 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
5375 * :indentSize=8:tabSize=8:noTabs=false:
5376 */