Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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