print-tftp.c revision 1.7
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#include <sys/cdefs.h>
25#ifndef lint
26__RCSID("$NetBSD: print-tftp.c,v 1.7 2017/02/05 04:05:05 spz Exp $");
27#endif
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <netdissect-stdinc.h>
34
35#include <string.h>
36
37#include "netdissect.h"
38#include "extract.h"
39
40/*
41 * Trivial File Transfer Protocol (IEN-133)
42 */
43
44/*
45 * Packet types.
46 */
47#define	RRQ	01			/* read request */
48#define	WRQ	02			/* write request */
49#define	DATA	03			/* data packet */
50#define	ACK	04			/* acknowledgement */
51#define	TFTP_ERROR	05			/* error code */
52#define OACK	06			/* option acknowledgement */
53
54struct	tftphdr {
55	unsigned short	th_opcode;		/* packet type */
56	union {
57		unsigned short	tu_block;	/* block # */
58		unsigned short	tu_code;	/* error code */
59		char	tu_stuff[1];	/* request packet stuff */
60	} th_u;
61	char	th_data[1];		/* data or error string */
62};
63
64#define	th_block	th_u.tu_block
65#define	th_code		th_u.tu_code
66#define	th_stuff	th_u.tu_stuff
67#define	th_msg		th_data
68
69/*
70 * Error codes.
71 */
72#define	EUNDEF		0		/* not defined */
73#define	ENOTFOUND	1		/* file not found */
74#define	EACCESS		2		/* access violation */
75#define	ENOSPACE	3		/* disk full or allocation exceeded */
76#define	EBADOP		4		/* illegal TFTP operation */
77#define	EBADID		5		/* unknown transfer ID */
78#define	EEXISTS		6		/* file already exists */
79#define	ENOUSER		7		/* no such user */
80
81static const char tstr[] = " [|tftp]";
82
83/* op code to string mapping */
84static const struct tok op2str[] = {
85	{ RRQ,		"RRQ" },	/* read request */
86	{ WRQ,		"WRQ" },	/* write request */
87	{ DATA,		"DATA" },	/* data packet */
88	{ ACK,		"ACK" },	/* acknowledgement */
89	{ TFTP_ERROR,	"ERROR" },	/* error code */
90	{ OACK,		"OACK" },	/* option acknowledgement */
91	{ 0,		NULL }
92};
93
94/* error code to string mapping */
95static const struct tok err2str[] = {
96	{ EUNDEF,	"EUNDEF" },	/* not defined */
97	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
98	{ EACCESS,	"EACCESS" },	/* access violation */
99	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
100	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
101	{ EBADID,	"EBADID" },	/* unknown transfer ID */
102	{ EEXISTS,	"EEXISTS" },	/* file already exists */
103	{ ENOUSER,	"ENOUSER" },	/* no such user */
104	{ 0,		NULL }
105};
106
107/*
108 * Print trivial file transfer program requests
109 */
110void
111tftp_print(netdissect_options *ndo,
112           register const u_char *bp, u_int length)
113{
114	register const struct tftphdr *tp;
115	register const char *cp;
116	register const u_char *p;
117	register int opcode;
118	u_int ui;
119
120	tp = (const struct tftphdr *)bp;
121
122	/* Print length */
123	ND_PRINT((ndo, " %d", length));
124
125	/* Print tftp request type */
126	if (length < 2)
127		goto trunc;
128	ND_TCHECK(tp->th_opcode);
129	opcode = EXTRACT_16BITS(&tp->th_opcode);
130	cp = tok2str(op2str, "tftp-#%d", opcode);
131	length -= 2;
132	ND_PRINT((ndo, " %s", cp));
133	/* Bail if bogus opcode */
134	if (*cp == 't')
135		return;
136
137	switch (opcode) {
138
139	case RRQ:
140	case WRQ:
141		p = (const u_char *)tp->th_stuff;
142		if (length == 0)
143			goto trunc;
144		ND_PRINT((ndo, " "));
145		/* Print filename */
146		ND_PRINT((ndo, "\""));
147		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
148		ND_PRINT((ndo, "\""));
149		if (ui == 0)
150			goto trunc;
151		p += ui;
152		length -= ui;
153
154		/* Print the mode - RRQ and WRQ only */
155		if (length == 0)
156			goto trunc;	/* no mode */
157		ND_PRINT((ndo, " "));
158		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
159		if (ui == 0)
160			goto trunc;
161		p += ui;
162		length -= ui;
163
164		/* Print options, if any */
165		while (length != 0) {
166			ND_TCHECK(*p);
167			if (*p != '\0')
168				ND_PRINT((ndo, " "));
169			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
170			if (ui == 0)
171				goto trunc;
172			p += ui;
173			length -= ui;
174		}
175		break;
176
177	case OACK:
178		p = (const u_char *)tp->th_stuff;
179		/* Print options */
180		while (length != 0) {
181			ND_TCHECK(*p);
182			if (*p != '\0')
183				ND_PRINT((ndo, " "));
184			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
185			if (ui == 0)
186				goto trunc;
187			p += ui;
188			length -= ui;
189		}
190		break;
191
192	case ACK:
193	case DATA:
194		if (length < 2)
195			goto trunc;	/* no block number */
196		ND_TCHECK(tp->th_block);
197		ND_PRINT((ndo, " block %d", EXTRACT_16BITS(&tp->th_block)));
198		break;
199
200	case TFTP_ERROR:
201		/* Print error code string */
202		if (length < 2)
203			goto trunc;	/* no error code */
204		ND_TCHECK(tp->th_code);
205		ND_PRINT((ndo, " %s", tok2str(err2str, "tftp-err-#%d \"",
206				       EXTRACT_16BITS(&tp->th_code))));
207		length -= 2;
208		/* Print error message string */
209		if (length == 0)
210			goto trunc;	/* no error message */
211		ND_PRINT((ndo, " \""));
212		ui = fn_printztn(ndo, (const u_char *)tp->th_data, length, ndo->ndo_snapend);
213		ND_PRINT((ndo, "\""));
214		if (ui == 0)
215			goto trunc;
216		break;
217
218	default:
219		/* We shouldn't get here */
220		ND_PRINT((ndo, "(unknown #%d)", opcode));
221		break;
222	}
223	return;
224trunc:
225	ND_PRINT((ndo, "%s", tstr));
226	return;
227}
228