Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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