Update from Paul Ionescu to set the reported length of the tvbuff for
[obnox/wireshark/wip.git] / packet-ftp.c
1 /* packet-ftp.c
2  * Routines for ftp packet dissection
3  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
4  *
5  * $Id: packet-ftp.c,v 1.25 2001/01/03 06:55:28 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-pop.c
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42
43 #include <string.h>
44 #include <glib.h>
45 #include "packet.h"
46 #include "strutil.h"
47
48 static int proto_ftp = -1;
49 static int proto_ftp_data = -1;
50 static int hf_ftp_response = -1;
51 static int hf_ftp_request = -1;
52 static int hf_ftp_request_command = -1;
53 static int hf_ftp_request_data = -1;
54 static int hf_ftp_response_code = -1;
55 static int hf_ftp_response_data = -1;
56
57 static gint ett_ftp = -1;
58 static gint ett_ftp_data = -1;
59
60 #define TCP_PORT_FTPDATA                20
61 #define TCP_PORT_FTP                    21
62
63 static void
64 dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
65 {
66         gboolean        is_request;
67         proto_tree      *ftp_tree;
68         proto_item      *ti;
69         gint            offset = 0;
70         const u_char    *line;
71         gint            next_offset;
72         int             linelen;
73         int             tokenlen;
74         const u_char    *next_token;
75
76         CHECK_DISPLAY_AS_DATA(proto_ftp, tvb, pinfo, tree);
77
78         if (pinfo->match_port == pinfo->destport)
79                 is_request = TRUE;
80         else
81                 is_request = FALSE;
82
83         pinfo->current_proto = "FTP";
84
85         if (check_col(pinfo->fd, COL_PROTOCOL))
86                 col_set_str(pinfo->fd, COL_PROTOCOL, "FTP");
87
88         /*
89          * Find the end of the first line.
90          */
91         linelen = tvb_find_line_end(tvb, offset, -1, &next_offset);
92         line = tvb_get_ptr(tvb, offset, linelen);
93
94         if (check_col(pinfo->fd, COL_INFO)) {
95                 /*
96                  * Put the first line from the buffer into the summary.
97                  * (but leave out the line terminator).
98                  */
99                 col_add_fstr(pinfo->fd, COL_INFO, "%s: %s",
100                     is_request ? "Request" : "Response",
101                     format_text(line, linelen));
102         }
103
104         if (tree) {
105                 ti = proto_tree_add_item(tree, proto_ftp, tvb, offset,
106                     tvb_length_remaining(tvb, offset), FALSE);
107                 ftp_tree = proto_item_add_subtree(ti, ett_ftp);
108
109                 if (is_request) {
110                         proto_tree_add_boolean_hidden(ftp_tree,
111                             hf_ftp_request, tvb, 0, 0, TRUE);
112                         proto_tree_add_boolean_hidden(ftp_tree,
113                             hf_ftp_response, tvb, 0, 0, FALSE);
114                 } else {
115                         proto_tree_add_boolean_hidden(ftp_tree,
116                             hf_ftp_request, tvb, 0, 0, FALSE);
117                         proto_tree_add_boolean_hidden(ftp_tree,
118                             hf_ftp_response, tvb, 0, 0, TRUE);
119                 }
120
121                 /*
122                  * Extract the first token, and, if there is a first
123                  * token, add it as the request or reply code.
124                  */
125                 tokenlen = get_token_len(line, line + linelen, &next_token);
126                 if (tokenlen != 0) {
127                         if (is_request) {
128                                 proto_tree_add_string_format(ftp_tree,
129                                     hf_ftp_request_command, tvb, offset,
130                                     tokenlen, line, "Request: %s",
131                                     format_text(line, tokenlen));
132                         } else {
133                                 proto_tree_add_uint_format(ftp_tree,
134                                     hf_ftp_response_code, tvb, offset,
135                                     tokenlen, atoi(line), "Response: %s",
136                                     format_text(line, tokenlen));
137                         }
138                         offset += next_token - line;
139                         linelen -= next_token - line;
140                         line = next_token;
141                 }
142
143                 /*
144                  * Add the rest of the first line as request or
145                  * reply data.
146                  */
147                 if (linelen != 0) {
148                         if (is_request) {
149                                 proto_tree_add_string_format(ftp_tree,
150                                     hf_ftp_request_data, tvb, offset,
151                                     linelen, line, "Request Arg: %s",
152                                     format_text(line, linelen));
153                         } else {
154                                 proto_tree_add_string_format(ftp_tree,
155                                     hf_ftp_response_data, tvb, offset,
156                                     linelen, line, "Response Arg: %s",
157                                     format_text(line, linelen));
158                         }
159                 }
160                 offset = next_offset;
161
162                 /*
163                  * Show the rest of the request or response as text,
164                  * a line at a time.
165                  */
166                 while (tvb_offset_exists(tvb, offset)) {
167                         /*
168                          * Find the end of the line.
169                          */
170                         linelen = tvb_find_line_end(tvb, offset, -1,
171                             &next_offset);
172
173                         /*
174                          * Put this line.
175                          */
176                         proto_tree_add_text(ftp_tree, tvb, offset,
177                             next_offset - offset, "%s",
178                             tvb_format_text(tvb, offset, next_offset - offset));
179                         offset = next_offset;
180                 }
181         }
182 }
183
184 static void
185 dissect_ftpdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
186 {
187         proto_tree      *ti, *ftp_data_tree;
188         int             data_length;
189
190         CHECK_DISPLAY_AS_DATA(proto_ftp_data, tvb, pinfo, tree);
191
192         pinfo->current_proto = "FTP-DATA";
193
194         if (check_col(pinfo->fd, COL_PROTOCOL))
195                 col_set_str(pinfo->fd, COL_PROTOCOL, "FTP-DATA");
196
197         if (check_col(pinfo->fd, COL_INFO)) {
198                 col_add_fstr(pinfo->fd, COL_INFO, "FTP Data: %u bytes",
199                     tvb_length(tvb));
200         }
201
202         if (tree) {
203                 data_length = tvb_length(tvb);
204
205                 ti = proto_tree_add_item(tree, proto_ftp_data, tvb, 0,
206                     data_length, FALSE);
207                 ftp_data_tree = proto_item_add_subtree(ti, ett_ftp_data);
208
209                 /*
210                  * XXX - if this is binary data, it'll produce
211                  * a *really* long line.
212                  */
213                 proto_tree_add_text(ftp_data_tree, tvb, 0, data_length,
214                     "FTP Data: %s", tvb_format_text(tvb, 0, data_length));
215         }
216 }
217
218 void
219 proto_register_ftp(void)
220 {
221     static hf_register_info hf[] = {
222     { &hf_ftp_response,
223       { "Response",           "ftp.response",
224         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
225         "TRUE if FTP response" }},
226
227     { &hf_ftp_request,
228       { "Request",            "ftp.request",
229         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
230         "TRUE if FTP request" }},
231
232     { &hf_ftp_request_command,
233       { "Request command",    "ftp.request.command",
234         FT_STRING,  BASE_NONE, NULL, 0x0,
235         "" }},
236
237     { &hf_ftp_request_data,
238       { "Request data",       "ftp.request.data",
239         FT_STRING,  BASE_NONE, NULL, 0x0,
240         "" }},
241
242     { &hf_ftp_response_code,
243       { "Response code",      "ftp.response.code",
244         FT_UINT8,   BASE_DEC, NULL, 0x0,
245         "" }},
246
247     { &hf_ftp_response_data,
248       { "Response data",      "ftp.reponse.data",
249         FT_STRING,  BASE_NONE, NULL, 0x0,
250         "" }}
251   };
252   static gint *ett[] = {
253     &ett_ftp,
254     &ett_ftp_data,
255   };
256
257   proto_ftp = proto_register_protocol("File Transfer Protocol (FTP)", "FTP",
258                                       "ftp");
259   proto_ftp_data = proto_register_protocol("FTP Data", "FTP-DATA", "ftp-data");
260   proto_register_field_array(proto_ftp, hf, array_length(hf));
261   proto_register_subtree_array(ett, array_length(ett));
262 }
263
264 void
265 proto_reg_handoff_ftp(void)
266 {
267   dissector_add("tcp.port", TCP_PORT_FTPDATA, &dissect_ftpdata);
268   dissector_add("tcp.port", TCP_PORT_FTP, &dissect_ftp);
269 }