/****************************************************************************
** 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();
}
syntax highlighted by Code2HTML, v. 0.9.1