/**************************************************************************** ** File: tftp.c ** ** Author: Mike Borella ** ** Comments: TFTP protocol module. ** ** $Id: tftp.c,v 1.1 2001/10/09 23:20:42 mborella Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Library General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** *****************************************************************************/ #include "tftp.h" #include "dynports.h" extern struct arg_t * my_args; #define FILENAME_SIZE 128 #define MODE_SIZE 64 /* TFTP opcodes */ #define TFTP_OPCODE_READ 1 #define TFTP_OPCODE_WRITE 2 #define TFTP_OPCODE_DATA 3 #define TFTP_OPCODE_ACK 4 #define TFTP_OPCODE_ERROR 5 /* TFTP opcode map */ strmap_t tftp_opcode_map[] = { { TFTP_OPCODE_READ, "read request" }, { TFTP_OPCODE_WRITE, "write request" }, { TFTP_OPCODE_DATA, "data" }, { TFTP_OPCODE_ACK, "acknowledgement" }, { TFTP_OPCODE_ERROR, "error" }, { 0, ""} }; /*---------------------------------------------------------------------------- ** ** dump_tftp() ** ** Parse and display TFTP packets ** **---------------------------------------------------------------------------- */ void dump_tftp(packet_t *pkt) { u_int16_t opcode; struct timeval t; /* Set the layer */ set_layer(LAYER_APPLICATION); /* Get the opcode */ if (get_packet_bytes((u_int8_t *) &opcode, pkt, 2) == 0) return; /* Conversions */ opcode = ntohs(opcode); /* Announcement */ if (!my_args->m) display_header_banner("TFTP"); else display_minimal_string("| TFTP "); switch(opcode) { case TFTP_OPCODE_READ: case TFTP_OPCODE_WRITE: { u_int8_t filename [FILENAME_SIZE]; u_int8_t mode [MODE_SIZE]; /* read the filename and mode */ if (get_packet_string(filename, FILENAME_SIZE, pkt) == 0) return; if (get_packet_string(mode, MODE_SIZE, pkt) == 0) return; if (my_args->m) { display_minimal_string(map2str(tftp_opcode_map, opcode)); display_minimal_string(" ("); display_minimal_string(filename); display_minimal_string(","); display_minimal_string(mode); display_minimal_string(")"); } else { display_strmap("Opcode", opcode, tftp_opcode_map); display_string("Filename", filename); display_string("Mode", mode); } /* set up a dynamic port binding to the source port */ gettimeofday(&t, NULL); dynports_add(state_get_srcport(), dump_tftp, t.tv_sec); } break; case TFTP_OPCODE_DATA: { u_int16_t block; u_int8_t * data; u_int32_t n; /* refresh up a dynamic port binding to the source and dest port */ dynports_refresh(state_get_srcport(), dump_tftp); dynports_refresh(state_get_dstport(), dump_tftp); /* read the block # */ if (get_packet_bytes((u_int8_t *) &block, pkt, 2) == 0) return; /* conversions */ block = ntohs(block); /* find out length of data field */ n = get_packet_apparentbytesleft(pkt); if (n <= 0) return; /* Allocate memory */ data = my_malloc(n+1); /* read data portion */ if (get_packet_bytes(data, pkt, n) == 0) return; if (my_args->m) { display_minimal_string(map2str(tftp_opcode_map, opcode)); display_minimal_string(" block "); display_minimal((u_int8_t *) &block, 2, DISP_DEC); } else { display_strmap("Opcode", opcode, tftp_opcode_map); display("Block", (u_int8_t *) &block, 2, DISP_DEC); display("Data", data, n, DISP_HEX_MULTILINE); } /* free memory for data */ my_free(data); } break; case TFTP_OPCODE_ACK: { u_int16_t block; /* refresh up a dynamic port binding to the source and dest port */ dynports_refresh(state_get_srcport(), dump_tftp); dynports_refresh(state_get_dstport(), dump_tftp); /* read the block # */ if (get_packet_bytes((u_int8_t *) &block, pkt, 2) == 0) return; /* conversions */ block = ntohs(block); if (my_args->m) { display_minimal_string(map2str(tftp_opcode_map, opcode)); display_minimal_string(" block "); display_minimal((u_int8_t *) &block, 2, DISP_DEC); } else { display_strmap("Opcode", opcode, tftp_opcode_map); display("Block", (u_int8_t *) &block, 2, DISP_DEC); } } break; case TFTP_OPCODE_ERROR: { u_int16_t errorcode; u_int8_t * msg; u_int32_t n; /* refresh up a dynamic port binding to the source and dest port */ dynports_refresh(state_get_srcport(), dump_tftp); dynports_refresh(state_get_dstport(), dump_tftp); /* read the block # */ if (get_packet_bytes((u_int8_t *) &errorcode, pkt, 2) == 0) return; /* conversions */ errorcode = ntohs(errorcode); /* find out length of msg field */ n = get_packet_apparentbytesleft(pkt); if (n <= 0) return; /* Allocate memory */ msg = my_malloc(n+1); /* read data portion */ if (get_packet_string(msg, n, pkt) == 0) return; if (my_args->m) { display_minimal_string(map2str(tftp_opcode_map, opcode)); display_minimal_string(" ("); display_minimal((u_int8_t *) &errorcode, 2, DISP_DEC); display_minimal_string(","); display_minimal_string(msg); display_minimal_string(")"); } else { display_strmap("Opcode", opcode, tftp_opcode_map); display("Error", (u_int8_t *) &error, 2, DISP_DEC); display_string("Message", msg); } /* free memory for data */ my_free(msg); } break; default: break; } /* dump the hex buffer */ hexbuffer_flush(); }