d5af2a572d62f8226094d6909bade6a4e125daf1
[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 <stdlib.h>
49 #include <epan/packet.h>
50 #include <epan/conversation.h>
51 #include <epan/emem.h>
52 #include <epan/expert.h>
53 #include <epan/range.h>
54 #include <epan/prefs.h>
55
56 /* Things we may want to remember for a whole conversation */
57 typedef struct _tftp_conv_info_t {
58         guint16 blocksize;
59         gchar *source_file, *destination_file;
60 } tftp_conv_info_t;
61
62
63 static int proto_tftp = -1;
64 static int hf_tftp_opcode = -1;
65 static int hf_tftp_source_file = -1;
66 static int hf_tftp_destination_file = -1;
67 static int hf_tftp_transfer_type = -1;
68 static int hf_tftp_blocknum = -1;
69 static int hf_tftp_error_code = -1;
70 static int hf_tftp_error_string = -1;
71 static int hf_tftp_option_name = -1;
72 static int hf_tftp_option_value = -1;
73
74 static gint ett_tftp = -1;
75 static gint ett_tftp_option = -1;
76
77 static dissector_handle_t tftp_handle;
78 static dissector_handle_t data_handle;
79
80 #define UDP_PORT_TFTP_RANGE    "69"
81
82 void proto_reg_handoff_tftp (void);
83
84 /* User definable values */
85 static range_t *global_tftp_port_range;
86
87 #define TFTP_RRQ        1
88 #define TFTP_WRQ        2
89 #define TFTP_DATA       3
90 #define TFTP_ACK        4
91 #define TFTP_ERROR      5
92 #define TFTP_OACK       6
93 #define TFTP_INFO       255
94
95 static const value_string tftp_opcode_vals[] = {
96   { TFTP_RRQ,   "Read Request" },
97   { TFTP_WRQ,   "Write Request" },
98   { TFTP_DATA,  "Data Packet" },
99   { TFTP_ACK,   "Acknowledgement" },
100   { TFTP_ERROR, "Error Code" },
101   { TFTP_OACK,  "Option Acknowledgement" },
102   { TFTP_INFO,  "Information (MSDP)" },
103   { 0,          NULL }
104 };
105
106 static const value_string tftp_error_code_vals[] = {
107   { 0, "Not defined" },
108   { 1, "File not found" },
109   { 2, "Access violation" },
110   { 3, "Disk full or allocation exceeded" },
111   { 4, "Illegal TFTP Operation" },
112   { 5, "Unknown transfer ID" },         /* Does not cause termination */
113   { 6, "File already exists" },
114   { 7, "No such user" },
115   { 8, "Option negotiation failed" },
116   { 0, NULL }
117 };
118
119 static void
120 tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset,
121         proto_tree *tree, guint16 opcode, tftp_conv_info_t *tftp_info)
122 {
123         int option_len, value_len;
124         int value_offset;
125         const char *optionname;
126         const char *optionvalue;
127         proto_item *opt_item;
128         proto_tree *opt_tree;
129
130         while (tvb_offset_exists(tvb, offset)) {
131           option_len = tvb_strsize(tvb, offset);        /* length of option */
132           value_offset = offset + option_len;
133           value_len = tvb_strsize(tvb, value_offset);   /* length of value */
134           optionname = tvb_format_text(tvb, offset, option_len);
135           optionvalue = tvb_format_text(tvb, value_offset, value_len);
136           opt_item = proto_tree_add_text(tree, tvb, offset, option_len+value_len,
137                   "Option: %s = %s", optionname, optionvalue);
138
139           opt_tree = proto_item_add_subtree(opt_item, ett_tftp_option);
140           proto_tree_add_item(opt_tree, hf_tftp_option_name, tvb, offset,
141                 option_len, ENC_ASCII|ENC_NA);
142           proto_tree_add_item(opt_tree, hf_tftp_option_value, tvb, value_offset,
143                 value_len, ENC_ASCII|ENC_NA);
144
145           offset += option_len + value_len;
146
147           col_append_fstr(pinfo->cinfo, COL_INFO, ", %s=%s",
148                           optionname, optionvalue);
149
150           /* Special code to handle individual options */
151           if (!g_ascii_strcasecmp((const char *)optionname, "blksize") &&
152               opcode == TFTP_OACK) {
153                 gint blocksize = strtol((const char *)optionvalue, NULL, 10);
154                 if (blocksize < 8 || blocksize > 65464) {
155                         expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE,
156                                 PI_WARN, "TFTP blocksize out of range");
157                 } else {
158                         tftp_info->blocksize = blocksize;
159                 }
160           }
161         }
162 }
163
164 static void dissect_tftp_message(tftp_conv_info_t *tftp_info,
165                                  tvbuff_t *tvb, packet_info *pinfo,
166                                  proto_tree *tree)
167 {
168         proto_tree       *tftp_tree = NULL;
169         proto_item       *ti;
170         gint             offset = 0;
171         guint16          opcode;
172         guint16          bytes;
173         guint16          blocknum;
174         guint            i1;
175         guint16          error;
176
177         col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP");
178
179         opcode = tvb_get_ntohs(tvb, offset);
180
181         col_add_str(pinfo->cinfo, COL_INFO,
182                     val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));
183
184         if (tree) {
185           ti = proto_tree_add_item(tree, proto_tftp, tvb, offset, -1, ENC_BIG_ENDIAN);
186           tftp_tree = proto_item_add_subtree(ti, ett_tftp);
187
188           if (tftp_info->source_file) {
189             ti = proto_tree_add_string(tftp_tree, hf_tftp_source_file, tvb,
190                                        0, 0, tftp_info->source_file);
191             PROTO_ITEM_SET_GENERATED(ti);
192           }
193
194           if (tftp_info->destination_file) {
195             ti = proto_tree_add_string(tftp_tree, hf_tftp_destination_file, tvb,
196                                        0, 0, tftp_info->destination_file);
197             PROTO_ITEM_SET_GENERATED(ti);
198           }
199
200           proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb,
201                               offset, 2, opcode);
202         }
203         offset += 2;
204
205         switch (opcode) {
206
207         case TFTP_RRQ:
208           i1 = tvb_strsize(tvb, offset);
209           proto_tree_add_item(tftp_tree, hf_tftp_source_file,
210                               tvb, offset, i1, ENC_ASCII|ENC_NA);
211
212           tftp_info->source_file = tvb_get_seasonal_string(tvb, offset, i1);
213
214           col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
215                           tvb_format_stringzpad(tvb, offset, i1));
216
217           offset += i1;
218
219           i1 = tvb_strsize(tvb, offset);
220           proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
221                               tvb, offset, i1, ENC_ASCII|ENC_NA);
222
223           col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
224                           tvb_format_stringzpad(tvb, offset, i1));
225
226           offset += i1;
227
228           tftp_dissect_options(tvb, pinfo,  offset, tftp_tree,
229                                opcode, tftp_info);
230           break;
231
232         case TFTP_WRQ:
233           i1 = tvb_strsize(tvb, offset);
234           proto_tree_add_item(tftp_tree, hf_tftp_destination_file,
235                               tvb, offset, i1, ENC_ASCII|ENC_NA);
236
237           tftp_info->destination_file =
238             tvb_get_seasonal_string(tvb, offset, i1);
239
240           col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
241                           tvb_format_stringzpad(tvb, offset, i1));
242
243           offset += i1;
244
245           i1 = tvb_strsize(tvb, offset);
246           proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
247                                    tvb, offset, i1, ENC_ASCII|ENC_NA);
248
249           col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
250                           tvb_format_stringzpad(tvb, offset, i1));
251
252           offset += i1;
253
254           tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
255                                opcode,  tftp_info);
256           break;
257
258         case TFTP_INFO:
259           tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
260                                opcode,  tftp_info);
261           break;
262
263         case TFTP_DATA:
264           blocknum = tvb_get_ntohs(tvb, offset);
265           proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
266                               blocknum);
267
268           offset += 2;
269
270           bytes = tvb_reported_length_remaining(tvb, offset);
271
272           col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s",
273                           blocknum,
274                           (bytes < tftp_info->blocksize)?" (last)":"" );
275
276           if (bytes != 0) {
277             tvbuff_t *data_tvb = tvb_new_subset(tvb, offset, -1, bytes);
278             call_dissector(data_handle, data_tvb, pinfo, tree);
279           }
280           break;
281
282         case TFTP_ACK:
283           blocknum = tvb_get_ntohs(tvb, offset);
284           proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
285                               blocknum);
286
287           col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i",
288                           blocknum);
289           break;
290
291         case TFTP_ERROR:
292           error = tvb_get_ntohs(tvb, offset);
293           proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
294                               error);
295
296           col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s",
297                           val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));
298
299           offset += 2;
300
301           i1 = tvb_strsize(tvb, offset);
302           proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset,
303                               i1, ENC_ASCII|ENC_NA);
304
305           col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s",
306                           tvb_format_stringzpad(tvb, offset, i1));
307
308           expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE,
309                                  PI_NOTE, "TFTP blocksize out of range");
310           break;
311
312         case TFTP_OACK:
313           tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
314                                opcode, tftp_info);
315           break;
316
317         default:
318           proto_tree_add_text(tftp_tree, tvb, offset, -1,
319                               "Data (%d bytes)", tvb_reported_length_remaining(tvb, offset));
320           break;
321
322         }
323
324   return;
325 }
326
327 static gboolean
328 dissect_embeddedtftp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
329 {
330   /* Used to dissect TFTP packets where one can not assume
331      that the TFTP is the only protocol used by that port, and
332      that TFTP may not be carried by UDP */
333   conversation_t   *conversation = NULL;
334   guint16           opcode;
335   tftp_conv_info_t *tftp_info;
336
337   conversation = find_or_create_conversation(pinfo);
338
339   tftp_info = conversation_get_proto_data(conversation, proto_tftp);
340   if (!tftp_info) {
341     tftp_info = se_alloc(sizeof(tftp_conv_info_t));
342     tftp_info->blocksize = 512; /* TFTP default block size */
343     tftp_info->source_file = NULL;
344     tftp_info->destination_file = NULL;
345     conversation_add_proto_data(conversation, proto_tftp, tftp_info);
346   }
347
348   opcode = tvb_get_ntohs(tvb, 0);
349
350   if ((opcode == TFTP_RRQ) ||
351       (opcode == TFTP_WRQ) ||
352       (opcode == TFTP_DATA) ||
353       (opcode == TFTP_ACK) ||
354       (opcode == TFTP_ERROR) ||
355       (opcode == TFTP_INFO) ||
356       (opcode == TFTP_OACK)) {
357     dissect_tftp_message(tftp_info, tvb, pinfo, tree);
358     return TRUE;
359   }
360   else {
361     return FALSE;
362   }
363 }
364
365 static void
366 dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
367 {
368         conversation_t   *conversation = NULL;
369         tftp_conv_info_t *tftp_info;
370
371         /*
372          * The first TFTP packet goes to the TFTP port; the second one
373          * comes from some *other* port, but goes back to the same
374          * IP address and port as the ones from which the first packet
375          * came; all subsequent packets go between those two IP addresses
376          * and ports.
377          *
378          * If this packet went to the TFTP port, we check to see if
379          * there's already a conversation with one address/port pair
380          * matching the source IP address and port of this packet,
381          * the other address matching the destination IP address of this
382          * packet, and any destination port.
383          *
384          * If not, we create one, with its address 1/port 1 pair being
385          * the source address/port of this packet, its address 2 being
386          * the destination address of this packet, and its port 2 being
387          * wildcarded, and give it the TFTP dissector as a dissector.
388          */
389         if (value_is_in_range(global_tftp_port_range, pinfo->destport)) {
390           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
391                                            pinfo->srcport, 0, NO_PORT_B);
392           if( (conversation == NULL) || (conversation->dissector_handle!=tftp_handle) ){
393             conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
394                                             pinfo->srcport, 0, NO_PORT2);
395             conversation_set_dissector(conversation, tftp_handle);
396           }
397         } else {
398           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
399                                            pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
400           if( (conversation == NULL) || (conversation->dissector_handle!=tftp_handle) ){
401             conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
402                                             pinfo->destport, pinfo->srcport, 0);
403             conversation_set_dissector(conversation, tftp_handle);
404           }
405         }
406         tftp_info = conversation_get_proto_data(conversation, proto_tftp);
407         if (!tftp_info) {
408           tftp_info = se_alloc(sizeof(tftp_conv_info_t));
409           tftp_info->blocksize = 512; /* TFTP default block size */
410           tftp_info->source_file = NULL;
411           tftp_info->destination_file = NULL;
412           conversation_add_proto_data(conversation, proto_tftp, tftp_info);
413         }
414
415         dissect_tftp_message(tftp_info, tvb, pinfo, tree);
416
417         return;
418 }
419
420
421 void
422 proto_register_tftp(void)
423 {
424   static hf_register_info hf[] = {
425     { &hf_tftp_opcode,
426       { "Opcode",             "tftp.opcode",
427         FT_UINT16, BASE_DEC, VALS(tftp_opcode_vals), 0x0,
428         "TFTP message type", HFILL }},
429
430     { &hf_tftp_source_file,
431       { "Source File",        "tftp.source_file",
432         FT_STRINGZ, BASE_NONE, NULL, 0x0,
433         "TFTP source file name", HFILL }},
434
435     { &hf_tftp_destination_file,
436       { "DESTINATION File",   "tftp.destination_file",
437         FT_STRINGZ, BASE_NONE, NULL, 0x0,
438         "TFTP source file name", HFILL }},
439
440     { &hf_tftp_transfer_type,
441       { "Type",               "tftp.type",
442         FT_STRINGZ, BASE_NONE, NULL, 0x0,
443         "TFTP transfer type", HFILL }},
444
445     { &hf_tftp_blocknum,
446       { "Block",              "tftp.block",
447         FT_UINT16, BASE_DEC, NULL, 0x0,
448         "Block number", HFILL }},
449
450     { &hf_tftp_error_code,
451       { "Error code",         "tftp.error.code",
452         FT_UINT16, BASE_DEC, VALS(tftp_error_code_vals), 0x0,
453         "Error code in case of TFTP error message", HFILL }},
454
455     { &hf_tftp_error_string,
456       { "Error message",      "tftp.error.message",
457         FT_STRINGZ, BASE_NONE, NULL, 0x0,
458         "Error string in case of TFTP error message", HFILL }},
459
460     { &hf_tftp_option_name,
461       { "Option name",        "tftp.option.name",
462         FT_STRINGZ, BASE_NONE, NULL, 0x0,
463         NULL, HFILL }},
464
465     { &hf_tftp_option_value,
466       { "Option value",       "tftp.option.value",
467         FT_STRINGZ, BASE_NONE, NULL, 0x0,
468         NULL, HFILL }},
469
470   };
471   static gint *ett[] = {
472     &ett_tftp,
473     &ett_tftp_option,
474   };
475
476   module_t *tftp_module;
477
478   proto_tftp = proto_register_protocol("Trivial File Transfer Protocol",
479                                        "TFTP", "tftp");
480   proto_register_field_array(proto_tftp, hf, array_length(hf));
481   proto_register_subtree_array(ett, array_length(ett));
482
483   register_dissector("tftp", dissect_tftp, proto_tftp);
484
485   /* Set default UDP ports */
486   range_convert_str(&global_tftp_port_range, UDP_PORT_TFTP_RANGE, MAX_UDP_PORT);
487
488   tftp_module = prefs_register_protocol(proto_tftp, proto_reg_handoff_tftp);
489   prefs_register_range_preference(tftp_module, "udp_ports",
490                                   "TFTP port numbers",
491                                   "Port numbers used for TFTP traffic "
492                                   "(default " UDP_PORT_TFTP_RANGE ")",
493                                   &global_tftp_port_range, MAX_UDP_PORT);
494 }
495
496 static void range_delete_callback (guint32 port)
497 {
498   dissector_delete_uint("udp.port", port, tftp_handle);
499 }
500
501 static void range_add_callback (guint32 port)
502 {
503   dissector_add_uint("udp.port", port, tftp_handle);
504 }
505
506 void
507 proto_reg_handoff_tftp(void)
508 {
509   static range_t *tftp_port_range;
510   static gboolean tftp_initialized = FALSE;
511
512   if (!tftp_initialized) {
513     tftp_handle = find_dissector("tftp");
514     data_handle = find_dissector("data");
515     heur_dissector_add("stun", dissect_embeddedtftp_heur, proto_tftp);
516     tftp_initialized = TRUE;
517   } else {
518     range_foreach(tftp_port_range, range_delete_callback);
519     g_free(tftp_port_range);
520   }
521
522   tftp_port_range = range_copy(global_tftp_port_range);
523   range_foreach(tftp_port_range, range_add_callback);
524 }
525
526 /*
527  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
528  *
529  * Local variables:
530  * c-basic-offset: 2
531  * tab-width: 8
532  * indent-tabs-mode: nil
533  * End:
534  *
535  * vi: set shiftwidth=2 tabstop=8 expandtab:
536  * :indentSize=2:tabSize=8:noTabs=true:
537  */