Don't assume the HTTP dissector is being called from the TCP dissector.

It's not - it could be called from the SSL dissector or the SCTP
dissector.  Create separate dissectors for all of them; they can, if
passed appropriate metadata in the "data" argument, process it
appropriately for the type of metadata the calling tissector supplies.

Bug: 12344
Change-Id: I8d9a2f3173e6de42b31993bbb6c81d161f68bf8c
Reviewed-on: https://code.wireshark.org/review/14944
Reviewed-by: Guy Harris <guy@alum.mit.edu>
This commit is contained in:
Guy Harris 2016-04-16 19:31:22 -07:00
parent 173ccf7a46
commit 8c3b36deb8
6 changed files with 140 additions and 62 deletions

View File

@ -417,7 +417,7 @@ void proto_reg_handoff_cmp(void) {
dissector_delete_uint("http.port", cmp_alternate_http_port_prev, NULL);
}
if (cmp_alternate_http_port != 0)
http_dissector_add( cmp_alternate_http_port, cmp_http_handle);
http_tcp_dissector_add( cmp_alternate_http_port, cmp_http_handle);
cmp_alternate_http_port_prev = cmp_alternate_http_port;
}
@ -428,7 +428,7 @@ void proto_reg_handoff_cmp(void) {
dissector_delete_uint("http.port", cmp_alternate_tcp_style_http_port_prev, NULL);
}
if (cmp_alternate_tcp_style_http_port != 0)
http_dissector_add( cmp_alternate_tcp_style_http_port, cmp_tcp_style_http_handle);
http_tcp_dissector_add( cmp_alternate_tcp_style_http_port, cmp_tcp_style_http_handle);
cmp_alternate_tcp_style_http_port_prev = cmp_alternate_tcp_style_http_port;
}

View File

@ -2538,7 +2538,7 @@ void proto_reg_handoff_cmp(void) {
dissector_delete_uint("http.port", cmp_alternate_http_port_prev, NULL);
}
if (cmp_alternate_http_port != 0)
http_dissector_add( cmp_alternate_http_port, cmp_http_handle);
http_tcp_dissector_add( cmp_alternate_http_port, cmp_http_handle);
cmp_alternate_http_port_prev = cmp_alternate_http_port;
}
@ -2549,7 +2549,7 @@ void proto_reg_handoff_cmp(void) {
dissector_delete_uint("http.port", cmp_alternate_tcp_style_http_port_prev, NULL);
}
if (cmp_alternate_tcp_style_http_port != 0)
http_dissector_add( cmp_alternate_tcp_style_http_port, cmp_tcp_style_http_handle);
http_tcp_dissector_add( cmp_alternate_tcp_style_http_port, cmp_tcp_style_http_handle);
cmp_alternate_tcp_style_http_port_prev = cmp_alternate_tcp_style_http_port;
}

View File

@ -775,7 +775,7 @@ proto_reg_handoff_daap(void)
dissector_handle_t daap_handle;
daap_handle = create_dissector_handle(dissect_daap, proto_daap);
http_port_add(TCP_PORT_DAAP);
http_tcp_port_add(TCP_PORT_DAAP);
dissector_add_string("media_type", "application/x-dmap-tagged", daap_handle);
png_handle = find_dissector_add_dependency("png", proto_daap);

View File

