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