* Routines for ftp packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
* Copyright 2001, Juan Toledo <toledo@users.sourceforge.net> (Passive FTP)
- *
- * $Id: packet-ftp.c,v 1.45 2002/07/14 00:40:07 guy Exp $
+ *
+ * $Id: packet-ftp.c,v 1.52 2003/06/10 23:12:15 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* Copied from packet-pop.c
- *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <stdlib.h>
#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
#include <string.h>
#include <glib.h>
#include <epan/packet.h>
static int hf_ftp_response_arg = -1;
static gint ett_ftp = -1;
+static gint ett_ftp_reqresp = -1;
static gint ett_ftp_data = -1;
static dissector_handle_t ftpdata_handle;
#define TCP_PORT_FTPDATA 20
#define TCP_PORT_FTP 21
+static const value_string response_table[] = {
+ { 110, "Restart marker reply" },
+ { 120, "Service ready in nnn minutes" },
+ { 125, "Data connection already open; transfer starting" },
+ { 150, "File status okay; about to open data connection" },
+ { 200, "Command okay" },
+ { 202, "Command not implemented, superfluous at this site" },
+ { 211, "System status, or system help reply" },
+ { 212, "Directory status" },
+ { 213, "File status" },
+ { 214, "Help message" },
+ { 215, "NAME system type" },
+ { 220, "Service ready for new user" },
+ { 221, "Service closing control connection" },
+ { 225, "Data connection open; no transfer in progress" },
+ { 226, "Closing data connection" },
+ { 227, "Entering Passive Mode" },
+ { 230, "User logged in, proceed" },
+ { 250, "Requested file action okay, completed" },
+ { 257, "PATHNAME created" },
+ { 331, "User name okay, need password" },
+ { 332, "Need account for login" },
+ { 350, "Requested file action pending further information" },
+ { 421, "Service not available, closing control connection" },
+ { 425, "Can't open data connection" },
+ { 426, "Connection closed; transfer aborted" },
+ { 450, "Requested file action not taken" },
+ { 451, "Requested action aborted: local error in processing" },
+ { 452, "Requested action not taken. Insufficient storage space in system" },
+ { 500, "Syntax error, command unrecognized" },
+ { 501, "Syntax error in parameters or arguments" },
+ { 502, "Command not implemented" },
+ { 503, "Bad sequence of commands" },
+ { 504, "Command not implemented for that parameter" },
+ { 530, "Not logged in" },
+ { 532, "Need account for storing files" },
+ { 550, "Requested action not taken: File unavailable" },
+ { 551, "Requested action aborted: page type unknown" },
+ { 552, "Requested file action aborted: Exceeded storage allocation" },
+ { 553, "Requested action not taken: File name not allowed" },
+ { 0, NULL }
+};
+
static void
dissect_ftpdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
* the address and port number.
*/
static void
-handle_pasv_response(const u_char *line, int linelen, packet_info *pinfo)
+handle_pasv_response(const guchar *line, int linelen, packet_info *pinfo)
{
char *args;
char *p;
- u_char c;
+ guchar c;
int i;
int address[4], port[2];
guint16 server_port;
*/
break;
}
-
+
/*
* See if we have six numbers.
*/
}
g_free(args);
-}
+}
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;
proto_item *ti;
gint offset = 0;
- const u_char *line;
- guint8 code;
+ const guchar *line;
+ guint32 code;
+ gchar code_str[4];
gboolean is_pasv_response = FALSE;
gint next_offset;
int linelen;
int tokenlen;
- const u_char *next_token;
+ const guchar *next_token;
if (pinfo->match_port == pinfo->destport)
is_request = TRUE;
* not longer than what's in the buffer, so the "tvb_get_ptr()"
* call won't throw an exception.
*/
- linelen = tvb_find_line_end(tvb, offset, -1, &next_offset);
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
line = tvb_get_ptr(tvb, offset, linelen);
if (check_col(pinfo->cinfo, COL_INFO)) {
is_request ? "Request" : "Response",
format_text(line, linelen));
}
-
+
if (tree) {
ti = proto_tree_add_item(tree, proto_ftp, tvb, offset, -1,
FALSE);
proto_tree_add_boolean_hidden(ftp_tree,
hf_ftp_response, tvb, 0, 0, TRUE);
}
+
+ /*
+ * Put the line into the protocol tree.
+ */
+ ti = proto_tree_add_text(ftp_tree, tvb, offset,
+ next_offset - offset, "%s",
+ tvb_format_text(tvb, offset, next_offset - offset));
+ reqresp_tree = proto_item_add_subtree(ti, ett_ftp_reqresp);
}
if (is_request) {
tokenlen = get_token_len(line, line + linelen, &next_token);
if (tokenlen != 0) {
if (tree) {
- proto_tree_add_item(ftp_tree,
+ proto_tree_add_item(reqresp_tree,
hf_ftp_request_command, tvb, offset,
tokenlen, FALSE);
}
* One-line reply, or first or last line
* of a multi-line reply.
*/
- code = (line[0] - '0')*100 + (line[1] - '0')*10
- + (line[2] - '0');
+ tvb_get_nstringz0(tvb, offset, sizeof(code_str), code_str);
+ code = strtoul(code_str, NULL, 10);
+
if (tree) {
- proto_tree_add_uint(ftp_tree,
+ proto_tree_add_uint(reqresp_tree,
hf_ftp_response_code, tvb, offset, 3, code);
-
}
/*
*/
if (linelen != 0) {
if (is_request) {
- proto_tree_add_item(ftp_tree,
+ proto_tree_add_item(reqresp_tree,
hf_ftp_request_arg, tvb, offset,
linelen, FALSE);
} else {
- proto_tree_add_item(ftp_tree,
+ proto_tree_add_item(reqresp_tree,
hf_ftp_response_arg, tvb, offset,
linelen, FALSE);
}
* Find the end of the line.
*/
linelen = tvb_find_line_end(tvb, offset, -1,
- &next_offset);
+ &next_offset, FALSE);
/*
* Put this line.
{ &hf_ftp_response_code,
{ "Response code", "ftp.response.code",
- FT_UINT8, BASE_DEC, NULL, 0x0,
+ FT_UINT32, BASE_DEC, VALS(response_table), 0x0,
"", HFILL }},
{ &hf_ftp_response_arg,
};
static gint *ett[] = {
&ett_ftp,
+ &ett_ftp_reqresp,
&ett_ftp_data,
};