Remove:
[obnox/wireshark/wip.git] / epan / dissectors / packet-tftp.c
1 /* packet-tftp.c
2  * Routines for tftp packet dissection
3  *
4  * Richard Sharpe <rsharpe@ns.aus.com>
5  * Craig Newell <CraigN@cheque.uq.edu.au>
6  *      RFC2347 TFTP Option Extension
7  * Joerg Mayer (see AUTHORS file)
8  *      RFC2348 TFTP Blocksize Option
9  *
10  * $Id$
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * Copied from packet-bootp.c
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31  */
32
33 /* Documentation:
34  * RFC 1350: THE TFTP PROTOCOL (REVISION 2)
35  * RFC 2090: TFTP Multicast Option
36  *           (not yet implemented)
37  * RFC 2347: TFTP Option Extension
38  * RFC 2348: TFTP Blocksize Option
39  * RFC 2349: TFTP Timeout Interval and Transfer Size Options
40  *           (not yet implemented)
41  */
42
43 #ifdef HAVE_CONFIG_H
44 # include "config.h"
45 #endif
46
47 #include <glib.h>
48 #include <string.h>
49 #include <epan/packet.h>
50 #include <epan/conversation.h>
51 #include <epan/emem.h>
52 #include <epan/expert.h>
53
54 /* Things we may want to remember for a whole conversation */
55 typedef struct _tftp_conv_info_t {
56         guint16 blocksize;
57 } tftp_conv_info_t;
58
59
60 static int proto_tftp = -1;
61 static int hf_tftp_opcode = -1;
62 static int hf_tftp_source_file = -1;
63 static int hf_tftp_destination_file = -1;
64 static int hf_tftp_transfer_type = -1;
65 static int hf_tftp_blocknum = -1;
66 static int hf_tftp_error_code = -1;
67 static int hf_tftp_error_string = -1;
68 static int hf_tftp_option_name = -1;
69 static int hf_tftp_option_value = -1;
70
71 static gint ett_tftp = -1;
72 static gint ett_tftp_option = -1;
73
74 static dissector_handle_t tftp_handle;
75
76 #define UDP_PORT_TFTP    69
77
78 #define TFTP_RRQ        1
79 #define TFTP_WRQ        2
80 #define TFTP_DATA       3
81 #define TFTP_ACK        4
82 #define TFTP_ERROR      5
83 #define TFTP_OACK       6
84
85 static const value_string tftp_opcode_vals[] = {
86   { TFTP_RRQ,   "Read Request" },
87   { TFTP_WRQ,   "Write Request" },
88   { TFTP_DATA,  "Data Packet" },
89   { TFTP_ACK,   "Acknowledgement" },
90   { TFTP_ERROR, "Error Code" },
91   { TFTP_OACK,  "Option Acknowledgement" },
92   { 0,          NULL }
93 };
94
95 static const value_string tftp_error_code_vals[] = {
96   { 0, "Not defined" },
97   { 1, "File not found" },
98   { 2, "Access violation" },
99   { 3, "Disk full or allocation exceeded" },
100   { 4, "Illegal TFTP Operation" },
101   { 5, "Unknown transfer ID" },         /* Does not cause termination */
102   { 6, "File already exists" },
103   { 7, "No such user" },
104   { 8, "Option negotiation failed" },
105   { 0, NULL }
106 };
107
108 static void
109 tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset,
110         proto_tree *tree, guint16 opcode, tftp_conv_info_t *tftp_info)
111 {
112         int option_len, value_len;
113         int value_offset;
114         const guint8 *optionname;
115         const guint8 *optionvalue;
116         proto_item *opt_item;
117         proto_tree *opt_tree;
118
119         while (tvb_offset_exists(tvb, offset)) {
120           option_len = tvb_strsize(tvb, offset);        /* length of option */
121           value_offset = offset + option_len;
122           value_len = tvb_strsize(tvb, value_offset);   /* length of value */
123           optionname = tvb_format_text(tvb, offset, option_len);
124           optionvalue = tvb_format_text(tvb, value_offset, value_len);
125           opt_item = proto_tree_add_text(tree, tvb, offset, option_len+value_len,
126                   "Option: %s = %s", optionname, optionvalue);
127
128           opt_tree = proto_item_add_subtree(opt_item, ett_tftp_option);
129           proto_tree_add_item(opt_tree, hf_tftp_option_name, tvb, offset,
130                 option_len, FALSE);
131           proto_tree_add_item(opt_tree, hf_tftp_option_value, tvb, value_offset,
132                 value_len, FALSE);
133
134           offset += option_len + value_len;
135
136           if (check_col(pinfo->cinfo, COL_INFO)) {
137             col_append_fstr(pinfo->cinfo, COL_INFO, ", %s=%s",
138                             optionname, optionvalue);
139           }
140
141           /* Special code to handle individual options */
142           if (!g_ascii_strcasecmp((const char *)optionname, "blksize") &&
143               opcode == TFTP_OACK) {
144                 gint blocksize = strtol((const char *)optionvalue, NULL, 10);
145                 if (blocksize < 8 || blocksize > 65464) {
146                         expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE,
147                                 PI_WARN, "TFTP blocksize out of range");
148
149                 } else {
150                         tftp_info->blocksize = blocksize;
151                 }
152           }
153         }
154 }
155
156 static void
157 dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
158 {
159         proto_tree       *tftp_tree = NULL;
160         proto_item       *ti;
161         conversation_t   *conversation = NULL;
162         gint             offset = 0;
163         guint16          opcode;
164         guint16          bytes;
165         guint16          blocknum;
166         guint            i1;
167         guint16          error;
168         tftp_conv_info_t *tftp_info;
169
170         /*
171          * The first TFTP packet goes to the TFTP port; the second one
172          * comes from some *other* port, but goes back to the same
173          * IP address and port as the ones from which the first packet
174          * came; all subsequent packets go between those two IP addresses
175          * and ports.
176          *
177          * If this packet went to the TFTP port, we check to see if
178          * there's already a conversation with one address/port pair
179          * matching the source IP address and port of this packet,
180          * the other address matching the destination IP address of this
181          * packet, and any destination port.
182          *
183          * If not, we create one, with its address 1/port 1 pair being
184          * the source address/port of this packet, its address 2 being
185          * the destination address of this packet, and its port 2 being
186          * wildcarded, and give it the TFTP dissector as a dissector.
187          */
188         if (pinfo->destport == UDP_PORT_TFTP) {
189           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
190                                            pinfo->srcport, 0, NO_PORT_B);
191           if( (conversation == NULL) || (conversation->dissector_handle!=tftp_handle) ){
192             conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
193                                             pinfo->srcport, 0, NO_PORT2);
194             conversation_set_dissector(conversation, tftp_handle);
195           }
196         } else {
197           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
198                 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
199           if( (conversation == NULL) || (conversation->dissector_handle!=tftp_handle) ){
200             conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
201                                             pinfo->destport, pinfo->srcport, 0);
202             conversation_set_dissector(conversation, tftp_handle);
203           }
204         }
205         tftp_info = conversation_get_proto_data(conversation, proto_tftp);
206         if (!tftp_info) {
207                 tftp_info = se_alloc(sizeof(tftp_conv_info_t));
208                 tftp_info->blocksize = 512; /* TFTP default block size */
209                 conversation_add_proto_data(conversation, proto_tftp, tftp_info);
210         }
211
212         if (check_col(pinfo->cinfo, COL_PROTOCOL))
213                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP");
214
215         opcode = tvb_get_ntohs(tvb, offset);
216
217         if (check_col(pinfo->cinfo, COL_INFO)) {
218
219           col_add_str(pinfo->cinfo, COL_INFO,
220             val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));
221
222         }
223
224         if (tree) {
225
226           ti = proto_tree_add_item(tree, proto_tftp, tvb, offset, -1, FALSE);
227           tftp_tree = proto_item_add_subtree(ti, ett_tftp);
228
229           proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb,
230                             offset, 2, opcode);
231         }
232         offset += 2;
233
234         switch (opcode) {
235
236         case TFTP_RRQ:
237           i1 = tvb_strsize(tvb, offset);
238           if (tree) {
239             proto_tree_add_item(tftp_tree, hf_tftp_source_file,
240                             tvb, offset, i1, FALSE);
241           }
242           if (check_col(pinfo->cinfo, COL_INFO)) {
243             col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
244                             tvb_format_text(tvb, offset, i1));
245           }
246           offset += i1;
247
248           i1 = tvb_strsize(tvb, offset);
249           if (tree) {
250             ti = proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
251                             tvb, offset, i1, FALSE);
252           }
253           if (check_col(pinfo->cinfo, COL_INFO)) {
254             col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
255                             tvb_format_text(tvb, offset, i1));
256           }
257           offset += i1;
258
259           if (tree)
260             tftp_dissect_options(tvb, pinfo,  offset, tftp_tree,
261                 opcode, tftp_info);
262           break;
263
264         case TFTP_WRQ:
265           i1 = tvb_strsize(tvb, offset);
266           if (tree) {
267             proto_tree_add_item(tftp_tree, hf_tftp_destination_file,
268                             tvb, offset, i1, FALSE);
269           }
270           if (check_col(pinfo->cinfo, COL_INFO)) {
271             col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
272                             tvb_format_text(tvb, offset, i1));
273           }
274           offset += i1;
275
276           i1 = tvb_strsize(tvb, offset);
277           if (tree) {
278             ti = proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
279                             tvb, offset, i1, FALSE);
280           }
281           if (check_col(pinfo->cinfo, COL_INFO)) {
282             col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
283                             tvb_format_text(tvb, offset, i1));
284           }
285           offset += i1;
286
287           if (tree)
288             tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
289                 opcode,  tftp_info);
290           break;
291
292         case TFTP_DATA:
293           blocknum = tvb_get_ntohs(tvb, offset);
294           if (tree) {
295             proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
296                             blocknum);
297           }
298           offset += 2;
299
300           bytes = tvb_reported_length_remaining(tvb, offset);
301
302           if (check_col(pinfo->cinfo, COL_INFO)) {
303             col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s",
304                     blocknum,
305                     (bytes < tftp_info->blocksize)?" (last)":"" );
306           }
307
308           if (bytes != 0) {
309             if (tree) {
310               proto_tree_add_text(tftp_tree, tvb, offset, -1,
311                 "Data (%d bytes)", bytes);
312             }
313           }
314           break;
315
316         case TFTP_ACK:
317           blocknum = tvb_get_ntohs(tvb, offset);
318           if (tree) {
319             proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
320                             blocknum);
321           }
322           if (check_col(pinfo->cinfo, COL_INFO)) {
323             col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i",
324                             blocknum);
325           }
326           break;
327
328         case TFTP_ERROR:
329           error = tvb_get_ntohs(tvb, offset);
330           if (tree) {
331             proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
332                             error);
333           }
334           if (check_col(pinfo->cinfo, COL_INFO)) {
335             col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s",
336                             val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));
337           }
338           offset += 2;
339
340           i1 = tvb_strsize(tvb, offset);
341           if (tree) {
342             proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset,
343                 i1, FALSE);
344           }
345           if (check_col(pinfo->cinfo, COL_INFO)) {
346             col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s",
347                             tvb_format_text(tvb, offset, i1));
348           }
349           expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE,
350                 PI_NOTE, "TFTP blocksize out of range");
351           break;
352
353         case TFTP_OACK:
354           if (tree)
355             tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
356                 opcode, tftp_info);
357           break;
358
359         default:
360           if (tree) {
361             proto_tree_add_text(tftp_tree, tvb, offset, -1,
362                 "Data (%d bytes)", tvb_reported_length_remaining(tvb, offset));
363           }
364           break;
365
366         }
367 }
368
369 void
370 proto_register_tftp(void)
371 {
372   static hf_register_info hf[] = {
373     { &hf_tftp_opcode,
374       { "Opcode",             "tftp.opcode",
375         FT_UINT16, BASE_DEC, VALS(tftp_opcode_vals), 0x0,
376         "TFTP message type", HFILL }},
377
378     { &hf_tftp_source_file,
379       { "Source File",        "tftp.source_file",
380         FT_STRINGZ, BASE_DEC, NULL, 0x0,
381         "TFTP source file name", HFILL }},
382
383     { &hf_tftp_destination_file,
384       { "DESTINATION File",   "tftp.destination_file",
385         FT_STRINGZ, BASE_DEC, NULL, 0x0,
386         "TFTP source file name", HFILL }},
387
388     { &hf_tftp_transfer_type,
389       { "Type",               "tftp.type",
390         FT_STRINGZ, BASE_DEC, NULL, 0x0,
391         "TFTP transfer type", HFILL }},
392
393     { &hf_tftp_blocknum,
394       { "Block",              "tftp.block",
395         FT_UINT16, BASE_DEC, NULL, 0x0,
396         "Block number", HFILL }},
397
398     { &hf_tftp_error_code,
399       { "Error code",         "tftp.error.code",
400         FT_UINT16, BASE_DEC, VALS(tftp_error_code_vals), 0x0,
401         "Error code in case of TFTP error message", HFILL }},
402
403     { &hf_tftp_error_string,
404       { "Error message",      "tftp.error.message",
405         FT_STRINGZ, BASE_DEC, NULL, 0x0,
406         "Error string in case of TFTP error message", HFILL }},
407
408     { &hf_tftp_option_name,
409       { "Option name",              "tftp.option.name",
410         FT_STRINGZ, BASE_DEC, NULL, 0x0,
411         "", HFILL }},
412
413     { &hf_tftp_option_value,
414       { "Option value",              "tftp.option.value",
415         FT_STRINGZ, BASE_DEC, NULL, 0x0,
416         "", HFILL }},
417
418   };
419   static gint *ett[] = {
420     &ett_tftp,
421     &ett_tftp_option,
422   };
423
424   proto_tftp = proto_register_protocol("Trivial File Transfer Protocol",
425                                        "TFTP", "tftp");
426   proto_register_field_array(proto_tftp, hf, array_length(hf));
427   proto_register_subtree_array(ett, array_length(ett));
428
429   register_dissector("tftp", dissect_tftp, proto_tftp);
430 }
431
432 void
433 proto_reg_handoff_tftp(void)
434 {
435   tftp_handle = find_dissector("tftp");
436
437   dissector_add("udp.port", UDP_PORT_TFTP, tftp_handle);
438 }