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