@ -151,6 +151,9 @@ static expert_field ei_http_ssl_port = EI_INIT;
static expert_field ei_http_leading_crlf = EI_INIT;
static dissector_handle_t http_handle;
static dissector_handle_t http_tcp_handle;
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;
@ -723,7 +726,8 @@ static http_info_value_t *stat_info;
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, struct tcpinfo *tcpinfo)
proto_tree *tree, http_conv_t *conv_data,
const char* proto_tag, int proto, gboolean end_of_stream)
{
proto_tree *http_tree = NULL;
proto_item *ti = NULL;
@ -830,7 +834,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
*/
gboolean try_desegment_body = (http_desegment_body &&
(!(conv_data->request_method && g_str_equal(conv_data->request_method, "HEAD"))) &&
((tcpinfo == NULL) || (!IS_TH_FIN(tcpinfo->flags))));
!end_of_stream);
if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
http_desegment_headers, try_desegment_body)) {
/*
@ -2034,6 +2038,19 @@ chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
}
#endif
static gboolean
conversation_dissector_is_http(conversation_t *conv, guint32 frame_num)
{
dissector_handle_t conv_handle;
if (conv == NULL)
return FALSE;
conv_handle = conversation_get_dissector(conv, frame_num);
return conv_handle == http_handle ||
conv_handle == http_tcp_handle ||
conv_handle == http_sctp_handle;
}
/* Call a subdissector to handle HTTP CONNECT's traffic */
static void
http_payload_subdissector(tvbuff_t *tvb, proto_tree *tree,
@ -2086,7 +2103,8 @@ http_payload_subdissector(tvbuff_t *tvb, proto_tree *tree,
* conversation (e.g., one we detected heuristically or via Decode-As) call the data
* dissector directly.
*/
if (value_is_in_range(http_tcp_range, uri_port) || (conv && conversation_get_dissector(conv, pinfo->num) == http_handle)) {
if (value_is_in_range(http_tcp_range, uri_port) ||
conversation_dissector_is_http(conv, pinfo->num)) {
call_data_dissector(tvb, pinfo, tree);
} else {
/* set pinfo->{src/dst port} and call the TCP sub-dissector lookup */
@ -3009,17 +3027,58 @@ check_auth_kerberos(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, con
return FALSE;
}
static int
dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
static void
dissect_http_on_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
http_conv_t *conv_data, gboolean end_of_stream)
{
http_conv_t *conv_data;
int offset = 0;
int len;
conversation_t *conversation;
dissector_handle_t next_handle = NULL;
while (tvb_reported_length_remaining(tvb, offset) > 0) {
if (conv_data->upgrade == UPGRADE_WEBSOCKET && pinfo->num >= conv_data->startframe) {
next_handle = websocket_handle;
}
if (conv_data->upgrade == UPGRADE_HTTP2 && pinfo->num >= conv_data->startframe) {
next_handle = http2_handle;
}
if (conv_data->upgrade == UPGRADE_SSTP && conv_data->response_code == 200 && pinfo->num >= conv_data->startframe) {
next_handle = sstp_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);
break;
}
len = dissect_http_message(tvb, offset, pinfo, tree, conv_data, "HTTP", proto_http, end_of_stream);
if (len == -1)
break;
offset += len;
/*
* OK, we've set the Protocol and Info columns for the
* first HTTP message; set a fence so that subsequent
* HTTP messages don't overwrite the Info column.
*/
col_set_fence(pinfo->cinfo, COL_INFO);
}
}
static int
dissect_http_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
conversation_t *conversation;
http_conv_t *conv_data;
gboolean end_of_stream;
conv_data = get_http_conversation_data(pinfo, &conversation);
/* 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) &&
@ -3041,42 +3100,12 @@ dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
if(conv_data->startframe == 0 && !pinfo->fd->flags.visited)
conv_data->startframe = pinfo->num;
http_payload_subdissector(tvb, tree, pinfo, conv_data, data);
} else {
while (tvb_reported_length_remaining(tvb, offset) > 0) {
if (conv_data->upgrade == UPGRADE_WEBSOCKET && pinfo->num >= conv_data->startframe) {
next_handle = websocket_handle;
}
if (conv_data->upgrade == UPGRADE_HTTP2 && pinfo->num >= conv_data->startframe) {
next_handle = http2_handle;
}
if (conv_data->upgrade == UPGRADE_SSTP && conv_data->response_code == 200 && pinfo->num >= conv_data->startframe) {
next_handle = sstp_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);
break;
}
len = dissect_http_message(tvb, offset, pinfo, tree, conv_data, "HTTP", proto_http, tcpinfo);
if (len == -1)
break;
offset += len;
/*
* OK, we've set the Protocol and Info columns for the
* first HTTP message; set a fence so that subsequent
* HTTP messages don't overwrite the Info column.
*/
col_set_fence(pinfo->cinfo, COL_INFO);
}
return tvb_captured_length(tvb);
}
end_of_stream = IS_TH_FIN(tcpinfo->flags);
dissect_http_on_stream(tvb, pinfo, tree, conv_data, end_of_stream);
return tvb_captured_length(tvb);
}
@ -3101,14 +3130,60 @@ dissect_http_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
/* Check if the line start or ends with the HTTP token */
if((tvb_strncaseeql(tvb, linelen-8, "HTTP/1.1", 8) == 0)||(tvb_strncaseeql(tvb, 0, "HTTP/1.1", 8) == 0)){
conversation = find_or_create_conversation(pinfo);
conversation_set_dissector_from_frame_number(conversation, pinfo->num, http_handle);
dissect_http(tvb, pinfo, tree, data);
conversation_set_dissector_from_frame_number(conversation, pinfo->num, http_tcp_handle);
dissect_http_tcp(tvb, pinfo, tree, data);
return TRUE;
}
return FALSE;
}
static int
dissect_http_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
conversation_t *conversation;
http_conv_t *conv_data;
conv_data = get_http_conversation_data(pinfo, &conversation);
/*
* XXX - we need to provide an end-of-stream indication.
*/
dissect_http_on_stream(tvb, pinfo, tree, conv_data, FALSE);
return tvb_captured_length(tvb);
}
static int
dissect_http_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
conversation_t *conversation;
http_conv_t *conv_data;
conv_data = get_http_conversation_data(pinfo, &conversation);
/*
* XXX - we need to provide an end-of-stream indication.
*/
dissect_http_on_stream(tvb, pinfo, tree, conv_data, FALSE);
return tvb_captured_length(tvb);
}
static int
dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
conversation_t *conversation;
http_conv_t *conv_data;
conv_data = get_http_conversation_data(pinfo, &conversation);
/*
* XXX - what should be done about reassembly, pipelining, etc.
* here?
*/
dissect_http_on_stream(tvb, pinfo, tree, conv_data, FALSE);
return tvb_captured_length(tvb);
}
static int
dissect_ssdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
@ -3116,30 +3191,30 @@ dissect_ssdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
http_conv_t *conv_data;
conv_data = get_http_conversation_data(pinfo, &conversation);
dissect_http_message(tvb, 0, pinfo, tree, conv_data, "SSDP", proto_ssdp, NULL);
dissect_http_message(tvb, 0, pinfo, tree, conv_data, "SSDP", proto_ssdp, FALSE);
return tvb_captured_length(tvb);
}
static void
range_delete_http_ssl_callback(guint32 port) {
ssl_dissector_delete(port, http_handle);
ssl_dissector_delete(port, http_ssl_handle);
}
static void
range_add_http_ssl_callback(guint32 port) {
ssl_dissector_add(port, http_handle);
ssl_dissector_add(port, http_ssl_handle);
}
static void reinit_http(void) {
dissector_delete_uint_range("tcp.port", http_tcp_range, http_handle);
dissector_delete_uint_range("tcp.port", http_tcp_range, http_tcp_handle);
g_free(http_tcp_range);
http_tcp_range = range_copy(global_http_tcp_range);
dissector_add_uint_range("tcp.port", http_tcp_range, http_handle);
dissector_add_uint_range("tcp.port", http_tcp_range, http_tcp_handle);
dissector_delete_uint_range("sctp.port", http_sctp_range, http_handle);
dissector_delete_uint_range("sctp.port", http_sctp_range, http_sctp_handle);
g_free(http_sctp_range);
http_sctp_range = range_copy(global_http_sctp_range);
dissector_add_uint_range("sctp.port", http_sctp_range, http_handle);
dissector_add_uint_range("sctp.port", http_sctp_range, http_sctp_handle);
range_foreach(http_ssl_range, range_delete_http_ssl_callback);
g_free(http_ssl_range);
@ -3441,6 +3516,9 @@ proto_register_http(void)
expert_register_field_array(expert_http, ei, array_length(ei));
http_handle = register_dissector("http", dissect_http, proto_http);
http_tcp_handle = register_dissector("http-over-tcp", dissect_http_tcp, proto_http);
http_ssl_handle = register_dissector("http-over-ssl", dissect_http_ssl, proto_http);
http_sctp_handle = register_dissector("http-over-sctp", dissect_http_sctp, proto_http);
http_module = prefs_register_protocol(proto_http, reinit_http);
prefs_register_bool_preference(http_module, "desegment_headers",
@ -3514,7 +3592,7 @@ proto_register_http(void)
/*
* Dissectors shouldn't register themselves in this table;
* instead, they should call "http_dissector_add()", and
* instead, they should call "http_tcp_dissector_add()", and
* we'll register the port number they specify as a port
* for HTTP, and register them in our subdissector table.
*
@ -3555,13 +3633,13 @@ proto_register_http(void)
* Called by dissectors for protocols that run atop HTTP/TCP.
*/
void
http_dissector_add(guint32 port, dissector_handle_t handle)
http_tcp_dissector_add(guint32 port, dissector_handle_t handle)
{
/*
* Register ourselves as the handler for that port number
* over TCP.
*/
dissector_add_uint("tcp.port", port, http_handle);
dissector_add_uint("tcp.port", port, http_tcp_handle);
/*
* And register them in *our* table for that port.
@ -3570,14 +3648,14 @@ http_dissector_add(guint32 port, dissector_handle_t handle)
}
void
http_port_add(guint32 port)
http_tcp_port_add(guint32 port)
{
/*
* Register ourselves as the handler for that port number
* over TCP. We rely on our caller having registered
* themselves for the appropriate media type.
*/
dissector_add_uint("tcp.port", port, http_handle);
dissector_add_uint("tcp.port", port, http_tcp_handle);
}
void

View File

@ -28,9 +28,9 @@
extern const value_string vals_http_status_code[];
WS_DLL_PUBLIC
void http_dissector_add(guint32 port, dissector_handle_t handle);
void http_tcp_dissector_add(guint32 port, dissector_handle_t handle);
WS_DLL_PUBLIC
void http_port_add(guint32 port);
void http_tcp_port_add(guint32 port);
/* Used for HTTP statistics */
typedef struct _http_info_value_t {

View File

@ -715,7 +715,7 @@ proto_reg_handoff_ipp(void)
* Register ourselves as running atop HTTP and using port 631.
*/
ipp_handle = create_dissector_handle(dissect_ipp, proto_ipp);
http_dissector_add(631, ipp_handle);
http_tcp_dissector_add(631, ipp_handle);
dissector_add_string("media_type", "application/ipp", ipp_handle);
}