print-tftp.c revision 1.6
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 * Format and print trivial file transfer protocol packets.
22 */
23
24#include <sys/cdefs.h>
25#ifndef lint
26__RCSID("$NetBSD: print-tftp.c,v 1.6 2017/01/24 23:29:14 christos 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, i;
118
119	tp = (const struct tftphdr *)bp;
120
121	/* Print length */
122	ND_PRINT((ndo, " %d", length));
123
124	/* Print tftp request type */
125	ND_TCHECK(tp->th_opcode);
126	opcode = EXTRACT_16BITS(&tp->th_opcode);
127	cp = tok2str(op2str, "tftp-#%d", opcode);
128	ND_PRINT((ndo, " %s", cp));
129	/* Bail if bogus opcode */
130	if (*cp == 't')
131		return;
132
133	switch (opcode) {
134
135	case RRQ:
136	case WRQ:
137	case OACK:
138		p = (const u_char *)tp->th_stuff;
139		ND_PRINT((ndo, " "));
140		/* Print filename or first option */
141		if (opcode != OACK)
142			ND_PRINT((ndo, "\""));
143		i = fn_print(ndo, p, ndo->ndo_snapend);
144		if (opcode != OACK)
145			ND_PRINT((ndo, "\""));
146
147		/* Print the mode (RRQ and WRQ only) and any options */
148		while ((p = (const u_char *)strchr((const char *)p, '\0')) != NULL) {
149			if (length <= (u_int)(p - (const u_char *)&tp->th_block))
150				break;
151			p++;
152			if (*p != '\0') {
153				ND_PRINT((ndo, " "));
154				fn_print(ndo, p, ndo->ndo_snapend);
155			}
156		}
157
158		if (i)
159			goto trunc;
160		break;
161
162	case ACK:
163	case DATA:
164		ND_TCHECK(tp->th_block);
165		ND_PRINT((ndo, " block %d", EXTRACT_16BITS(&tp->th_block)));
166		break;
167
168	case TFTP_ERROR:
169		/* Print error code string */
170		ND_TCHECK(tp->th_code);
171		ND_PRINT((ndo, " %s \"", tok2str(err2str, "tftp-err-#%d \"",
172				       EXTRACT_16BITS(&tp->th_code))));
173		/* Print error message string */
174		i = fn_print(ndo, (const u_char *)tp->th_data, ndo->ndo_snapend);
175		ND_PRINT((ndo, "\""));
176		if (i)
177			goto trunc;
178		break;
179
180	default:
181		/* We shouldn't get here */
182		ND_PRINT((ndo, "(unknown #%d)", opcode));
183		break;
184	}
185	return;
186trunc:
187	ND_PRINT((ndo, "%s", tstr));
188	return;
189}
190