tftp.c 14 KB

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