Bug Summary

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