1 /* packet-http.c
2 * Routines for HTTP packet disassembly
3 * RFC 1945 (HTTP/1.0)
4 * RFC 2616 (HTTP/1.1)
5 *
6 * Guy Harris <guy@alum.mit.edu>
7 *
8 * Copyright 2017, Eugene Adell <eugene.adell@gmail.com>
9 * Copyright 2004, Jerry Talkington <jtalkington@users.sourceforge.net>
10 * Copyright 2002, Tim Potter <tpot@samba.org>
11 * Copyright 1999, Andrew Tridgell <tridge@samba.org>
12 *
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
16 *
17 * SPDX-License-Identifier: GPL-2.0-or-later
18 */
19
20 #include "config.h"
21
22 #include <errno.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/strutil.h>
31 #include <epan/stats_tree.h>
32 #include <epan/to_str.h>
33 #include <epan/req_resp_hdrs.h>
34 #include <epan/proto_data.h>
35 #include <epan/export_object.h>
36 #include <epan/exceptions.h>
37 #include <epan/show_exception.h>
38
39 #include "packet-http.h"
40 #include "packet-http2.h"
41 #include "packet-tcp.h"
42 #include "packet-tls.h"
43 #include "packet-acdr.h"
44
45 #include <ui/tap-credentials.h>
46
47 void proto_register_http(void);
48 void proto_reg_handoff_http(void);
49 void proto_register_message_http(void);
50 void proto_reg_handoff_message_http(void);
51
52 static int http_tap = -1;
53 static int http_eo_tap = -1;
54 static int http_follow_tap = -1;
55 static int credentials_tap = -1;
56
57 static int proto_http = -1;
58 static int proto_http2 = -1;
59 static int proto_ssdp = -1;
60 static int hf_http_notification = -1;
61 static int hf_http_response = -1;
62 static int hf_http_request = -1;
63 static int hf_http_response_number = -1;
64 static int hf_http_request_number = -1;
65 static int hf_http_response_line = -1;
66 static int hf_http_request_line = -1;
67 static int hf_http_basic = -1;
68 static int hf_http_citrix = -1;
69 static int hf_http_citrix_user = -1;
70 static int hf_http_citrix_domain = -1;
71 static int hf_http_citrix_passwd = -1;
72 static int hf_http_citrix_session = -1;
73 static int hf_http_request_method = -1;
74 static int hf_http_request_uri = -1;
75 static int hf_http_request_full_uri = -1;
76 static int hf_http_request_path = -1;
77 static int hf_http_request_query = -1;
78 static int hf_http_request_query_parameter = -1;
79 static int hf_http_request_version = -1;
80 static int hf_http_response_version = -1;
81 static int hf_http_response_code = -1;
82 static int hf_http_response_code_desc = -1;
83 static int hf_http_response_for_uri = -1;
84 static int hf_http_response_phrase = -1;
85 static int hf_http_authorization = -1;
86 static int hf_http_proxy_authenticate = -1;
87 static int hf_http_proxy_authorization = -1;
88 static int hf_http_proxy_connect_host = -1;
89 static int hf_http_proxy_connect_port = -1;
90 static int hf_http_www_authenticate = -1;
91 static int hf_http_content_type = -1;
92 static int hf_http_content_length_header = -1;
93 static int hf_http_content_length = -1;
94 static int hf_http_content_encoding = -1;
95 static int hf_http_transfer_encoding = -1;
96 static int hf_http_upgrade = -1;
97 static int hf_http_user_agent = -1;
98 static int hf_http_host = -1;
99 static int hf_http_connection = -1;
100 static int hf_http_cookie = -1;
101 static int hf_http_cookie_pair = -1;
102 static int hf_http_accept = -1;
103 static int hf_http_referer = -1;
104 static int hf_http_accept_language = -1;
105 static int hf_http_accept_encoding = -1;
106 static int hf_http_date = -1;
107 static int hf_http_cache_control = -1;
108 static int hf_http_server = -1;
109 static int hf_http_location = -1;
110 static int hf_http_sec_websocket_accept = -1;
111 static int hf_http_sec_websocket_extensions = -1;
112 static int hf_http_sec_websocket_key = -1;
113 static int hf_http_sec_websocket_protocol = -1;
114 static int hf_http_sec_websocket_version = -1;
115 static int hf_http_set_cookie = -1;
116 static int hf_http_last_modified = -1;
117 static int hf_http_x_forwarded_for = -1;
118 static int hf_http_http2_settings = -1;
119 static int hf_http_request_in = -1;
120 static int hf_http_response_in = -1;
121 static int hf_http_next_request_in = -1;
122 static int hf_http_next_response_in = -1;
123 static int hf_http_prev_request_in = -1;
124 static int hf_http_prev_response_in = -1;
125 static int hf_http_time = -1;
126 static int hf_http_chunk_size = -1;
127 static int hf_http_chunk_boundary = -1;
128 static int hf_http_chunked_trailer_part = -1;
129 static int hf_http_file_data = -1;
130 static int hf_http_unknown_header = -1;
131 static int hf_http_http2_settings_uri = -1;
132
133 static gint ett_http = -1;
134 static gint ett_http_ntlmssp = -1;
135 static gint ett_http_kerberos = -1;
136 static gint ett_http_request = -1;
137 static gint ett_http_request_path = -1;
138 static gint ett_http_request_query = -1;
139 static gint ett_http_chunked_response = -1;
140 static gint ett_http_chunk_data = -1;
141 static gint ett_http_encoded_entity = -1;
142 static gint ett_http_header_item = -1;
143 static gint ett_http_http2_settings_item = -1;
144
145 static expert_field ei_http_chat = EI_INIT;
146 static expert_field ei_http_te_and_length = EI_INIT;
147 static expert_field ei_http_te_unknown = EI_INIT;
148 static expert_field ei_http_subdissector_failed = EI_INIT;
149 static expert_field ei_http_tls_port = EI_INIT;
150 static expert_field ei_http_leading_crlf = EI_INIT;
151 static expert_field ei_http_bad_header_name = EI_INIT;
152 static expert_field ei_http_decompression_failed = EI_INIT;
153 static expert_field ei_http_decompression_disabled = EI_INIT;
154
155 static dissector_handle_t http_handle;
156 static dissector_handle_t http_tcp_handle;
157 static dissector_handle_t http_tls_handle;
158 static dissector_handle_t http_sctp_handle;
159
160 static dissector_handle_t media_handle;
161 static dissector_handle_t http2_handle;
162 static dissector_handle_t sstp_handle;
163 static dissector_handle_t ntlmssp_handle;
164 static dissector_handle_t gssapi_handle;
165
166 /* Stuff for generation/handling of fields for custom HTTP headers */
167 typedef struct _header_field_t {
168 gchar* header_name;
169 gchar* header_desc;
170 } header_field_t;
171
172 static header_field_t* header_fields;
173 static guint num_header_fields;
174
175 static GHashTable* header_fields_hash;
176 static hf_register_info* dynamic_hf;
177 static guint dynamic_hf_size;
178
179 static gboolean
header_fields_update_cb(void * r,char ** err)180 header_fields_update_cb(void *r, char **err)
181 {
182 header_field_t *rec = (header_field_t *)r;
183 char c;
184
185 if (rec->header_name == NULL) {
186 *err = g_strdup("Header name can't be empty");
187 return FALSE;
188 }
189
190 g_strstrip(rec->header_name);
191 if (rec->header_name[0] == 0) {
192 *err = g_strdup("Header name can't be empty");
193 return FALSE;
194 }
195
196 /* Check for invalid characters (to avoid asserting out when
197 * registering the field).
198 */
199 c = proto_check_field_name(rec->header_name);
200 if (c) {
201 *err = g_strdup_printf("Header name can't contain '%c'", c);
202 return FALSE;
203 }
204
205 *err = NULL;
206 return TRUE;
207 }
208
209 static void *
header_fields_copy_cb(void * n,const void * o,size_t siz _U_)210 header_fields_copy_cb(void* n, const void* o, size_t siz _U_)
211 {
212 header_field_t* new_rec = (header_field_t*)n;
213 const header_field_t* old_rec = (const header_field_t*)o;
214
215 new_rec->header_name = g_strdup(old_rec->header_name);
216 new_rec->header_desc = g_strdup(old_rec->header_desc);
217
218 return new_rec;
219 }
220
221 static void
header_fields_free_cb(void * r)222 header_fields_free_cb(void*r)
223 {
224 header_field_t* rec = (header_field_t*)r;
225
226 g_free(rec->header_name);
227 g_free(rec->header_desc);
228 }
229
230 UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t)
231 UAT_CSTRING_CB_DEF(header_fields, header_desc, header_field_t)
232
233 /*
234 * desegmentation of HTTP headers
235 * (when we are over TCP or another protocol providing the desegmentation API)
236 */
237 static gboolean http_desegment_headers = TRUE;
238
239 /*
240 * desegmentation of HTTP bodies
241 * (when we are over TCP or another protocol providing the desegmentation API)
242 * TODO let the user filter on content-type the bodies he wants desegmented
243 */
244 static gboolean http_desegment_body = TRUE;
245
246 /*
247 * De-chunking of content-encoding: chunk entity bodies.
248 */
249 static gboolean http_dechunk_body = TRUE;
250
251 /*
252 * Decompression of zlib or brotli encoded entities.
253 */
254 #if defined(HAVE_ZLIB) || defined(HAVE_BROTLI)
255 static gboolean http_decompress_body = TRUE;
256 #endif
257
258 /* Simple Service Discovery Protocol
259 * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
260 * SSDP is the discovery protocol of Universal Plug and Play
261 * UPnP http://www.upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
262 */
263 #define TCP_PORT_SSDP 1900
264 #define UDP_PORT_SSDP 1900
265
266 /*
267 * TCP and TLS ports
268 *
269 * 2710 is the XBT BitTorrent tracker
270 */
271
272 #define TCP_DEFAULT_RANGE "80,3128,3132,5985,8080,8088,11371,1900,2869,2710"
273 #define SCTP_DEFAULT_RANGE "80"
274 #define TLS_DEFAULT_RANGE "443"
275
276 static range_t *global_http_sctp_range = NULL;
277 static range_t *global_http_tls_range = NULL;
278
279 static range_t *http_tcp_range = NULL;
280 static range_t *http_sctp_range = NULL;
281 static range_t *http_tls_range = NULL;
282
283 typedef void (*ReqRespDissector)(tvbuff_t*, proto_tree*, int, const guchar*,
284 const guchar*, http_conv_t *);
285
286 /**
287 * Transfer codings from
288 * https://www.iana.org/assignments/http-parameters/http-parameters.xhtml#transfer-coding
289 * Note: chunked encoding is handled separately.
290 */
291 typedef enum _http_transfer_coding {
292 HTTP_TE_NONE, /* Dummy value for header which is not set */
293 /* HTTP_TE_CHUNKED, */
294 HTTP_TE_COMPRESS,
295 HTTP_TE_DEFLATE,
296 HTTP_TE_GZIP,
297 HTTP_TE_IDENTITY,
298 HTTP_TE_UNKNOWN, /* Header was set, but no valid name was found */
299 } http_transfer_coding;
300
301 /*
302 * Structure holding information from headers needed by main
303 * HTTP dissector code.
304 */
305 typedef struct {
306 char *content_type;
307 char *content_type_parameters;
308 gboolean have_content_length;
309 gint64 content_length;
310 char *content_encoding;
311 gboolean transfer_encoding_chunked;
312 http_transfer_coding transfer_encoding;
313 char *upgrade;
314 } headers_t;
315
316 static gint parse_http_status_code(const guchar *line, const guchar *lineend);
317 static int is_http_request_or_reply(const gchar *data, int linelen,
318 http_type_t *type, ReqRespDissector
319 *reqresp_dissector, http_conv_t *conv_data);
320 static guint chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
321 proto_tree *tree, int offset);
322 static void process_header(tvbuff_t *tvb, int offset, int next_offset,
323 const guchar *line, int linelen, int colon_offset,
324 packet_info *pinfo, proto_tree *tree,
325 headers_t *eh_ptr, http_conv_t *conv_data,
326 http_type_t http_type);
327 static gint find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len);
328 static gboolean check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb,
329 packet_info *pinfo, gchar *value);
330 static gboolean check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb,
331 packet_info *pinfo, gchar *value);
332 static gboolean check_auth_digest(proto_item* hdr_item, tvbuff_t* tvb, packet_info* pinfo _U_, gchar* value, int offset, int len);
333 static gboolean check_auth_citrixbasic(proto_item *hdr_item, tvbuff_t *tvb,
334 gchar *value, int offset);
335 static gboolean check_auth_kerberos(proto_item *hdr_item, tvbuff_t *tvb,
336 packet_info *pinfo, const gchar *value);
337
338 static dissector_table_t port_subdissector_table;
339 static dissector_table_t media_type_subdissector_table;
340 static dissector_table_t upgrade_subdissector_table;
341 static heur_dissector_list_t heur_subdissector_list;
342
343 /* Used for HTTP Export Object feature */
344 typedef struct _http_eo_t {
345 guint32 pkt_num;
346 gchar *hostname;
347 gchar *filename;
348 gchar *content_type;
349 guint32 payload_len;
350 const guint8 *payload_data;
351 } http_eo_t;
352
353 static tap_packet_status
http_eo_packet(void * tapdata,packet_info * pinfo,epan_dissect_t * edt _U_,const void * data)354 http_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
355 {
356 export_object_list_t *object_list = (export_object_list_t *)tapdata;
357 const http_eo_t *eo_info = (const http_eo_t *)data;
358 export_object_entry_t *entry;
359
360 if(eo_info) { /* We have data waiting for us */
361 /* These values will be freed when the Export Object window
362 * is closed. */
363 entry = g_new(export_object_entry_t, 1);
364
365 entry->pkt_num = pinfo->num;
366 entry->hostname = g_strdup(eo_info->hostname);
367 entry->content_type = g_strdup(eo_info->content_type);
368 entry->filename = eo_info->filename ? g_path_get_basename(eo_info->filename) : NULL;
369 entry->payload_len = eo_info->payload_len;
370 entry->payload_data = (guint8 *)g_memdup2(eo_info->payload_data, eo_info->payload_len);
371
372 object_list->add_entry(object_list->gui_data, entry);
373
374 return TAP_PACKET_REDRAW; /* State changed - window should be redrawn */
375 } else {
376 return TAP_PACKET_DONT_REDRAW; /* State unchanged - no window updates needed */
377 }
378 }
379
380 /* --- HTTP Status Codes */
381 /* Note: The reference for uncommented entries is RFC 2616 */
382 const value_string vals_http_status_code[] = {
383 { 100, "Continue" },
384 { 101, "Switching Protocols" },
385 { 102, "Processing" }, /* RFC 2518 */
386 { 103, "Early Hints" }, /* RFC-ietf-httpbis-early-hints-05 */
387 { 199, "Informational - Others" },
388
389 { 200, "OK"},
390 { 201, "Created"},
391 { 202, "Accepted"},
392 { 203, "Non-authoritative Information"},
393 { 204, "No Content"},
394 { 205, "Reset Content"},
395 { 206, "Partial Content"},
396 { 207, "Multi-Status"}, /* RFC 4918 */
397 { 208, "Already Reported"}, /* RFC 5842 */
398 { 226, "IM Used"}, /* RFC 3229 */
399 { 299, "Success - Others"},
400
401 { 300, "Multiple Choices"},
402 { 301, "Moved Permanently"},
403 { 302, "Found"},
404 { 303, "See Other"},
405 { 304, "Not Modified"},
406 { 305, "Use Proxy"},
407 { 307, "Temporary Redirect"},
408 { 308, "Permanent Redirect"}, /* RFC 7538 */
409 { 399, "Redirection - Others"},
410
411 { 400, "Bad Request"},
412 { 401, "Unauthorized"},
413 { 402, "Payment Required"},
414 { 403, "Forbidden"},
415 { 404, "Not Found"},
416 { 405, "Method Not Allowed"},
417 { 406, "Not Acceptable"},
418 { 407, "Proxy Authentication Required"},
419 { 408, "Request Time-out"},
420 { 409, "Conflict"},
421 { 410, "Gone"},
422 { 411, "Length Required"},
423 { 412, "Precondition Failed"},
424 { 413, "Request Entity Too Large"},
425 { 414, "Request-URI Too Long"},
426 { 415, "Unsupported Media Type"},
427 { 416, "Requested Range Not Satisfiable"},
428 { 417, "Expectation Failed"},
429 { 418, "I'm a teapot"}, /* RFC 2324 */
430 { 421, "Misdirected Request"}, /* RFC 7540 */
431 { 422, "Unprocessable Entity"}, /* RFC 4918 */
432 { 423, "Locked"}, /* RFC 4918 */
433 { 424, "Failed Dependency"}, /* RFC 4918 */
434 { 425, "Too Early"}, /* RFC 8470 */
435 { 426, "Upgrade Required"}, /* RFC 2817 */
436 { 428, "Precondition Required"}, /* RFC 6585 */
437 { 429, "Too Many Requests"}, /* RFC 6585 */
438 { 431, "Request Header Fields Too Large"}, /* RFC 6585 */
439 { 451, "Unavailable For Legal Reasons"}, /* RFC 7725 */
440 { 499, "Client Error - Others"},
441
442 { 500, "Internal Server Error"},
443 { 501, "Not Implemented"},
444 { 502, "Bad Gateway"},
445 { 503, "Service Unavailable"},
446 { 504, "Gateway Time-out"},
447 { 505, "HTTP Version not supported"},
448 { 506, "Variant Also Negotiates"}, /* RFC 2295 */
449 { 507, "Insufficient Storage"}, /* RFC 4918 */
450 { 508, "Loop Detected"}, /* RFC 5842 */
451 { 510, "Not Extended"}, /* RFC 2774 */
452 { 511, "Network Authentication Required"}, /* RFC 6585 */
453 { 599, "Server Error - Others"},
454
455 { 0, NULL}
456 };
457
458 static const gchar* st_str_reqs = "HTTP Requests by Server";
459 static const gchar* st_str_reqs_by_srv_addr = "HTTP Requests by Server Address";
460 static const gchar* st_str_reqs_by_http_host = "HTTP Requests by HTTP Host";
461 static const gchar* st_str_resps_by_srv_addr = "HTTP Responses by Server Address";
462
463 static int st_node_reqs = -1;
464 static int st_node_reqs_by_srv_addr = -1;
465 static int st_node_reqs_by_http_host = -1;
466 static int st_node_resps_by_srv_addr = -1;
467
468 /* HTTP/Load Distribution stats init function */
469 static void
http_reqs_stats_tree_init(stats_tree * st)470 http_reqs_stats_tree_init(stats_tree* st)
471 {
472 st_node_reqs = stats_tree_create_node(st, st_str_reqs, 0, STAT_DT_INT, TRUE);
473 st_node_reqs_by_srv_addr = stats_tree_create_node(st, st_str_reqs_by_srv_addr, st_node_reqs, STAT_DT_INT, TRUE);
474 st_node_reqs_by_http_host = stats_tree_create_node(st, st_str_reqs_by_http_host, st_node_reqs, STAT_DT_INT, TRUE);
475 st_node_resps_by_srv_addr = stats_tree_create_node(st, st_str_resps_by_srv_addr, 0, STAT_DT_INT, TRUE);
476 }
477
478 /* HTTP/Load Distribution stats packet function */
479 static tap_packet_status
http_reqs_stats_tree_packet(stats_tree * st,packet_info * pinfo,epan_dissect_t * edt _U_,const void * p)480 http_reqs_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p)
481 {
482 const http_info_value_t* v = (const http_info_value_t*)p;
483 int reqs_by_this_host;
484 int reqs_by_this_addr;
485 int resps_by_this_addr;
486 int i = v->response_code;
487 gchar *ip_str;
488
489
490 if (v->request_method) {
491 ip_str = address_to_str(NULL, &pinfo->dst);
492
493 tick_stat_node(st, st_str_reqs, 0, FALSE);
494 tick_stat_node(st, st_str_reqs_by_srv_addr, st_node_reqs, TRUE);
495 tick_stat_node(st, st_str_reqs_by_http_host, st_node_reqs, TRUE);
496 reqs_by_this_addr = tick_stat_node(st, ip_str, st_node_reqs_by_srv_addr, TRUE);
497
498 if (v->http_host) {
499 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_reqs_by_http_host, TRUE);
500 tick_stat_node(st, ip_str, reqs_by_this_host, FALSE);
501
502 tick_stat_node(st, v->http_host, reqs_by_this_addr, FALSE);
503 }
504
505 wmem_free(NULL, ip_str);
506
507 return TAP_PACKET_REDRAW;
508
509 } else if (i != 0) {
510 ip_str = address_to_str(NULL, &pinfo->src);
511
512 tick_stat_node(st, st_str_resps_by_srv_addr, 0, FALSE);
513 resps_by_this_addr = tick_stat_node(st, ip_str, st_node_resps_by_srv_addr, TRUE);
514
515 if ( (i>100)&&(i<400) ) {
516 tick_stat_node(st, "OK", resps_by_this_addr, FALSE);
517 } else {
518 tick_stat_node(st, "KO", resps_by_this_addr, FALSE);
519 }
520
521 wmem_free(NULL, ip_str);
522
523 return TAP_PACKET_REDRAW;
524 }
525
526 return TAP_PACKET_DONT_REDRAW;
527 }
528
529
530 static int st_node_requests_by_host = -1;
531 static const gchar *st_str_requests_by_host = "HTTP Requests by HTTP Host";
532
533 /* HTTP/Requests stats init function */
534 static void
http_req_stats_tree_init(stats_tree * st)535 http_req_stats_tree_init(stats_tree* st)
536 {
537 st_node_requests_by_host = stats_tree_create_node(st, st_str_requests_by_host, 0, STAT_DT_INT, TRUE);
538 }
539
540 /* HTTP/Requests stats packet function */
541 static tap_packet_status
http_req_stats_tree_packet(stats_tree * st,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * p)542 http_req_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p)
543 {
544 const http_info_value_t* v = (const http_info_value_t*)p;
545 int reqs_by_this_host;
546
547 if (v->request_method) {
548 tick_stat_node(st, st_str_requests_by_host, 0, FALSE);
549
550 if (v->http_host) {
551 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_requests_by_host, TRUE);
552
553 if (v->request_uri) {
554 tick_stat_node(st, v->request_uri, reqs_by_this_host, TRUE);
555 }
556 }
557
558 return TAP_PACKET_REDRAW;
559 }
560
561 return TAP_PACKET_DONT_REDRAW;
562 }
563
564 static const gchar *st_str_packets = "Total HTTP Packets";
565 static const gchar *st_str_requests = "HTTP Request Packets";
566 static const gchar *st_str_responses = "HTTP Response Packets";
567 static const gchar *st_str_resp_broken = "???: broken";
568 static const gchar *st_str_resp_100 = "1xx: Informational";
569 static const gchar *st_str_resp_200 = "2xx: Success";
570 static const gchar *st_str_resp_300 = "3xx: Redirection";
571 static const gchar *st_str_resp_400 = "4xx: Client Error";
572 static const gchar *st_str_resp_500 = "5xx: Server Error";
573 static const gchar *st_str_other = "Other HTTP Packets";
574
575 static int st_node_packets = -1;
576 static int st_node_requests = -1;
577 static int st_node_responses = -1;
578 static int st_node_resp_broken = -1;
579 static int st_node_resp_100 = -1;
580 static int st_node_resp_200 = -1;
581 static int st_node_resp_300 = -1;
582 static int st_node_resp_400 = -1;
583 static int st_node_resp_500 = -1;
584 static int st_node_other = -1;
585
586
587 /* HTTP/Packet Counter stats init function */
588 static void
http_stats_tree_init(stats_tree * st)589 http_stats_tree_init(stats_tree* st)
590 {
591 st_node_packets = stats_tree_create_node(st, st_str_packets, 0, STAT_DT_INT, TRUE);
592 st_node_requests = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
593 st_node_responses = stats_tree_create_node(st, st_str_responses, st_node_packets, STAT_DT_INT, TRUE);
594 st_node_resp_broken = stats_tree_create_node(st, st_str_resp_broken, st_node_responses, STAT_DT_INT, TRUE);
595 st_node_resp_100 = stats_tree_create_node(st, st_str_resp_100, st_node_responses, STAT_DT_INT, TRUE);
596 st_node_resp_200 = stats_tree_create_node(st, st_str_resp_200, st_node_responses, STAT_DT_INT, TRUE);
597 st_node_resp_300 = stats_tree_create_node(st, st_str_resp_300, st_node_responses, STAT_DT_INT, TRUE);
598 st_node_resp_400 = stats_tree_create_node(st, st_str_resp_400, st_node_responses, STAT_DT_INT, TRUE);
599 st_node_resp_500 = stats_tree_create_node(st, st_str_resp_500, st_node_responses, STAT_DT_INT, TRUE);
600 st_node_other = stats_tree_create_node(st, st_str_other, st_node_packets, STAT_DT_INT, FALSE);
601 }
602
603 /* HTTP/Packet Counter stats packet function */
604 static tap_packet_status
http_stats_tree_packet(stats_tree * st,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * p)605 http_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p)
606 {
607 const http_info_value_t* v = (const http_info_value_t*)p;
608 guint i = v->response_code;
609 int resp_grp;
610 const gchar *resp_str;
611 gchar str[64];
612
613 tick_stat_node(st, st_str_packets, 0, FALSE);
614
615 if (i) {
616 tick_stat_node(st, st_str_responses, st_node_packets, FALSE);
617
618 if ( (i<100)||(i>=600) ) {
619 resp_grp = st_node_resp_broken;
620 resp_str = st_str_resp_broken;
621 } else if (i<200) {
622 resp_grp = st_node_resp_100;
623 resp_str = st_str_resp_100;
624 } else if (i<300) {
625 resp_grp = st_node_resp_200;
626 resp_str = st_str_resp_200;
627 } else if (i<400) {
628 resp_grp = st_node_resp_300;
629 resp_str = st_str_resp_300;
630 } else if (i<500) {
631 resp_grp = st_node_resp_400;
632 resp_str = st_str_resp_400;
633 } else {
634 resp_grp = st_node_resp_500;
635 resp_str = st_str_resp_500;
636 }
637
638 tick_stat_node(st, resp_str, st_node_responses, FALSE);
639
640 g_snprintf(str, sizeof(str), "%u %s", i,
641 val_to_str(i, vals_http_status_code, "Unknown (%d)"));
642 tick_stat_node(st, str, resp_grp, FALSE);
643 } else if (v->request_method) {
644 stats_tree_tick_pivot(st,st_node_requests,v->request_method);
645 } else {
646 tick_stat_node(st, st_str_other, st_node_packets, FALSE);
647 }
648
649 return TAP_PACKET_REDRAW;
650 }
651
652 /*
653 Generates a referer tree - a best-effort representation of which web request led to which.
654
655 Some challenges:
656 A user can be forwarded to a single sites from multiple sources. For example,
657 google.com -> foo.com and bing.com -> foo.com. A URI alone is not unique.
658
659 Additionally, if a user has a subsequent request to foo.com -> bar.com, the
660 full chain could either be:
661 google.com -> foo.com -> bar.com, or
662 bing.com -> foo.com -> bar.com,
663
664 This indicates that a URI and its referer are not unique. Only a URI and its
665 full referer chain are unique. However, HTTP requests only contain the URI
666 and the immediate referer. This means that any attempt at generating a
667 referer tree is inherently going to be a best-effort approach.
668
669 This code assumes that the referer in a request is from the most-recent request
670 to that referer.
671
672 * To maintain readability of the statistics, whenever a site is visited, all
673 prior referers are 'ticked' as well, so that one can easily see the breakdown.
674 */
675
676 /* Root node for all referer statistics */
677 static int st_node_requests_by_referer = -1;
678 /* Referer statistics root node's text */
679 static const gchar *st_str_request_sequences = "HTTP Request Sequences";
680
681 /* Mapping of URIs to the most-recently seen node id */
682 static wmem_map_t* refstats_uri_to_node_id_hash = NULL;
683 /* Mapping of node ids to the node's URI ('name' value) */
684 static wmem_map_t* refstats_node_id_to_uri_hash = NULL;
685 /* Mapping of node ids to the parent node id */
686 static wmem_map_t* refstats_node_id_to_parent_node_id_hash = NULL;
687
688
689 /* HTTP/Request Sequences stats init function */
690 static void
http_seq_stats_tree_init(stats_tree * st)691 http_seq_stats_tree_init(stats_tree* st)
692 {
693 gint root_node_id = 0;
694 gpointer root_node_id_p = GINT_TO_POINTER(root_node_id);
695 gpointer node_id_p = NULL;
696 gchar *uri = NULL;
697
698 refstats_node_id_to_parent_node_id_hash = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
699 refstats_node_id_to_uri_hash = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
700 refstats_uri_to_node_id_hash = wmem_map_new(wmem_file_scope(), wmem_str_hash, g_str_equal);
701
702 /* Add the root node and its mappings */
703 st_node_requests_by_referer = stats_tree_create_node(st, st_str_request_sequences, root_node_id, STAT_DT_INT, TRUE);
704 node_id_p = GINT_TO_POINTER(st_node_requests_by_referer);
705 uri = wmem_strdup(wmem_file_scope(), st_str_request_sequences);
706
707 wmem_map_insert(refstats_uri_to_node_id_hash, uri, node_id_p);
708 wmem_map_insert(refstats_node_id_to_uri_hash, node_id_p, uri);
709 wmem_map_insert(refstats_node_id_to_parent_node_id_hash, node_id_p, root_node_id_p);
710 }
711
712 static gint
http_seq_stats_tick_referer(stats_tree * st,const gchar * arg_referer_uri)713 http_seq_stats_tick_referer(stats_tree* st, const gchar* arg_referer_uri)
714 {
715 gint root_node_id = st_node_requests_by_referer;
716 gpointer root_node_id_p = GINT_TO_POINTER(st_node_requests_by_referer);
717 gint referer_node_id;
718 gpointer referer_node_id_p;
719 gint referer_parent_node_id;
720 gpointer referer_parent_node_id_p;
721 gchar *referer_uri;
722
723 /* Tick the referer's URI */
724 /* Does the node exist? */
725 if (!wmem_map_lookup_extended(refstats_uri_to_node_id_hash, arg_referer_uri, NULL, &referer_node_id_p)) {
726 /* The node for the referer didn't already exist, create the mappings */
727 referer_node_id = tick_stat_node(st, arg_referer_uri, root_node_id, TRUE);
728 referer_node_id_p = GINT_TO_POINTER(referer_node_id);
729 referer_parent_node_id_p = root_node_id_p;
730
731 referer_uri = wmem_strdup(wmem_file_scope(), arg_referer_uri);
732 wmem_map_insert(refstats_uri_to_node_id_hash, referer_uri, referer_node_id_p);
733 wmem_map_insert(refstats_node_id_to_uri_hash, referer_node_id_p, referer_uri);
734 wmem_map_insert(refstats_node_id_to_parent_node_id_hash, referer_node_id_p, referer_parent_node_id_p);
735 } else {
736 /* The node for the referer already exists, tick it */
737 referer_parent_node_id_p = wmem_map_lookup(refstats_node_id_to_parent_node_id_hash, referer_node_id_p);
738 referer_parent_node_id = GPOINTER_TO_INT(referer_parent_node_id_p);
739 referer_node_id = tick_stat_node(st, arg_referer_uri, referer_parent_node_id, TRUE);
740 }
741 return referer_node_id;
742 }
743
744 static void
http_seq_stats_tick_request(stats_tree * st,const gchar * arg_full_uri,gint referer_node_id)745 http_seq_stats_tick_request(stats_tree* st, const gchar* arg_full_uri, gint referer_node_id)
746 {
747 gpointer referer_node_id_p = GINT_TO_POINTER(referer_node_id);
748 gint node_id;
749 gpointer node_id_p;
750 gchar *uri;
751
752 node_id = tick_stat_node(st, arg_full_uri, referer_node_id, TRUE);
753 node_id_p = GINT_TO_POINTER(node_id);
754
755 /* Update the mappings. Even if the URI was already seen, the URI->node mapping may need to be updated */
756
757 /* Is this a new node? */
758 uri = (gchar *) wmem_map_lookup(refstats_node_id_to_uri_hash, node_id_p);
759 if (!uri) {
760 /* node not found, add mappings for the node and uri */
761 uri = wmem_strdup(wmem_file_scope(), arg_full_uri);
762
763 wmem_map_insert(refstats_uri_to_node_id_hash, uri, node_id_p);
764 wmem_map_insert(refstats_node_id_to_uri_hash, node_id_p, uri);
765 wmem_map_insert(refstats_node_id_to_parent_node_id_hash, node_id_p, referer_node_id_p);
766 } else {
767 /* We've seen the node id before. Update the URI mapping refer to this node id*/
768 wmem_map_insert(refstats_uri_to_node_id_hash, uri, node_id_p);
769 }
770 }
771
772 static gchar*
determine_http_location_target(const gchar * base_url,const gchar * location_url)773 determine_http_location_target(const gchar *base_url, const gchar * location_url)
774 {
775 /* Resolving a base URI + relative URI to an absolute URI ("Relative Resolution")
776 is complicated. Because of that, we take shortcuts that may result in
777 inaccurate results, but is also significantly simpler.
778 It would be best to use an external library to do this for us.
779 For reference, the RFC is located at https://tools.ietf.org/html/rfc3986#section-5.4
780
781 Returns NULL if the resolution fails
782 */
783 gchar *final_target;
784
785 /* base_url must be an absolute URL.*/
786 if (strstr(base_url, "://") == NULL){
787 return NULL;
788 }
789
790 /* Empty Location */
791 if (location_url[0] == '\0') {
792 final_target = wmem_strdup(wmem_packet_scope(), base_url);
793 return final_target;
794 }
795 /* Protocol Relative */
796 else if (g_str_has_prefix(location_url, "//") ) {
797 char *base_scheme = g_uri_parse_scheme(base_url);
798 if (base_scheme == NULL) {
799 return NULL;
800 }
801 final_target = wmem_strdup_printf(wmem_packet_scope(), "%s:%s", base_scheme, location_url);
802 g_free(base_scheme);
803 return final_target;
804 }
805 /* Absolute URL*/
806 else if (strstr(location_url, "://") != NULL) {
807 final_target = wmem_strdup(wmem_packet_scope(), location_url);
808 return final_target;
809 }
810 /* Relative */
811 else {
812 gchar *start_fragment = strstr(base_url, "#");
813 gchar *start_query = NULL;
814 gchar *base_url_no_fragment = NULL;
815 gchar *base_url_no_query = NULL;
816
817 /* Strip off the fragment (which should never be present)*/
818 if (start_fragment == NULL) {
819 base_url_no_fragment = wmem_strdup(wmem_packet_scope(), base_url);
820 }
821 else {
822 base_url_no_fragment = wmem_strndup(wmem_packet_scope(), base_url, start_fragment - base_url);
823 }
824
825 /* Strip off the query (Queries are stripped from all relative URIs) */
826 start_query = strstr(base_url_no_fragment, "?");
827 if (start_query == NULL) {
828 base_url_no_query = wmem_strdup(wmem_packet_scope(), base_url_no_fragment);
829 }
830 else {
831 base_url_no_query = wmem_strndup(wmem_packet_scope(), base_url_no_fragment, start_query - base_url_no_fragment);
832 }
833
834 /* A leading question mark (?) means to replace the old query with the new*/
835 if (g_str_has_prefix(location_url, "?")) {
836 final_target = wmem_strdup_printf(wmem_packet_scope(), "%s%s", base_url_no_query, location_url);
837 return final_target;
838 }
839 /* A leading slash means to put the location after the netloc */
840 else if (g_str_has_prefix(location_url, "/")) {
841 gchar *scheme_end = strstr(base_url_no_query, "://") + 3;
842 gchar *netloc_end;
843 gint netloc_length;
844 if (scheme_end[0] == '\0') {
845 return NULL;
846 }
847 netloc_end = strstr(scheme_end, "/");
848 if (netloc_end == NULL) {
849 return NULL;
850 }
851 netloc_length = (gint) (netloc_end - base_url_no_query);
852 final_target = wmem_strdup_printf(wmem_packet_scope(), "%.*s%s", netloc_length, base_url_no_query, location_url);
853 return final_target;
854 }
855 /* Otherwise, it replaces the last element in the URI */
856 else {
857 gchar *scheme_end = strstr(base_url_no_query, "://") + 3;
858 gchar *end_of_path = g_strrstr(scheme_end, "/");
859
860 if (end_of_path != NULL) {
861 gint base_through_path = (gint) (end_of_path - base_url_no_query);
862 final_target = wmem_strdup_printf(wmem_packet_scope(), "%.*s/%s", base_through_path, base_url_no_query, location_url);
863 }
864 else {
865 final_target = wmem_strdup_printf(wmem_packet_scope(), "%s/%s", base_url_no_query, location_url);
866 }
867
868 return final_target;
869 }
870 }
871 return NULL;
872 }
873
874 /* HTTP/Request Sequences stats packet function */
875 static tap_packet_status
http_seq_stats_tree_packet(stats_tree * st,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * p)876 http_seq_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p)
877 {
878 const http_info_value_t* v = (const http_info_value_t*)p;
879
880 /* Track HTTP Redirects */
881 if (v->location_target && v->location_base_uri) {
882 gint referer_node_id;
883 gint parent_node_id;
884 gpointer parent_node_id_p;
885 gpointer current_node_id_p;
886 gchar *uri = NULL;
887
888 gchar *absolute_target = determine_http_location_target(v->location_base_uri, v->location_target);
889 /* absolute_target is NULL if the resolution fails */
890 if (absolute_target != NULL) {
891 /* We assume the user makes the request to the absolute_target */
892 /* Tick the base URI */
893 referer_node_id = http_seq_stats_tick_referer(st, v->location_base_uri);
894
895 /* Tick the location header's resolved URI */
896 http_seq_stats_tick_request(st, absolute_target, referer_node_id);
897
898 /* Tick all stats nodes above the location */
899 current_node_id_p = GINT_TO_POINTER(referer_node_id);
900 while (wmem_map_lookup_extended(refstats_node_id_to_parent_node_id_hash, current_node_id_p, NULL, &parent_node_id_p)) {
901 parent_node_id = GPOINTER_TO_INT(parent_node_id_p);
902 uri = (gchar *) wmem_map_lookup(refstats_node_id_to_uri_hash, current_node_id_p);
903 tick_stat_node(st, uri, parent_node_id, TRUE);
904 current_node_id_p = parent_node_id_p;
905 }
906 }
907 }
908
909 /* Track HTTP Requests/Referers */
910 if (v->request_method && v->referer_uri && v->full_uri) {
911 gint referer_node_id;
912 gint parent_node_id;
913 gpointer parent_node_id_p;
914 gpointer current_node_id_p;
915 gchar *uri = NULL;
916 /* Tick the referer's URI */
917 referer_node_id = http_seq_stats_tick_referer(st, v->referer_uri);
918
919 /* Tick the request's URI */
920 http_seq_stats_tick_request(st, v->full_uri, referer_node_id);
921
922 /* Tick all stats nodes above the referer */
923 current_node_id_p = GINT_TO_POINTER(referer_node_id);
924 while (wmem_map_lookup_extended(refstats_node_id_to_parent_node_id_hash, current_node_id_p, NULL, &parent_node_id_p)) {
925 parent_node_id = GPOINTER_TO_INT(parent_node_id_p);
926 uri = (gchar *) wmem_map_lookup(refstats_node_id_to_uri_hash, current_node_id_p);
927 tick_stat_node(st, uri, parent_node_id, TRUE);
928 current_node_id_p = parent_node_id_p;
929 }
930 }
931 return TAP_PACKET_DONT_REDRAW;
932 }
933
934
935 static void
dissect_http_ntlmssp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,const char * line)936 dissect_http_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
937 const char *line)
938 {
939 tvbuff_t *ntlmssp_tvb;
940
941 ntlmssp_tvb = base64_to_tvb(tvb, line);
942 add_new_data_source(pinfo, ntlmssp_tvb, "NTLMSSP / GSSAPI Data");
943 if (tvb_strneql(ntlmssp_tvb, 0, "NTLMSSP", 7) == 0)
944 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo, tree);
945 else
946 call_dissector(gssapi_handle, ntlmssp_tvb, pinfo, tree);
947 }
948
949 static void
dissect_http_kerberos(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,const char * line)950 dissect_http_kerberos(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
951 const char *line)
952 {
953 tvbuff_t *kerberos_tvb;
954
955 kerberos_tvb = base64_to_tvb(tvb, line + 9); /* skip 'Kerberos ' which is 9 chars */
956 add_new_data_source(pinfo, kerberos_tvb, "Kerberos Data");
957 call_dissector(gssapi_handle, kerberos_tvb, pinfo, tree);
958
959 }
960
961
962 static http_conv_t *
get_http_conversation_data(packet_info * pinfo,conversation_t ** conversation)963 get_http_conversation_data(packet_info *pinfo, conversation_t **conversation)
964 {
965 http_conv_t *conv_data;
966
967 *conversation = find_or_create_conversation(pinfo);
968
969 /* Retrieve information from conversation
970 * or add it if it isn't there yet
971 */
972 conv_data = (http_conv_t *)conversation_get_proto_data(*conversation, proto_http);
973 if(!conv_data) {
974 /* Setup the conversation structure itself */
975 conv_data = wmem_new0(wmem_file_scope(), http_conv_t);
976
977 conversation_add_proto_data(*conversation, proto_http,
978 conv_data);
979 }
980
981 return conv_data;
982 }
983
984 /**
985 * create a new http_req_res_t and add it to the conversation.
986 * @return the new allocated object which is already added to the linked list
987 */
push_req_res(http_conv_t * conv_data)988 static http_req_res_t* push_req_res(http_conv_t *conv_data)
989 {
990 http_req_res_t *req_res = wmem_new0(wmem_file_scope(), http_req_res_t);
991 nstime_set_unset(&(req_res->req_ts));
992 req_res->number = ++conv_data->req_res_num;
993
994 if (! conv_data->req_res_tail) {
995 conv_data->req_res_tail = req_res;
996 } else {
997 req_res->prev = conv_data->req_res_tail;
998 conv_data->req_res_tail->next = req_res;
999 conv_data->req_res_tail = req_res;
1000 }
1001
1002 return req_res;
1003 }
1004
1005 /**
1006 * push a request frame number and its time stamp to the conversation data.
1007 */
push_req(http_conv_t * conv_data,packet_info * pinfo)1008 static void push_req(http_conv_t *conv_data, packet_info *pinfo)
1009 {
1010 /* a request will always create a new http_req_res_t object */
1011 http_req_res_t *req_res = push_req_res(conv_data);
1012
1013 req_res->req_framenum = pinfo->num;
1014 req_res->req_ts = pinfo->abs_ts;
1015
1016 p_add_proto_data(wmem_file_scope(), pinfo, proto_http, 0, req_res);
1017 }
1018
1019 /**
1020 * push a response frame number to the conversation data.
1021 */
push_res(http_conv_t * conv_data,packet_info * pinfo)1022 static void push_res(http_conv_t *conv_data, packet_info *pinfo)
1023 {
1024 /* a response will create a new http_req_res_t object: if no
1025 object exists, or if one exists for another response. In
1026 both cases the corresponding request was not
1027 detected/included in the conversation. In all other cases
1028 the http_req_res_t object created by the request is
1029 used. */
1030 http_req_res_t *req_res = conv_data->req_res_tail;
1031 if (!req_res || req_res->res_framenum > 0) {
1032 req_res = push_req_res(conv_data);
1033 }
1034 req_res->res_framenum = pinfo->num;
1035 p_add_proto_data(wmem_file_scope(), pinfo, proto_http, 0, req_res);
1036 }
1037
1038 /*
1039 * TODO: remove this ugly global variable.
1040 * XXX: do we really want to have to pass this from one function to another?
1041 */
1042 static http_info_value_t *stat_info;
1043
1044 static int
dissect_http_message(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,http_conv_t * conv_data,const char * proto_tag,int proto,gboolean end_of_stream)1045 dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
1046 proto_tree *tree, http_conv_t *conv_data,
1047 const char* proto_tag, int proto, gboolean end_of_stream)
1048 {
1049 proto_tree *http_tree = NULL;
1050 proto_item *ti = NULL;
1051 proto_item *hidden_item;
1052 const guchar *line, *firstline;
1053 gint next_offset;
1054 const guchar *linep, *lineend;
1055 int orig_offset;
1056 int first_linelen, linelen;
1057 gboolean is_request_or_reply, is_tls = FALSE;
1058 gboolean saw_req_resp_or_header;
1059 http_type_t http_type;
1060 proto_item *hdr_item = NULL;
1061 ReqRespDissector reqresp_dissector;
1062 proto_tree *req_tree;
1063 int colon_offset;
1064 headers_t headers;
1065 int datalen;
1066 int reported_datalen = -1;
1067 dissector_handle_t handle;
1068 gboolean dissected = FALSE;
1069 gboolean first_loop = TRUE;
1070 gboolean have_seen_http = FALSE;
1071 /*guint i;*/
1072 /*http_info_value_t *si;*/
1073 http_eo_t *eo_info;
1074 heur_dtbl_entry_t *hdtbl_entry;
1075 int reported_length;
1076 guint16 word;
1077 gboolean leading_crlf = FALSE;
1078 http_message_info_t message_info;
1079
1080 reported_length = tvb_reported_length_remaining(tvb, offset);
1081 if (reported_length < 1) {
1082 return -1;
1083 }
1084
1085 /* RFC 2616
1086 * In the interest of robustness, servers SHOULD ignore any empty
1087 * line(s) received where a Request-Line is expected. In other words, if
1088 * the server is reading the protocol stream at the beginning of a
1089 * message and receives a CRLF first, it should ignore the CRLF.
1090 */
1091 if (reported_length > 3) {
1092 word = tvb_get_ntohs(tvb,offset);
1093 if (word == 0x0d0a) {
1094 leading_crlf = TRUE;
1095 offset += 2;
1096 }
1097 }
1098
1099 /*
1100 * If we previously dissected an HTTP request in this conversation then
1101 * we should be pretty sure that whatever we got in this TVB is
1102 * actually HTTP (even if what we have here is part of a file being
1103 * transferred over HTTP).
1104 */
1105 if (conv_data->request_uri)
1106 have_seen_http = TRUE;
1107
1108 /*
1109 * If this is binary data then there's no point in doing all the string
1110 * operations below: they'll just be slow on this data.
1111 */
1112 if (!g_ascii_isprint(tvb_get_guint8(tvb, offset))) {
1113 /*
1114 * But, if we've seen some real HTTP then we're sure this is
1115 * an HTTP conversation. Mark it as such.
1116 */
1117 if (have_seen_http) {
1118 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
1119 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1120 ti = proto_tree_add_item(tree, proto, tvb, offset, -1, ENC_NA);
1121 http_tree = proto_item_add_subtree(ti, ett_http);
1122
1123 call_data_dissector(tvb, pinfo, http_tree);
1124 }
1125 return -1;
1126 }
1127
1128 /*
1129 * Is this a request or response?
1130 *
1131 * Note that "tvb_find_line_end()" will return a value that
1132 * is not longer than what's in the buffer, so the
1133 * "tvb_get_ptr()" call won't throw an exception.
1134 */
1135 first_linelen = tvb_find_line_end(tvb, offset,
1136 tvb_ensure_captured_length_remaining(tvb, offset), &next_offset,
1137 TRUE);
1138
1139 if (first_linelen == -1) {
1140 /* No complete line was found in this segment, do
1141 * desegmentation if we're told to.
1142 */
1143 if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
1144 http_desegment_headers, http_desegment_body, FALSE)) {
1145 /*
1146 * More data needed for desegmentation.
1147 */
1148 return -1;
1149 }
1150 }
1151
1152 /*
1153 * Is the first line a request or response?
1154 *
1155 * Note that "tvb_find_line_end()" will return a value that
1156 * is not longer than what's in the buffer, so the
1157 * "tvb_get_ptr()" call won't throw an exception.
1158 */
1159 firstline = tvb_get_ptr(tvb, offset, first_linelen);
1160 http_type = HTTP_OTHERS; /* type not known yet */
1161 is_request_or_reply = is_http_request_or_reply((const gchar *)firstline,
1162 first_linelen, &http_type, NULL, conv_data);
1163 if (is_request_or_reply) {
1164 gboolean try_desegment_body;
1165
1166 /*
1167 * Yes, it's a request or response.
1168 * Put the first line from the buffer into the summary
1169 * (but leave out the line terminator).
1170 */
1171 col_add_fstr(pinfo->cinfo, COL_INFO, "%s ", format_text(wmem_packet_scope(), firstline, first_linelen));
1172
1173 /*
1174 * Do header desegmentation if we've been told to,
1175 * and do body desegmentation if we've been told to and
1176 * we find a Content-Length header in requests.
1177 *
1178 * The following cases (from RFC 7230, Section 3.3) never have a
1179 * response body, so do not attempt to desegment the body for:
1180 * * Responses to HEAD requests.
1181 * * 2xx responses to CONNECT requests.
1182 * * 1xx, 204 No Content, 304 Not Modified responses.
1183 *
1184 * Additionally if we are at the end of stream, no more segments
1185 * will be added so disable body segmentation too in that case.
1186 */
1187 try_desegment_body = (http_desegment_body && !end_of_stream);
1188 if (try_desegment_body && http_type == HTTP_RESPONSE) {
1189 /*
1190 * conv_data->response_code is not yet set, so extract
1191 * the response code from the current line.
1192 */
1193 gint response_code = parse_http_status_code(firstline, firstline + first_linelen);
1194 if ((g_strcmp0(conv_data->request_method, "HEAD") == 0 ||
1195 (response_code / 100 == 2 &&
1196 (g_strcmp0(conv_data->request_method, "CONNECT") == 0 ||
1197 g_strcmp0(conv_data->request_method, "SSTP_DUPLEX_POST") == 0)) ||
1198 response_code / 100 == 1 ||
1199 response_code == 204 ||
1200 response_code == 304)) {
1201 /* No response body is present. */
1202 try_desegment_body = FALSE;
1203 }
1204 }
1205 if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
1206 http_desegment_headers, try_desegment_body, http_type == HTTP_RESPONSE)) {
1207 /*
1208 * More data needed for desegmentation.
1209 */
1210 return -1;
1211 }
1212 } else if (have_seen_http) {
1213 /*
1214 * If we know this is HTTP then call it continuation.
1215 */
1216 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1217 }
1218
1219 if (is_request_or_reply || have_seen_http) {
1220 /*
1221 * Now set COL_PROTOCOL and create the http tree for the
1222 * cases where we set COL_INFO above.
1223 */
1224 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
1225 ti = proto_tree_add_item(tree, proto, tvb, offset, -1, ENC_NA);
1226 http_tree = proto_item_add_subtree(ti, ett_http);
1227
1228 if (leading_crlf) {
1229 proto_tree_add_expert(http_tree, pinfo, &ei_http_leading_crlf, tvb, offset-2, 2);
1230 }
1231 }
1232
1233 is_tls = proto_is_frame_protocol(pinfo->layers, "tls");
1234
1235 stat_info = wmem_new(wmem_packet_scope(), http_info_value_t);
1236 stat_info->framenum = pinfo->num;
1237 stat_info->response_code = 0;
1238 stat_info->request_method = NULL;
1239 stat_info->request_uri = NULL;
1240 stat_info->referer_uri = NULL;
1241 stat_info->http_host = NULL;
1242 stat_info->full_uri = NULL;
1243 stat_info->location_target = NULL;
1244 stat_info->location_base_uri = NULL;
1245
1246 orig_offset = offset;
1247
1248 /*
1249 * Process the packet data, a line at a time.
1250 */
1251 http_type = HTTP_OTHERS; /* type not known yet */
1252 headers.content_type = NULL; /* content type not known yet */
1253 headers.content_type_parameters = NULL; /* content type parameters too */
1254 headers.have_content_length = FALSE; /* content length not known yet */
1255 headers.content_length = 0; /* content length set to 0 (avoid a gcc warning) */
1256 headers.content_encoding = NULL; /* content encoding not known yet */
1257 headers.transfer_encoding_chunked = FALSE;
1258 headers.transfer_encoding = HTTP_TE_NONE;
1259 headers.upgrade = NULL; /* assume no upgrade header */
1260 saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
1261 while (tvb_offset_exists(tvb, offset)) {
1262 /*
1263 * Find the end of the line.
1264 * XXX - what if we don't find it because the packet
1265 * is cut short by a snapshot length or the header is
1266 * split across TCP segments? How much dissection should
1267 * we do on it?
1268 */
1269 linelen = tvb_find_line_end(tvb, offset,
1270 tvb_ensure_captured_length_remaining(tvb, offset), &next_offset,
1271 FALSE);
1272 if (linelen < 0)
1273 return -1;
1274
1275 /*
1276 * Get a buffer that refers to the line.
1277 *
1278 * Note that "tvb_find_line_end()" will return a value that
1279 * is not longer than what's in the buffer, so the
1280 * "tvb_get_ptr()" call won't throw an exception.
1281 */
1282 line = tvb_get_ptr(tvb, offset, linelen);
1283 lineend = line + linelen;
1284 colon_offset = -1;
1285
1286 /*
1287 * OK, does it look like an HTTP request or response?
1288 */
1289 reqresp_dissector = NULL;
1290 is_request_or_reply =
1291 is_http_request_or_reply((const gchar *)line,
1292 linelen, &http_type, &reqresp_dissector, conv_data);
1293 if (is_request_or_reply)
1294 goto is_http;
1295
1296 /*
1297 * No. Does it look like a blank line (as would appear
1298 * at the end of an HTTP request)?
1299 */
1300 if (linelen == 0)
1301 goto is_http; /* Yes. */
1302
1303 /*
1304 * No. Does it look like a header?
1305 */
1306 colon_offset = offset;
1307
1308 linep = (const guchar *)memchr(line, ':', linelen);
1309 if (linep) {
1310 /*
1311 * Colon found, assume it is a header.
1312 */
1313 colon_offset += (int)(linep - line);
1314 goto is_http;
1315 }
1316
1317 /*
1318 * We haven't seen the colon yet.
1319 *
1320 * If we've already seen an HTTP request or response
1321 * line, or a header line, and we're at the end of
1322 * the tvbuff, we assume this is an incomplete header
1323 * line. (We quit this loop after seeing a blank line,
1324 * so if we've seen a request or response line, or a
1325 * header line, this is probably more of the request
1326 * or response we're presumably seeing. There is some
1327 * risk of false positives, but the same applies for
1328 * full request or response lines or header lines,
1329 * although that's less likely.)
1330 *
1331 * We throw an exception in that case, by checking for
1332 * the existence of the next byte after the last one
1333 * in the line. If it exists, "tvb_ensure_bytes_exist()"
1334 * throws no exception, and we fall through to the
1335 * "not HTTP" case. If it doesn't exist,
1336 * "tvb_ensure_bytes_exist()" will throw the appropriate
1337 * exception.
1338 */
1339 if (saw_req_resp_or_header)
1340 tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
1341
1342 /*
1343 * We don't consider this part of an HTTP request or
1344 * reply, so we don't display it.
1345 * (Yeah, that means we don't display, say, a text/http
1346 * page, but you can get that from the data pane.)
1347 */
1348 break;
1349
1350 is_http:
1351 if ((tree) && (http_tree == NULL)) {
1352 ti = proto_tree_add_item(tree, proto, tvb, orig_offset, -1, ENC_NA);
1353 http_tree = proto_item_add_subtree(ti, ett_http);
1354 if (leading_crlf) {
1355 proto_tree_add_expert(http_tree, pinfo, &ei_http_leading_crlf, tvb, orig_offset-2, 2);
1356 }
1357 }
1358
1359 if (first_loop && !is_tls && pinfo->ptype == PT_TCP &&
1360 (pinfo->srcport == 443 || pinfo->destport == 443)) {
1361 expert_add_info(pinfo, ti, &ei_http_tls_port);
1362 }
1363
1364 first_loop = FALSE;
1365
1366 /*
1367 * Process this line.
1368 */
1369
1370 if (linelen == 0) {
1371 /*
1372 * This is a blank line, which means that
1373 * whatever follows it isn't part of this
1374 * request or reply.
1375 */
1376 proto_tree_add_format_text(http_tree, tvb, offset, next_offset - offset);
1377 offset = next_offset;
1378 break;
1379 }
1380
1381 /*
1382 * Not a blank line - either a request, a reply, or a header
1383 * line.
1384 */
1385 saw_req_resp_or_header = TRUE;
1386 if (is_request_or_reply) {
1387 char *text = tvb_format_text(pinfo->pool, tvb, offset, next_offset - offset);
1388
1389 req_tree = proto_tree_add_subtree(http_tree, tvb,
1390 offset, next_offset - offset, ett_http_request, &hdr_item, text);
1391
1392 expert_add_info_format(pinfo, hdr_item, &ei_http_chat, "%s", text);
1393 if (reqresp_dissector) {
1394 reqresp_dissector(tvb, req_tree, offset, line,
1395 lineend, conv_data);
1396 }
1397 } else {
1398 /*
1399 * Header.
1400 */
1401 process_header(tvb, offset, next_offset, line, linelen,
1402 colon_offset, pinfo, http_tree, &headers, conv_data,
1403 http_type);
1404 }
1405 offset = next_offset;
1406 }
1407 if (stat_info->http_host && stat_info->request_uri) {
1408 proto_item *e_ti;
1409 gchar *uri;
1410
1411 if ((g_ascii_strncasecmp(stat_info->request_uri, "http://", 7) == 0) ||
1412 (g_ascii_strncasecmp(stat_info->request_uri, "https://", 8) == 0) ||
1413 (g_ascii_strncasecmp(conv_data->request_method, "CONNECT", 7) == 0)) {
1414 uri = wmem_strdup(wmem_packet_scope(), stat_info->request_uri);
1415 }
1416 else {
1417 uri = wmem_strdup_printf(wmem_packet_scope(), "%s://%s%s",
1418 is_tls ? "https" : "http",
1419 g_strstrip(wmem_strdup(wmem_packet_scope(), stat_info->http_host)), stat_info->request_uri);
1420 }
1421 stat_info->full_uri = wmem_strdup(wmem_packet_scope(), uri);
1422 conv_data->full_uri = wmem_strdup(wmem_file_scope(), uri);
1423 if (tree) {
1424 e_ti = proto_tree_add_string(http_tree,
1425 hf_http_request_full_uri, tvb, 0,
1426 0, uri);
1427
1428 proto_item_set_url(e_ti);
1429 proto_item_set_generated(e_ti);
1430 }
1431 }
1432
1433 if (!PINFO_FD_VISITED(pinfo)) {
1434 if (http_type == HTTP_REQUEST) {
1435 push_req(conv_data, pinfo);
1436 } else if (http_type == HTTP_RESPONSE) {
1437 push_res(conv_data, pinfo);
1438 }
1439 }
1440
1441 if (tree) {
1442 proto_item *pi;
1443 http_req_res_t *curr = (http_req_res_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_http, 0);
1444 http_req_res_t *prev = curr ? curr->prev : NULL;
1445 http_req_res_t *next = curr ? curr->next : NULL;
1446
1447 switch (http_type) {
1448
1449 case HTTP_NOTIFICATION:
1450 hidden_item = proto_tree_add_boolean(http_tree,
1451 hf_http_notification, tvb, 0, 0, 1);
1452 proto_item_set_hidden(hidden_item);
1453 break;
1454
1455 case HTTP_RESPONSE:
1456 hidden_item = proto_tree_add_boolean(http_tree,
1457 hf_http_response, tvb, 0, 0, 1);
1458 proto_item_set_hidden(hidden_item);
1459
1460 if (curr) {
1461 nstime_t delta;
1462
1463 pi = proto_tree_add_uint_format(http_tree, hf_http_response_number, tvb, 0, 0, curr->number, "HTTP response %u/%u", curr->number, conv_data->req_res_num);
1464 proto_item_set_generated(pi);
1465
1466 if (! nstime_is_unset(&(curr->req_ts))) {
1467 nstime_delta(&delta, &pinfo->abs_ts, &(curr->req_ts));
1468 pi = proto_tree_add_time(http_tree, hf_http_time, tvb, 0, 0, &delta);
1469 proto_item_set_generated(pi);
1470 }
1471 }
1472 if (prev && prev->req_framenum) {
1473 pi = proto_tree_add_uint(http_tree, hf_http_prev_request_in, tvb, 0, 0, prev->req_framenum);
1474 proto_item_set_generated(pi);
1475 }
1476 if (prev && prev->res_framenum) {
1477 pi = proto_tree_add_uint(http_tree, hf_http_prev_response_in, tvb, 0, 0, prev->res_framenum);
1478 proto_item_set_generated(pi);
1479 }
1480 if (curr && curr->req_framenum) {
1481 pi = proto_tree_add_uint(http_tree, hf_http_request_in, tvb, 0, 0, curr->req_framenum);
1482 proto_item_set_generated(pi);
1483 }
1484 if (next && next->req_framenum) {
1485 pi = proto_tree_add_uint(http_tree, hf_http_next_request_in, tvb, 0, 0, next->req_framenum);
1486 proto_item_set_generated(pi);
1487 }
1488 if (next && next->res_framenum) {
1489 pi = proto_tree_add_uint(http_tree, hf_http_next_response_in, tvb, 0, 0, next->res_framenum);
1490 proto_item_set_generated(pi);
1491 }
1492
1493 /*
1494 * add the request URI to the response to allow filtering responses filtered by URI
1495 */
1496 if (conv_data && (conv_data->full_uri || conv_data->request_uri)) {
1497 if (conv_data->full_uri) {
1498 pi = proto_tree_add_string(http_tree, hf_http_response_for_uri, tvb, 0, 0, conv_data->full_uri);
1499 }
1500 else {
1501 pi = proto_tree_add_string(http_tree, hf_http_response_for_uri, tvb, 0, 0, conv_data->request_uri);
1502 }
1503 proto_item_set_generated(pi);
1504 }
1505
1506 break;
1507
1508 case HTTP_REQUEST:
1509 hidden_item = proto_tree_add_boolean(http_tree,
1510 hf_http_request, tvb, 0, 0, 1);
1511 proto_item_set_hidden(hidden_item);
1512
1513 if (curr) {
1514 pi = proto_tree_add_uint_format(http_tree, hf_http_request_number, tvb, 0, 0, curr->number, "HTTP request %u/%u", curr->number, conv_data->req_res_num);
1515 proto_item_set_generated(pi);
1516 }
1517 if (prev && prev->req_framenum) {
1518 pi = proto_tree_add_uint(http_tree, hf_http_prev_request_in, tvb, 0, 0, prev->req_framenum);
1519 proto_item_set_generated(pi);
1520 }
1521 if (curr && curr->res_framenum) {
1522 pi = proto_tree_add_uint(http_tree, hf_http_response_in, tvb, 0, 0, curr->res_framenum);
1523 proto_item_set_generated(pi);
1524 }
1525 if (next && next->req_framenum) {
1526 pi = proto_tree_add_uint(http_tree, hf_http_next_request_in, tvb, 0, 0, next->req_framenum);
1527 proto_item_set_generated(pi);
1528 }
1529
1530 break;
1531
1532 case HTTP_OTHERS:
1533 default:
1534 break;
1535 }
1536 }
1537
1538 /* Give the follw tap what we've currently dissected */
1539 if(have_tap_listener(http_follow_tap)) {
1540 tap_queue_packet(http_follow_tap, pinfo, tvb_new_subset_length(tvb, 0, offset));
1541 }
1542
1543 reported_datalen = tvb_reported_length_remaining(tvb, offset);
1544 datalen = tvb_captured_length_remaining(tvb, offset);
1545
1546 /*
1547 * If a content length was supplied, the amount of data to be
1548 * processed as HTTP payload is the minimum of the content
1549 * length and the amount of data remaining in the frame.
1550 *
1551 * If a message is received with both a Transfer-Encoding
1552 * header field and a Content-Length header field, the latter
1553 * MUST be ignored.
1554 *
1555 * If no content length was supplied (or if a bad content length
1556 * was supplied), the amount of data to be processed is the amount
1557 * of data remaining in the frame.
1558 *
1559 * If there was no Content-Length entity header, we should
1560 * accumulate all data until the end of the connection.
1561 * That'd require that the TCP dissector call subdissectors
1562 * for all frames with FIN, even if they contain no data,
1563 * which would require subdissectors to deal intelligently
1564 * with empty segments.
1565 *
1566 * According to RFC 2616, however, 1xx responses, 204 responses,
1567 * and 304 responses MUST NOT include a message body; if no
1568 * content length is specified for them, we don't attempt to
1569 * dissect the body.
1570 *
1571 * XXX - it says the same about responses to HEAD requests;
1572 * unless there's a way to determine from the response
1573 * whether it's a response to a HEAD request, we have to
1574 * keep information about the request and associate that with
1575 * the response in order to handle that.
1576 */
1577 if (headers.have_content_length &&
1578 headers.transfer_encoding == HTTP_TE_NONE) {
1579 if (datalen > headers.content_length)
1580 datalen = (int)headers.content_length;
1581
1582 /*
1583 * XXX - limit the reported length in the tvbuff we'll
1584 * hand to a subdissector to be no greater than the
1585 * content length.
1586 *
1587 * We really need both unreassembled and "how long it'd
1588 * be if it were reassembled" lengths for tvbuffs, so
1589 * that we throw the appropriate exceptions for
1590 * "not enough data captured" (running past the length),
1591 * "packet needed reassembly" (within the length but
1592 * running past the unreassembled length), and
1593 * "packet is malformed" (running past the reassembled
1594 * length).
1595 */
1596 if (reported_datalen > headers.content_length)
1597 reported_datalen = (int)headers.content_length;
1598 } else {
1599 switch (http_type) {
1600
1601 case HTTP_REQUEST:
1602 /*
1603 * Requests have no content if there's no
1604 * Content-Length header and no Transfer-Encoding
1605 * header.
1606 */
1607 if (headers.transfer_encoding == HTTP_TE_NONE)
1608 datalen = 0;
1609 else
1610 reported_datalen = -1;
1611 break;
1612
1613 case HTTP_RESPONSE:
1614 if ((stat_info->response_code/100) == 1 ||
1615 stat_info->response_code == 204 ||
1616 stat_info->response_code == 304)
1617 datalen = 0; /* no content! */
1618 else {
1619 /*
1620 * XXX - responses to HEAD requests,
1621 * and possibly other responses,
1622 * "MUST NOT" include a
1623 * message-body.
1624 */
1625 reported_datalen = -1;
1626 }
1627 break;
1628
1629 default:
1630 /*
1631 * XXX - what about HTTP_NOTIFICATION?
1632 */
1633 reported_datalen = -1;
1634 break;
1635 }
1636 }
1637
1638 if (datalen > 0) {
1639 /*
1640 * There's stuff left over; process it.
1641 */
1642 tvbuff_t *next_tvb;
1643 guint chunked_datalen = 0;
1644 char *media_str = NULL;
1645 const gchar *file_data;
1646
1647 /*
1648 * Create a tvbuff for the payload.
1649 *
1650 * The amount of data to be processed that's
1651 * available in the tvbuff is "datalen", which
1652 * is the minimum of the amount of data left in
1653 * the tvbuff and any specified content length.
1654 *
1655 * The amount of data to be processed that's in
1656 * this frame, regardless of whether it was
1657 * captured or not, is "reported_datalen",
1658 * which, if no content length was specified,
1659 * is -1, i.e. "to the end of the frame.
1660 */
1661 next_tvb = tvb_new_subset_length_caplen(tvb, offset, datalen,
1662 reported_datalen);
1663
1664 /*
1665 * Handle *transfer* encodings.
1666 */
1667 if (headers.transfer_encoding_chunked) {
1668 if (!http_dechunk_body) {
1669 /* Chunking disabled, cannot dissect further. */
1670 call_data_dissector(next_tvb, pinfo, http_tree);
1671 goto body_dissected;
1672 }
1673
1674 chunked_datalen = chunked_encoding_dissector(
1675 &next_tvb, pinfo, http_tree, 0);
1676
1677 if (chunked_datalen == 0) {
1678 /*
1679 * The chunks weren't reassembled,
1680 * or there was a single zero
1681 * length chunk.
1682 */
1683 goto body_dissected;
1684 } else {
1685 /*
1686 * Add a new data source for the
1687 * de-chunked data.
1688 */
1689 #if 0 /* Handled in chunked_encoding_dissector() */
1690 tvb_set_child_real_data_tvbuff(tvb,
1691 next_tvb);
1692 #endif
1693 add_new_data_source(pinfo, next_tvb,
1694 "De-chunked entity body");
1695 /* chunked-body might be smaller than
1696 * datalen. */
1697 datalen = chunked_datalen;
1698 }
1699 }
1700 /* Handle other transfer codings after de-chunking. */
1701 switch (headers.transfer_encoding) {
1702 case HTTP_TE_COMPRESS:
1703 case HTTP_TE_DEFLATE:
1704 case HTTP_TE_GZIP:
1705 /*
1706 * We currently can't handle, for example, "gzip",
1707 * "compress", or "deflate" as *transfer* encodings;
1708 * just handle them as data for now.
1709 */
1710 call_data_dissector(next_tvb, pinfo, http_tree);
1711 goto body_dissected;
1712 default:
1713 /* Nothing to do for "identity" or when header is
1714 * missing or invalid. */
1715 break;
1716 }
1717 /*
1718 * At this point, any chunked *transfer* coding has been removed
1719 * (the entity body has been dechunked) so it can be presented
1720 * for the following operation (*content* encoding), or it has
1721 * been been handed off to the data dissector.
1722 *
1723 * Handle *content* encodings other than "identity" (which
1724 * shouldn't appear in a Content-Encoding header, but
1725 * we handle it in any case).
1726 */
1727 if (headers.content_encoding != NULL &&
1728 g_ascii_strcasecmp(headers.content_encoding, "identity") != 0) {
1729 /*
1730 * We currently don't handle, for example, "compress";
1731 * just handle them as data for now.
1732 *
1733 * After July 7, 2004 the LZW patent expired, so
1734 * support could be added. However, I don't think
1735 * that anybody ever really implemented "compress",
1736 * due to the aforementioned patent.
1737 */
1738 tvbuff_t *uncomp_tvb = NULL;
1739 proto_item *e_ti = NULL;
1740 proto_tree *e_tree = NULL;
1741
1742 #ifdef HAVE_ZLIB
1743 if (http_decompress_body &&
1744 (g_ascii_strcasecmp(headers.content_encoding, "gzip") == 0 ||
1745 g_ascii_strcasecmp(headers.content_encoding, "deflate") == 0 ||
1746 g_ascii_strcasecmp(headers.content_encoding, "x-gzip") == 0 ||
1747 g_ascii_strcasecmp(headers.content_encoding, "x-deflate") == 0))
1748 {
1749 uncomp_tvb = tvb_child_uncompress(tvb, next_tvb, 0,
1750 tvb_captured_length(next_tvb));
1751 }
1752 #endif
1753
1754 #ifdef HAVE_BROTLI
1755 if (http_decompress_body &&
1756 g_ascii_strcasecmp(headers.content_encoding, "br") == 0)
1757 {
1758 uncomp_tvb = tvb_child_uncompress_brotli(tvb, next_tvb, 0,
1759 tvb_captured_length(next_tvb));
1760 }
1761 #endif
1762
1763 /*
1764 * Add the encoded entity to the protocol tree
1765 */
1766 e_tree = proto_tree_add_subtree_format(http_tree, next_tvb,
1767 0, tvb_captured_length(next_tvb), ett_http_encoded_entity, &e_ti,
1768 "Content-encoded entity body (%s): %u bytes",
1769 headers.content_encoding,
1770 tvb_captured_length(next_tvb));
1771
1772 if (uncomp_tvb != NULL) {
1773 /*
1774 * Decompression worked
1775 */
1776
1777 /* XXX - Don't free this, since it's possible
1778 * that the data was only partially
1779 * decompressed, such as when desegmentation
1780 * isn't enabled.
1781 *
1782 tvb_free(next_tvb);
1783 */
1784 proto_item_append_text(e_ti, " -> %u bytes", tvb_captured_length(uncomp_tvb));
1785 next_tvb = uncomp_tvb;
1786 add_new_data_source(pinfo, next_tvb,
1787 "Uncompressed entity body");
1788 } else {
1789 #if defined(HAVE_ZLIB) || defined(HAVE_BROTLI)
1790 if (http_decompress_body) {
1791 expert_add_info(pinfo, e_ti, &ei_http_decompression_failed);
1792 }
1793 else {
1794 expert_add_info(pinfo, e_ti, &ei_http_decompression_disabled);
1795 }
1796 #endif
1797 call_data_dissector(next_tvb, pinfo, e_tree);
1798
1799 goto body_dissected;
1800 }
1801 }
1802 /*
1803 * Note that a new data source is added for the entity body
1804 * only if it was content-encoded and/or transfer-encoded.
1805 */
1806
1807 /* Save values for the Export Object GUI feature if we have
1808 * an active listener to process it (which happens when
1809 * the export object window is open). */
1810 if(have_tap_listener(http_eo_tap)) {
1811 eo_info = wmem_new(wmem_packet_scope(), http_eo_t);
1812
1813 eo_info->hostname = conv_data->http_host;
1814 eo_info->filename = conv_data->request_uri;
1815 eo_info->content_type = headers.content_type;
1816 eo_info->payload_len = tvb_captured_length(next_tvb);
1817 eo_info->payload_data = tvb_get_ptr(next_tvb, 0, eo_info->payload_len);
1818
1819 tap_queue_packet(http_eo_tap, pinfo, eo_info);
1820 }
1821
1822 /* Save values for the Export Object GUI feature if we have
1823 * an active listener to process it (which happens when
1824 * the export object window is open). */
1825 if(have_tap_listener(http_follow_tap)) {
1826 tap_queue_packet(http_follow_tap, pinfo, next_tvb);
1827 }
1828 file_data = tvb_get_string_enc(wmem_packet_scope(), next_tvb, 0, tvb_captured_length(next_tvb), ENC_ASCII);
1829 proto_tree_add_string_format_value(http_tree, hf_http_file_data,
1830 next_tvb, 0, tvb_captured_length(next_tvb), file_data, "%u bytes", tvb_captured_length(next_tvb));
1831
1832 if (tvb_captured_length(next_tvb) == 0)
1833 goto body_dissected;
1834
1835 /*
1836 * Do subdissector checks.
1837 *
1838 * First, if we have a Content-Type value, check whether
1839 * there's a subdissector for that media type.
1840 */
1841 handle = NULL;
1842 if (headers.content_type != NULL) {
1843 /*
1844 * We didn't find any subdissector that
1845 * registered for the port, and we have a
1846 * Content-Type value. Is there any subdissector
1847 * for that content type?
1848 */
1849 if (headers.content_type_parameters)
1850 media_str = wmem_strdup(wmem_packet_scope(), headers.content_type_parameters);
1851
1852 /*
1853 * Calling the string handle for the media type
1854 * dissector table will set pinfo->match_string
1855 * to headers.content_type for us.
1856 */
1857 pinfo->match_string = headers.content_type;
1858 handle = dissector_get_string_handle(
1859 media_type_subdissector_table,
1860 headers.content_type);
1861 if (handle == NULL &&
1862 strncmp(headers.content_type, "multipart/", sizeof("multipart/")-1) == 0) {
1863 /* Try to decode the unknown multipart subtype anyway */
1864 handle = dissector_get_string_handle(
1865 media_type_subdissector_table,
1866 "multipart/");
1867 }
1868 }
1869
1870 /*
1871 * Now, if we didn't find such a subdissector, check
1872 * whether some subdissector asked that they be called
1873 * if HTTP traffic was on some particular port. This
1874 * handles protocols that use HTTP syntax but don't have
1875 * a media type and instead use a specified port.
1876 */
1877 if (handle == NULL) {
1878 handle = dissector_get_uint_handle(port_subdissector_table,
1879 pinfo->match_uint);
1880 }
1881
1882 message_info.type = http_type;
1883 message_info.media_str = media_str;
1884 if (handle != NULL) {
1885 /*
1886 * We have a subdissector - call it.
1887 */
1888 dissected = call_dissector_only(handle, next_tvb, pinfo, tree, &message_info);
1889 if (!dissected)
1890 expert_add_info(pinfo, http_tree, &ei_http_subdissector_failed);
1891 }
1892
1893 if (!dissected) {
1894 /*
1895 * We don't have a subdissector or we have one and it did not
1896 * dissect the payload - try the heuristic subdissectors.
1897 */
1898 dissected = dissector_try_heuristic(heur_subdissector_list,
1899 next_tvb, pinfo, tree, &hdtbl_entry, NULL);
1900 }
1901
1902 if (dissected) {
1903 /*
1904 * The subdissector dissected the body.
1905 * Fix up the top-level item so that it doesn't
1906 * include the stuff for that protocol.
1907 */
1908 if (ti != NULL)
1909 proto_item_set_len(ti, offset);
1910 } else {
1911 if (headers.content_type != NULL) {
1912 /*
1913 * Calling the default media handle if there is a content-type that
1914 * wasn't handled above.
1915 */
1916 call_dissector_with_data(media_handle, next_tvb, pinfo, tree, &message_info);
1917 } else {
1918 /* Call the default data dissector */
1919 call_data_dissector(next_tvb, pinfo, http_tree);
1920 }
1921 }
1922
1923 body_dissected:
1924 /*
1925 * We've processed "datalen" bytes worth of data
1926 * (which may be no data at all); advance the
1927 * offset past whatever data we've processed.
1928 */
1929 offset += datalen;
1930 }
1931
1932 /* Detect protocol changes after receiving full response headers. */
1933 if (conv_data->request_method && http_type == HTTP_RESPONSE && pinfo->desegment_offset <= 0 && pinfo->desegment_len <= 0) {
1934 dissector_handle_t next_handle = NULL;
1935 gboolean server_acked = FALSE;
1936
1937 /*
1938 * SSTP uses a special request method (instead of the Upgrade
1939 * header) and expects a 200 response to set up the session.
1940 */
1941 if (strcmp(conv_data->request_method, "SSTP_DUPLEX_POST") == 0 && conv_data->response_code == 200) {
1942 next_handle = sstp_handle;
1943 server_acked = TRUE;
1944 }
1945
1946 /*
1947 * An HTTP/1.1 upgrade only proceeds if the server responds
1948 * with 101 Switching Protocols. See RFC 7230 Section 6.7.
1949 */
1950 if (headers.upgrade && conv_data->response_code == 101) {
1951 next_handle = dissector_get_string_handle(upgrade_subdissector_table, headers.upgrade);
1952 if (!next_handle) {
1953 char *slash_pos = strchr(headers.upgrade, '/');
1954 if (slash_pos) {
1955 /* Try again without version suffix. */
1956 next_handle = dissector_get_string_handle(upgrade_subdissector_table,
1957 wmem_strndup(wmem_packet_scope(), headers.upgrade, slash_pos - headers.upgrade));
1958 }
1959 }
1960 server_acked = TRUE;
1961 }
1962
1963 if (server_acked) {
1964 conv_data->startframe = pinfo->num;
1965 conv_data->startoffset = offset;
1966 conv_data->next_handle = next_handle;
1967 copy_address_wmem(wmem_file_scope(), &conv_data->server_addr, &pinfo->src);
1968 conv_data->server_port = pinfo->srcport;
1969 }
1970 }
1971
1972 tap_queue_packet(http_tap, pinfo, stat_info);
1973
1974 return offset - orig_offset;
1975 }
1976
1977 /* This can be used to dissect an HTTP request until such time
1978 * that a more complete dissector is written for that HTTP request.
1979 * This simple dissector only puts the request method, URI, and
1980 * protocol version into a sub-tree.
1981 */
1982 static void
basic_request_dissector(tvbuff_t * tvb,proto_tree * tree,int offset,const guchar * line,const guchar * lineend,http_conv_t * conv_data)1983 basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
1984 const guchar *line, const guchar *lineend,
1985 http_conv_t *conv_data)
1986 {
1987 const guchar *next_token;
1988 const gchar *request_uri;
1989 gchar *query_str, *parameter_str, *path_str;
1990 int request_uri_len, query_str_len, parameter_str_len;
1991 int tokenlen, query_offset, path_len;
1992 proto_item *ti, *tj;
1993 proto_tree *query_tree, *path_tree;
1994
1995 /* The first token is the method. */
1996 tokenlen = get_token_len(line, lineend, &next_token);
1997 if (tokenlen == 0)
1998 return;
1999 proto_tree_add_item(tree, hf_http_request_method, tvb, offset, tokenlen,
2000 ENC_ASCII|ENC_NA);
2001 if ((next_token - line) > 2 && next_token[-1] == ' ' && next_token[-2] == ' ') {
2002 /* Two spaces in a now indicates empty URI, so roll back one here */
2003 next_token--;
2004 }
2005 offset += (int) (next_token - line);
2006 line = next_token;
2007
2008 /* The next token is the URI. */
2009 tokenlen = get_token_len(line, lineend, &next_token);
2010
2011 /* Save the request URI for various later uses */
2012 request_uri = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tokenlen, ENC_ASCII);
2013 stat_info->request_uri = wmem_strdup(wmem_packet_scope(), request_uri);
2014 conv_data->request_uri = wmem_strdup(wmem_file_scope(), request_uri);
2015
2016 tj = proto_tree_add_string(tree, hf_http_request_uri, tvb, offset, tokenlen, request_uri);
2017 if (( query_str = strchr(request_uri, '?')) != NULL) {
2018 if (strlen(query_str) > 1) {
2019 query_str++;
2020 query_str_len = (int)strlen(query_str);
2021 request_uri_len = (int)strlen(request_uri);
2022 path_len = request_uri_len - query_str_len;
2023 query_offset = offset + path_len;
2024 path_tree = proto_item_add_subtree(tj, ett_http_request_path);
2025 path_str = wmem_strndup(wmem_packet_scope(), request_uri, path_len-1);
2026 proto_tree_add_string(path_tree, hf_http_request_path, tvb, offset, path_len-1, path_str);
2027 ti = proto_tree_add_string(path_tree, hf_http_request_query, tvb, query_offset, query_str_len, query_str);
2028 query_tree = proto_item_add_subtree(ti, ett_http_request_query);
2029 for ( parameter_str = strtok(query_str, "&"); parameter_str; parameter_str = strtok(NULL, "&") ) {
2030 parameter_str_len = (int) strlen(parameter_str);
2031 proto_tree_add_string(query_tree, hf_http_request_query_parameter, tvb, query_offset, parameter_str_len, parameter_str);
2032 query_offset += parameter_str_len + 1;
2033 }
2034 }
2035 }
2036 offset += (int) (next_token - line);
2037 line = next_token;
2038
2039 /* Everything to the end of the line is the version. */
2040 tokenlen = (int) (lineend - line);
2041 proto_tree_add_item(tree, hf_http_request_version, tvb, offset, tokenlen,
2042 ENC_ASCII|ENC_NA);
2043 }
2044
2045 static gint
parse_http_status_code(const guchar * line,const guchar * lineend)2046 parse_http_status_code(const guchar *line, const guchar *lineend)
2047 {
2048 const guchar *next_token;
2049 int tokenlen;
2050 gchar response_code_chars[4];
2051 gint32 status_code = 0;
2052
2053 /*
2054 * The first token is the HTTP Version.
2055 */
2056 tokenlen = get_token_len(line, lineend, &next_token);
2057 if (tokenlen == 0)
2058 return 0;
2059 line = next_token;
2060
2061 /*
2062 * The second token is the Status Code.
2063 */
2064 tokenlen = get_token_len(line, lineend, &next_token);
2065 if (tokenlen != 3)
2066 return 0;
2067
2068 memcpy(response_code_chars, line, 3);
2069 response_code_chars[3] = '\0';
2070 if (!ws_strtoi32(response_code_chars, NULL, &status_code))
2071 return 0;
2072
2073 return status_code;
2074 }
2075
2076 static void
basic_response_dissector(tvbuff_t * tvb,proto_tree * tree,int offset,const guchar * line,const guchar * lineend,http_conv_t * conv_data _U_)2077 basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
2078 const guchar *line, const guchar *lineend,
2079 http_conv_t *conv_data _U_)
2080 {
2081 const guchar *next_token;
2082 int tokenlen;
2083 gchar response_code_chars[4];
2084 proto_item *r_ti;
2085
2086 /*
2087 * The first token is the HTTP Version.
2088 */
2089 tokenlen = get_token_len(line, lineend, &next_token);
2090 if (tokenlen == 0)
2091 return;
2092 proto_tree_add_item(tree, hf_http_response_version, tvb, offset, tokenlen,
2093 ENC_ASCII|ENC_NA);
2094 /* Advance to the start of the next token. */
2095 offset += (int) (next_token - line);
2096 line = next_token;
2097
2098 /*
2099 * The second token is the Status Code.
2100 */
2101 tokenlen = get_token_len(line, lineend, &next_token);
2102 if (tokenlen < 3)
2103 return;
2104
2105 /* The Status Code characters must be copied into a null-terminated
2106 * buffer for strtoul() to parse them into an unsigned integer value.
2107 */
2108 memcpy(response_code_chars, line, 3);
2109 response_code_chars[3] = '\0';
2110
2111 stat_info->response_code = conv_data->response_code =
2112 (guint)strtoul(response_code_chars, NULL, 10);
2113
2114 proto_tree_add_uint(tree, hf_http_response_code, tvb, offset, 3,
2115 stat_info->response_code);
2116
2117 r_ti = proto_tree_add_string(tree, hf_http_response_code_desc,
2118 tvb, offset, 3, val_to_str(stat_info->response_code,
2119 vals_http_status_code, "Unknown (%d)"));
2120
2121 proto_item_set_generated(r_ti);
2122
2123 /* Advance to the start of the next token. */
2124 offset += (int) (next_token - line);
2125 line = next_token;
2126
2127 /*
2128 * The remaining tokens in the line comprise the Reason Phrase.
2129 */
2130 tokenlen = (int) (lineend - line);
2131 if (tokenlen >= 1) {
2132 proto_tree_add_item(tree, hf_http_response_phrase, tvb, offset,
2133 tokenlen, ENC_ASCII|ENC_NA);
2134 }
2135 }
2136
2137 #if 0 /* XXX: Replaced by code creating the "Dechunked" tvb O(N) rather than O(N^2) */
2138 /*
2139 * Dissect the http data chunks and add them to the tree.
2140 */
2141 static int
2142 chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
2143 proto_tree *tree, int offset)
2144 {
2145 guint8 *chunk_string = NULL;
2146 guint32 chunk_size = 0;
2147 gint chunk_offset = 0;
2148 guint32 datalen = 0;
2149 gint linelen = 0;
2150 gint chunks_decoded = 0;
2151 tvbuff_t *tvb = NULL;
2152 tvbuff_t *new_tvb = NULL;
2153 gint chunked_data_size = 0;
2154 proto_tree *subtree;
2155 proto_item *ti;
2156
2157 if (tvb_ptr == NULL || *tvb_ptr == NULL) {
2158 return 0;
2159 }
2160
2161 tvb = *tvb_ptr;
2162
2163 datalen = tvb_reported_length_remaining(tvb, offset);
2164
2165 subtree = proto_tree_add_subtree(tree, tvb, offset, datalen,
2166 ett_http_chunked_response, NULL, "HTTP chunked response");
2167
2168 while (datalen > 0) {
2169 proto_item *chunk_ti = NULL, *chuck_size_item;
2170 proto_tree *chunk_subtree = NULL;
2171 tvbuff_t *data_tvb = NULL; /* */
2172 gchar *c = NULL;
2173 guint8 *raw_data;
2174 gint raw_len = 0;
2175
2176 linelen = tvb_find_line_end(tvb, offset, -1, &chunk_offset, TRUE);
2177
2178 if (linelen <= 0) {
2179 /* Can't get the chunk size line */
2180 break;
2181 }
2182
2183 chunk_string = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, linelen, ENC_ASCII);
2184
2185 if (chunk_string == NULL) {
2186 /* Can't get the chunk size line */
2187 break;
2188 }
2189
2190 c = (gchar*) chunk_string;
2191
2192 /*
2193 * We don't care about the extensions.
2194 */
2195 if ((c = strchr(c, ';'))) {
2196 *c = '\0';
2197 }
2198
2199 chunk_size = (guint32)strtol((gchar*)chunk_string, NULL, 16);
2200
2201 if (chunk_size > datalen) {
2202 /*
2203 * The chunk size is more than what's in the tvbuff,
2204 * so either the user hasn't enabled decoding, or all
2205 * of the segments weren't captured.
2206 */
2207 chunk_size = datalen;
2208 }
2209 #if 0
2210 else if (new_tvb == NULL) {
2211 new_tvb = tvb_new_composite();
2212 }
2213
2214
2215
2216 if (new_tvb != NULL && chunk_size != 0) {
2217 tvbuff_t *chunk_tvb = NULL;
2218
2219 chunk_tvb = tvb_new_subset_length_caplen(tvb, chunk_offset,
2220 chunk_size, datalen);
2221
2222 tvb_composite_append(new_tvb, chunk_tvb);
2223
2224 }
2225 #endif
2226
2227 chunked_data_size += chunk_size;
2228
2229 raw_data = wmem_alloc(pinfo->pool, chunked_data_size);
2230 raw_len = 0;
2231
2232 if (new_tvb != NULL) {
2233 raw_len = tvb_captured_length_remaining(new_tvb, 0);
2234 tvb_memcpy(new_tvb, raw_data, 0, raw_len);
2235
2236 tvb_free(new_tvb);
2237 }
2238
2239 tvb_memcpy(tvb, (guint8 *)(raw_data + raw_len),
2240 chunk_offset, chunk_size);
2241
2242 /* Don't create a new tvb if we have a single chunk with
2243 * a size of zero (meaning it is the end of the chunks). */
2244 if(chunked_data_size > 0) {
2245 new_tvb = tvb_new_real_data(raw_data,
2246 chunked_data_size, chunked_data_size);
2247 }
2248
2249
2250 if (subtree) {
2251 if(chunk_size == 0) {
2252 chunk_subtree = proto_tree_add_subtree(subtree, tvb,
2253 offset, chunk_offset - offset + chunk_size + 2,
2254 ett_http_chunk_data, NULL, "End of chunked encoding");
2255 } else {
2256 chunk_subtree = proto_tree_add_subtree_format(subtree, tvb,
2257 offset,
2258 chunk_offset - offset + chunk_size + 2,
2259 ett_http_chunk_data, NULL, "Data chunk (%u octets)", chunk_size);
2260 }
2261
2262 chuck_size_item = proto_tree_add_uint(chunk_subtree, hf_http_chunk_size, tvb, offset,
2263 1, chunk_size);
2264 proto_item_set_len(chuck_size_item, chunk_offset - offset);
2265
2266 /*
2267 * XXX - just add the chunk's data as an item?
2268 *
2269 * Using the data dissector means that, in
2270 * TShark, you get the entire chunk dumped
2271 * out in hex, in addition to whatever
2272 * dissection is done on the reassembled data.
2273 */
2274 data_tvb = tvb_new_subset_length(tvb, chunk_offset, chunk_size);
2275 call_data_dissector(data_tvb, pinfo, chunk_subtree);
2276
2277 proto_tree_add_item(chunk_subtree, hf_http_chunked_boundary, tvb,
2278 chunk_offset + chunk_size, 2, ENC_NA);
2279 }
2280
2281 chunks_decoded++;
2282 offset = chunk_offset + chunk_size + 2;
2283 datalen = tvb_reported_length_remaining(tvb, offset);
2284 }
2285
2286 if (new_tvb != NULL) {
2287
2288 /* Placeholder for the day that composite tvbuffer's will work.
2289 tvb_composite_finalize(new_tvb);
2290 / * tvb_set_reported_length(new_tvb, chunked_data_size); * /
2291 */
2292
2293 /*
2294 * XXX - Don't free this, since the tvbuffer that was passed
2295 * may be used if the data spans multiple frames and reassembly
2296 * isn't enabled.
2297 *
2298 tvb_free(*tvb_ptr);
2299 */
2300 *tvb_ptr = new_tvb;
2301
2302 } else {
2303 /*
2304 * We didn't create a new tvb, so don't allow sub dissectors
2305 * try to decode the non-existent entity body.
2306 */
2307 chunks_decoded = -1;
2308 }
2309
2310 return chunks_decoded;
2311
2312 }
2313 #else
2314 /*
2315 * Dissect the http data chunks and add them to the tree.
2316 */
2317 static guint
chunked_encoding_dissector(tvbuff_t ** tvb_ptr,packet_info * pinfo,proto_tree * tree,int offset)2318 chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
2319 proto_tree *tree, int offset)
2320 {
2321 tvbuff_t *tvb;
2322 guint32 datalen;
2323 guint32 orig_datalen;
2324 gint chunked_data_size;
2325 proto_tree *subtree;
2326 proto_item *pi_chunked = NULL;
2327 guint8 *raw_data;
2328 gint raw_len;
2329
2330 if ((tvb_ptr == NULL) || (*tvb_ptr == NULL)) {
2331 return 0;
2332 }
2333
2334 tvb = *tvb_ptr;
2335
2336 datalen = tvb_reported_length_remaining(tvb, offset);
2337
2338 subtree = proto_tree_add_subtree(tree, tvb, offset, datalen,
2339 ett_http_chunked_response, &pi_chunked,
2340 "HTTP chunked response");
2341
2342 /* Dechunk the "chunked response" to a new memory buffer */
2343 orig_datalen = datalen;
2344 raw_data = (guint8 *)wmem_alloc(pinfo->pool, datalen);
2345 raw_len = 0;
2346 chunked_data_size = 0;
2347
2348 while (datalen > 0) {
2349 tvbuff_t *data_tvb;
2350 guint32 chunk_size;
2351 gint chunk_offset;
2352 guint8 *chunk_string;
2353 gint linelen;
2354 gchar *c;
2355
2356 linelen = tvb_find_line_end(tvb, offset, -1, &chunk_offset, TRUE);
2357
2358 if (linelen <= 0) {
2359 /* Can't get the chunk size line */
2360 break;
2361 }
2362
2363 chunk_string = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, linelen, ENC_ASCII);
2364
2365 if (chunk_string == NULL) {
2366 /* Can't get the chunk size line */
2367 break;
2368 }
2369
2370 c = (gchar*)chunk_string;
2371
2372 /*
2373 * We don't care about the extensions.
2374 */
2375 if ((c = strchr(c, ';'))) {
2376 *c = '\0';
2377 }
2378
2379 chunk_size = (guint32)strtol((gchar*)chunk_string, NULL, 16);
2380
2381 if (chunk_size > datalen) {
2382 /*
2383 * The chunk size is more than what's in the tvbuff,
2384 * so either the user hasn't enabled decoding, or all
2385 * of the segments weren't captured.
2386 */
2387 chunk_size = datalen;
2388 }
2389
2390 chunked_data_size += chunk_size;
2391
2392 DISSECTOR_ASSERT((raw_len+chunk_size) <= orig_datalen);
2393 tvb_memcpy(tvb, (guint8 *)(raw_data + raw_len), chunk_offset, chunk_size);
2394 raw_len += chunk_size;
2395
2396 if (subtree) {
2397 proto_tree *chunk_subtree;
2398 proto_item *chunk_size_item;
2399
2400 if(chunk_size == 0) {
2401 chunk_subtree = proto_tree_add_subtree(subtree, tvb,
2402 offset,
2403 chunk_offset - offset + chunk_size + 2,
2404 ett_http_chunk_data, NULL,
2405 "End of chunked encoding");
2406 } else {
2407 chunk_subtree = proto_tree_add_subtree_format(subtree, tvb,
2408 offset,
2409 chunk_offset - offset + chunk_size + 2,
2410 ett_http_chunk_data, NULL,
2411 "Data chunk (%u octets)", chunk_size);
2412 }
2413
2414 chunk_size_item = proto_tree_add_uint(chunk_subtree, hf_http_chunk_size, tvb, offset,
2415 1, chunk_size);
2416 proto_item_set_len(chunk_size_item, chunk_offset - offset);
2417
2418 /* last-chunk does not have chunk-data CRLF. */
2419 if (chunk_size > 0) {
2420 /*
2421 * XXX - just add the chunk's data as an item?
2422 *
2423 * Using the data dissector means that, in
2424 * TShark, you get the entire chunk dumped
2425 * out in hex, in addition to whatever
2426 * dissection is done on the reassembled data.
2427 */
2428 data_tvb = tvb_new_subset_length(tvb, chunk_offset, chunk_size);
2429 call_data_dissector(data_tvb, pinfo, chunk_subtree);
2430
2431 proto_tree_add_item(chunk_subtree, hf_http_chunk_boundary, tvb,
2432 chunk_offset + chunk_size, 2, ENC_NA);
2433 }
2434 }
2435
2436 offset = chunk_offset + chunk_size; /* beginning of next chunk */
2437 if (chunk_size > 0) offset += 2; /* CRLF of chunk */
2438 datalen = tvb_reported_length_remaining(tvb, offset);
2439
2440 /* This is the last chunk */
2441 if (chunk_size == 0) {
2442 /* Check for: trailer-part CRLF.
2443 * trailer-part = *( header-field CRLF ) */
2444 gint trailer_offset = offset, trailer_len;
2445 gint header_field_len;
2446 /* Skip all header-fields. */
2447 do {
2448 trailer_len = trailer_offset - offset;
2449 header_field_len = tvb_find_line_end(tvb,
2450 trailer_offset,
2451 datalen - trailer_len,
2452 &trailer_offset, TRUE);
2453 } while (header_field_len > 0);
2454 if (trailer_len > 0) {
2455 proto_tree_add_item(subtree,
2456 hf_http_chunked_trailer_part,
2457 tvb, offset, trailer_len, ENC_ASCII|ENC_NA);
2458 offset += trailer_len;
2459 datalen -= trailer_len;
2460 }
2461
2462 /* last CRLF of chunked-body is found. */
2463 if (header_field_len == 0) {
2464 proto_tree_add_format_text(subtree, tvb, offset,
2465 trailer_offset - offset);
2466 datalen -= trailer_offset - offset;
2467 }
2468 break;
2469 }
2470 }
2471
2472 /* datalen is the remaining bytes that are available for consumption. If
2473 * smaller than orig_datalen, then bytes were consumed. */
2474 if (datalen < orig_datalen) {
2475 tvbuff_t *new_tvb;
2476 proto_item_set_len(pi_chunked, orig_datalen - datalen);
2477 new_tvb = tvb_new_child_real_data(tvb, raw_data, chunked_data_size, chunked_data_size);
2478 *tvb_ptr = new_tvb;
2479 }
2480
2481 /* Size of chunked-body or 0 if none was found. */
2482 return orig_datalen - datalen;
2483 }
2484 #endif
2485
2486 static gboolean
conversation_dissector_is_http(conversation_t * conv,guint32 frame_num)2487 conversation_dissector_is_http(conversation_t *conv, guint32 frame_num)
2488 {
2489 dissector_handle_t conv_handle;
2490
2491 if (conv == NULL)
2492 return FALSE;
2493 conv_handle = conversation_get_dissector(conv, frame_num);
2494 return conv_handle == http_handle ||
2495 conv_handle == http_tcp_handle ||
2496 conv_handle == http_sctp_handle;
2497 }
2498
2499 /* Call a subdissector to handle HTTP CONNECT's traffic */
2500 static void
http_payload_subdissector(tvbuff_t * tvb,proto_tree * tree,packet_info * pinfo,http_conv_t * conv_data,void * data)2501 http_payload_subdissector(tvbuff_t *tvb, proto_tree *tree,
2502 packet_info *pinfo, http_conv_t *conv_data, void* data)
2503 {
2504 guint32 *ptr = NULL;
2505 guint32 uri_port, saved_port, srcport, destport;
2506 gchar **strings; /* An array for splitting the request URI into hostname and port */
2507 proto_item *item;
2508 proto_tree *proxy_tree;
2509 conversation_t *conv;
2510 gboolean from_server = pinfo->srcport == conv_data->server_port &&
2511 addresses_equal(&conv_data->server_addr, &pinfo->src);
2512
2513 /* Grab the destination port number from the request URI to find the right subdissector */
2514 strings = wmem_strsplit(wmem_packet_scope(), conv_data->request_uri, ":", 2);
2515
2516 if(strings[0] != NULL && strings[1] != NULL) {
2517 /*
2518 * The string was successfully split in two
2519 * Create a proxy-connect subtree
2520 */
2521 if(tree) {
2522 item = proto_tree_add_item(tree, proto_http, tvb, 0, -1, ENC_NA);
2523 proxy_tree = proto_item_add_subtree(item, ett_http);
2524
2525 item = proto_tree_add_string(proxy_tree, hf_http_proxy_connect_host,
2526 tvb, 0, 0, strings[0]);
2527 proto_item_set_generated(item);
2528
2529 item = proto_tree_add_uint(proxy_tree, hf_http_proxy_connect_port,
2530 tvb, 0, 0, (guint32)strtol(strings[1], NULL, 10) );
2531 proto_item_set_generated(item);
2532 }
2533
2534 uri_port = (int)strtol(strings[1], NULL, 10); /* Convert string to a base-10 integer */
2535
2536 if (!from_server) {
2537 srcport = pinfo->srcport;
2538 destport = uri_port;
2539 } else {
2540 srcport = uri_port;
2541 destport = pinfo->destport;
2542 }
2543
2544 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_TCP, srcport, destport, 0);
2545
2546 /* We may get stuck in a recursion loop if we let process_tcp_payload() call us.
2547 * So, if the port in the URI is one we're registered for or we have set up a
2548 * conversation (e.g., one we detected heuristically or via Decode-As) call the data
2549 * dissector directly.
2550 */
2551 if (value_is_in_range(http_tcp_range, uri_port) ||
2552 conversation_dissector_is_http(conv, pinfo->num)) {
2553 call_data_dissector(tvb, pinfo, tree);
2554 } else {
2555 /* set pinfo->{src/dst port} and call the TCP sub-dissector lookup */
2556 if (!from_server)
2557 ptr = &pinfo->destport;
2558 else
2559 ptr = &pinfo->srcport;
2560
2561 /* Increase pinfo->can_desegment because we are traversing
2562 * http and want to preserve desegmentation functionality for
2563 * the proxied protocol
2564 */
2565 if( pinfo->can_desegment>0 )
2566 pinfo->can_desegment++;
2567
2568 saved_port = *ptr;
2569 *ptr = uri_port;
2570 decode_tcp_ports(tvb, 0, pinfo, tree,
2571 pinfo->srcport, pinfo->destport, NULL,
2572 (struct tcpinfo *)data);
2573 *ptr = saved_port;
2574 }
2575 }
2576 }
2577
2578
2579
2580 /*
2581 * XXX - this won't handle HTTP 0.9 replies, but they're all data
2582 * anyway.
2583 */
2584 static int
is_http_request_or_reply(const gchar * data,int linelen,http_type_t * type,ReqRespDissector * reqresp_dissector,http_conv_t * conv_data)2585 is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
2586 ReqRespDissector *reqresp_dissector,
2587 http_conv_t *conv_data)
2588 {
2589 int isHttpRequestOrReply = FALSE;
2590
2591 /*
2592 * From RFC 2774 - An HTTP Extension Framework
2593 *
2594 * Support the command prefix that identifies the presence of
2595 * a "mandatory" header.
2596 */
2597 if (linelen >= 2 && strncmp(data, "M-", 2) == 0) {
2598 data += 2;
2599 linelen -= 2;
2600 }
2601
2602 /*
2603 * From draft-cohen-gena-client-01.txt, available from the uPnP forum:
2604 * NOTIFY, SUBSCRIBE, UNSUBSCRIBE
2605 *
2606 * From draft-ietf-dasl-protocol-00.txt, a now vanished Microsoft draft:
2607 * SEARCH
2608 */
2609 if ((linelen >= 5 && strncmp(data, "HTTP/", 5) == 0) ||
2610 (linelen >= 3 && strncmp(data, "ICY", 3) == 0)) {
2611 *type = HTTP_RESPONSE;
2612 isHttpRequestOrReply = TRUE; /* response */
2613 if (reqresp_dissector)
2614 *reqresp_dissector = basic_response_dissector;
2615 } else {
2616 const guchar * ptr = (const guchar *)data;
2617 int indx = 0;
2618
2619 /* Look for the space following the Method */
2620 while (indx < linelen) {
2621 if (*ptr == ' ')
2622 break;
2623 else {
2624 ptr++;
2625 indx++;
2626 }
2627 }
2628
2629 /* Check the methods that have same length */
2630 switch (indx) {
2631
2632 case 3:
2633 if (strncmp(data, "GET", indx) == 0 ||
2634 strncmp(data, "PUT", indx) == 0) {
2635 *type = HTTP_REQUEST;
2636 isHttpRequestOrReply = TRUE;
2637 }
2638 break;
2639
2640 case 4:
2641 if (strncmp(data, "COPY", indx) == 0 ||
2642 strncmp(data, "HEAD", indx) == 0 ||
2643 strncmp(data, "LOCK", indx) == 0 ||
2644 strncmp(data, "MOVE", indx) == 0 ||
2645 strncmp(data, "POLL", indx) == 0 ||
2646 strncmp(data, "POST", indx) == 0) {
2647 *type = HTTP_REQUEST;
2648 isHttpRequestOrReply = TRUE;
2649 }
2650 break;
2651
2652 case 5:
2653 if (strncmp(data, "BCOPY", indx) == 0 ||
2654 strncmp(data, "BMOVE", indx) == 0 ||
2655 strncmp(data, "MKCOL", indx) == 0 ||
2656 strncmp(data, "TRACE", indx) == 0 ||
2657 strncmp(data, "PATCH", indx) == 0 || /* RFC 5789 */
2658 strncmp(data, "LABEL", indx) == 0 || /* RFC 3253 8.2 */
2659 strncmp(data, "MERGE", indx) == 0) { /* RFC 3253 11.2 */
2660 *type = HTTP_REQUEST;
2661 isHttpRequestOrReply = TRUE;
2662 }
2663 break;
2664
2665 case 6:
2666 if (strncmp(data, "DELETE", indx) == 0 ||
2667 strncmp(data, "SEARCH", indx) == 0 ||
2668 strncmp(data, "UNLOCK", indx) == 0 ||
2669 strncmp(data, "REPORT", indx) == 0 || /* RFC 3253 3.6 */
2670 strncmp(data, "UPDATE", indx) == 0) { /* RFC 3253 7.1 */
2671 *type = HTTP_REQUEST;
2672 isHttpRequestOrReply = TRUE;
2673 }
2674 else if (strncmp(data, "NOTIFY", indx) == 0) {
2675 *type = HTTP_NOTIFICATION;
2676 isHttpRequestOrReply = TRUE;
2677 }
2678 break;
2679
2680 case 7:
2681 if (strncmp(data, "BDELETE", indx) == 0 ||
2682 strncmp(data, "CONNECT", indx) == 0 ||
2683 strncmp(data, "OPTIONS", indx) == 0 ||
2684 strncmp(data, "CHECKIN", indx) == 0) { /* RFC 3253 4.4, 9.4 */
2685 *type = HTTP_REQUEST;
2686 isHttpRequestOrReply = TRUE;
2687 }
2688 break;
2689
2690 case 8:
2691 if (strncmp(data, "PROPFIND", indx) == 0 ||
2692 strncmp(data, "CHECKOUT", indx) == 0 || /* RFC 3253 4.3, 9.3 */
2693 strncmp(data, "CCM_POST", indx) == 0) {
2694 *type = HTTP_REQUEST;
2695 isHttpRequestOrReply = TRUE;
2696 }
2697 break;
2698
2699 case 9:
2700 if (strncmp(data, "SUBSCRIBE", indx) == 0) {
2701 *type = HTTP_NOTIFICATION;
2702 isHttpRequestOrReply = TRUE;
2703 } else if (strncmp(data, "PROPPATCH", indx) == 0 ||
2704 strncmp(data, "BPROPFIND", indx) == 0) {
2705 *type = HTTP_REQUEST;
2706 isHttpRequestOrReply = TRUE;
2707 }
2708 break;
2709
2710 case 10:
2711 if (strncmp(data, "BPROPPATCH", indx) == 0 ||
2712 strncmp(data, "UNCHECKOUT", indx) == 0 || /* RFC 3253 4.5 */
2713 strncmp(data, "MKACTIVITY", indx) == 0) { /* RFC 3253 13.5 */
2714 *type = HTTP_REQUEST;
2715 isHttpRequestOrReply = TRUE;
2716 }
2717 break;
2718
2719 case 11:
2720 if (strncmp(data, "MKWORKSPACE", indx) == 0 || /* RFC 3253 6.3 */
2721 strncmp(data, "RPC_CONNECT", indx) == 0 || /* [MS-RPCH] 2.1.1.1.1 */
2722 strncmp(data, "RPC_IN_DATA", indx) == 0) { /* [MS-RPCH] 2.1.2.1.1 */
2723 *type = HTTP_REQUEST;
2724 isHttpRequestOrReply = TRUE;
2725 } else if (strncmp(data, "UNSUBSCRIBE", indx) == 0) {
2726 *type = HTTP_NOTIFICATION;
2727 isHttpRequestOrReply = TRUE;
2728 }
2729 break;
2730
2731 case 12:
2732 if (strncmp(data, "RPC_OUT_DATA", indx) == 0) { /* [MS-RPCH] 2.1.2.1.2 */
2733 *type = HTTP_REQUEST;
2734 isHttpRequestOrReply = TRUE;
2735 }
2736 break;
2737
2738 case 15:
2739 if (strncmp(data, "VERSION-CONTROL", indx) == 0) { /* RFC 3253 3.5 */
2740 *type = HTTP_REQUEST;
2741 isHttpRequestOrReply = TRUE;
2742 }
2743 break;
2744
2745 case 16:
2746 if (strncmp(data, "BASELINE-CONTROL", indx) == 0) { /* RFC 3253 12.6 */
2747 *type = HTTP_REQUEST;
2748 isHttpRequestOrReply = TRUE;
2749 } else if (strncmp(data, "SSTP_DUPLEX_POST", indx) == 0) { /* MS SSTP */
2750 *type = HTTP_REQUEST;
2751 isHttpRequestOrReply = TRUE;
2752 }
2753 break;
2754
2755 default:
2756 break;
2757 }
2758
2759 if (isHttpRequestOrReply && reqresp_dissector) {
2760 *reqresp_dissector = basic_request_dissector;
2761
2762 stat_info->request_method = wmem_strndup(wmem_packet_scope(), data, indx);
2763 conv_data->request_method = wmem_strndup(wmem_file_scope(), data, indx);
2764 }
2765
2766
2767
2768 }
2769
2770 return isHttpRequestOrReply;
2771 }
2772
2773 /*
2774 * Process headers.
2775 */
2776 typedef struct {
2777 const char *name;
2778 gint *hf;
2779 int special;
2780 } header_info;
2781
2782 #define HDR_NO_SPECIAL 0
2783 #define HDR_AUTHORIZATION 1
2784 #define HDR_AUTHENTICATE 2
2785 #define HDR_CONTENT_TYPE 3
2786 #define HDR_CONTENT_LENGTH 4
2787 #define HDR_CONTENT_ENCODING 5
2788 #define HDR_TRANSFER_ENCODING 6
2789 #define HDR_HOST 7
2790 #define HDR_UPGRADE 8
2791 #define HDR_COOKIE 9
2792 #define HDR_WEBSOCKET_PROTOCOL 10
2793 #define HDR_WEBSOCKET_EXTENSIONS 11
2794 #define HDR_REFERER 12
2795 #define HDR_LOCATION 13
2796 #define HDR_HTTP2_SETTINGS 14
2797
2798 static const header_info headers[] = {
2799 { "Authorization", &hf_http_authorization, HDR_AUTHORIZATION },
2800 { "Proxy-Authorization", &hf_http_proxy_authorization, HDR_AUTHORIZATION },
2801 { "Proxy-Authenticate", &hf_http_proxy_authenticate, HDR_AUTHENTICATE },
2802 { "WWW-Authenticate", &hf_http_www_authenticate, HDR_AUTHENTICATE },
2803 { "Content-Type", &hf_http_content_type, HDR_CONTENT_TYPE },
2804 { "Content-Length", &hf_http_content_length_header, HDR_CONTENT_LENGTH },
2805 { "Content-Encoding", &hf_http_content_encoding, HDR_CONTENT_ENCODING },
2806 { "Transfer-Encoding", &hf_http_transfer_encoding, HDR_TRANSFER_ENCODING },
2807 { "Upgrade", &hf_http_upgrade, HDR_UPGRADE },
2808 { "User-Agent", &hf_http_user_agent, HDR_NO_SPECIAL },
2809 { "Host", &hf_http_host, HDR_HOST },
2810 { "Connection", &hf_http_connection, HDR_NO_SPECIAL },
2811 { "Cookie", &hf_http_cookie, HDR_COOKIE },
2812 { "Accept", &hf_http_accept, HDR_NO_SPECIAL },
2813 { "Referer", &hf_http_referer, HDR_REFERER },
2814 { "Accept-Language", &hf_http_accept_language, HDR_NO_SPECIAL },
2815 { "Accept-Encoding", &hf_http_accept_encoding, HDR_NO_SPECIAL },
2816 { "Date", &hf_http_date, HDR_NO_SPECIAL },
2817 { "Cache-Control", &hf_http_cache_control, HDR_NO_SPECIAL },
2818 { "Server", &hf_http_server, HDR_NO_SPECIAL },
2819 { "Location", &hf_http_location, HDR_LOCATION },
2820 { "Sec-WebSocket-Accept", &hf_http_sec_websocket_accept, HDR_NO_SPECIAL },
2821 { "Sec-WebSocket-Extensions", &hf_http_sec_websocket_extensions, HDR_WEBSOCKET_EXTENSIONS },
2822 { "Sec-WebSocket-Key", &hf_http_sec_websocket_key, HDR_NO_SPECIAL },
2823 { "Sec-WebSocket-Protocol", &hf_http_sec_websocket_protocol, HDR_WEBSOCKET_PROTOCOL },
2824 { "Sec-WebSocket-Version", &hf_http_sec_websocket_version, HDR_NO_SPECIAL },
2825 { "Set-Cookie", &hf_http_set_cookie, HDR_NO_SPECIAL },
2826 { "Last-Modified", &hf_http_last_modified, HDR_NO_SPECIAL },
2827 { "X-Forwarded-For", &hf_http_x_forwarded_for, HDR_NO_SPECIAL },
2828 { "HTTP2-Settings", &hf_http_http2_settings, HDR_HTTP2_SETTINGS },
2829 };
2830
2831 /*
2832 * Look up a header name (assume lower-case header_name).
2833 */
2834 static gint*
get_hf_for_header(char * header_name)2835 get_hf_for_header(char* header_name)
2836 {
2837 gint* hf_id = NULL;
2838
2839 if (header_fields_hash) {
2840 hf_id = (gint*) g_hash_table_lookup(header_fields_hash, header_name);
2841 } else {
2842 hf_id = NULL;
2843 }
2844
2845 return hf_id;
2846 }
2847
2848 /*
2849 *
2850 */
2851 static void
deregister_header_fields(void)2852 deregister_header_fields(void)
2853 {
2854 if (dynamic_hf) {
2855 /* Deregister all fields */
2856 for (guint i = 0; i < dynamic_hf_size; i++) {
2857 proto_deregister_field (proto_http, *(dynamic_hf[i].p_id));
2858 g_free (dynamic_hf[i].p_id);
2859 }
2860
2861 proto_add_deregistered_data (dynamic_hf);
2862 dynamic_hf = NULL;
2863 dynamic_hf_size = 0;
2864 }
2865
2866 if (header_fields_hash) {
2867 g_hash_table_destroy (header_fields_hash);
2868 header_fields_hash = NULL;
2869 }
2870 }
2871
2872 static void
header_fields_post_update_cb(void)2873 header_fields_post_update_cb(void)
2874 {
2875 gint* hf_id;
2876 gchar* header_name;
2877 gchar* header_name_key;
2878
2879 deregister_header_fields();
2880
2881 if (num_header_fields) {
2882 header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
2883 dynamic_hf = g_new0(hf_register_info, num_header_fields);
2884 dynamic_hf_size = num_header_fields;
2885
2886 for (guint i = 0; i < dynamic_hf_size; i++) {
2887 hf_id = g_new(gint,1);
2888 *hf_id = -1;
2889 header_name = g_strdup(header_fields[i].header_name);
2890 header_name_key = g_ascii_strdown(header_name, -1);
2891
2892 dynamic_hf[i].p_id = hf_id;
2893 dynamic_hf[i].hfinfo.name = header_name;
2894 dynamic_hf[i].hfinfo.abbrev = g_strdup_printf("http.header.%s", header_name);
2895 dynamic_hf[i].hfinfo.type = FT_STRING;
2896 dynamic_hf[i].hfinfo.display = BASE_NONE;
2897 dynamic_hf[i].hfinfo.strings = NULL;
2898 dynamic_hf[i].hfinfo.bitmask = 0;
2899 dynamic_hf[i].hfinfo.blurb = g_strdup(header_fields[i].header_desc);
2900 HFILL_INIT(dynamic_hf[i]);
2901
2902 g_hash_table_insert(header_fields_hash, header_name_key, hf_id);
2903 }
2904
2905 proto_register_field_array(proto_http, dynamic_hf, dynamic_hf_size);
2906 }
2907 }
2908
2909 static void
header_fields_reset_cb(void)2910 header_fields_reset_cb(void)
2911 {
2912 deregister_header_fields();
2913 }
2914
2915 /**
2916 * Parses the transfer-coding, returning TRUE if everything was fully understood
2917 * or FALSE when unknown names were encountered.
2918 */
2919 static gboolean
http_parse_transfer_coding(const char * value,headers_t * eh_ptr)2920 http_parse_transfer_coding(const char *value, headers_t *eh_ptr)
2921 {
2922 gboolean is_fully_parsed = TRUE;
2923
2924 /* Mark header as set, but with unknown encoding. */
2925 eh_ptr->transfer_encoding = HTTP_TE_UNKNOWN;
2926
2927 while (*value) {
2928 /* skip OWS (SP / HTAB) and commas; stop at the end. */
2929 while (*value == ' ' || *value == '\t' || *value == ',')
2930 value++;
2931 if (!*value)
2932 break;
2933
2934 if (g_str_has_prefix(value, "chunked")) {
2935 eh_ptr->transfer_encoding_chunked = TRUE;
2936 value += sizeof("chunked") - 1;
2937 continue;
2938 }
2939
2940 /* For now assume that chunked can only combined with exactly
2941 * one other (compression) encoding. Anything else is
2942 * unsupported. */
2943 if (eh_ptr->transfer_encoding != HTTP_TE_UNKNOWN) {
2944 /* No more transfer codings are expected. */
2945 is_fully_parsed = FALSE;
2946 break;
2947 }
2948
2949 if (g_str_has_prefix(value, "compress")) {
2950 eh_ptr->transfer_encoding = HTTP_TE_COMPRESS;
2951 value += sizeof("compress") - 1;
2952 } else if (g_str_has_prefix(value, "deflate")) {
2953 eh_ptr->transfer_encoding = HTTP_TE_DEFLATE;
2954 value += sizeof("deflate") - 1;
2955 } else if (g_str_has_prefix(value, "gzip")) {
2956 eh_ptr->transfer_encoding = HTTP_TE_GZIP;
2957 value += sizeof("gzip") - 1;
2958 } else if (g_str_has_prefix(value, "identity")) {
2959 eh_ptr->transfer_encoding = HTTP_TE_IDENTITY;
2960 value += sizeof("identity") - 1;
2961 } else if (g_str_has_prefix(value, "x-compress")) {
2962 eh_ptr->transfer_encoding = HTTP_TE_COMPRESS;
2963 value += sizeof("x-compress") - 1;
2964 } else if (g_str_has_prefix(value, "x-gzip")) {
2965 eh_ptr->transfer_encoding = HTTP_TE_GZIP;
2966 value += sizeof("x-gzip") - 1;
2967 } else {
2968 /* Unknown transfer encoding, skip until next comma.
2969 * Stop when no more names are found. */
2970 is_fully_parsed = FALSE;
2971 value = strchr(value, ',');
2972 if (!value)
2973 break;
2974 }
2975 }
2976
2977 return is_fully_parsed;
2978 }
2979
2980 static gboolean
is_token_char(char c)2981 is_token_char(char c)
2982 {
2983 /* tchar according to https://tools.ietf.org/html/rfc7230#section-3.2.6 */
2984 return strchr("!#$%&\\:*+-.^_`|~", c) || g_ascii_isalnum(c);
2985 }
2986
2987 static void
process_header(tvbuff_t * tvb,int offset,int next_offset,const guchar * line,int linelen,int colon_offset,packet_info * pinfo,proto_tree * tree,headers_t * eh_ptr,http_conv_t * conv_data,http_type_t http_type)2988 process_header(tvbuff_t *tvb, int offset, int next_offset,
2989 const guchar *line, int linelen, int colon_offset,
2990 packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr,
2991 http_conv_t *conv_data, http_type_t http_type)
2992 {
2993 int len;
2994 int line_end_offset;
2995 int header_len;
2996 gint hf_index;
2997 guchar c;
2998 int value_offset;
2999 int value_len;
3000 char *value;
3001 char *header_name;
3002 char *p;
3003 guchar *up;
3004 proto_item *hdr_item, *it;
3005 int i;
3006 int* hf_id;
3007 tap_credential_t* auth;
3008
3009 len = next_offset - offset;
3010 line_end_offset = offset + linelen;
3011 header_len = colon_offset - offset;
3012
3013 /*
3014 * Validate the header name. This allows no space between the field name
3015 * and colon (RFC 7230, Section. 3.2.4).
3016 */
3017 gboolean valid_header_name = header_len != 0;
3018 if (valid_header_name) {
3019 for (i = 0; i < header_len; i++) {
3020 /*
3021 * NUL is not a valid character; treat it specially
3022 * due to C's notion that strings are NUL-terminated.
3023 */
3024 if (line[i] == '\0') {
3025 valid_header_name = FALSE;
3026 break;
3027 }
3028 if (!is_token_char(line[i])) {
3029 valid_header_name = FALSE;
3030 break;
3031 }
3032 }
3033 }
3034 /**
3035 * Not a valid header name? Just add a line plus expert info.
3036 */
3037 if (!valid_header_name) {
3038 if (http_type == HTTP_REQUEST) {
3039 hf_index = hf_http_request_line;
3040 } else if (http_type == HTTP_RESPONSE) {
3041 hf_index = hf_http_response_line;
3042 } else {
3043 hf_index = hf_http_unknown_header;
3044 }
3045 it = proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_NA|ENC_ASCII);
3046 proto_item_set_text(it, "%s", format_text(wmem_packet_scope(), line, len));
3047 expert_add_info(pinfo, it, &ei_http_bad_header_name);
3048 return;
3049 }
3050
3051 /*
3052 * Make a null-terminated, all-lower-case version of the header
3053 * name.
3054 */
3055 header_name = wmem_ascii_strdown(wmem_packet_scope(), &line[0], header_len);
3056
3057 hf_index = find_header_hf_value(tvb, offset, header_len);
3058
3059 /*
3060 * Skip whitespace after the colon.
3061 */
3062 value_offset = colon_offset + 1;
3063 while (value_offset < line_end_offset
3064 && ((c = line[value_offset - offset]) == ' ' || c == '\t'))
3065 value_offset++;
3066
3067 /*
3068 * Fetch the value.
3069 *
3070 * XXX - the line may well have a NUL in it. Wireshark should
3071 * really treat strings extracted from packets as counted
3072 * strings, so that NUL isn't any different from any other
3073 * character. For now, we just allocate a buffer that's
3074 * value_len+1 bytes long, copy value_len bytes, and stick
3075 * in a NUL terminator, so that the buffer for value actually
3076 * has value_len bytes in it.
3077 */
3078 value_len = line_end_offset - value_offset;
3079 value = (char *)wmem_alloc(wmem_packet_scope(), value_len+1);
3080 memcpy(value, &line[value_offset - offset], value_len);
3081 value[value_len] = '\0';
3082
3083 if (hf_index == -1) {
3084 /*
3085 * Not a header we know anything about.
3086 * Check if a HF generated from UAT information exists.
3087 */
3088 hf_id = get_hf_for_header(header_name);
3089
3090 if (tree) {
3091 if (!hf_id) {
3092 if (http_type == HTTP_REQUEST ||
3093 http_type == HTTP_RESPONSE) {
3094 it = proto_tree_add_item(tree,
3095 http_type == HTTP_RESPONSE ?
3096 hf_http_response_line :
3097 hf_http_request_line,
3098 tvb, offset, len,
3099 ENC_NA|ENC_ASCII);
3100 proto_item_set_text(it, "%s",
3101 format_text(wmem_packet_scope(), line, len));
3102 } else {
3103 gchar* str = format_text(wmem_packet_scope(), line, len);
3104 proto_tree_add_string_format(tree, hf_http_unknown_header, tvb, offset,
3105 len, str, "%s", str);
3106 }
3107
3108 } else {
3109 proto_tree_add_string_format(tree,
3110 *hf_id, tvb, offset, len,
3111 value, "%s", format_text(wmem_packet_scope(), line, len));
3112 if (http_type == HTTP_REQUEST ||
3113 http_type == HTTP_RESPONSE) {
3114 it = proto_tree_add_item(tree,
3115 http_type == HTTP_RESPONSE ?
3116 hf_http_response_line :
3117 hf_http_request_line,
3118 tvb, offset, len,
3119 ENC_NA|ENC_ASCII);
3120 proto_item_set_text(it, "%s",
3121 format_text(wmem_packet_scope(), line, len));
3122 proto_item_set_hidden(it);
3123 }
3124 }
3125 }
3126 } else {
3127 /*
3128 * Add it to the protocol tree as a particular field,
3129 * but display the line as is.
3130 */
3131 if (tree) {
3132 header_field_info *hfinfo;
3133 guint32 tmp;
3134
3135 hfinfo = proto_registrar_get_nth(*headers[hf_index].hf);
3136 switch(hfinfo->type){
3137 case FT_UINT8:
3138 case FT_UINT16:
3139 case FT_UINT24:
3140 case FT_UINT32:
3141 case FT_INT8:
3142 case FT_INT16:
3143 case FT_INT24:
3144 case FT_INT32:
3145 tmp=(guint32)strtol(value, NULL, 10);
3146 hdr_item = proto_tree_add_uint(tree, *headers[hf_index].hf, tvb, offset, len, tmp);
3147 if (http_type == HTTP_REQUEST ||
3148 http_type == HTTP_RESPONSE) {
3149 it = proto_tree_add_item(tree,
3150 http_type == HTTP_RESPONSE ?
3151 hf_http_response_line :
3152 hf_http_request_line,
3153 tvb, offset, len,
3154 ENC_NA|ENC_ASCII);
3155 proto_item_set_text(it, "%d", tmp);
3156 proto_item_set_hidden(it);
3157 }
3158 break;
3159 default:
3160 hdr_item = proto_tree_add_string_format(tree,
3161 *headers[hf_index].hf, tvb, offset, len,
3162 value, "%s", format_text(wmem_packet_scope(), line, len));
3163 if (http_type == HTTP_REQUEST ||
3164 http_type == HTTP_RESPONSE) {
3165 it = proto_tree_add_item(tree,
3166 http_type == HTTP_RESPONSE ?
3167 hf_http_response_line :
3168 hf_http_request_line,
3169 tvb, offset, len,
3170 ENC_NA|ENC_ASCII);
3171 proto_item_set_text(it, "%s",
3172 format_text(wmem_packet_scope(), line, len));
3173 proto_item_set_hidden(it);
3174 }
3175 }
3176 } else
3177 hdr_item = NULL;
3178
3179 /*
3180 * Do any special processing that particular headers
3181 * require.
3182 */
3183 switch (headers[hf_index].special) {
3184
3185 case HDR_AUTHORIZATION:
3186 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
3187 break; /* dissected NTLMSSP */
3188 if (check_auth_basic(hdr_item, tvb, pinfo, value))
3189 break; /* dissected basic auth */
3190 if (check_auth_citrixbasic(hdr_item, tvb, value, offset))
3191 break; /* dissected citrix basic auth */
3192 if (check_auth_kerberos(hdr_item, tvb, pinfo, value))
3193 break;
3194 if (check_auth_digest(hdr_item, tvb, pinfo, value, offset, value_len))
3195 break;/* dissected digest basic auth */
3196 auth = wmem_new0(wmem_packet_scope(), tap_credential_t);
3197 auth->num = pinfo->num;
3198 auth->password_hf_id = *headers[hf_index].hf;
3199 auth->proto = "HTTP header auth";
3200 auth->username = wmem_strdup(wmem_packet_scope(), TAP_CREDENTIALS_PLACEHOLDER);
3201 tap_queue_packet(credentials_tap, pinfo, auth);
3202 break;
3203
3204 case HDR_AUTHENTICATE:
3205 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
3206 break; /* dissected NTLMSSP */
3207 check_auth_kerberos(hdr_item, tvb, pinfo, value);
3208 break;
3209
3210 case HDR_CONTENT_TYPE:
3211 eh_ptr->content_type = (gchar*) wmem_memdup(wmem_packet_scope(), (guint8*)value,value_len + 1);
3212
3213 for (i = 0; i < value_len; i++) {
3214 c = value[i];
3215 if (c == ';' || g_ascii_isspace(c)) {
3216 /*
3217 * End of subtype - either
3218 * white space or a ";"
3219 * separating the subtype from
3220 * a parameter.
3221 */
3222 break;
3223 }
3224
3225 /*
3226 * Map the character to lower case;
3227 * content types are case-insensitive.
3228 */
3229 eh_ptr->content_type[i] = g_ascii_tolower(eh_ptr->content_type[i]);
3230 }
3231 eh_ptr->content_type[i] = '\0';
3232 /*
3233 * Now find the start of the optional parameters;
3234 * skip the optional white space and the semicolon
3235 * if this has not been done before.
3236 */
3237 i++;
3238 while (i < value_len) {
3239 c = eh_ptr->content_type[i];
3240 if (c == ';' || g_ascii_isspace(c))
3241 /* Skip till start of parameters */
3242 i++;
3243 else
3244 break;
3245 }
3246 if (i < value_len)
3247 eh_ptr->content_type_parameters = eh_ptr->content_type + i;
3248 else
3249 eh_ptr->content_type_parameters = NULL;
3250 break;
3251
3252 case HDR_CONTENT_LENGTH:
3253 errno = 0;
3254 eh_ptr->content_length = g_ascii_strtoll(value, &p, 10);
3255 up = (guchar *)p;
3256 if (eh_ptr->content_length < 0 ||
3257 p == value ||
3258 errno == ERANGE ||
3259 (*up != '\0' && !g_ascii_isspace(*up))) {
3260 /*
3261 * Content length not valid; pretend
3262 * we don't have it.
3263 */
3264 eh_ptr->have_content_length = FALSE;
3265 } else {
3266 proto_tree *header_tree;
3267 proto_item *tree_item;
3268 /*
3269 * We do have a valid content length.
3270 */
3271 eh_ptr->have_content_length = TRUE;
3272 header_tree = proto_item_add_subtree(hdr_item, ett_http_header_item);
3273 tree_item = proto_tree_add_uint64(header_tree, hf_http_content_length,
3274 tvb, offset, len, eh_ptr->content_length);
3275 proto_item_set_generated(tree_item);
3276 if (eh_ptr->transfer_encoding != HTTP_TE_NONE) {
3277 expert_add_info(pinfo, hdr_item, &ei_http_te_and_length);
3278 }
3279 }
3280 break;
3281
3282 case HDR_CONTENT_ENCODING:
3283 eh_ptr->content_encoding = wmem_strndup(wmem_packet_scope(), value, value_len);
3284 break;
3285
3286 case HDR_TRANSFER_ENCODING:
3287 if (eh_ptr->have_content_length) {
3288 expert_add_info(pinfo, hdr_item, &ei_http_te_and_length);
3289 }
3290 if (!http_parse_transfer_coding(value, eh_ptr)) {
3291 expert_add_info(pinfo, hdr_item, &ei_http_te_unknown);
3292 }
3293 break;
3294
3295 case HDR_HOST:
3296 stat_info->http_host = wmem_strndup(wmem_packet_scope(), value, value_len);
3297 conv_data->http_host = wmem_strndup(wmem_file_scope(), value, value_len);
3298 break;
3299
3300 case HDR_UPGRADE:
3301 eh_ptr->upgrade = wmem_ascii_strdown(wmem_packet_scope(), value, value_len);
3302 break;
3303
3304 case HDR_COOKIE:
3305 if (hdr_item) {
3306 proto_tree *cookie_tree;
3307 char *part, *part_end;
3308 int part_len;
3309
3310 cookie_tree = proto_item_add_subtree(hdr_item, ett_http_header_item);
3311 for (i = 0; i < value_len; ) {
3312 /* skip whitespace and ';' (terminates at '\0' or earlier) */
3313 c = value[i];
3314 while (c == ';' || g_ascii_isspace(c))
3315 c = value[++i];
3316
3317 if (i >= value_len)
3318 break;
3319
3320 /* find "cookie=foo " in "cookie=foo ; bar" */
3321 part = value + i;
3322 part_end = (char *)memchr(part, ';', value_len - i);
3323 if (part_end)
3324 part_len =(int)(part_end - part);
3325 else
3326 part_len = value_len - i;
3327
3328 /* finally add cookie to tree */
3329 proto_tree_add_item(cookie_tree, hf_http_cookie_pair,
3330 tvb, value_offset + i, part_len, ENC_NA|ENC_ASCII);
3331 i += part_len;
3332 }
3333 }
3334 break;
3335
3336 case HDR_WEBSOCKET_PROTOCOL:
3337 if (http_type == HTTP_RESPONSE) {
3338 conv_data->websocket_protocol = wmem_strndup(wmem_file_scope(), value, value_len);
3339 }
3340 break;
3341
3342 case HDR_WEBSOCKET_EXTENSIONS:
3343 if (http_type == HTTP_RESPONSE) {
3344 conv_data->websocket_extensions = wmem_strndup(wmem_file_scope(), value, value_len);
3345 }
3346 break;
3347
3348 case HDR_REFERER:
3349 stat_info->referer_uri = wmem_strndup(wmem_packet_scope(), value, value_len);
3350 break;
3351
3352 case HDR_LOCATION:
3353 if (conv_data->request_uri){
3354 stat_info->location_target = wmem_strndup(wmem_packet_scope(), value, value_offset);
3355 stat_info->location_base_uri = wmem_strdup(wmem_packet_scope(), conv_data->full_uri);
3356 }
3357 break;
3358 case HDR_HTTP2_SETTINGS:
3359 {
3360 proto_tree* settings_tree = proto_item_add_subtree(hdr_item, ett_http_http2_settings_item);
3361 tvbuff_t* new_tvb = base64uri_tvb_to_new_tvb(tvb, value_offset, value_len);
3362 add_new_data_source(pinfo, new_tvb, "Base64uri decoded");
3363 TRY{
3364 dissect_http2_settings_ext(new_tvb, pinfo, settings_tree, 0);
3365 } CATCH_ALL{
3366 show_exception(tvb, pinfo, settings_tree, EXCEPT_CODE, GET_MESSAGE);
3367 }
3368 ENDTRY;
3369
3370 break;
3371 }
3372 }
3373 }
3374 }
3375
3376 /* Returns index of header tag in headers */
3377 static gint
find_header_hf_value(tvbuff_t * tvb,int offset,guint header_len)3378 find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len)
3379 {
3380 guint i;
3381
3382 for (i = 0; i < array_length(headers); i++) {
3383 if (header_len == strlen(headers[i].name) &&
3384 tvb_strncaseeql(tvb, offset,
3385 headers[i].name, header_len) == 0)
3386 return i;
3387 }
3388
3389 return -1;
3390 }
3391
3392 /*
3393 * Dissect Microsoft's abomination called NTLMSSP over HTTP.
3394 */
3395 static gboolean
check_auth_ntlmssp(proto_item * hdr_item,tvbuff_t * tvb,packet_info * pinfo,gchar * value)3396 check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, gchar *value)
3397 {
3398 static const char *ntlm_headers[] = {
3399 "NTLM ",
3400 "Negotiate ",
3401 NULL
3402 };
3403 const char **header;
3404 size_t hdrlen;
3405 proto_tree *hdr_tree;
3406
3407 /*
3408 * Check for NTLM credentials and challenge; those can
3409 * occur with WWW-Authenticate.
3410 */
3411 for (header = &ntlm_headers[0]; *header != NULL; header++) {
3412 hdrlen = strlen(*header);
3413 if (strncmp(value, *header, hdrlen) == 0) {
3414 if (hdr_item != NULL) {
3415 hdr_tree = proto_item_add_subtree(hdr_item,
3416 ett_http_ntlmssp);
3417 } else
3418 hdr_tree = NULL;
3419 value += hdrlen;
3420 dissect_http_ntlmssp(tvb, pinfo, hdr_tree, value);
3421 return TRUE;
3422 }
3423 }
3424 return FALSE;
3425 }
3426
3427 static tap_credential_t*
basic_auth_credentials(gchar * str)3428 basic_auth_credentials(gchar* str)
3429 {
3430 gchar **tokens = g_strsplit(str, ":", -1);
3431
3432 if (!tokens || !tokens[0] || !tokens[1]) {
3433 g_strfreev(tokens);
3434 return NULL;
3435 }
3436
3437 tap_credential_t* auth = wmem_new0(wmem_packet_scope(), tap_credential_t);
3438
3439 auth->username = wmem_strdup(wmem_packet_scope(), tokens[0]);
3440 auth->proto = "HTTP basic auth";
3441
3442 g_strfreev(tokens);
3443
3444 return auth;
3445 }
3446
3447 /*
3448 * Dissect HTTP Basic authorization.
3449 */
3450 static gboolean
check_auth_basic(proto_item * hdr_item,tvbuff_t * tvb,packet_info * pinfo,gchar * value)3451 check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, gchar *value)
3452 {
3453 static const char *basic_headers[] = {
3454 "Basic ",
3455 NULL
3456 };
3457 const char **header;
3458 size_t hdrlen;
3459 proto_tree *hdr_tree;
3460 gsize len;
3461
3462 for (header = &basic_headers[0]; *header != NULL; header++) {
3463 hdrlen = strlen(*header);
3464 if (strncmp(value, *header, hdrlen) == 0) {
3465 if (hdr_item != NULL) {
3466 hdr_tree = proto_item_add_subtree(hdr_item,
3467 ett_http_ntlmssp);
3468 } else
3469 hdr_tree = NULL;
3470 value += hdrlen;
3471
3472 if (strlen(value) > 1) {
3473 g_base64_decode_inplace(value, &len);
3474 value[len] = 0;
3475 }
3476 proto_tree_add_string(hdr_tree, hf_http_basic, tvb,
3477 0, 0, value);
3478 tap_credential_t* auth = basic_auth_credentials(value);
3479 if (auth) {
3480 auth->num = auth->username_num = pinfo->num;
3481 auth->password_hf_id = hf_http_basic;
3482 tap_queue_packet(credentials_tap, pinfo, auth);
3483 }
3484
3485 return TRUE;
3486 }
3487 }
3488 return FALSE;
3489 }
3490
3491 /*
3492 * Dissect HTTP Digest authorization.
3493 */
3494 static gboolean
check_auth_digest(proto_item * hdr_item,tvbuff_t * tvb,packet_info * pinfo _U_,gchar * value,int offset,int len)3495 check_auth_digest(proto_item* hdr_item, tvbuff_t* tvb, packet_info* pinfo _U_, gchar* value, int offset, int len)
3496 {
3497 proto_tree* hdr_tree;
3498 int queried_offset;
3499
3500 if (strncmp(value, "Digest", 6) == 0) {
3501 if (hdr_item != NULL) {
3502 hdr_tree = proto_item_add_subtree(hdr_item, ett_http_ntlmssp);
3503 } else {
3504 hdr_tree = NULL;
3505 }
3506 offset += 21;
3507 len -= 21;
3508 while (len > 0) {
3509 /* Find comma/end of line */
3510 queried_offset = tvb_find_guint8(tvb, offset, len, ',');
3511 if (queried_offset > 0) {
3512 proto_tree_add_format_text(hdr_tree, tvb, offset, queried_offset - offset);
3513 len -= (queried_offset - offset);
3514 offset = queried_offset + 1;
3515 } else {
3516 len = 0;
3517 }
3518 }
3519 return TRUE;
3520 } else {
3521 return FALSE;
3522 }
3523 }
3524 /*
3525 * Dissect HTTP CitrixAGBasic authorization.
3526 */
3527 static gboolean
check_auth_citrixbasic(proto_item * hdr_item,tvbuff_t * tvb,gchar * value,int offset)3528 check_auth_citrixbasic(proto_item *hdr_item, tvbuff_t *tvb, gchar *value, int offset)
3529 {
3530 static const char *basic_headers[] = {
3531 "CitrixAGBasic ",
3532 NULL
3533 };
3534 const char **header;
3535 size_t hdrlen;
3536 proto_tree *hdr_tree;
3537 char *ch_ptr;
3538 int data_len;
3539 char *data_val;
3540 proto_item *hidden_item;
3541 proto_item *pi;
3542 gsize len;
3543
3544 for (header = &basic_headers[0]; *header != NULL; header++) {
3545 hdrlen = strlen(*header);
3546 if (strncmp(value, *header, hdrlen) == 0) {
3547 if (hdr_item != NULL) {
3548 hdr_tree = proto_item_add_subtree(hdr_item,
3549 ett_http_ntlmssp);
3550 } else
3551 hdr_tree = NULL;
3552 value += hdrlen;
3553 offset += (int)hdrlen + 15;
3554 hidden_item = proto_tree_add_boolean(hdr_tree,
3555 hf_http_citrix, tvb, 0, 0, 1);
3556 proto_item_set_hidden(hidden_item);
3557
3558 if(strncmp(value, "username=\"", 10) == 0) {
3559 value += 10;
3560 offset += 10;
3561 ch_ptr = strchr(value, '"');
3562 if ( ch_ptr != NULL ) {
3563 data_len = (int)(ch_ptr - value + 1);
3564 data_val = wmem_strndup(wmem_packet_scope(), value, data_len);
3565 if (data_len > 1) {
3566 g_base64_decode_inplace(data_val, &len);
3567 data_val[len] = 0;
3568 }
3569 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_user, tvb,
3570 offset , data_len - 1, data_val);
3571 proto_item_set_generated(pi);
3572 value += data_len;
3573 offset += data_len;
3574 }
3575 }
3576 if(strncmp(value, "; domain=\"", 10) == 0) {
3577 value += 10;
3578 offset += 10;
3579 ch_ptr = strchr(value, '"');
3580 if ( ch_ptr != NULL ) {
3581 data_len = (int)(ch_ptr - value + 1);
3582 data_val = wmem_strndup(wmem_packet_scope(), value, data_len);
3583 if (data_len > 1) {
3584 g_base64_decode_inplace(data_val, &len);
3585 data_val[len] = 0;
3586 }
3587 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_domain, tvb,
3588 offset, data_len - 1, data_val);
3589 proto_item_set_generated(pi);
3590 value += data_len;
3591 offset += data_len;
3592 }
3593 }
3594 if(strncmp(value, "; password=\"", 12) == 0) {
3595 value += 12;
3596 offset += 12;
3597 ch_ptr = strchr(value, '"');
3598 if ( ch_ptr != NULL ) {
3599 data_len = (int)(ch_ptr - value + 1);
3600 data_val = wmem_strndup(wmem_packet_scope(), value, data_len);
3601 if (data_len > 1) {
3602 g_base64_decode_inplace(data_val, &len);
3603 data_val[len] = 0;
3604 }
3605 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_passwd, tvb,
3606 offset, data_len - 1, data_val);
3607 proto_item_set_generated(pi);
3608 value += data_len;
3609 offset += data_len;
3610 }
3611 }
3612 if(strncmp(value, "; AGESessionId=\"", 16) == 0) {
3613 value += 16;
3614 offset += 16;
3615 ch_ptr = strchr(value, '"');
3616 if ( ch_ptr != NULL ) {
3617 data_len = (int)(ch_ptr - value + 1);
3618 data_val = wmem_strndup(wmem_packet_scope(), value, data_len);
3619 if (data_len > 1) {
3620 g_base64_decode_inplace(data_val, &len);
3621 data_val[len] = 0;
3622 }
3623 pi = proto_tree_add_string(hdr_tree, hf_http_citrix_session, tvb,
3624 offset, data_len - 1, data_val);
3625 proto_item_set_generated(pi);
3626 }
3627 }
3628 return TRUE;
3629 }
3630 }
3631 return FALSE;
3632 }
3633
3634 static gboolean
check_auth_kerberos(proto_item * hdr_item,tvbuff_t * tvb,packet_info * pinfo,const gchar * value)3635 check_auth_kerberos(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, const gchar *value)
3636 {
3637 proto_tree *hdr_tree;
3638
3639 if (strncmp(value, "Kerberos ", 9) == 0) {
3640 if (hdr_item != NULL) {
3641 hdr_tree = proto_item_add_subtree(hdr_item, ett_http_kerberos);
3642 } else
3643 hdr_tree = NULL;
3644
3645 dissect_http_kerberos(tvb, pinfo, hdr_tree, value);
3646 return TRUE;
3647 }
3648 return FALSE;
3649 }
3650
3651 static void
dissect_http_on_stream(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,http_conv_t * conv_data,gboolean end_of_stream)3652 dissect_http_on_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
3653 http_conv_t *conv_data, gboolean end_of_stream)
3654 {
3655 int offset = 0;
3656 int len;
3657
3658 while (tvb_reported_length_remaining(tvb, offset) > 0) {
3659 /* Switch protocol if the data starts after response headers. */
3660 if (conv_data->startframe &&
3661 (pinfo->num > conv_data->startframe ||
3662 (pinfo->num == conv_data->startframe && offset >= conv_data->startoffset))) {
3663 /* Increase pinfo->can_desegment because we are traversing
3664 * http and want to preserve desegmentation functionality for
3665 * the proxied protocol
3666 */
3667 if (pinfo->can_desegment > 0)
3668 pinfo->can_desegment++;
3669 if (conv_data->next_handle) {
3670 call_dissector_only(conv_data->next_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
3671 } else {
3672 call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
3673 }
3674 /*
3675 * If a subdissector requests reassembly, be sure not to
3676 * include the preceding HTTP headers.
3677 */
3678 if (pinfo->desegment_len) {
3679 pinfo->desegment_offset += offset;
3680 }
3681 break;
3682 }
3683 len = dissect_http_message(tvb, offset, pinfo, tree, conv_data, "HTTP", proto_http, end_of_stream);
3684 if (len == -1)
3685 break;
3686 offset += len;
3687
3688 /*
3689 * OK, we've set the Protocol and Info columns for the
3690 * first HTTP message; set a fence so that subsequent
3691 * HTTP messages don't overwrite the Info column.
3692 */
3693 col_set_fence(pinfo->cinfo, COL_INFO);
3694 }
3695 }
3696
3697 static int
dissect_http_tcp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)3698 dissect_http_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
3699 {
3700 struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
3701 conversation_t *conversation;
3702 http_conv_t *conv_data;
3703 gboolean end_of_stream;
3704
3705 conv_data = get_http_conversation_data(pinfo, &conversation);
3706
3707 /* Call HTTP2 dissector directly when detected via heuristics, but not
3708 * when it was upgraded (the conversation started with HTTP). */
3709 if (conversation_get_proto_data(conversation, proto_http2) &&
3710 !conv_data->startframe) {
3711 if (pinfo->can_desegment > 0)
3712 pinfo->can_desegment++;
3713 return call_dissector_only(http2_handle, tvb, pinfo, tree, data);
3714 }
3715
3716 /*
3717 * Check if this is proxied connection and if so, hand of dissection to the
3718 * payload-dissector.
3719 * Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */
3720 if(pinfo->num >= conv_data->startframe &&
3721 conv_data->response_code == 200 &&
3722 conv_data->request_method &&
3723 strncmp(conv_data->request_method, "CONNECT", 7) == 0 &&
3724 conv_data->request_uri) {
3725 if (conv_data->startframe == 0 && !PINFO_FD_VISITED(pinfo)) {
3726 conv_data->startframe = pinfo->num;
3727 conv_data->startoffset = 0;
3728 copy_address_wmem(wmem_file_scope(), &conv_data->server_addr, &pinfo->dst);
3729 conv_data->server_port = pinfo->destport;
3730 }
3731 http_payload_subdissector(tvb, tree, pinfo, conv_data, data);
3732
3733 return tvb_captured_length(tvb);
3734 }
3735
3736 /* XXX - how to detect end-of-stream without tcpinfo */
3737 end_of_stream = (tcpinfo && IS_TH_FIN(tcpinfo->flags));
3738 dissect_http_on_stream(tvb, pinfo, tree, conv_data, end_of_stream);
3739 return tvb_captured_length(tvb);
3740 }
3741
3742 static gboolean
dissect_http_heur_tcp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)3743 dissect_http_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3744 {
3745 gint offset = 0, next_offset, linelen;
3746 conversation_t *conversation;
3747
3748
3749 /* Check if we have a line terminated by CRLF
3750 * Return the length of the line (not counting the line terminator at
3751 * the end), or, if we don't find a line terminator:
3752 *
3753 * if "deseg" is true, return -1;
3754 */
3755 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, TRUE);
3756 if((linelen == -1)||(linelen == 8)){
3757 return FALSE;
3758 }
3759
3760 /* Check if the line start or ends with the HTTP token */
3761 if((tvb_strncaseeql(tvb, linelen-8, "HTTP/1.", 7) == 0)||(tvb_strncaseeql(tvb, 0, "HTTP/1.", 7) == 0)){
3762 conversation = find_or_create_conversation(pinfo);
3763 conversation_set_dissector_from_frame_number(conversation, pinfo->num, http_tcp_handle);
3764 dissect_http_tcp(tvb, pinfo, tree, data);
3765 return TRUE;
3766 }
3767
3768 return FALSE;
3769 }
3770
3771 static int
dissect_http_tls(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)3772 dissect_http_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3773 {
3774 conversation_t *conversation;
3775 http_conv_t *conv_data;
3776
3777 conv_data = get_http_conversation_data(pinfo, &conversation);
3778
3779 /*
3780 * XXX - we need to provide an end-of-stream indication.
3781 */
3782 dissect_http_on_stream(tvb, pinfo, tree, conv_data, FALSE);
3783 return tvb_captured_length(tvb);
3784 }
3785
3786 static gboolean
dissect_http_heur_tls(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)3787 dissect_http_heur_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3788 {
3789 gint offset = 0, next_offset, linelen;
3790 conversation_t *conversation;
3791 http_conv_t *conv_data;
3792
3793 conversation = find_or_create_conversation(pinfo);
3794 conv_data = (http_conv_t *)conversation_get_proto_data(conversation, proto_http);
3795 /* A http conversation was previously started, assume it is still active */
3796 if (conv_data) {
3797 dissect_http_tls(tvb, pinfo, tree, data);
3798 return TRUE;
3799 }
3800
3801 /* Check if we have a line terminated by CRLF
3802 * Return the length of the line (not counting the line terminator at
3803 * the end), or, if we don't find a line terminator:
3804 *
3805 * if "deseg" is true, return -1;
3806 */
3807 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, TRUE);
3808 if((linelen == -1)||(linelen == 8)){
3809 return FALSE;
3810 }
3811
3812 /* Check if the line start or ends with the HTTP token */
3813 if((tvb_strncaseeql(tvb, linelen-8, "HTTP/1.", 7) != 0) && (tvb_strncaseeql(tvb, 0, "HTTP/1.", 7) != 0)) {
3814 /* we couldn't find the Magic Hello HTTP/1.X. */
3815 return FALSE;
3816 }
3817
3818 conv_data = wmem_new0(wmem_file_scope(), http_conv_t);
3819 conversation_add_proto_data(conversation, proto_http, conv_data);
3820 dissect_http_tls(tvb, pinfo, tree, data);
3821 return TRUE;
3822 }
3823
3824 static int
dissect_http_sctp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)3825 dissect_http_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3826 {
3827 conversation_t *conversation;
3828 http_conv_t *conv_data;
3829
3830 conv_data = get_http_conversation_data(pinfo, &conversation);
3831
3832 /*
3833 * XXX - we need to provide an end-of-stream indication.
3834 */
3835 dissect_http_on_stream(tvb, pinfo, tree, conv_data, FALSE);
3836 return tvb_captured_length(tvb);
3837 }
3838
3839 static int
dissect_http(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)3840 dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3841 {
3842 conversation_t *conversation;
3843 http_conv_t *conv_data;
3844
3845 conv_data = get_http_conversation_data(pinfo, &conversation);
3846
3847 /*
3848 * XXX - what should be done about reassembly, pipelining, etc.
3849 * here?
3850 */
3851 dissect_http_on_stream(tvb, pinfo, tree, conv_data, FALSE);
3852 return tvb_captured_length(tvb);
3853 }
3854
3855 static int
dissect_ssdp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)3856 dissect_ssdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3857 {
3858 conversation_t *conversation;
3859 http_conv_t *conv_data;
3860
3861 conv_data = get_http_conversation_data(pinfo, &conversation);
3862 dissect_http_message(tvb, 0, pinfo, tree, conv_data, "SSDP", proto_ssdp, FALSE);
3863 return tvb_captured_length(tvb);
3864 }
3865
3866 static void
range_delete_http_tls_callback(guint32 port,gpointer ptr _U_)3867 range_delete_http_tls_callback(guint32 port, gpointer ptr _U_) {
3868 ssl_dissector_delete(port, http_tls_handle);
3869 }
3870
3871 static void
range_add_http_tls_callback(guint32 port,gpointer ptr _U_)3872 range_add_http_tls_callback(guint32 port, gpointer ptr _U_) {
3873 ssl_dissector_add(port, http_tls_handle);
3874 }
3875
reinit_http(void)3876 static void reinit_http(void) {
3877 http_tcp_range = prefs_get_range_value("http", "tcp.port");
3878
3879 dissector_delete_uint_range("sctp.port", http_sctp_range, http_sctp_handle);
3880 wmem_free(wmem_epan_scope(), http_sctp_range);
3881 http_sctp_range = range_copy(wmem_epan_scope(), global_http_sctp_range);
3882 dissector_add_uint_range("sctp.port", http_sctp_range, http_sctp_handle);
3883
3884 range_foreach(http_tls_range, range_delete_http_tls_callback, NULL);
3885 wmem_free(wmem_epan_scope(), http_tls_range);
3886 http_tls_range = range_copy(wmem_epan_scope(), global_http_tls_range);
3887 range_foreach(http_tls_range, range_add_http_tls_callback, NULL);
3888 }
3889
3890 void
proto_register_http(void)3891 proto_register_http(void)
3892 {
3893 static hf_register_info hf[] = {
3894 { &hf_http_notification,
3895 { "Notification", "http.notification",
3896 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3897 "TRUE if HTTP notification", HFILL }},
3898 { &hf_http_response,
3899 { "Response", "http.response",
3900 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3901 "TRUE if HTTP response", HFILL }},
3902 { &hf_http_request,
3903 { "Request", "http.request",
3904 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3905 "TRUE if HTTP request", HFILL }},
3906 { &hf_http_response_number,
3907 { "Response number", "http.response_number",
3908 FT_UINT32, BASE_DEC, NULL, 0x0,
3909 NULL, HFILL }},
3910 { &hf_http_request_number,
3911 { "Request number", "http.request_number",
3912 FT_UINT32, BASE_DEC, NULL, 0x0,
3913 NULL, HFILL }},
3914 { &hf_http_basic,
3915 { "Credentials", "http.authbasic",
3916 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3917 { &hf_http_citrix,
3918 { "Citrix AG Auth", "http.authcitrix",
3919 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3920 "TRUE if CitrixAGBasic Auth", HFILL }},
3921 { &hf_http_citrix_user,
3922 { "Citrix AG Username", "http.authcitrix.user",
3923 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3924 { &hf_http_citrix_domain,
3925 { "Citrix AG Domain", "http.authcitrix.domain",
3926 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3927 { &hf_http_citrix_passwd,
3928 { "Citrix AG Password", "http.authcitrix.password",
3929 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3930 { &hf_http_citrix_session,
3931 { "Citrix AG Session ID", "http.authcitrix.session",
3932 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3933 { &hf_http_response_line,
3934 { "Response line", "http.response.line",
3935 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3936 { &hf_http_request_line,
3937 { "Request line", "http.request.line",
3938 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3939 { &hf_http_request_method,
3940 { "Request Method", "http.request.method",
3941 FT_STRING, BASE_NONE, NULL, 0x0,
3942 "HTTP Request Method", HFILL }},
3943 { &hf_http_request_uri,
3944 { "Request URI", "http.request.uri",
3945 FT_STRING, STR_UNICODE, NULL, 0x0,
3946 "HTTP Request-URI", HFILL }},
3947 { &hf_http_request_path,
3948 { "Request URI Path", "http.request.uri.path",
3949 FT_STRING, STR_UNICODE, NULL, 0x0,
3950 "HTTP Request-URI Path", HFILL }},
3951 { &hf_http_request_query,
3952 { "Request URI Query", "http.request.uri.query",
3953 FT_STRING, STR_UNICODE, NULL, 0x0,
3954 "HTTP Request-URI Query", HFILL }},
3955 { &hf_http_request_query_parameter,
3956 { "Request URI Query Parameter", "http.request.uri.query.parameter",
3957 FT_STRING, STR_UNICODE, NULL, 0x0,
3958 "HTTP Request-URI Query Parameter", HFILL }},
3959 { &hf_http_request_version,
3960 { "Request Version", "http.request.version",
3961 FT_STRING, BASE_NONE, NULL, 0x0,
3962 "HTTP Request HTTP-Version", HFILL }},
3963 { &hf_http_response_version,
3964 { "Response Version", "http.response.version",
3965 FT_STRING, BASE_NONE, NULL, 0x0,
3966 "HTTP Response HTTP-Version", HFILL }},
3967 { &hf_http_request_full_uri,
3968 { "Full request URI", "http.request.full_uri",
3969 FT_STRING, BASE_NONE, NULL, 0x0,
3970 "The full requested URI (including host name)", HFILL }},
3971 { &hf_http_response_code,
3972 { "Status Code", "http.response.code",
3973 FT_UINT16, BASE_DEC, NULL, 0x0,
3974 "HTTP Response Status Code", HFILL }},
3975 { &hf_http_response_code_desc,
3976 { "Status Code Description", "http.response.code.desc",
3977 FT_STRING, BASE_NONE, NULL, 0x0,
3978 "HTTP Response Status Code Description", HFILL }},
3979 { &hf_http_response_for_uri,
3980 { "Request URI", "http.response_for.uri",
3981 FT_STRING, STR_UNICODE, NULL, 0x0,
3982 "HTTP Response For-URI", HFILL }},
3983 { &hf_http_response_phrase,
3984 { "Response Phrase", "http.response.phrase",
3985 FT_STRING, BASE_NONE, NULL, 0x0,
3986 "HTTP Response Reason Phrase", HFILL }},
3987 { &hf_http_authorization,
3988 { "Authorization", "http.authorization",
3989 FT_STRING, BASE_NONE, NULL, 0x0,
3990 "HTTP Authorization header", HFILL }},
3991 { &hf_http_proxy_authenticate,
3992 { "Proxy-Authenticate", "http.proxy_authenticate",
3993 FT_STRING, BASE_NONE, NULL, 0x0,
3994 "HTTP Proxy-Authenticate header", HFILL }},
3995 { &hf_http_proxy_authorization,
3996 { "Proxy-Authorization", "http.proxy_authorization",
3997 FT_STRING, BASE_NONE, NULL, 0x0,
3998 "HTTP Proxy-Authorization header", HFILL }},
3999 { &hf_http_proxy_connect_host,
4000 { "Proxy-Connect-Hostname", "http.proxy_connect_host",
4001 FT_STRING, BASE_NONE, NULL, 0x0,
4002 "HTTP Proxy Connect Hostname", HFILL }},
4003 { &hf_http_proxy_connect_port,
4004 { "Proxy-Connect-Port", "http.proxy_connect_port",
4005 FT_UINT16, BASE_DEC, NULL, 0x0,
4006 "HTTP Proxy Connect Port", HFILL }},
4007 { &hf_http_www_authenticate,
4008 { "WWW-Authenticate", "http.www_authenticate",
4009 FT_STRING, BASE_NONE, NULL, 0x0,
4010 "HTTP WWW-Authenticate header", HFILL }},
4011 { &hf_http_content_type,
4012 { "Content-Type", "http.content_type",
4013 FT_STRING, BASE_NONE, NULL, 0x0,
4014 "HTTP Content-Type header", HFILL }},
4015 { &hf_http_content_length_header,
4016 { "Content-Length", "http.content_length_header",
4017 FT_STRING, BASE_NONE, NULL, 0x0,
4018 "HTTP Content-Length header", HFILL }},
4019 { &hf_http_content_length,
4020 { "Content length", "http.content_length",
4021 FT_UINT64, BASE_DEC, NULL, 0x0,
4022 NULL, HFILL }},
4023 { &hf_http_content_encoding,
4024 { "Content-Encoding", "http.content_encoding",
4025 FT_STRING, BASE_NONE, NULL, 0x0,
4026 "HTTP Content-Encoding header", HFILL }},
4027 { &hf_http_transfer_encoding,
4028 { "Transfer-Encoding", "http.transfer_encoding",
4029 FT_STRING, BASE_NONE, NULL, 0x0,
4030 "HTTP Transfer-Encoding header", HFILL }},
4031 { &hf_http_upgrade,
4032 { "Upgrade", "http.upgrade",
4033 FT_STRING, BASE_NONE, NULL, 0x0,
4034 "HTTP Upgrade header", HFILL }},
4035 { &hf_http_user_agent,
4036 { "User-Agent", "http.user_agent",
4037 FT_STRING, BASE_NONE, NULL, 0x0,
4038 "HTTP User-Agent header", HFILL }},
4039 { &hf_http_host,
4040 { "Host", "http.host",
4041 FT_STRING, BASE_NONE, NULL, 0x0,
4042 "HTTP Host", HFILL }},
4043 { &hf_http_connection,
4044 { "Connection", "http.connection",
4045 FT_STRING, BASE_NONE, NULL, 0x0,
4046 "HTTP Connection", HFILL }},
4047 { &hf_http_cookie,
4048 { "Cookie", "http.cookie",
4049 FT_STRING, BASE_NONE, NULL, 0x0,
4050 "HTTP Cookie", HFILL }},
4051 { &hf_http_cookie_pair,
4052 { "Cookie pair", "http.cookie_pair",
4053 FT_STRING, BASE_NONE, NULL, 0x0,
4054 "A name/value HTTP cookie pair", HFILL }},
4055 { &hf_http_accept,
4056 { "Accept", "http.accept",
4057 FT_STRING, BASE_NONE, NULL, 0x0,
4058 "HTTP Accept", HFILL }},
4059 { &hf_http_referer,
4060 { "Referer", "http.referer",
4061 FT_STRING, BASE_NONE, NULL, 0x0,
4062 "HTTP Referer", HFILL }},
4063 { &hf_http_accept_language,
4064 { "Accept-Language", "http.accept_language",
4065 FT_STRING, BASE_NONE, NULL, 0x0,
4066 "HTTP Accept Language", HFILL }},
4067 { &hf_http_accept_encoding,
4068 { "Accept Encoding", "http.accept_encoding",
4069 FT_STRING, BASE_NONE, NULL, 0x0,
4070 "HTTP Accept Encoding", HFILL }},
4071 { &hf_http_date,
4072 { "Date", "http.date",
4073 FT_STRING, BASE_NONE, NULL, 0x0,
4074 "HTTP Date", HFILL }},
4075 { &hf_http_cache_control,
4076 { "Cache-Control", "http.cache_control",
4077 FT_STRING, BASE_NONE, NULL, 0x0,
4078 "HTTP Cache Control", HFILL }},
4079 { &hf_http_server,
4080 { "Server", "http.server",
4081 FT_STRING, BASE_NONE, NULL, 0x0,
4082 "HTTP Server", HFILL }},
4083 { &hf_http_location,
4084 { "Location", "http.location",
4085 FT_STRING, BASE_NONE, NULL, 0x0,
4086 "HTTP Location", HFILL }},
4087 { &hf_http_sec_websocket_accept,
4088 { "Sec-WebSocket-Accept", "http.sec_websocket_accept",
4089 FT_STRING, BASE_NONE, NULL, 0x0,
4090 NULL, HFILL }},
4091 { &hf_http_sec_websocket_extensions,
4092 { "Sec-WebSocket-Extensions", "http.sec_websocket_extensions",
4093 FT_STRING, BASE_NONE, NULL, 0x0,
4094 NULL, HFILL }},
4095 { &hf_http_sec_websocket_key,
4096 { "Sec-WebSocket-Key", "http.sec_websocket_key",
4097 FT_STRING, BASE_NONE, NULL, 0x0,
4098 NULL, HFILL }},
4099 { &hf_http_sec_websocket_protocol,
4100 { "Sec-WebSocket-Protocol", "http.sec_websocket_protocol",
4101 FT_STRING, BASE_NONE, NULL, 0x0,
4102 NULL, HFILL }},
4103 { &hf_http_sec_websocket_version,
4104 { "Sec-WebSocket-Version", "http.sec_websocket_version",
4105 FT_STRING, BASE_NONE, NULL, 0x0,
4106 NULL, HFILL }},
4107 { &hf_http_set_cookie,
4108 { "Set-Cookie", "http.set_cookie",
4109 FT_STRING, BASE_NONE, NULL, 0x0,
4110 "HTTP Set Cookie", HFILL }},
4111 { &hf_http_last_modified,
4112 { "Last-Modified", "http.last_modified",
4113 FT_STRING, BASE_NONE, NULL, 0x0,
4114 "HTTP Last Modified", HFILL }},
4115 { &hf_http_x_forwarded_for,
4116 { "X-Forwarded-For", "http.x_forwarded_for",
4117 FT_STRING, BASE_NONE, NULL, 0x0,
4118 "HTTP X-Forwarded-For", HFILL }},
4119 { &hf_http_http2_settings,
4120 { "HTTP2-Settings", "http.http2_settings",
4121 FT_STRING, BASE_NONE, NULL, 0x0,
4122 NULL, HFILL }},
4123 { &hf_http_request_in,
4124 { "Request in frame", "http.request_in",
4125 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0,
4126 "This packet is a response to the packet with this number", HFILL }},
4127 { &hf_http_response_in,
4128 { "Response in frame", "http.response_in",
4129 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0,
4130 "This packet will be responded in the packet with this number", HFILL }},
4131 { &hf_http_next_request_in,
4132 { "Next request in frame", "http.next_request_in",
4133 FT_FRAMENUM, BASE_NONE, NULL, 0,
4134 "The next HTTP request starts in packet number", HFILL }},
4135 { &hf_http_next_response_in,
4136 { "Next response in frame", "http.next_response_in",
4137 FT_FRAMENUM, BASE_NONE, NULL, 0,
4138 "The next HTTP response starts in packet number", HFILL }},
4139 { &hf_http_prev_request_in,
4140 { "Prev request in frame", "http.prev_request_in",
4141 FT_FRAMENUM, BASE_NONE, NULL, 0,
4142 "The previous HTTP request starts in packet number", HFILL }},
4143 { &hf_http_prev_response_in,
4144 { "Prev response in frame", "http.prev_response_in",
4145 FT_FRAMENUM, BASE_NONE, NULL, 0,
4146 "The previous HTTP response starts in packet number", HFILL }},
4147 { &hf_http_time,
4148 { "Time since request", "http.time",
4149 FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
4150 "Time since the request was sent", HFILL }},
4151 { &hf_http_chunked_trailer_part,
4152 { "trailer-part", "http.chunked_trailer_part",
4153 FT_STRING, BASE_NONE, NULL, 0,
4154 "Optional trailer in a chunked body", HFILL }},
4155 { &hf_http_chunk_boundary,
4156 { "Chunk boundary", "http.chunk_boundary",
4157 FT_BYTES, BASE_NONE, NULL, 0,
4158 NULL, HFILL }},
4159 { &hf_http_chunk_size,
4160 { "Chunk size", "http.chunk_size",
4161 FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_octet_octets, 0,
4162 NULL, HFILL }},
4163 { &hf_http_file_data,
4164 { "File Data", "http.file_data",
4165 FT_STRING, STR_UNICODE, NULL, 0,
4166 NULL, HFILL }},
4167 { &hf_http_unknown_header,
4168 { "Unknown header", "http.unknown_header",
4169 FT_STRING, BASE_NONE, NULL, 0,
4170 NULL, HFILL }},
4171 { &hf_http_http2_settings_uri,
4172 { "HTTP2 Settings URI", "http.http2_settings_uri",
4173 FT_BYTES, BASE_NONE, NULL, 0,
4174 NULL, HFILL }},
4175 };
4176 static gint *ett[] = {
4177 &ett_http,
4178 &ett_http_ntlmssp,
4179 &ett_http_kerberos,
4180 &ett_http_request,
4181 &ett_http_request_path,
4182 &ett_http_request_query,
4183 &ett_http_chunked_response,
4184 &ett_http_chunk_data,
4185 &ett_http_encoded_entity,
4186 &ett_http_header_item,
4187 &ett_http_http2_settings_item
4188 };
4189
4190 static ei_register_info ei[] = {
4191 { &ei_http_chat, { "http.chat", PI_SEQUENCE, PI_CHAT, "Formatted text", EXPFILL }},
4192 { &ei_http_te_and_length, { "http.te_and_length", PI_MALFORMED, PI_WARN, "The Content-Length and Transfer-Encoding header must not be set together", EXPFILL }},
4193 { &ei_http_te_unknown, { "http.te_unknown", PI_UNDECODED, PI_WARN, "Unknown transfer coding name in Transfer-Encoding header", EXPFILL }},
4194 { &ei_http_subdissector_failed, { "http.subdissector_failed", PI_MALFORMED, PI_NOTE, "HTTP body subdissector failed, trying heuristic subdissector", EXPFILL }},
4195 { &ei_http_tls_port, { "http.tls_port", PI_SECURITY, PI_WARN, "Unencrypted HTTP protocol detected over encrypted port, could indicate a dangerous misconfiguration.", EXPFILL }},
4196 { &ei_http_leading_crlf, { "http.leading_crlf", PI_MALFORMED, PI_ERROR, "Leading CRLF previous message in the stream may have extra CRLF", EXPFILL }},
4197 { &ei_http_bad_header_name, { "http.bad_header_name", PI_PROTOCOL, PI_WARN, "Illegal characters found in header name", EXPFILL }},
4198 { &ei_http_decompression_failed, { "http.decompression_failed", PI_UNDECODED, PI_WARN, "Decompression failed", EXPFILL }},
4199 { &ei_http_decompression_disabled, { "http.decompression_disabled", PI_UNDECODED, PI_CHAT, "Decompression disabled", EXPFILL }},
4200 };
4201
4202 /* UAT for header fields */
4203 static uat_field_t custom_header_uat_fields[] = {
4204 UAT_FLD_CSTRING(header_fields, header_name, "Header name", "HTTP header name"),
4205 UAT_FLD_CSTRING(header_fields, header_desc, "Field desc", "Description of the value contained in the header"),
4206 UAT_END_FIELDS
4207 };
4208
4209 module_t *http_module;
4210 expert_module_t* expert_http;
4211 uat_t* headers_uat;
4212
4213 proto_http = proto_register_protocol("Hypertext Transfer Protocol", "HTTP", "http");
4214 proto_ssdp = proto_register_protocol("Simple Service Discovery Protocol", "SSDP", "ssdp");
4215
4216 proto_register_field_array(proto_http, hf, array_length(hf));
4217 proto_register_subtree_array(ett, array_length(ett));
4218 expert_http = expert_register_protocol(proto_http);
4219 expert_register_field_array(expert_http, ei, array_length(ei));
4220
4221 http_handle = register_dissector("http", dissect_http, proto_http);
4222 http_tcp_handle = register_dissector("http-over-tcp", dissect_http_tcp, proto_http);
4223 http_tls_handle = register_dissector("http-over-tls", dissect_http_tls, proto_http); /* RFC 2818 */
4224 http_sctp_handle = register_dissector("http-over-sctp", dissect_http_sctp, proto_http);
4225
4226 http_module = prefs_register_protocol(proto_http, reinit_http);
4227 prefs_register_bool_preference(http_module, "desegment_headers",
4228 "Reassemble HTTP headers spanning multiple TCP segments",
4229 "Whether the HTTP dissector should reassemble headers "
4230 "of a request spanning multiple TCP segments. "
4231 "To use this option, you must also enable "
4232 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
4233 &http_desegment_headers);
4234 prefs_register_bool_preference(http_module, "desegment_body",
4235 "Reassemble HTTP bodies spanning multiple TCP segments",
4236 "Whether the HTTP dissector should use the "
4237 "\"Content-length:\" value, if present, to reassemble "
4238 "the body of a request spanning multiple TCP segments, "
4239 "and reassemble chunked data spanning multiple TCP segments. "
4240 "To use this option, you must also enable "
4241 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
4242 &http_desegment_body);
4243 prefs_register_bool_preference(http_module, "dechunk_body",
4244 "Reassemble chunked transfer-coded bodies",
4245 "Whether to reassemble bodies of entities that are transferred "
4246 "using the \"Transfer-Encoding: chunked\" method",
4247 &http_dechunk_body);
4248 #if defined(HAVE_ZLIB) || defined(HAVE_BROTLI)
4249 prefs_register_bool_preference(http_module, "decompress_body",
4250 "Uncompress entity bodies",
4251 "Whether to uncompress entity bodies that are compressed "
4252 "using \"Content-Encoding: \"",
4253 &http_decompress_body);
4254 #endif
4255 prefs_register_obsolete_preference(http_module, "tcp_alternate_port");
4256
4257 range_convert_str(wmem_epan_scope(), &global_http_sctp_range, SCTP_DEFAULT_RANGE, 65535);
4258 prefs_register_range_preference(http_module, "sctp.port", "SCTP Ports",
4259 "SCTP Ports range",
4260 &global_http_sctp_range, 65535);
4261
4262 range_convert_str(wmem_epan_scope(), &global_http_tls_range, TLS_DEFAULT_RANGE, 65535);
4263 prefs_register_range_preference(http_module, "tls.port", "SSL/TLS Ports",
4264 "SSL/TLS Ports range",
4265 &global_http_tls_range, 65535);
4266 prefs_register_obsolete_preference(http_module, "ssl.port");
4267 /* UAT */
4268 headers_uat = uat_new("Custom HTTP Header Fields",
4269 sizeof(header_field_t),
4270 "custom_http_header_fields",
4271 TRUE,
4272 &header_fields,
4273 &num_header_fields,
4274 /* specifies named fields, so affects dissection
4275 and the set of named fields */
4276 UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
4277 NULL,
4278 header_fields_copy_cb,
4279 header_fields_update_cb,
4280 header_fields_free_cb,
4281 header_fields_post_update_cb,
4282 header_fields_reset_cb,
4283 custom_header_uat_fields
4284 );
4285
4286 prefs_register_uat_preference(http_module, "custom_http_header_fields", "Custom HTTP header fields",
4287 "A table to define custom HTTP header for which fields can be setup and used for filtering/data extraction etc.",
4288 headers_uat);
4289
4290 /*
4291 * Dissectors shouldn't register themselves in this table;
4292 * instead, they should call "http_tcp_dissector_add()", and
4293 * we'll register the port number they specify as a port
4294 * for HTTP, and register them in our subdissector table.
4295 *
4296 * This only works for protocols such as IPP that run over
4297 * HTTP on a specific non-HTTP port.
4298 */
4299 port_subdissector_table = register_dissector_table("http.port",
4300 "TCP port for protocols using HTTP", proto_http, FT_UINT16, BASE_DEC);
4301
4302 /*
4303 * Dissectors can register themselves in this table.
4304 * It's just "media_type", not "http.content_type", because
4305 * it's an Internet media type, usable by other protocols as well.
4306 */
4307 media_type_subdissector_table =
4308 register_dissector_table("media_type",
4309 "Internet media type", proto_http, FT_STRING, BASE_NONE);
4310
4311 /*
4312 * Maps the lowercase Upgrade header value.
4313 * https://tools.ietf.org/html/rfc7230#section-8.6
4314 */
4315 upgrade_subdissector_table = register_dissector_table("http.upgrade", "HTTP Upgrade", proto_http, FT_STRING, BASE_NONE);
4316
4317 /*
4318 * Heuristic dissectors SHOULD register themselves in
4319 * this table using the standard heur_dissector_add()
4320 * function.
4321 */
4322 heur_subdissector_list = register_heur_dissector_list("http", proto_http);
4323
4324 /*
4325 * Register for tapping
4326 */
4327 http_tap = register_tap("http"); /* HTTP statistics tap */
4328 http_follow_tap = register_tap("http_follow"); /* HTTP Follow tap */
4329 credentials_tap = register_tap("credentials"); /* credentials tap */
4330
4331 register_follow_stream(proto_http, "http_follow", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
4332 tcp_port_to_display, follow_tvb_tap_listener);
4333 http_eo_tap = register_export_object(proto_http, http_eo_packet, NULL);
4334 }
4335
4336 /*
4337 * Called by dissectors for protocols that run atop HTTP/TCP.
4338 */
4339 void
http_tcp_dissector_add(guint32 port,dissector_handle_t handle)4340 http_tcp_dissector_add(guint32 port, dissector_handle_t handle)
4341 {
4342 /*
4343 * Register ourselves as the handler for that port number
4344 * over TCP. "Auto-preference" not needed
4345 */
4346 dissector_add_uint("tcp.port", port, http_tcp_handle);
4347
4348 /*
4349 * And register them in *our* table for that port.
4350 */
4351 dissector_add_uint("http.port", port, handle);
4352 }
4353
4354 WS_DLL_PUBLIC
http_tcp_dissector_delete(guint32 port)4355 void http_tcp_dissector_delete(guint32 port)
4356 {
4357 /*
4358 * Unregister ourselves as the handler for that port number
4359 * over TCP. "Auto-preference" not needed
4360 */
4361 dissector_delete_uint("tcp.port", port, NULL);
4362
4363 /*
4364 * And unregister them in *our* table for that port.
4365 */
4366 dissector_delete_uint("http.port", port, NULL);
4367 }
4368
4369 void
http_tcp_port_add(guint32 port)4370 http_tcp_port_add(guint32 port)
4371 {
4372 /*
4373 * Register ourselves as the handler for that port number
4374 * over TCP. We rely on our caller having registered
4375 * themselves for the appropriate media type.
4376 * No "auto-preference" used.
4377 */
4378 dissector_add_uint("tcp.port", port, http_tcp_handle);
4379 }
4380
4381 void
proto_reg_handoff_http(void)4382 proto_reg_handoff_http(void)
4383 {
4384 dissector_handle_t ssdp_handle;
4385
4386 media_handle = find_dissector_add_dependency("media", proto_http);
4387 http2_handle = find_dissector("http2");
4388 /*
4389 * XXX - is there anything to dissect in the body of an SSDP
4390 * request or reply? I.e., should there be an SSDP dissector?
4391 */
4392 ssdp_handle = create_dissector_handle(dissect_ssdp, proto_ssdp);
4393 dissector_add_uint_with_preference("udp.port", UDP_PORT_SSDP, ssdp_handle);
4394
4395 /*
4396 * TLS Application-Layer Protocol Negotiation (ALPN) protocol ID.
4397 */
4398 dissector_add_string("tls.alpn", "http/1.1", http_tls_handle);
4399
4400 ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_http);
4401 gssapi_handle = find_dissector_add_dependency("gssapi", proto_http);
4402 sstp_handle = find_dissector_add_dependency("sstp", proto_http);
4403
4404 stats_tree_register("http", "http", "HTTP/Packet Counter", 0, http_stats_tree_packet, http_stats_tree_init, NULL );
4405 stats_tree_register("http", "http_req", "HTTP/Requests", 0, http_req_stats_tree_packet, http_req_stats_tree_init, NULL );
4406 stats_tree_register("http", "http_srv", "HTTP/Load Distribution",0, http_reqs_stats_tree_packet, http_reqs_stats_tree_init, NULL );
4407 stats_tree_register("http", "http_seq", "HTTP/Request Sequences",0, http_seq_stats_tree_packet, http_seq_stats_tree_init, NULL );
4408
4409 dissector_add_uint("acdr.tls_application_port", 443, http_handle);
4410 dissector_add_uint("acdr.tls_application", TLS_APP_HTTP, http_handle);
4411 dissector_add_uint("acdr.tls_application", TLS_APP_TR069, http_handle);
4412 dissector_add_uint("ippusb", 0, http_tcp_handle);
4413 }
4414
4415 /*
4416 * Content-Type: message/http
4417 */
4418
4419 static gint proto_message_http = -1;
4420 static gint ett_message_http = -1;
4421
4422 static int
dissect_message_http(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)4423 dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
4424 {
4425 proto_tree *subtree;
4426 proto_item *ti;
4427 gint offset = 0, next_offset;
4428 gint len;
4429
4430 col_append_str(pinfo->cinfo, COL_INFO, " (message/http)");
4431 if (tree) {
4432 ti = proto_tree_add_item(tree, proto_message_http,
4433 tvb, 0, -1, ENC_NA);
4434 subtree = proto_item_add_subtree(ti, ett_message_http);
4435 while (tvb_offset_exists(tvb, offset)) {
4436 len = tvb_find_line_end(tvb, offset,
4437 tvb_ensure_captured_length_remaining(tvb, offset),
4438 &next_offset, FALSE);
4439 if (len == -1)
4440 break;
4441 proto_tree_add_format_text(subtree, tvb, offset, len);
4442 offset = next_offset;
4443 }
4444 }
4445 return tvb_captured_length(tvb);
4446 }
4447
4448 void
proto_register_message_http(void)4449 proto_register_message_http(void)
4450 {
4451 static gint *ett[] = {
4452 &ett_message_http,
4453 };
4454
4455 proto_message_http = proto_register_protocol(
4456 "Media Type: message/http",
4457 "message/http",
4458 "message-http"
4459 );
4460 proto_register_subtree_array(ett, array_length(ett));
4461 }
4462
4463 void
proto_reg_handoff_message_http(void)4464 proto_reg_handoff_message_http(void)
4465 {
4466 dissector_handle_t message_http_handle;
4467
4468 message_http_handle = create_dissector_handle(dissect_message_http,
4469 proto_message_http);
4470
4471 dissector_add_string("media_type", "message/http", message_http_handle);
4472
4473 heur_dissector_add("tcp", dissect_http_heur_tcp, "HTTP over TCP", "http_tcp", proto_http, HEURISTIC_ENABLE);
4474 heur_dissector_add("tls", dissect_http_heur_tls, "HTTP over TLS", "http_tls", proto_http, HEURISTIC_ENABLE);
4475
4476 proto_http2 = proto_get_id_by_filter_name("http2");
4477
4478 dissector_add_uint_range_with_preference("tcp.port", TCP_DEFAULT_RANGE, http_tcp_handle);
4479
4480 reinit_http();
4481 }
4482
4483 /*
4484 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4485 *
4486 * Local variables:
4487 * c-basic-offset: 8
4488 * tab-width: 8
4489 * indent-tabs-mode: t
4490 * End:
4491 *
4492 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
4493 * :indentSize=8:tabSize=8:noTabs=false:
4494 */
4495