2 * Routines for tftp packet dissection
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
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 1998 Gerald Combs
16 * Copied from packet-bootp.c
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.
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.
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.
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)
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>
56 /* Things we may want to remember for a whole conversation */
57 typedef struct _tftp_conv_info_t {
59 gchar *source_file, *destination_file;
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;
74 static gint ett_tftp = -1;
75 static gint ett_tftp_option = -1;
77 static dissector_handle_t tftp_handle;
78 static dissector_handle_t data_handle;
80 #define UDP_PORT_TFTP_RANGE "69"
82 void proto_reg_handoff_tftp (void);
84 /* User definable values */
85 static range_t *global_tftp_port_range;
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)" },
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" },
120 tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset,
121 proto_tree *tree, guint16 opcode, tftp_conv_info_t *tftp_info)
123 int option_len, value_len;
125 const char *optionname;
126 const char *optionvalue;
127 proto_item *opt_item;
128 proto_tree *opt_tree;
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);
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);
145 offset += option_len + value_len;
147 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s=%s",
148 optionname, optionvalue);
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");
158 tftp_info->blocksize = blocksize;
164 static void dissect_tftp_message(tftp_conv_info_t *tftp_info,
165 tvbuff_t *tvb, packet_info *pinfo,
168 proto_tree *tftp_tree = NULL;
177 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP");
179 opcode = tvb_get_ntohs(tvb, offset);
181 col_add_str(pinfo->cinfo, COL_INFO,
182 val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));
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);
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);
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);
200 proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb,
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);
212 tftp_info->source_file = tvb_get_seasonal_string(tvb, offset, i1);
214 col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
215 tvb_format_stringzpad(tvb, offset, i1));
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);
223 col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
224 tvb_format_stringzpad(tvb, offset, i1));
228 tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
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);
237 tftp_info->destination_file =
238 tvb_get_seasonal_string(tvb, offset, i1);
240 col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
241 tvb_format_stringzpad(tvb, offset, i1));
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);
249 col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
250 tvb_format_stringzpad(tvb, offset, i1));
254 tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
259 tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
264 blocknum = tvb_get_ntohs(tvb, offset);
265 proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
270 bytes = tvb_reported_length_remaining(tvb, offset);
272 col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s",
274 (bytes < tftp_info->blocksize)?" (last)":"" );
277 tvbuff_t *data_tvb = tvb_new_subset(tvb, offset, -1, bytes);
278 call_dissector(data_handle, data_tvb, pinfo, tree);
283 blocknum = tvb_get_ntohs(tvb, offset);
284 proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
287 col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i",
292 error = tvb_get_ntohs(tvb, offset);
293 proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
296 col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s",
297 val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));
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);
305 col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s",
306 tvb_format_stringzpad(tvb, offset, i1));
308 expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE,
309 PI_NOTE, "TFTP blocksize out of range");
313 tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
318 proto_tree_add_text(tftp_tree, tvb, offset, -1,
319 "Data (%d bytes)", tvb_reported_length_remaining(tvb, offset));
328 dissect_embeddedtftp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
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;
335 tftp_conv_info_t *tftp_info;
337 conversation = find_or_create_conversation(pinfo);
339 tftp_info = conversation_get_proto_data(conversation, proto_tftp);
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);
348 opcode = tvb_get_ntohs(tvb, 0);
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);
366 dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
368 conversation_t *conversation = NULL;
369 tftp_conv_info_t *tftp_info;
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
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.
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.
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);
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);
406 tftp_info = conversation_get_proto_data(conversation, proto_tftp);
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);
415 dissect_tftp_message(tftp_info, tvb, pinfo, tree);
422 proto_register_tftp(void)
424 static hf_register_info hf[] = {
426 { "Opcode", "tftp.opcode",
427 FT_UINT16, BASE_DEC, VALS(tftp_opcode_vals), 0x0,
428 "TFTP message type", HFILL }},
430 { &hf_tftp_source_file,
431 { "Source File", "tftp.source_file",
432 FT_STRINGZ, BASE_NONE, NULL, 0x0,
433 "TFTP source file name", HFILL }},
435 { &hf_tftp_destination_file,
436 { "DESTINATION File", "tftp.destination_file",
437 FT_STRINGZ, BASE_NONE, NULL, 0x0,
438 "TFTP source file name", HFILL }},
440 { &hf_tftp_transfer_type,
441 { "Type", "tftp.type",
442 FT_STRINGZ, BASE_NONE, NULL, 0x0,
443 "TFTP transfer type", HFILL }},
446 { "Block", "tftp.block",
447 FT_UINT16, BASE_DEC, NULL, 0x0,
448 "Block number", HFILL }},
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 }},
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 }},
460 { &hf_tftp_option_name,
461 { "Option name", "tftp.option.name",
462 FT_STRINGZ, BASE_NONE, NULL, 0x0,
465 { &hf_tftp_option_value,
466 { "Option value", "tftp.option.value",
467 FT_STRINGZ, BASE_NONE, NULL, 0x0,
471 static gint *ett[] = {
476 module_t *tftp_module;
478 proto_tftp = proto_register_protocol("Trivial File Transfer Protocol",
480 proto_register_field_array(proto_tftp, hf, array_length(hf));
481 proto_register_subtree_array(ett, array_length(ett));
483 register_dissector("tftp", dissect_tftp, proto_tftp);
485 /* Set default UDP ports */
486 range_convert_str(&global_tftp_port_range, UDP_PORT_TFTP_RANGE, MAX_UDP_PORT);
488 tftp_module = prefs_register_protocol(proto_tftp, proto_reg_handoff_tftp);
489 prefs_register_range_preference(tftp_module, "udp_ports",
491 "Port numbers used for TFTP traffic "
492 "(default " UDP_PORT_TFTP_RANGE ")",
493 &global_tftp_port_range, MAX_UDP_PORT);
496 static void range_delete_callback (guint32 port)
498 dissector_delete_uint("udp.port", port, tftp_handle);
501 static void range_add_callback (guint32 port)
503 dissector_add_uint("udp.port", port, tftp_handle);
507 proto_reg_handoff_tftp(void)
509 static range_t *tftp_port_range;
510 static gboolean tftp_initialized = FALSE;
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;
518 range_foreach(tftp_port_range, range_delete_callback);
519 g_free(tftp_port_range);
522 tftp_port_range = range_copy(global_tftp_port_range);
523 range_foreach(tftp_port_range, range_add_callback);
527 * Editor modelines - http://www.wireshark.org/tools/modelines.html
532 * indent-tabs-mode: nil
535 * vi: set shiftwidth=2 tabstop=8 expandtab:
536 * :indentSize=2:tabSize=8:noTabs=true: