Bug Summary

File:builds/wireshark/wireshark/epan/dissectors/packet-http.c
Warning:line 2741, column 2
Value stored to 'line' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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