diff options
author | Martin Mathieson <martin.r.mathieson@googlemail.com> | 2007-07-30 18:45:48 +0000 |
---|---|---|
committer | Martin Mathieson <martin.r.mathieson@googlemail.com> | 2007-07-30 18:45:48 +0000 |
commit | 0d437580eed2149e0d313aa00a64c11a4df37633 (patch) | |
tree | 232f801037938091179496e7afb7908929bcc3c2 | |
parent | 5bf02175302495e8f238236c597906a6c608fd86 (diff) | |
download | wireshark-0d437580eed2149e0d313aa00a64c11a4df37633.tar.gz |
Parse EPSV responses (229) & set up FTP-DATA conversation.
svn path=/trunk/; revision=22423
-rw-r--r-- | epan/dissectors/packet-ftp.c | 125 |
1 files changed, 113 insertions, 12 deletions
diff --git a/epan/dissectors/packet-ftp.c b/epan/dissectors/packet-ftp.c index ea62b24274..205ee6db22 100644 --- a/epan/dissectors/packet-ftp.c +++ b/epan/dissectors/packet-ftp.c @@ -82,6 +82,7 @@ static const value_string response_table[] = { { 225, "Data connection open; no transfer in progress" }, { 226, "Closing data connection" }, { 227, "Entering Passive Mode" }, + { 229, "Entering Extended Passive Mode" }, { 230, "User logged in, proceed" }, { 250, "Requested file action okay, completed" }, { 257, "PATHNAME created" }, @@ -223,12 +224,80 @@ parse_port_pasv(const guchar *line, int linelen, guint32 *ftp_ip, return ret; } + +static gboolean +parse_extended_pasv_response(const guchar *line, int linelen, guint16 *ftp_port) +{ + int n; + char *args; + char *p; + guchar c; + gboolean ret = FALSE; + gboolean delimiters_seen = FALSE; + + /* + * Copy the rest of the line into a null-terminated buffer. + */ + args = ep_alloc(linelen + 1); + memcpy(args, line, linelen); + args[linelen] = '\0'; + p = args; + + /* + * Look for ( <d> <d> <d> + (Try to cope with '(' in description) + */ + for (; !delimiters_seen;) { + char delimiter = '\0'; + while ((c = *p) != '\0' && (c != '(')) + p++; + + if (*p == '\0') { + return FALSE; + } + + /* Skip '(' */ + p++; + + /* Make sure same delimiter is used 3 times */ + for (n=0; n<3; n++) { + if ((c = *p) != '\0') { + if (delimiter == '\0') { + delimiter = c; + } + if (c != delimiter) { + break;; + } + p++; + } + else { + break; + } + } + delimiters_seen = TRUE; + } + + /* + * Should now be at digits. + */ + if (*p != '\0') { + /* + * We didn't run out of text without finding anything. + */ + *ftp_port = atoi(p); + ret = TRUE; + } + + return ret; +} + + static void dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - gboolean is_request; - proto_tree *ftp_tree = NULL; - proto_tree *reqresp_tree = NULL; + gboolean is_request; + proto_tree *ftp_tree = NULL; + proto_tree *reqresp_tree = NULL; proto_item *ti; gint offset = 0; const guchar *line; @@ -236,6 +305,7 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) gchar code_str[4]; gboolean is_port_request = FALSE; gboolean is_pasv_response = FALSE; + gboolean is_epasv_response = FALSE; gint next_offset; int linelen; int tokenlen; @@ -348,9 +418,6 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* * See if it's a passive-mode response. * - * XXX - check for "229" responses to EPSV - * commands, to handle IPv6, as per RFC 2428? - * * XXX - does anybody do FOOBAR, as per RFC * 1639, or has that been supplanted by RFC 2428? */ @@ -358,6 +425,13 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) is_pasv_response = TRUE; /* + * Responses to EPSV command, as per RFC 2428 + * XXX - handle IPv6? + */ + if (code == 229) + is_epasv_response = TRUE; + + /* * Skip the 3 digits and, if present, the * space or hyphen. */ @@ -400,8 +474,7 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) * If this is a PORT request or a PASV response, handle it. */ if (is_port_request) { - if (parse_port_pasv(line, linelen, &ftp_ip, - &ftp_port)) { + if (parse_port_pasv(line, linelen, &ftp_ip, &ftp_port)) { if (tree) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_active_ip, tvb, 0, 0, @@ -410,10 +483,8 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) hf_ftp_active_port, tvb, 0, 0, ftp_port); } - SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, - (const guint8 *)&ftp_ip); - ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, - &ftp_ip_address); + SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&ftp_ip); + ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, &ftp_ip_address); if (ftp_nat) { if (tree) { proto_tree_add_boolean( @@ -498,6 +569,36 @@ dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } } + + if (is_epasv_response) { + if (linelen != 0) { + /* + * This frame contains an EPSV response; set up a + * conversation for the data. + */ + if (parse_extended_pasv_response(line, linelen, &ftp_port)) { + /* Add port number to tree */ + if (tree) { + proto_tree_add_uint(reqresp_tree, + hf_ftp_pasv_port, tvb, 0, 0, + ftp_port); + } + + /* Find/create conversation for data */ + conversation = find_conversation(pinfo->fd->num, &pinfo->src, + &pinfo->dst, PT_TCP, ftp_port, 0, + NO_PORT_B); + if (conversation == NULL) { + conversation = conversation_new( + pinfo->fd->num, &pinfo->src, &pinfo->dst, + PT_TCP, ftp_port, 0, NO_PORT2); + conversation_set_dissector(conversation, + ftpdata_handle); + } + } + } + } + if (tree) { /* * Show the rest of the request or response as text, |