aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2018-08-12 18:51:10 +0200
committerAnders Broman <a.broman58@gmail.com>2018-08-13 08:20:35 +0000
commitca75c14f05777f2aa35f3c69aa547822bcc6081b (patch)
treefdca5559015d8e266af1a5c719de7fba4a4a6668
parent3a9f1717634a331507e9ccae74108fd9e3c1222a (diff)
HTTP: create dissector table for HTTP Upgrade
Based on an idea from David M. Lloyd, let subdissectors register themselves with the HTTP dissector based on the Upgrade header instead of the other way round. Tested with SSTP (bug 82390), WebSocket (bug 13889), HTTP2 PRI without Upgrade (bug 11331), h2c (from HTTP2 wiki), spdy/3.1 (bug 12874). Change-Id: I1425b7119d4d85e626032408504fc2c6b2f2eeb8 Reviewed-on: https://code.wireshark.org/review/29112 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--epan/dissectors/packet-http.c73
-rw-r--r--epan/dissectors/packet-http.h2
-rw-r--r--epan/dissectors/packet-http2.c5
-rw-r--r--epan/dissectors/packet-spdy.c1
-rw-r--r--epan/dissectors/packet-websocket.c5
5 files changed, 40 insertions, 46 deletions
diff --git a/epan/dissectors/packet-http.c b/epan/dissectors/packet-http.c
index c6589176c9..5f16071321 100644
--- a/epan/dissectors/packet-http.c
+++ b/epan/dissectors/packet-http.c
@@ -146,10 +146,8 @@ static dissector_handle_t http_ssl_handle;
static dissector_handle_t http_sctp_handle;
static dissector_handle_t media_handle;
-static dissector_handle_t websocket_handle;
static dissector_handle_t http2_handle;
static dissector_handle_t sstp_handle;
-static dissector_handle_t spdy_handle;
static dissector_handle_t ntlmssp_handle;
static dissector_handle_t gssapi_handle;
@@ -265,11 +263,6 @@ static gboolean http_decompress_body = FALSE;
#define SCTP_DEFAULT_RANGE "80"
#define SSL_DEFAULT_RANGE "443"
-#define UPGRADE_WEBSOCKET 1
-#define UPGRADE_HTTP2 2
-#define UPGRADE_SSTP 3
-#define UPGRADE_SPDY 4
-
static range_t *global_http_sctp_range = NULL;
static range_t *global_http_ssl_range = NULL;
@@ -307,7 +300,7 @@ typedef struct {
char *content_encoding;
gboolean transfer_encoding_chunked;
http_transfer_coding transfer_encoding;
- guint8 upgrade;
+ char *upgrade;
} headers_t;
static int is_http_request_or_reply(const gchar *data, int linelen,
@@ -332,6 +325,7 @@ static gboolean check_auth_kerberos(proto_item *hdr_item, tvbuff_t *tvb,
static dissector_table_t port_subdissector_table;
static dissector_table_t media_type_subdissector_table;
+static dissector_table_t upgrade_subdissector_table;
static heur_dissector_list_t heur_subdissector_list;
/* Used for HTTP Export Object feature */
@@ -1227,7 +1221,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
headers.content_encoding = NULL; /* content encoding not known yet */
headers.transfer_encoding_chunked = FALSE;
headers.transfer_encoding = HTTP_TE_NONE;
- headers.upgrade = 0; /* assume we're not upgrading */
+ headers.upgrade = NULL; /* assume no upgrade header */
saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
while (tvb_offset_exists(tvb, offset)) {
/*
@@ -1867,13 +1861,16 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
}
/* Detect protocol changes after receiving full response headers. */
- if (http_type == HTTP_RESPONSE && pinfo->desegment_offset <= 0 && pinfo->desegment_len <= 0) {
+ if (conv_data->request_method && http_type == HTTP_RESPONSE && pinfo->desegment_offset <= 0 && pinfo->desegment_len <= 0) {
+ dissector_handle_t next_handle = NULL;
gboolean server_acked = FALSE;
+
/*
* SSTP uses a special request method (instead of the Upgrade
* header) and expects a 200 response to set up the session.
*/
- if (conv_data->upgrade == UPGRADE_SSTP && conv_data->response_code == 200) {
+ if (strcmp(conv_data->request_method, "SSTP_DUPLEX_POST") == 0 && conv_data->response_code == 200) {
+ next_handle = sstp_handle;
server_acked = TRUE;
}
@@ -1882,13 +1879,22 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
* with 101 Switching Protocols. See RFC 7230 Section 6.7.
*/
if (headers.upgrade && conv_data->response_code == 101) {
- conv_data->upgrade = headers.upgrade;
+ next_handle = dissector_get_string_handle(upgrade_subdissector_table, headers.upgrade);
+ if (!next_handle) {
+ char *slash_pos = strchr(headers.upgrade, '/');
+ if (slash_pos) {
+ /* Try again without version suffix. */
+ next_handle = dissector_get_string_handle(upgrade_subdissector_table,
+ wmem_strndup(wmem_packet_scope(), headers.upgrade, slash_pos - headers.upgrade));
+ }
+ }
server_acked = TRUE;
}
if (server_acked) {
conv_data->startframe = pinfo->num;
conv_data->startoffset = offset;
+ conv_data->next_handle = next_handle;
copy_address_wmem(wmem_file_scope(), &conv_data->server_addr, &pinfo->src);
conv_data->server_port = pinfo->srcport;
}
@@ -2643,7 +2649,6 @@ is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
} else if (strncmp(data, "SSTP_DUPLEX_POST", indx) == 0) { /* MS SSTP */
*type = HTTP_REQUEST;
isHttpRequestOrReply = TRUE;
- conv_data->upgrade = UPGRADE_SSTP;
}
break;
@@ -3181,16 +3186,7 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
break;
case HDR_UPGRADE:
- if (g_ascii_strncasecmp(value, "WebSocket", value_len) == 0) {
- eh_ptr->upgrade = UPGRADE_WEBSOCKET;
- }
- /* Check if upgrade is HTTP 2.0 (Start with h2...) */
- if ( (g_str_has_prefix(value, "h2")) == 1){
- eh_ptr->upgrade = UPGRADE_HTTP2;
- }
- if (g_ascii_strncasecmp(value, "spdy/", 5) == 0) {
- eh_ptr->upgrade = UPGRADE_SPDY;
- }
+ eh_ptr->upgrade = wmem_ascii_strdown(wmem_packet_scope(), value, value_len);
break;
case HDR_COOKIE:
@@ -3456,34 +3452,23 @@ dissect_http_on_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
{
int offset = 0;
int len;
- dissector_handle_t next_handle = NULL;
while (tvb_reported_length_remaining(tvb, offset) > 0) {
/* Switch protocol if the data starts after response headers. */
if (conv_data->startframe &&
(pinfo->num > conv_data->startframe ||
(pinfo->num == conv_data->startframe && offset >= conv_data->startoffset))) {
- if (conv_data->upgrade == UPGRADE_WEBSOCKET) {
- next_handle = websocket_handle;
- }
- if (conv_data->upgrade == UPGRADE_HTTP2) {
- next_handle = http2_handle;
- }
- if (conv_data->upgrade == UPGRADE_SSTP) {
- next_handle = sstp_handle;
- }
- if (conv_data->upgrade == UPGRADE_SPDY) {
- next_handle = spdy_handle;
- }
- }
- if (next_handle) {
/* Increase pinfo->can_desegment because we are traversing
* http and want to preserve desegmentation functionality for
* the proxied protocol
*/
if (pinfo->can_desegment > 0)
pinfo->can_desegment++;
- call_dissector_only(next_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
+ if (conv_data->next_handle) {
+ call_dissector_only(conv_data->next_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
+ } else {
+ call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
+ }
break;
}
len = dissect_http_message(tvb, offset, pinfo, tree, conv_data, "HTTP", proto_http, end_of_stream);
@@ -3513,7 +3498,7 @@ dissect_http_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
/* Call HTTP2 dissector directly when detected via heuristics, but not
* when it was upgraded (the conversation started with HTTP). */
if (conversation_get_proto_data(conversation, proto_http2) &&
- conv_data->upgrade != UPGRADE_HTTP2) {
+ !conv_data->startframe) {
if (pinfo->can_desegment > 0)
pinfo->can_desegment++;
return call_dissector_only(http2_handle, tvb, pinfo, tree, data);
@@ -4061,6 +4046,12 @@ proto_register_http(void)
"Internet media type", proto_http, FT_STRING, BASE_NONE);
/*
+ * Maps the lowercase Upgrade header value.
+ * https://tools.ietf.org/html/rfc7230#section-8.6
+ */
+ upgrade_subdissector_table = register_dissector_table("http.upgrade", "HTTP Upgrade", proto_http, FT_STRING, BASE_NONE);
+
+ /*
* Heuristic dissectors SHOULD register themselves in
* this table using the standard heur_dissector_add()
* function.
@@ -4129,7 +4120,6 @@ proto_reg_handoff_http(void)
dissector_handle_t ssdp_handle;
media_handle = find_dissector_add_dependency("media", proto_http);
- websocket_handle = find_dissector_add_dependency("websocket", proto_http);
http2_handle = find_dissector("http2");
/*
* XXX - is there anything to dissect in the body of an SSDP
@@ -4147,7 +4137,6 @@ proto_reg_handoff_http(void)
ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_http);
gssapi_handle = find_dissector_add_dependency("gssapi", proto_http);
sstp_handle = find_dissector_add_dependency("sstp", proto_http);
- spdy_handle = find_dissector_add_dependency("spdy", proto_http);
stats_tree_register("http", "http", "HTTP/Packet Counter", 0, http_stats_tree_packet, http_stats_tree_init, NULL );
stats_tree_register("http", "http_req", "HTTP/Requests", 0, http_req_stats_tree_packet, http_req_stats_tree_init, NULL );
diff --git a/epan/dissectors/packet-http.h b/epan/dissectors/packet-http.h
index 129cfc67c3..ae42aa3f2b 100644
--- a/epan/dissectors/packet-http.h
+++ b/epan/dissectors/packet-http.h
@@ -63,7 +63,7 @@ typedef struct _http_conv_t {
/* Fields related to proxied/tunneled/Upgraded connections. */
guint32 startframe; /* First frame of proxied connection */
int startoffset; /* Offset within the frame where the new protocol begins. */
- guint8 upgrade;
+ dissector_handle_t next_handle; /* New protocol */
gchar *websocket_protocol; /* Negotiated WebSocket protocol */
gchar *websocket_extensions; /* Negotiated WebSocket extensions */
diff --git a/epan/dissectors/packet-http2.c b/epan/dissectors/packet-http2.c
index ba5c8abeee..77683d5bdd 100644
--- a/epan/dissectors/packet-http2.c
+++ b/epan/dissectors/packet-http2.c
@@ -3347,10 +3347,11 @@ proto_reg_handoff_http2(void)
dissector_add_for_decode_as_with_preference("tcp.port", http2_handle);
/*
- * SSL/TLS Application-Layer Protocol Negotiation (ALPN) protocol
- * ID.
+ * SSL/TLS Application-Layer Protocol Negotiation (ALPN) protocol ID.
*/
dissector_add_string("ssl.handshake.extensions_alpn_str", "h2", http2_handle);
+ dissector_add_string("http.upgrade", "h2", http2_handle);
+ dissector_add_string("http.upgrade", "h2c", http2_handle);
heur_dissector_add("ssl", dissect_http2_heur_ssl, "HTTP2 over SSL", "http2_ssl", proto_http2, HEURISTIC_ENABLE);
heur_dissector_add("http", dissect_http2_heur, "HTTP2 over TCP", "http2_tcp", proto_http2, HEURISTIC_ENABLE);
diff --git a/epan/dissectors/packet-spdy.c b/epan/dissectors/packet-spdy.c
index 048d467159..c773eff3e5 100644
--- a/epan/dissectors/packet-spdy.c
+++ b/epan/dissectors/packet-spdy.c
@@ -1940,6 +1940,7 @@ void proto_reg_handoff_spdy(void) {
dissector_add_uint_with_preference("tcp.port", TCP_PORT_SPDY, spdy_handle);
/* Use "0" to avoid overwriting HTTPS port and still offer support over SSL */
ssl_dissector_add(0, spdy_handle);
+ dissector_add_string("http.upgrade", "spdy", spdy_handle);
media_handle = find_dissector_add_dependency("media", proto_spdy);
port_subdissector_table = find_dissector_table("http.port");
diff --git a/epan/dissectors/packet-websocket.c b/epan/dissectors/packet-websocket.c
index decb724e91..37aee6ed67 100644
--- a/epan/dissectors/packet-websocket.c
+++ b/epan/dissectors/packet-websocket.c
@@ -36,6 +36,7 @@
void proto_register_websocket(void);
void proto_reg_handoff_websocket(void);
+static dissector_handle_t websocket_handle;
static dissector_handle_t text_lines_handle;
static dissector_handle_t json_handle;
static dissector_handle_t sip_handle;
@@ -793,7 +794,7 @@ proto_register_websocket(void)
expert_websocket = expert_register_protocol(proto_websocket);
expert_register_field_array(expert_websocket, ei, array_length(ei));
- register_dissector("websocket", dissect_websocket, proto_websocket);
+ websocket_handle = register_dissector("websocket", dissect_websocket, proto_websocket);
websocket_module = prefs_register_protocol(proto_websocket, proto_reg_handoff_websocket);
@@ -808,6 +809,8 @@ proto_register_websocket(void)
void
proto_reg_handoff_websocket(void)
{
+ dissector_add_string("http.upgrade", "websocket", websocket_handle);
+
text_lines_handle = find_dissector_add_dependency("data-text-lines", proto_websocket);
json_handle = find_dissector_add_dependency("json", proto_websocket);
sip_handle = find_dissector_add_dependency("sip", proto_websocket);