Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  */
     21 
     22 /* \summary: Trivial File Transfer Protocol (TFTP) printer */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include "config.h"
     26 #endif
     27 
     28 #include <netdissect-stdinc.h>
     29 
     30 #include <string.h>
     31 
     32 #include "netdissect.h"
     33 #include "extract.h"
     34 
     35 /*
     36  * Trivial File Transfer Protocol (IEN-133)
     37  */
     38 
     39 /*
     40  * Packet types.
     41  */
     42 #define	RRQ	01			/* read request */
     43 #define	WRQ	02			/* write request */
     44 #define	DATA	03			/* data packet */
     45 #define	ACK	04			/* acknowledgement */
     46 #define	TFTP_ERROR	05			/* error code */
     47 #define OACK	06			/* option acknowledgement */
     48 
     49 struct	tftphdr {
     50 	unsigned short	th_opcode;		/* packet type */
     51 	union {
     52 		unsigned short	tu_block;	/* block # */
     53 		unsigned short	tu_code;	/* error code */
     54 		char	tu_stuff[1];	/* request packet stuff */
     55 	} th_u;
     56 	char	th_data[1];		/* data or error string */
     57 };
     58 
     59 #define	th_block	th_u.tu_block
     60 #define	th_code		th_u.tu_code
     61 #define	th_stuff	th_u.tu_stuff
     62 #define	th_msg		th_data
     63 
     64 /*
     65  * Error codes.
     66  */
     67 #define	EUNDEF		0		/* not defined */
     68 #define	ENOTFOUND	1		/* file not found */
     69 #define	EACCESS		2		/* access violation */
     70 #define	ENOSPACE	3		/* disk full or allocation exceeded */
     71 #define	EBADOP		4		/* illegal TFTP operation */
     72 #define	EBADID		5		/* unknown transfer ID */
     73 #define	EEXISTS		6		/* file already exists */
     74 #define	ENOUSER		7		/* no such user */
     75 
     76 static const char tstr[] = " [|tftp]";
     77 
     78 /* op code to string mapping */
     79 static const struct tok op2str[] = {
     80 	{ RRQ,		"RRQ" },	/* read request */
     81 	{ WRQ,		"WRQ" },	/* write request */
     82 	{ DATA,		"DATA" },	/* data packet */
     83 	{ ACK,		"ACK" },	/* acknowledgement */
     84 	{ TFTP_ERROR,	"ERROR" },	/* error code */
     85 	{ OACK,		"OACK" },	/* option acknowledgement */
     86 	{ 0,		NULL }
     87 };
     88 
     89 /* error code to string mapping */
     90 static const struct tok err2str[] = {
     91 	{ EUNDEF,	"EUNDEF" },	/* not defined */
     92 	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
     93 	{ EACCESS,	"EACCESS" },	/* access violation */
     94 	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
     95 	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
     96 	{ EBADID,	"EBADID" },	/* unknown transfer ID */
     97 	{ EEXISTS,	"EEXISTS" },	/* file already exists */
     98 	{ ENOUSER,	"ENOUSER" },	/* no such user */
     99 	{ 0,		NULL }
    100 };
    101 
    102 /*
    103  * Print trivial file transfer program requests
    104  */
    105 void
    106 tftp_print(netdissect_options *ndo,
    107            register const u_char *bp, u_int length)
    108 {
    109 	register const struct tftphdr *tp;
    110 	register const char *cp;
    111 	register const u_char *p;
    112 	register int opcode;
    113 	u_int ui;
    114 
    115 	tp = (const struct tftphdr *)bp;
    116 
    117 	/* Print length */
    118 	ND_PRINT((ndo, " %d", length));
    119 
    120 	/* Print tftp request type */
    121 	if (length < 2)
    122 		goto trunc;
    123 	ND_TCHECK(tp->th_opcode);
    124 	opcode = EXTRACT_16BITS(&tp->th_opcode);
    125 	cp = tok2str(op2str, "tftp-#%d", opcode);
    126 	length -= 2;
    127 	ND_PRINT((ndo, " %s", cp));
    128 	/* Bail if bogus opcode */
    129 	if (*cp == 't')
    130 		return;
    131 
    132 	switch (opcode) {
    133 
    134 	case RRQ:
    135 	case WRQ:
    136 		p = (const u_char *)tp->th_stuff;
    137 		if (length == 0)
    138 			goto trunc;
    139 		ND_PRINT((ndo, " "));
    140 		/* Print filename */
    141 		ND_PRINT((ndo, "\""));
    142 		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
    143 		ND_PRINT((ndo, "\""));
    144 		if (ui == 0)
    145 			goto trunc;
    146 		p += ui;
    147 		length -= ui;
    148 
    149 		/* Print the mode - RRQ and WRQ only */
    150 		if (length == 0)
    151 			goto trunc;	/* no mode */
    152 		ND_PRINT((ndo, " "));
    153 		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
    154 		if (ui == 0)
    155 			goto trunc;
    156 		p += ui;
    157 		length -= ui;
    158 
    159 		/* Print options, if any */
    160 		while (length != 0) {
    161 			ND_TCHECK(*p);
    162 			if (*p != '\0')
    163 				ND_PRINT((ndo, " "));
    164 			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
    165 			if (ui == 0)
    166 				goto trunc;
    167 			p += ui;
    168 			length -= ui;
    169 		}
    170 		break;
    171 
    172 	case OACK:
    173 		p = (const u_char *)tp->th_stuff;
    174 		/* Print options */
    175 		while (length != 0) {
    176 			ND_TCHECK(*p);
    177 			if (*p != '\0')
    178 				ND_PRINT((ndo, " "));
    179 			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
    180 			if (ui == 0)
    181 				goto trunc;
    182 			p += ui;
    183 			length -= ui;
    184 		}
    185 		break;
    186 
    187 	case ACK:
    188 	case DATA:
    189 		if (length < 2)
    190 			goto trunc;	/* no block number */
    191 		ND_TCHECK(tp->th_block);
    192 		ND_PRINT((ndo, " block %d", EXTRACT_16BITS(&tp->th_block)));
    193 		break;
    194 
    195 	case TFTP_ERROR:
    196 		/* Print error code string */
    197 		if (length < 2)
    198 			goto trunc;	/* no error code */
    199 		ND_TCHECK(tp->th_code);
    200 		ND_PRINT((ndo, " %s", tok2str(err2str, "tftp-err-#%d \"",
    201 				       EXTRACT_16BITS(&tp->th_code))));
    202 		length -= 2;
    203 		/* Print error message string */
    204 		if (length == 0)
    205 			goto trunc;	/* no error message */
    206 		ND_PRINT((ndo, " \""));
    207 		ui = fn_printztn(ndo, (const u_char *)tp->th_data, length, ndo->ndo_snapend);
    208 		ND_PRINT((ndo, "\""));
    209 		if (ui == 0)
    210 			goto trunc;
    211 		break;
    212 
    213 	default:
    214 		/* We shouldn't get here */
    215 		ND_PRINT((ndo, "(unknown #%d)", opcode));
    216 		break;
    217 	}
    218 	return;
    219 trunc:
    220 	ND_PRINT((ndo, "%s", tstr));
    221 	return;
    222 }
    223