2 * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/tftp.h>
35 #include <arpa/inet.h>
46 #include "tftp-file.h"
48 #include "tftp-utils.h"
49 #include "tftp-options.h"
51 struct sockaddr_storage peer_sock;
52 struct sockaddr_storage me_sock;
54 static int send_packet(int peer, uint16_t block, char *pkt, int size);
56 static struct errmsg {
60 { EUNDEF, "Undefined error code" },
61 { ENOTFOUND, "File not found" },
62 { EACCESS, "Access violation" },
63 { ENOSPACE, "Disk full or allocation exceeded" },
64 { EBADOP, "Illegal TFTP operation" },
65 { EBADID, "Unknown transfer ID" },
66 { EEXISTS, "File already exists" },
67 { ENOUSER, "No such user" },
68 { EOPTNEG, "Option negotiation" },
72 #define DROPPACKET(s) \
73 if (packetdroppercentage != 0 && \
74 random()%100 < packetdroppercentage) { \
75 tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \
78 #define DROPPACKETn(s,n) \
79 if (packetdroppercentage != 0 && \
80 random()%100 < packetdroppercentage) { \
81 tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \
93 for (pe = errmsgs; pe->e_code >= 0; pe++)
94 if (pe->e_code == error)
96 snprintf(ebuf, sizeof(ebuf), "error %d", error);
101 send_packet(int peer, uint16_t block, char *pkt, int size)
106 for (i = 0; i < 12 ; i++) {
107 DROPPACKETn("send_packet", 0);
109 if (sendto(peer, pkt, size, 0, (struct sockaddr *)&peer_sock,
110 peer_sock.ss_len) == size) {
113 "%s block %d, attempt %d successful",
114 packettype(ntohs(((struct tftphdr *)
115 (pkt))->th_opcode)), block, i);
119 "%s block %d, attempt %d failed (Error %d: %s)",
120 packettype(ntohs(((struct tftphdr *)(pkt))->th_opcode)),
121 block, i, errno, strerror(errno));
126 tftp_log(LOG_ERR, "send_packet: %s", strerror(errno));
131 * Send an ERROR packet (error message).
132 * Error code passed in is one of the
133 * standard TFTP codes, or a UNIX errno
137 send_error(int peer, int error)
142 char buf[MAXPKTSIZE];
144 if (debug&DEBUG_PACKETS)
145 tftp_log(LOG_DEBUG, "Sending ERROR %d", error);
147 DROPPACKET("send_error");
149 tp = (struct tftphdr *)buf;
150 tp->th_opcode = htons((u_short)ERROR);
151 tp->th_code = htons((u_short)error);
152 for (pe = errmsgs; pe->e_code >= 0; pe++)
153 if (pe->e_code == error)
155 if (pe->e_code < 0) {
156 pe->e_msg = strerror(error - 100);
157 tp->th_code = EUNDEF; /* set 'undef' errorcode */
159 strcpy(tp->th_msg, pe->e_msg);
160 length = strlen(pe->e_msg);
161 tp->th_msg[length] = '\0';
164 if (debug&DEBUG_PACKETS)
165 tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg);
167 if (sendto(peer, buf, length, 0,
168 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != length)
169 tftp_log(LOG_ERR, "send_error: %s", strerror(errno));
173 * Send an WRQ packet (write request).
176 send_wrq(int peer, char *filename, char *mode)
181 char buf[MAXPKTSIZE];
184 if (debug&DEBUG_PACKETS)
185 tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'",
189 DROPPACKETn("send_wrq", 1);
191 tp = (struct tftphdr *)buf;
192 tp->th_opcode = htons((u_short)WRQ);
196 strcpy(bp, filename);
197 bp += strlen(filename);
200 size += strlen(filename) + 1;
206 size += strlen(mode) + 1;
208 if (options_rfc_enabled)
209 size += make_options(peer, bp, sizeof(buf) - size);
211 n = sendto(peer, buf, size, 0,
212 (struct sockaddr *)&peer_sock, peer_sock.ss_len);
214 tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno));
221 * Send an RRQ packet (write request).
224 send_rrq(int peer, char *filename, char *mode)
229 char buf[MAXPKTSIZE];
232 if (debug&DEBUG_PACKETS)
233 tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'",
237 DROPPACKETn("send_rrq", 1);
239 tp = (struct tftphdr *)buf;
240 tp->th_opcode = htons((u_short)RRQ);
244 strcpy(bp, filename);
245 bp += strlen(filename);
248 size += strlen(filename) + 1;
254 size += strlen(mode) + 1;
256 if (options_rfc_enabled) {
257 options[OPT_TSIZE].o_request = strdup("0");
258 size += make_options(peer, bp, sizeof(buf) - size);
261 n = sendto(peer, buf, size, 0,
262 (struct sockaddr *)&peer_sock, peer_sock.ss_len);
264 tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno));
271 * Send an OACK packet (option acknowledgement).
279 char buf[MAXPKTSIZE];
281 if (debug&DEBUG_PACKETS)
282 tftp_log(LOG_DEBUG, "Sending OACK");
284 DROPPACKETn("send_oack", 0);
287 * Send back an options acknowledgement (only the ones with
290 tp = (struct tftphdr *)buf;
292 size = sizeof(buf) - 2;
293 tp->th_opcode = htons((u_short)OACK);
294 for (i = 0; options[i].o_type != NULL; i++) {
295 if (options[i].o_reply != NULL) {
296 n = snprintf(bp, size, "%s%c%s", options[i].o_type,
297 0, options[i].o_reply);
301 tftp_log(LOG_ERR, "oack: buffer overflow");
308 if (sendto(peer, buf, size, 0,
309 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
310 tftp_log(LOG_INFO, "send_oack: %s", strerror(errno));
318 * Send an ACK packet (acknowledgement).
321 send_ack(int fp, uint16_t block)
325 char buf[MAXPKTSIZE];
327 if (debug&DEBUG_PACKETS)
328 tftp_log(LOG_DEBUG, "Sending ACK for block %d", block);
330 DROPPACKETn("send_ack", 0);
332 tp = (struct tftphdr *)buf;
333 size = sizeof(buf) - 2;
334 tp->th_opcode = htons((u_short)ACK);
335 tp->th_block = htons((u_short)block);
338 if (sendto(fp, buf, size, 0,
339 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
340 tftp_log(LOG_INFO, "send_ack: %s", strerror(errno));
351 send_data(int peer, uint16_t block, char *data, int size)
353 char buf[MAXPKTSIZE];
357 if (debug&DEBUG_PACKETS)
358 tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes",
361 DROPPACKETn("send_data", 0);
363 pkt = (struct tftphdr *)buf;
365 pkt->th_opcode = htons((u_short)DATA);
366 pkt->th_block = htons((u_short)block);
367 memcpy(pkt->th_data, data, size);
369 n = send_packet(peer, block, (char *)pkt, size + 4);
377 static jmp_buf timeoutbuf;
380 timeout(int sig __unused)
383 /* tftp_log(LOG_DEBUG, "Timeout\n"); Inside a signal handler... */
384 longjmp(timeoutbuf, 1);
388 receive_packet(int peer, char *data, int size, struct sockaddr_storage *from,
392 struct sockaddr_storage from_local;
393 struct sockaddr_storage *pfrom;
398 if (debug&DEBUG_PACKETS)
400 "Waiting %d seconds for packet", timeoutpacket);
402 pkt = (struct tftphdr *)data;
405 signal(SIGALRM, timeout);
415 tftp_log(LOG_ERR, "receive_packet: timeout");
421 pfrom = (from == NULL) ? &from_local : from;
422 fromlen = sizeof(*pfrom);
423 n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
427 DROPPACKETn("receive_packet", RP_TIMEOUT);
430 tftp_log(LOG_ERR, "receive_packet: timeout");
437 /* No idea what could have happened if it isn't a timeout */
438 tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
439 return (RP_RECVFROM);
443 "receive_packet: packet too small (%d bytes)", n);
444 return (RP_TOOSMALL);
447 pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
448 if (pkt->th_opcode == DATA ||
449 pkt->th_opcode == ACK)
450 pkt->th_block = ntohs((u_short)pkt->th_block);
452 if (pkt->th_opcode == DATA && n > pktsize) {
453 tftp_log(LOG_ERR, "receive_packet: packet too big");
457 if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
458 ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
460 "receive_packet: received packet from wrong source");
461 return (RP_WRONGSOURCE);
464 if (pkt->th_opcode == ERROR) {
465 tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR,
466 "Got ERROR packet: %s", pkt->th_msg);
470 if (debug&DEBUG_PACKETS)
471 tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
472 n, packettype(pkt->th_opcode));