diff options
author | Martin Mathieson <martin.r.mathieson@googlemail.com> | 2017-08-05 12:18:43 +0100 |
---|---|---|
committer | Martin Mathieson <martin.r.mathieson@googlemail.com> | 2017-08-10 22:03:45 +0000 |
commit | ef24608db1e4b881667ca7a670a76842ae52853d (patch) | |
tree | 1abd782431d11ebbfb20c92664b3a941bf23859f /epan/dissectors/packet-ftp.c | |
parent | 108b9b869bfe7475be0218d5f9682818dd3f4e8b (diff) |
Link forward to ftp-data from ftp commands
Change-Id: I57013fefed2e588749a208bb3e3562ca4bbef0ac
Reviewed-on: https://code.wireshark.org/review/22953
Petri-Dish: Martin Mathieson <martin.r.mathieson@googlemail.com>
Petri-Dish: Graham Bloice <graham.bloice@trihedral.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Martin Mathieson <martin.r.mathieson@googlemail.com>
Diffstat (limited to 'epan/dissectors/packet-ftp.c')
-rw-r--r-- | epan/dissectors/packet-ftp.c | 124 |
1 files changed, 102 insertions, 22 deletions
diff --git a/epan/dissectors/packet-ftp.c b/epan/dissectors/packet-ftp.c index b5cb5da4e5..0902115aa5 100644 --- a/epan/dissectors/packet-ftp.c +++ b/epan/dissectors/packet-ftp.c @@ -61,10 +61,14 @@ static int hf_ftp_eprt_port = -1; static int hf_ftp_epsv_ip = -1; static int hf_ftp_epsv_ipv6 = -1; static int hf_ftp_epsv_port = -1; +static int hf_ftp_command_response_frames = -1; +static int hf_ftp_command_response_first_frame_num = -1; + static int hf_ftp_data_setup_frame = -1; static int hf_ftp_data_setup_method = -1; static int hf_ftp_data_command = -1; +static int hf_ftp_data_command_frame = -1; static int hf_ftp_data_current_working_directory = -1; static gint ett_ftp = -1; @@ -157,21 +161,30 @@ static const value_string eprt_af_vals[] = { typedef struct ftp_data_conversation_t { - const gchar *command; /* Command that this data answers */ + const gchar *command; /* Command that this data answers */ + guint32 command_frame; /* Frame command was seen */ const gchar *setup_method; /* Type of command used to set up data conversation */ wmem_strbuf_t *current_working_directory; + + /* Summary details of stream to show in command frame. + * Could include last frame, data rate, etc */ + guint first_frame_num; + guint frames_seen; } ftp_data_conversation_t; +/* Data to associate with individual FTP frame */ typedef struct ftp_packet_data_t { wmem_strbuf_t *current_working_directory; } ftp_packet_data_t; +/* State of FTP conversation */ typedef struct ftp_conversation_t { - const gchar *last_command; + const gchar *last_command; /* Most recent request command seen (on first pass) */ + guint32 last_command_frame; /* When request was seen */ wmem_strbuf_t *current_working_directory; - ftp_data_conversation_t *current_data_conv; + ftp_data_conversation_t *current_data_conv; /* Current data conversation (during first pass) */ } ftp_conversation_t; /* For a given packet, retrieve or initialise a new conversation, and return it */ @@ -193,6 +206,10 @@ static ftp_conversation_t *find_or_create_ftp_conversation(packet_info *pinfo) return p_ftp_conv; } +/* Keep track of ftp_data_conversation_t*, keyed by the ftp command frame */ +static GHashTable *ftp_command_to_data_hash = NULL; + + /* When new data conversation is being created, should: * - create data conversation * - create control conversation, and have it point at control conversation @@ -926,10 +943,15 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) command yet, attempt to update here */ if (p_ftp_conv) { p_ftp_conv->last_command = wmem_strndup(wmem_file_scope(), line, linelen); + p_ftp_conv->last_command_frame = pinfo->num; } /* And make sure set for FTP data conversation */ if (p_ftp_conv && p_ftp_conv->current_data_conv && !p_ftp_conv->current_data_conv->command) { p_ftp_conv->current_data_conv->command = wmem_strndup(wmem_file_scope(), line, linelen); + p_ftp_conv->current_data_conv->command_frame = pinfo->num; + + /* Add to table to ftp-data response can be shown with this frame on later passes */ + g_hash_table_insert(ftp_command_to_data_hash, GUINT_TO_POINTER(pinfo->num), p_ftp_conv->current_data_conv); } } else { /* @@ -1255,13 +1277,30 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) } } + /* If this is a command resulting in an ftp-data stream, show details */ + if (pinfo->fd->flags.visited) { + ftp_data_conversation_t *ftp_data = + (ftp_data_conversation_t *)g_hash_table_lookup(ftp_command_to_data_hash, GUINT_TO_POINTER(pinfo->num)); + if (ftp_data) { + /* Number of frames */ + ti = proto_tree_add_uint(tree, hf_ftp_command_response_frames, + tvb, 0, 0, ftp_data->frames_seen); + PROTO_ITEM_SET_GENERATED(ti); + + /* First frame */ + ti = proto_tree_add_uint(tree, hf_ftp_command_response_first_frame_num, + tvb, 0, 0, ftp_data->first_frame_num); + PROTO_ITEM_SET_GENERATED(ti); + } + } + return tvb_captured_length(tvb); } static int dissect_ftpdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { - proto_item *ti; + proto_item *data_ti, *ti; int data_length = tvb_captured_length(tvb); gboolean is_text = TRUE; gint check_chars, i; @@ -1273,7 +1312,7 @@ dissect_ftpdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data col_add_fstr(pinfo->cinfo, COL_INFO, "FTP Data: %u bytes", tvb_reported_length(tvb)); - ti = proto_tree_add_item(tree, proto_ftp_data, tvb, 0, -1, ENC_NA); + data_ti = proto_tree_add_item(tree, proto_ftp_data, tvb, 0, -1, ENC_NA); /* Link back to setup of this stream */ p_conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, @@ -1282,36 +1321,47 @@ dissect_ftpdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data 0); if (p_conv) { - proto_item *setup_ti; - setup_ti = proto_tree_add_uint(tree, hf_ftp_data_setup_frame, - tvb, 0, 0, p_conv->setup_frame); - PROTO_ITEM_SET_GENERATED(setup_ti); + /* Link back to FTP frame where this conversation was created */ + ti = proto_tree_add_uint(tree, hf_ftp_data_setup_frame, + tvb, 0, 0, p_conv->setup_frame); + PROTO_ITEM_SET_GENERATED(ti); p_ftp_data_conv = (ftp_data_conversation_t*)conversation_get_proto_data(p_conv, proto_ftp_data); if (p_ftp_data_conv) { + /* First time around, update info. */ + if (!pinfo->fd->flags.visited) { + if (!p_ftp_data_conv->first_frame_num) { + p_ftp_data_conv->first_frame_num = pinfo->num; + } + p_ftp_data_conv->frames_seen++; + } + /* Show setup method as field and in info column */ if (p_ftp_data_conv->setup_method) { - setup_ti = proto_tree_add_string(tree, hf_ftp_data_setup_method, - tvb, 0, 0, p_ftp_data_conv->setup_method); + ti = proto_tree_add_string(tree, hf_ftp_data_setup_method, + tvb, 0, 0, p_ftp_data_conv->setup_method); col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", p_ftp_data_conv->setup_method); - PROTO_ITEM_SET_GENERATED(setup_ti); + PROTO_ITEM_SET_GENERATED(ti); } /* Show command in info column */ if (p_ftp_data_conv->command) { - proto_item *desc_ti; - desc_ti = proto_tree_add_string(tree, hf_ftp_data_command, - tvb, 0, 0, p_ftp_data_conv->command); - PROTO_ITEM_SET_GENERATED(desc_ti); + ti = proto_tree_add_string(tree, hf_ftp_data_command, + tvb, 0, 0, p_ftp_data_conv->command); + PROTO_ITEM_SET_GENERATED(ti); col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", p_ftp_data_conv->command); + + proto_tree_add_uint(tree, hf_ftp_data_command_frame, + tvb, 0, 0, p_ftp_data_conv->command_frame); + PROTO_ITEM_SET_GENERATED(ti); } /* Show current working directory */ if (p_ftp_data_conv->current_working_directory) { - proto_item *cwd_ti = proto_tree_add_string(tree, hf_ftp_data_current_working_directory, - tvb, 0, 0, wmem_strbuf_get_str(p_ftp_data_conv->current_working_directory)); - PROTO_ITEM_SET_GENERATED(cwd_ti); + ti = proto_tree_add_string(tree, hf_ftp_data_current_working_directory, + tvb, 0, 0, wmem_strbuf_get_str(p_ftp_data_conv->current_working_directory)); + PROTO_ITEM_SET_GENERATED(ti); } } } @@ -1327,7 +1377,7 @@ dissect_ftpdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data } /* Show the number of bytes */ - proto_item_append_text(ti, " (%u bytes data)", data_length); + proto_item_append_text(data_ti, " (%u bytes data)", data_length); /* Show line-by-line if text */ if (is_text) { @@ -1337,6 +1387,16 @@ dissect_ftpdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data return data_length; } +static void ftp_init_protocol(void) +{ + ftp_command_to_data_hash = g_hash_table_new(g_direct_hash, g_direct_equal); +} + +static void ftp_cleanup_protocol(void) +{ + g_hash_table_destroy(ftp_command_to_data_hash); +} + void proto_register_ftp(void) { @@ -1439,8 +1499,17 @@ proto_register_ftp(void) { &hf_ftp_epsv_port, { "Extended passive port", "ftp.epsv.port", FT_UINT16, BASE_DEC, NULL, 0, - "Extended passive FTP server port", HFILL }} + "Extended passive FTP server port", HFILL }}, + + { &hf_ftp_command_response_first_frame_num, + { "Command response first frame", "ftp.command-response.first-frame-num", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "First frame seen in resulting ftp-data stream", HFILL }}, + { &hf_ftp_command_response_frames, + { "Command response frames", "ftp.command-response.frames", + FT_UINT32, BASE_DEC, NULL, 0, + "Number of frames seen in resulting ftp-data stream", HFILL }} }; static gint *ett[] = { &ett_ftp, @@ -1451,15 +1520,23 @@ proto_register_ftp(void) { &hf_ftp_data_setup_frame, { "Setup frame", "ftp-data.setup-frame", FT_FRAMENUM, BASE_NONE, NULL, 0, - "Where ftp-data conversation was created", HFILL }}, + "Where ftp-data conversation was signalled", HFILL }}, + { &hf_ftp_data_setup_method, { "Setup method", "ftp-data.setup-method", FT_STRING, BASE_NONE, NULL, 0, "Method used to set up data conversation", HFILL }}, + { &hf_ftp_data_command, { "Command", "ftp-data.command", FT_STRING, BASE_NONE, NULL, 0, "Command that this data stream answers", HFILL }}, + + { &hf_ftp_data_command_frame, + { "Command frame", "ftp-data.command-frame", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "Where command for this data was seen", HFILL }}, + { &hf_ftp_data_current_working_directory, { "Current working directory", "ftp-data.current-working-directory", FT_STRING, BASE_NONE, NULL, 0, @@ -1485,6 +1562,9 @@ proto_register_ftp(void) proto_register_subtree_array(ett, array_length(ett)); expert_ftp = expert_register_protocol(proto_ftp); expert_register_field_array(expert_ftp, ei, array_length(ei)); + + register_init_routine(&ftp_init_protocol); + register_cleanup_routine(&ftp_cleanup_protocol); } void |