1 /* tftp.c - TFTP client. 2 * 3 * Copyright 2012 Madhur Verma <mad.flexi (at) gmail.com> 4 * Copyright 2015 Sameer Prakash Pradhan <sameer.p.pradhan (at) gmail.com> 5 * 6 * No Standard. 7 8 USE_TFTP(NEWTOY(tftp, "<1b#<8>65464r:l:g|p|[!gp]", TOYFLAG_USR|TOYFLAG_BIN)) 9 10 config TFTP 11 bool "tftp" 12 default n 13 help 14 usage: tftp [OPTIONS] HOST [PORT] 15 16 Transfer file from/to tftp server. 17 18 -l FILE Local FILE 19 -r FILE Remote FILE 20 -g Get file 21 -p Put file 22 -b SIZE Transfer blocks of SIZE octets(8 <= SIZE <= 65464) 23 */ 24 #define FOR_tftp 25 #include "toys.h" 26 27 GLOBALS( 28 char *local_file; 29 char *remote_file; 30 long block_size; 31 32 struct sockaddr_storage inaddr; 33 int af; 34 ) 35 36 #define TFTP_BLKSIZE 512 37 #define TFTP_RETRIES 3 38 #define TFTP_DATAHEADERSIZE 4 39 #define TFTP_MAXPACKETSIZE (TFTP_DATAHEADERSIZE + TFTP_BLKSIZE) 40 #define TFTP_PACKETSIZE TFTP_MAXPACKETSIZE 41 #define TFTP_DATASIZE (TFTP_PACKETSIZE-TFTP_DATAHEADERSIZE) 42 #define TFTP_IOBUFSIZE (TFTP_PACKETSIZE+8) 43 44 #define TFTP_OP_RRQ 1 /* Read Request RFC 1350, RFC 2090 */ 45 #define TFTP_OP_WRQ 2 /* Write Request RFC 1350 */ 46 #define TFTP_OP_DATA 3 /* Data chunk RFC 1350 */ 47 #define TFTP_OP_ACK 4 /* Acknowledgement RFC 1350 */ 48 #define TFTP_OP_ERR 5 /* Error Message RFC 1350 */ 49 #define TFTP_OP_OACK 6 /* Option acknowledgment RFC 2347 */ 50 51 #define TFTP_ER_ILLEGALOP 4 /* Illegal TFTP operation */ 52 #define TFTP_ER_UNKID 5 /* Unknown transfer ID */ 53 54 #define TFTP_ES_NOSUCHFILE "File not found" 55 #define TFTP_ES_ACCESS "Access violation" 56 #define TFTP_ES_FULL "Disk full or allocation exceeded" 57 #define TFTP_ES_ILLEGALOP "Illegal TFTP operation" 58 #define TFTP_ES_UNKID "Unknown transfer ID" 59 #define TFTP_ES_EXISTS "File already exists" 60 #define TFTP_ES_UNKUSER "No such user" 61 #define TFTP_ES_NEGOTIATE "Terminate transfer due to option negotiation" 62 63 // Initializes SERVER with ADDR and returns socket. 64 static int init_tftp(struct sockaddr_storage *server) 65 { 66 struct timeval to = { .tv_sec = 10, //Time out 67 .tv_usec = 0 }; 68 const int set = 1; 69 int port = 69, sd = xsocket(TT.af, SOCK_DGRAM, IPPROTO_UDP); 70 71 xsetsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (void *)&to, sizeof(struct timeval)); 72 xsetsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&set, sizeof(set)); 73 74 if(toys.optc == 2) port = atolx_range(toys.optargs[1], 1, 65535); 75 memset(server, 0, sizeof(struct sockaddr_storage)); 76 if (TT.af == AF_INET6) { 77 ((struct sockaddr_in6 *)server)->sin6_family = AF_INET6; 78 ((struct sockaddr_in6 *)server)->sin6_addr = 79 ((struct sockaddr_in6 *)&TT.inaddr)->sin6_addr; 80 ((struct sockaddr_in6 *)server)->sin6_port = htons(port); 81 } 82 else { 83 ((struct sockaddr_in *)server)->sin_family = AF_INET; 84 ((struct sockaddr_in *)server)->sin_addr.s_addr = 85 ((struct sockaddr_in *)&TT.inaddr)->sin_addr.s_addr; 86 ((struct sockaddr_in *)server)->sin_port = htons(port); 87 } 88 return sd; 89 } 90 91 /* 92 * Makes a request packet in BUFFER with OPCODE and file PATH of MODE 93 * and returns length of packet. 94 */ 95 static int mkpkt_request(uint8_t *buffer, int opcode, char *path, int mode) 96 { 97 buffer[0] = opcode >> 8; 98 buffer[1] = opcode & 0xff; 99 if(strlen(path) > TFTP_BLKSIZE) error_exit("path too long"); 100 return sprintf((char*) &buffer[2], "%s%c%s", path, 0, 101 (mode ? "octet" : "netascii")) + 3; 102 } 103 104 /* 105 * Makes an acknowledgement packet in BUFFER of BLOCNO 106 * and returns packet length. 107 */ 108 static int mkpkt_ack(uint8_t *buffer, uint16_t blockno) 109 { 110 buffer[0] = TFTP_OP_ACK >> 8; 111 buffer[1] = TFTP_OP_ACK & 0xff; 112 buffer[2] = blockno >> 8; 113 buffer[3] = blockno & 0xff; 114 return 4; 115 } 116 117 /* 118 * Makes an error packet in BUFFER with ERRORCODE and ERRORMSG. 119 * and returns packet length. 120 */ 121 static int mkpkt_err(uint8_t *buffer, uint16_t errorcode, char *errormsg) 122 { 123 buffer[0] = TFTP_OP_ERR >> 8; 124 buffer[1] = TFTP_OP_ERR & 0xff; 125 buffer[2] = errorcode >> 8; 126 buffer[3] = errorcode & 0xff; 127 strcpy((char*) &buffer[4], errormsg); 128 return strlen(errormsg) + 5; 129 } 130 131 /* 132 * Recieves data from server in BUFF with socket SD and updates FROM 133 * and returns read length. 134 */ 135 static ssize_t read_server(int sd, void *buf, size_t len, 136 struct sockaddr_storage *from) 137 { 138 socklen_t alen; 139 ssize_t nb; 140 141 for (;;) { 142 memset(buf, 0, len); 143 alen = sizeof(struct sockaddr_storage); 144 nb = recvfrom(sd, buf, len, 0, (struct sockaddr *) from, &alen); 145 if (nb < 0) { 146 if (errno == EAGAIN) { 147 perror_msg("server read timed out"); 148 return nb; 149 }else if (errno != EINTR) { 150 perror_msg("server read failed"); 151 return nb; 152 } 153 }else return nb; 154 } 155 return nb; 156 } 157 158 /* 159 * sends data to server TO from BUFF of length LEN through socket SD 160 * and returns successfully send bytes number. 161 */ 162 static ssize_t write_server(int sd, void *buf, size_t len, 163 struct sockaddr_storage *to) 164 { 165 ssize_t nb; 166 167 for (;;) { 168 nb = sendto(sd, buf, len, 0, (struct sockaddr *)to, 169 sizeof(struct sockaddr_storage)); 170 if (nb < 0) { 171 if (errno != EINTR) { 172 perror_msg("server write failed"); 173 return nb; 174 } 175 } else return nb; 176 } 177 return nb; 178 } 179 180 // checks packet for data and updates block no 181 static inline int check_data( uint8_t *packet, uint16_t *opcode, 182 uint16_t *blockno) 183 { 184 *opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1]; 185 if (*opcode == TFTP_OP_DATA) { 186 *blockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3]; 187 return 0; 188 } 189 return -1; 190 } 191 192 // Makes data packet through FD from file OFFSET in buffer PACKET of BLOCKNO 193 static int mkpkt_data(int fd, off_t offset, uint8_t *packet, uint16_t blockno) 194 { 195 off_t tmp; 196 int nbytesread; 197 198 packet[0] = TFTP_OP_DATA >> 8; 199 packet[1] = TFTP_OP_DATA & 0xff; 200 packet[2] = blockno >> 8; 201 packet[3] = blockno & 0xff; 202 tmp = lseek(fd, offset, SEEK_SET); 203 if (tmp == (off_t) -1) { 204 perror_msg("lseek failed"); 205 return -1; 206 } 207 nbytesread = readall(fd, &packet[TFTP_DATAHEADERSIZE], TFTP_DATASIZE); 208 if (nbytesread < 0) return -1; 209 return nbytesread + TFTP_DATAHEADERSIZE; 210 } 211 212 // Receives ACK responses from server and updates blockno 213 static int read_ack(int sd, uint8_t *packet, struct sockaddr_storage *server, 214 uint16_t *port, uint16_t *blockno) 215 { 216 struct sockaddr_storage from; 217 ssize_t nbytes; 218 uint16_t opcode, rblockno; 219 int packetlen, retry; 220 221 for (retry = 0; retry < TFTP_RETRIES; retry++) { 222 for (;;) { 223 nbytes = read_server(sd, packet, TFTP_IOBUFSIZE, &from); 224 if (nbytes < 4) { // Ack headersize = 4 225 if (nbytes == 0) error_msg("Connection lost."); 226 else if (nbytes > 0) error_msg("Short packet: %d bytes", nbytes); 227 else error_msg("Server read ACK failure."); 228 break; 229 } else { 230 if (!*port) { 231 *port = ((struct sockaddr_in *)&from)->sin_port; 232 ((struct sockaddr_in *)server)->sin_port = 233 ((struct sockaddr_in *)&from)->sin_port; 234 } 235 if (((struct sockaddr_in *)server)->sin_addr.s_addr != 236 ((struct sockaddr_in *)&from)->sin_addr.s_addr) { 237 error_msg("Invalid address in DATA."); 238 continue; 239 } 240 if (*port != ((struct sockaddr_in *)server)->sin_port) { 241 error_msg("Invalid port in DATA."); 242 packetlen = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID); 243 (void) write_server(sd, packet, packetlen, server); 244 continue; 245 } 246 opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1]; 247 rblockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3]; 248 249 if (opcode != TFTP_OP_ACK) { 250 error_msg("Bad opcode."); 251 if (opcode > 5) { 252 packetlen = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP); 253 (void) write_server(sd, packet, packetlen, server); 254 } 255 break; 256 } 257 if (blockno) *blockno = rblockno; 258 return 0; 259 } 260 } 261 } 262 error_msg("Timeout, Waiting for ACK."); 263 return -1; 264 } 265 266 // receives file from server. 267 static int file_get(void) 268 { 269 struct sockaddr_storage server, from; 270 uint8_t *packet; 271 uint16_t blockno = 0, opcode, rblockno = 0; 272 int len, sd, fd, retry, nbytesrecvd = 0, ndatabytes, ret, result = -1; 273 274 sd = init_tftp(&server); 275 276 packet = (uint8_t*) xzalloc(TFTP_IOBUFSIZE); 277 fd = xcreate(TT.local_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); 278 279 len = mkpkt_request(packet, TFTP_OP_RRQ, TT.remote_file, 1); 280 ret = write_server(sd, packet, len, &server); 281 if (ret != len){ 282 unlink(TT.local_file); 283 goto errout_with_sd; 284 } 285 if (TT.af == AF_INET6) ((struct sockaddr_in6 *)&server)->sin6_port = 0; 286 else ((struct sockaddr_in *)&server)->sin_port = 0; 287 288 do { 289 blockno++; 290 for (retry = 0 ; retry < TFTP_RETRIES; retry++) { 291 nbytesrecvd = read_server(sd, packet, TFTP_IOBUFSIZE, &from); 292 if (nbytesrecvd > 0) { 293 if ( ((TT.af == AF_INET) && 294 memcmp(&((struct sockaddr_in *)&server)->sin_addr, 295 &((struct sockaddr_in *)&from)->sin_addr, 296 sizeof(struct in_addr))) || 297 ((TT.af == AF_INET6) && 298 memcmp(&((struct sockaddr_in6 *)&server)->sin6_addr, 299 &((struct sockaddr_in6 *)&from)->sin6_addr, 300 sizeof(struct in6_addr)))) { 301 error_msg("Invalid address in DATA."); 302 retry--; 303 continue; 304 } 305 if ( ((TT.af == AF_INET) && ((struct sockaddr_in *)&server)->sin_port 306 && (((struct sockaddr_in *)&server)->sin_port != 307 ((struct sockaddr_in *)&from)->sin_port)) || 308 ((TT.af == AF_INET6) && ((struct sockaddr_in6 *)&server)->sin6_port 309 && (((struct sockaddr_in6 *)&server)->sin6_port != 310 ((struct sockaddr_in6 *)&from)->sin6_port))) { 311 error_msg("Invalid port in DATA."); 312 len = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID); 313 ret = write_server(sd, packet, len, &from); 314 retry--; 315 continue; 316 } 317 if (nbytesrecvd < TFTP_DATAHEADERSIZE) { 318 error_msg("Tiny data packet ignored."); 319 continue; 320 } 321 if (check_data(packet, &opcode, &rblockno) != 0 322 || blockno != rblockno) { 323 324 if (opcode == TFTP_OP_ERR) { 325 char *message = "DATA Check failure."; 326 char *arr[] = {TFTP_ES_NOSUCHFILE, TFTP_ES_ACCESS, 327 TFTP_ES_FULL, TFTP_ES_ILLEGALOP, 328 TFTP_ES_UNKID, TFTP_ES_EXISTS, 329 TFTP_ES_UNKUSER, TFTP_ES_NEGOTIATE}; 330 if (rblockno && (rblockno < 9)) message = arr[rblockno - 1]; 331 error_msg(message); 332 } 333 if (opcode > 5) { 334 len = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP); 335 ret = write_server(sd, packet, len, &from); 336 } 337 continue; 338 } 339 if ((TT.af == AF_INET6) && !((struct sockaddr_in6 *)&server)->sin6_port) 340 ((struct sockaddr_in6 *)&server)->sin6_port = 341 ((struct sockaddr_in6 *)&from)->sin6_port; 342 else if ((TT.af == AF_INET) && !((struct sockaddr_in *)&server)->sin_port) 343 ((struct sockaddr_in *)&server)->sin_port = 344 ((struct sockaddr_in *)&from)->sin_port; 345 break; 346 } 347 } 348 if (retry == TFTP_RETRIES) { 349 error_msg("Retry limit exceeded."); 350 unlink(TT.local_file); 351 goto errout_with_sd; 352 } 353 ndatabytes = nbytesrecvd - TFTP_DATAHEADERSIZE; 354 if (writeall(fd, packet + TFTP_DATAHEADERSIZE, ndatabytes) < 0){ 355 unlink(TT.local_file); 356 goto errout_with_sd; 357 } 358 len = mkpkt_ack(packet, blockno); 359 ret = write_server(sd, packet, len, &server); 360 if (ret != len){ 361 unlink(TT.local_file); 362 goto errout_with_sd; 363 } 364 } while (ndatabytes >= TFTP_DATASIZE); 365 366 result = 0; 367 368 errout_with_sd: xclose(sd); 369 free(packet); 370 return result; 371 } 372 373 // Sends file to server. 374 int file_put(void) 375 { 376 struct sockaddr_storage server; 377 uint8_t *packet; 378 off_t offset = 0; 379 uint16_t blockno = 1, rblockno, port = 0; 380 int packetlen, sd, fd, retry = 0, ret, result = -1; 381 382 sd = init_tftp(&server); 383 packet = (uint8_t*)xzalloc(TFTP_IOBUFSIZE); 384 fd = xopen(TT.local_file, O_RDONLY); 385 386 for (;;) { //first loop for request send and confirmation from server. 387 packetlen = mkpkt_request(packet, TFTP_OP_WRQ, TT.remote_file, 1); 388 ret = write_server(sd, packet, packetlen, &server); 389 if (ret != packetlen) goto errout_with_sd; 390 if (read_ack(sd, packet, &server, &port, NULL) == 0) break; 391 if (++retry > TFTP_RETRIES) { 392 error_msg("Retry count exceeded."); 393 goto errout_with_sd; 394 } 395 } 396 for (;;) { // loop for data sending and receving ack from server. 397 packetlen = mkpkt_data(fd, offset, packet, blockno); 398 if (packetlen < 0) goto errout_with_sd; 399 400 ret = write_server(sd, packet, packetlen, &server); 401 if (ret != packetlen) goto errout_with_sd; 402 403 if (read_ack(sd, packet, &server, &port, &rblockno) == 0) { 404 if (rblockno == blockno) { 405 if (packetlen < TFTP_PACKETSIZE) break; 406 blockno++; 407 offset += TFTP_DATASIZE; 408 retry = 0; 409 continue; 410 } 411 } 412 if (++retry > TFTP_RETRIES) { 413 error_msg("Retry count exceeded."); 414 goto errout_with_sd; 415 } 416 } 417 result = 0; 418 419 errout_with_sd: close(sd); 420 free(packet); 421 return result; 422 } 423 424 void tftp_main(void) 425 { 426 struct addrinfo *info, rp, *res=0; 427 int ret; 428 429 if (toys.optflags & FLAG_r) { 430 if (!(toys.optflags & FLAG_l)) { 431 char *slash = strrchr(TT.remote_file, '/'); 432 TT.local_file = (slash) ? slash + 1 : TT.remote_file; 433 } 434 } else if (toys.optflags & FLAG_l) TT.remote_file = TT.local_file; 435 else error_exit("Please provide some files."); 436 437 memset(&rp, 0, sizeof(rp)); 438 rp.ai_family = AF_UNSPEC; 439 rp.ai_socktype = SOCK_STREAM; 440 ret = getaddrinfo(toys.optargs[0], toys.optargs[1], &rp, &info); 441 if (!ret) { 442 for (res = info; res; res = res->ai_next) 443 if ( (res->ai_family == AF_INET) || (res->ai_family == AF_INET6)) break; 444 } 445 if (!res) 446 error_exit("bad address '%s' : %s", toys.optargs[0], gai_strerror(ret)); 447 TT.af = info->ai_family; 448 449 memcpy((void *)&TT.inaddr, info->ai_addr, info->ai_addrlen); 450 freeaddrinfo(info); 451 452 if (toys.optflags & FLAG_g) file_get(); 453 if (toys.optflags & FLAG_p) file_put(); 454 } 455