tftp.c (1a0fda2b547365c9453523592a445dfe21266d4b) | tftp.c (752fa694029c20397f7928fa5f6b80f787677be2) |
---|---|
1/* 2 * Copyright (c) 1983, 1993 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 the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 31 unchanged lines hidden (view full) --- 40#include <sys/cdefs.h> 41__FBSDID("$FreeBSD$"); 42 43/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 44 45/* 46 * TFTP User Program -- Protocol Machines 47 */ | 1/* 2 * Copyright (c) 1983, 1993 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 the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 31 unchanged lines hidden (view full) --- 40#include <sys/cdefs.h> 41__FBSDID("$FreeBSD$"); 42 43/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 44 45/* 46 * TFTP User Program -- Protocol Machines 47 */ |
48#include <sys/types.h> | |
49#include <sys/socket.h> | 48#include <sys/socket.h> |
50#include <sys/time.h> | 49#include <sys/stat.h> |
51 52#include <netinet/in.h> 53 | 50 51#include <netinet/in.h> 52 |
54#include <arpa/inet.h> | |
55#include <arpa/tftp.h> 56 57#include <err.h> | 53#include <arpa/tftp.h> 54 55#include <err.h> |
58#include <errno.h> 59#include <setjmp.h> 60#include <signal.h> | 56#include <netdb.h> |
61#include <stdio.h> | 57#include <stdio.h> |
58#include <stdlib.h> |
|
62#include <string.h> | 59#include <string.h> |
63#include <unistd.h> 64#include <netdb.h> | 60#include <syslog.h> |
65 | 61 |
66#include "extern.h" 67#include "tftpsubs.h" | 62#include "tftp.h" 63#include "tftp-file.h" 64#include "tftp-utils.h" 65#include "tftp-io.h" 66#include "tftp-transfer.h" 67#include "tftp-options.h" |
68 | 68 |
69extern struct sockaddr_storage peeraddr; /* filled in by main */ 70extern int f; /* the opened socket */ 71extern int trace; 72extern int verbose; 73extern int rexmtval; 74extern int maxtimeout; 75extern volatile int txrx_error; 76 77#define PKTSIZE SEGSIZE+4 78char ackbuf[PKTSIZE]; 79int timeout; 80jmp_buf toplevel; 81jmp_buf timeoutbuf; 82 83static void nak(int, const struct sockaddr *); 84static int makerequest(int, const char *, struct tftphdr *, const char *); 85static void printstats(const char *, unsigned long); 86static void startclock(void); 87static void stopclock(void); 88static void timer(int); 89static void tpacket(const char *, struct tftphdr *, int); 90static int cmpport(const struct sockaddr *, const struct sockaddr *); 91 | |
92/* 93 * Send the requested file. 94 */ 95void | 69/* 70 * Send the requested file. 71 */ 72void |
96xmitfile(int fd, const char *name, const char *mode) | 73xmitfile(int peer, char *port, int fd, char *name, char *mode) |
97{ | 74{ |
98 struct tftphdr *ap; /* data and ack packets */ 99 struct tftphdr *dp; 100 int n; 101 volatile unsigned short block; 102 volatile int size, convert; 103 volatile unsigned long amount; 104 struct sockaddr_storage from; 105 socklen_t fromlen; 106 FILE *file; 107 struct sockaddr_storage peer; | 75 struct tftphdr *rp; 76 int n, i; 77 uint16_t block; 78 uint32_t amount; |
108 struct sockaddr_storage serv; /* valid server port number */ | 79 struct sockaddr_storage serv; /* valid server port number */ |
80 char recvbuffer[MAXPKTSIZE]; 81 struct tftp_stats tftp_stats; |
|
109 | 82 |
110 startclock(); /* start stat's clock */ 111 dp = r_init(); /* reset fillbuf/read-ahead code */ 112 ap = (struct tftphdr *)ackbuf; 113 file = fdopen(fd, "r"); 114 convert = !strcmp(mode, "netascii"); 115 block = 0; 116 amount = 0; 117 memcpy(&peer, &peeraddr, peeraddr.ss_len); | 83 stats_init(&tftp_stats); 84 |
118 memset(&serv, 0, sizeof(serv)); | 85 memset(&serv, 0, sizeof(serv)); |
86 rp = (struct tftphdr *)recvbuffer; |
|
119 | 87 |
120 signal(SIGALRM, timer); 121 do { 122 if (block == 0) 123 size = makerequest(WRQ, name, dp, mode) - 4; 124 else { 125 /* size = read(fd, dp->th_data, SEGSIZE); */ 126 size = readit(file, &dp, convert); 127 if (size < 0) { 128 nak(errno + 100, (struct sockaddr *)&peer); 129 break; 130 } 131 dp->th_opcode = htons((u_short)DATA); 132 dp->th_block = htons((u_short)block); | 88 if (port == NULL) { 89 struct servent *se; 90 se = getservbyname("tftp", "udp"); 91 ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 92 } else 93 ((struct sockaddr_in *)&peer_sock)->sin_port = 94 htons(atoi(port)); 95 96 for (i = 0; i < 12; i++) { 97 struct sockaddr_storage from; 98 99 /* Tell the other side what we want to do */ 100 if (debug&DEBUG_SIMPLE) 101 printf("Sending %s\n", name); 102 103 n = send_wrq(peer, name, mode); 104 if (n > 0) { 105 printf("Cannot send WRQ packet\n"); 106 return; |
133 } | 107 } |
134 timeout = 0; 135 (void) setjmp(timeoutbuf); 136send_data: 137 if (trace) 138 tpacket("sent", dp, size + 4); 139 n = sendto(f, dp, size + 4, 0, 140 (struct sockaddr *)&peer, peer.ss_len); 141 if (n != size + 4) { 142 warn("sendto"); 143 txrx_error = 1; 144 goto abort; | 108 109 /* 110 * The first packet we receive has the new destination port 111 * we have to send the next packets to. 112 */ 113 n = receive_packet(peer, recvbuffer, 114 MAXPKTSIZE, &from, timeoutpacket); 115 116 /* We got some data! */ 117 if (n >= 0) { 118 ((struct sockaddr_in *)&peer_sock)->sin_port = 119 ((struct sockaddr_in *)&from)->sin_port; 120 break; |
145 } | 121 } |
146 read_ahead(file, convert); 147 for ( ; ; ) { 148 alarm(rexmtval); 149 do { 150 fromlen = sizeof(from); 151 n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, 152 (struct sockaddr *)&from, &fromlen); 153 } while (n <= 0); 154 alarm(0); 155 if (n < 0) { 156 warn("recvfrom"); 157 txrx_error = 1; 158 goto abort; 159 } 160 if (!serv.ss_family) 161 serv = from; 162 else if (!cmpport((struct sockaddr *)&serv, 163 (struct sockaddr *)&from)) { 164 warn("server port mismatch"); 165 txrx_error = 1; 166 goto abort; 167 } 168 peer = from; 169 if (trace) 170 tpacket("received", ap, n); 171 /* should verify packet came from server */ 172 ap->th_opcode = ntohs(ap->th_opcode); 173 ap->th_block = ntohs(ap->th_block); 174 if (ap->th_opcode == ERROR) { 175 printf("Error code %d: %s\n", ap->th_code, 176 ap->th_msg); 177 txrx_error = 1; 178 goto abort; 179 } 180 if (ap->th_opcode == ACK) { 181 int j; | |
182 | 122 |
183 if (ap->th_block == block) { 184 break; 185 } 186 /* On an error, try to synchronize 187 * both sides. 188 */ 189 j = synchnet(f); 190 if (j && trace) { 191 printf("discarded %d packets\n", 192 j); 193 } 194 if (ap->th_block == (block-1)) { 195 goto send_data; 196 } 197 } | 123 /* This should be retried */ 124 if (n == RP_TIMEOUT) { 125 printf("Try %d, didn't receive answer from remote.\n", 126 i + 1); 127 continue; |
198 } | 128 } |
199 if (block > 0) 200 amount += size; 201 block++; 202 } while (size == SEGSIZE || block == 1); 203abort: 204 fclose(file); 205 stopclock(); | 129 130 /* Everything else is fatal */ 131 break; 132 } 133 if (i == 12) { 134 printf("Transfer timed out.\n"); 135 return; 136 } 137 if (rp->th_opcode == ERROR) { 138 printf("Got ERROR, aborted\n"); 139 return; 140 } 141 142 /* 143 * If the first packet is an OACK instead of an ACK packet, 144 * handle it different. 145 */ 146 if (rp->th_opcode == OACK) { 147 if (!options_rfc_enabled) { 148 printf("Got OACK while options are not enabled!\n"); 149 send_error(peer, EBADOP); 150 return; 151 } 152 153 parse_options(peer, rp->th_stuff, n + 2); 154 } 155 156 if (read_init(fd, NULL, mode) < 0) { 157 warn("read_init()"); 158 return; 159 } 160 161 block = 1; 162 tftp_send(peer, &block, &tftp_stats); 163 164 read_close(); |
206 if (amount > 0) | 165 if (amount > 0) |
207 printstats("Sent", amount); | 166 printstats("Sent", verbose, &tftp_stats); 167 168 txrx_error = 1; |
208} 209 210/* 211 * Receive a file. 212 */ 213void | 169} 170 171/* 172 * Receive a file. 173 */ 174void |
214recvfile(int fd, const char *name, const char *mode) | 175recvfile(int peer, char *port, int fd, char *name, char *mode) |
215{ | 176{ |
216 struct tftphdr *ap; 217 struct tftphdr *dp; 218 int n; 219 volatile unsigned short block; 220 volatile int size, firsttrip; 221 volatile unsigned long amount; 222 struct sockaddr_storage from; 223 socklen_t fromlen; 224 FILE *file; 225 volatile int convert; /* true if converting crlf -> lf */ 226 struct sockaddr_storage peer; 227 struct sockaddr_storage serv; /* valid server port number */ | 177 struct tftphdr *rp; 178 uint16_t block; 179 char recvbuffer[MAXPKTSIZE]; 180 int n, i; 181 struct tftp_stats tftp_stats; |
228 | 182 |
229 startclock(); 230 dp = w_init(); 231 ap = (struct tftphdr *)ackbuf; 232 file = fdopen(fd, "w"); 233 convert = !strcmp(mode, "netascii"); 234 block = 1; 235 firsttrip = 1; 236 amount = 0; 237 memcpy(&peer, &peeraddr, peeraddr.ss_len); 238 memset(&serv, 0, sizeof(serv)); | 183 stats_init(&tftp_stats); |
239 | 184 |
240 signal(SIGALRM, timer); 241 do { 242 if (firsttrip) { 243 size = makerequest(RRQ, name, ap, mode); 244 firsttrip = 0; 245 } else { 246 ap->th_opcode = htons((u_short)ACK); 247 ap->th_block = htons((u_short)(block)); 248 size = 4; 249 block++; 250 } 251 timeout = 0; 252 (void) setjmp(timeoutbuf); 253send_ack: 254 if (trace) 255 tpacket("sent", ap, size); 256 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer, 257 peer.ss_len) != size) { 258 alarm(0); 259 warn("sendto"); 260 txrx_error = 1; 261 goto abort; 262 } 263 write_behind(file, convert); 264 for ( ; ; ) { 265 alarm(rexmtval); 266 do { 267 fromlen = sizeof(from); 268 n = recvfrom(f, dp, PKTSIZE, 0, 269 (struct sockaddr *)&from, &fromlen); 270 } while (n <= 0); 271 alarm(0); 272 if (n < 0) { 273 warn("recvfrom"); 274 txrx_error = 1; 275 goto abort; 276 } 277 if (!serv.ss_family) 278 serv = from; 279 else if (!cmpport((struct sockaddr *)&serv, 280 (struct sockaddr *)&from)) { 281 warn("server port mismatch"); 282 txrx_error = 1; 283 goto abort; 284 } 285 peer = from; 286 if (trace) 287 tpacket("received", dp, n); 288 /* should verify client address */ 289 dp->th_opcode = ntohs(dp->th_opcode); 290 dp->th_block = ntohs(dp->th_block); 291 if (dp->th_opcode == ERROR) { 292 printf("Error code %d: %s\n", dp->th_code, 293 dp->th_msg); 294 txrx_error = 1; 295 goto abort; 296 } 297 if (dp->th_opcode == DATA) { 298 int j; | 185 rp = (struct tftphdr *)recvbuffer; |
299 | 186 |
300 if (dp->th_block == block) { 301 break; /* have next packet */ 302 } 303 /* On an error, try to synchronize 304 * both sides. 305 */ 306 j = synchnet(f); 307 if (j && trace) { 308 printf("discarded %d packets\n", j); 309 } 310 if (dp->th_block == (block-1)) { 311 goto send_ack; /* resend ack */ 312 } 313 } 314 } 315 /* size = write(fd, dp->th_data, n - 4); */ 316 size = writeit(file, &dp, n - 4, convert); 317 if (size < 0) { 318 nak(errno + 100, (struct sockaddr *)&peer); 319 break; 320 } 321 amount += size; 322 } while (size == SEGSIZE); 323abort: /* ok to ack, since user */ 324 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 325 ap->th_block = htons((u_short)block); 326 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, 327 peer.ss_len); 328 write_behind(file, convert); /* flush last buffer */ 329 fclose(file); 330 stopclock(); 331 if (amount > 0) 332 printstats("Received", amount); 333} | 187 if (port == NULL) { 188 struct servent *se; 189 se = getservbyname("tftp", "udp"); 190 ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 191 } else 192 ((struct sockaddr_in *)&peer_sock)->sin_port = 193 htons(atoi(port)); |
334 | 194 |
335static int 336makerequest(int request, const char *name, struct tftphdr *tp, const char *mode) 337{ 338 char *cp; | 195 for (i = 0; i < 12; i++) { 196 struct sockaddr_storage from; |
339 | 197 |
340 tp->th_opcode = htons((u_short)request); 341 cp = tp->th_stuff; 342 strcpy(cp, name); 343 cp += strlen(name); 344 *cp++ = '\0'; 345 strcpy(cp, mode); 346 cp += strlen(mode); 347 *cp++ = '\0'; 348 return (cp - (char *)tp); 349} | 198 /* Tell the other side what we want to do */ 199 if (debug&DEBUG_SIMPLE) 200 printf("Requesting %s\n", name); |
350 | 201 |
351struct errmsg { 352 int e_code; 353 const char *e_msg; 354} errmsgs[] = { 355 { EUNDEF, "Undefined error code" }, 356 { ENOTFOUND, "File not found" }, 357 { EACCESS, "Access violation" }, 358 { ENOSPACE, "Disk full or allocation exceeded" }, 359 { EBADOP, "Illegal TFTP operation" }, 360 { EBADID, "Unknown transfer ID" }, 361 { EEXISTS, "File already exists" }, 362 { ENOUSER, "No such user" }, 363 { -1, 0 } 364}; | 202 n = send_rrq(peer, name, mode); 203 if (n > 0) { 204 printf("Cannot send RRQ packet\n"); 205 return; 206 } |
365 | 207 |
366/* 367 * Send a nak packet (error message). 368 * Error code passed in is one of the 369 * standard TFTP codes, or a UNIX errno 370 * offset by 100. 371 */ 372static void 373nak(int error, const struct sockaddr *peer) 374{ 375 struct errmsg *pe; 376 struct tftphdr *tp; 377 int length; | 208 /* 209 * The first packet we receive has the new destination port 210 * we have to send the next packets to. 211 */ 212 n = receive_packet(peer, recvbuffer, 213 MAXPKTSIZE, &from, timeoutpacket); |
378 | 214 |
379 tp = (struct tftphdr *)ackbuf; 380 tp->th_opcode = htons((u_short)ERROR); 381 tp->th_code = htons((u_short)error); 382 for (pe = errmsgs; pe->e_code >= 0; pe++) 383 if (pe->e_code == error) | 215 /* We got something useful! */ 216 if (n >= 0) { 217 ((struct sockaddr_in *)&peer_sock)->sin_port = 218 ((struct sockaddr_in *)&from)->sin_port; |
384 break; | 219 break; |
385 if (pe->e_code < 0) { 386 pe->e_msg = strerror(error - 100); 387 tp->th_code = EUNDEF; 388 } 389 strcpy(tp->th_msg, pe->e_msg); 390 length = strlen(pe->e_msg) + 4; 391 if (trace) 392 tpacket("sent", tp, length); 393 if (sendto(f, ackbuf, length, 0, peer, peer->sa_len) != length) 394 warn("nak"); 395} | 220 } |
396 | 221 |
397static void 398tpacket(const char *s, struct tftphdr *tp, int n) 399{ 400 static const char *opcodes[] = 401 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 402 char *cp, *file; 403 u_short op = ntohs(tp->th_opcode); | 222 /* We should retry if this happens */ 223 if (n == RP_TIMEOUT) { 224 printf("Try %d, didn't receive answer from remote.\n", 225 i + 1); 226 continue; 227 } |
404 | 228 |
405 if (op < RRQ || op > ERROR) 406 printf("%s opcode=%x ", s, op); 407 else 408 printf("%s %s ", s, opcodes[op]); 409 switch (op) { 410 411 case RRQ: 412 case WRQ: 413 n -= 2; 414 file = cp = tp->th_stuff; 415 cp = index(cp, '\0'); 416 printf("<file=%s, mode=%s>\n", file, cp + 1); | 229 /* Otherwise it is a fatal error */ |
417 break; | 230 break; |
231 } |
|
418 | 232 |
419 case DATA: 420 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 421 break; | 233 if (rp->th_opcode == ERROR) { 234 tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg); 235 return; 236 } |
422 | 237 |
423 case ACK: 424 printf("<block=%d>\n", ntohs(tp->th_block)); 425 break; 426 427 case ERROR: 428 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 429 break; | 238 if (write_init(fd, NULL, mode) < 0) { 239 warn("write_init"); 240 return; |
430 } | 241 } |
431} | |
432 | 242 |
433struct timeval tstart; 434struct timeval tstop; | 243 stats_init(&tftp_stats); |
435 | 244 |
436static void 437startclock(void) 438{ | 245 /* 246 * If the first packet is an OACK packet instead of an DATA packet, 247 * handle it different. 248 */ 249 if (rp->th_opcode == OACK) { 250 if (!options_rfc_enabled) { 251 printf("Got OACK while options are not enabled!\n"); 252 send_error(peer, EBADOP); 253 return; 254 } |
439 | 255 |
440 (void)gettimeofday(&tstart, NULL); 441} | 256 parse_options(peer, rp->th_stuff, n + 2); |
442 | 257 |
443static void 444stopclock(void) 445{ 446 447 (void)gettimeofday(&tstop, NULL); 448} 449 450static void 451printstats(const char *direction, unsigned long amount) 452{ 453 double delta; 454 /* compute delta in 1/10's second units */ 455 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 456 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 457 delta = delta/10.; /* back to seconds */ 458 printf("%s %ld bytes in %.1f seconds", direction, amount, delta); 459 if (verbose) 460 printf(" [%.0f bits/sec]", (amount*8.)/delta); 461 putchar('\n'); 462} 463 464static void 465timer(int sig __unused) 466{ 467 468 timeout += rexmtval; 469 if (timeout >= maxtimeout) { 470 printf("Transfer timed out.\n"); 471 longjmp(toplevel, -1); | 258 n = send_ack(peer, 0); 259 if (n > 0) { 260 printf("Cannot send ACK on OACK.\n"); 261 return; 262 } 263 block = 0; 264 tftp_receive(peer, &block, &tftp_stats, NULL, 0); 265 } else { 266 block = 1; 267 tftp_receive(peer, &block, &tftp_stats, rp, n); |
472 } | 268 } |
473 txrx_error = 1; 474 longjmp(timeoutbuf, 1); 475} | |
476 | 269 |
477static int 478cmpport(const struct sockaddr *sa, const struct sockaddr *sb) 479{ 480 char a[NI_MAXSERV], b[NI_MAXSERV]; 481 482 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) 483 return 0; 484 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) 485 return 0; 486 if (strcmp(a, b) != 0) 487 return 0; 488 489 return 1; | 270 write_close(); 271 if (tftp_stats.amount > 0) 272 printstats("Received", verbose, &tftp_stats); 273 return; |
490} | 274} |