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); \
94 for (pe = errmsgs; pe->e_code >= 0; pe++)
95 if (pe->e_code == error)
97 snprintf(ebuf, sizeof(buf), "error %d", error);
102 send_packet(int peer, uint16_t block, char *pkt, int size)
107 for (i = 0; i < 12 ; i++) {
108 DROPPACKETn("send_packet", 0);
110 if (sendto(peer, pkt, size, 0,
111 (struct sockaddr *)&peer_sock, peer_sock.ss_len)
115 "%s block %d, attempt %d successful",
120 "%s block %d, attempt %d failed (Error %d: %s)",
121 packettype(ntohs(((struct tftphdr *)(pkt))->th_opcode)),
122 block, i, errno, strerror(errno));
127 tftp_log(LOG_ERR, "send_packet: %s", strerror(errno));
132 * Send an ERROR packet (error message).
133 * Error code passed in is one of the
134 * standard TFTP codes, or a UNIX errno
138 send_error(int peer, int error)
143 char buf[MAXPKTSIZE];
145 if (debug&DEBUG_PACKETS)
146 tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error);
148 DROPPACKET("send_error");
150 tp = (struct tftphdr *)buf;
151 tp->th_opcode = htons((u_short)ERROR);
152 tp->th_code = htons((u_short)error);
153 for (pe = errmsgs; pe->e_code >= 0; pe++)
154 if (pe->e_code == error)
156 if (pe->e_code < 0) {
157 pe->e_msg = strerror(error - 100);
158 tp->th_code = EUNDEF; /* set 'undef' errorcode */
160 strcpy(tp->th_msg, pe->e_msg);
161 length = strlen(pe->e_msg);
162 tp->th_msg[length] = '\0';
165 if (debug&DEBUG_PACKETS)
166 tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg);
168 if (sendto(peer, buf, length, 0,
169 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != length)
170 tftp_log(LOG_ERR, "send_error: %s", strerror(errno));
174 * Send an WRQ packet (write request).
177 send_wrq(int peer, char *filename, char *mode)
182 char buf[MAXPKTSIZE];
185 if (debug&DEBUG_PACKETS)
186 tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'",
190 DROPPACKETn("send_wrq", 1);
192 tp = (struct tftphdr *)buf;
193 tp->th_opcode = htons((u_short)WRQ);
197 strcpy(bp, filename);
198 bp += strlen(filename);
201 size += strlen(filename) + 1;
207 size += strlen(mode) + 1;
209 if (options_rfc_enabled)
210 size += make_options(peer, bp, sizeof(buf) - size);
212 n = sendto(peer, buf, size, 0,
213 (struct sockaddr *)&peer_sock, peer_sock.ss_len);
215 tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno));
222 * Send an RRQ packet (write request).
225 send_rrq(int peer, char *filename, char *mode)
230 char buf[MAXPKTSIZE];
233 if (debug&DEBUG_PACKETS)
234 tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'",
238 DROPPACKETn("send_rrq", 1);
240 tp = (struct tftphdr *)buf;
241 tp->th_opcode = htons((u_short)RRQ);
245 strcpy(bp, filename);
246 bp += strlen(filename);
249 size += strlen(filename) + 1;
255 size += strlen(mode) + 1;
257 if (options_rfc_enabled) {
258 options[OPT_TSIZE].o_request = strdup("0");
259 size += make_options(peer, bp, sizeof(buf) - size);
262 n = sendto(peer, buf, size, 0,
263 (struct sockaddr *)&peer_sock, peer_sock.ss_len);
265 tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno));
272 * Send an OACK packet (option acknowledgement).
280 char buf[MAXPKTSIZE];
282 if (debug&DEBUG_PACKETS)
283 tftp_log(LOG_DEBUG, "Sending OACK");
285 DROPPACKETn("send_oack", 0);
288 * Send back an options acknowledgement (only the ones with
291 tp = (struct tftphdr *)buf;
293 size = sizeof(buf) - 2;
294 tp->th_opcode = htons((u_short)OACK);
295 for (i = 0; options[i].o_type != NULL; i++) {
296 if (options[i].o_reply != NULL) {
297 n = snprintf(bp, size, "%s%c%s", options[i].o_type,
298 0, options[i].o_reply);
302 tftp_log(LOG_ERR, "oack: buffer overflow");
309 if (sendto(peer, buf, size, 0,
310 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
311 tftp_log(LOG_INFO, "send_oack: %s", strerror(errno));
319 * Send an ACK packet (acknowledgement).
322 send_ack(int fp, uint16_t block)
326 char buf[MAXPKTSIZE];
328 if (debug&DEBUG_PACKETS)
329 tftp_log(LOG_DEBUG, "Sending ACK for block %d", block);
331 DROPPACKETn("send_ack", 0);
333 tp = (struct tftphdr *)buf;
334 size = sizeof(buf) - 2;
335 tp->th_opcode = htons((u_short)ACK);
336 tp->th_block = htons((u_short)block);
339 if (sendto(fp, buf, size, 0,
340 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
341 tftp_log(LOG_INFO, "send_ack: %s", strerror(errno));
352 send_data(int peer, uint16_t block, char *data, int size)
354 char buf[MAXPKTSIZE];
358 if (debug&DEBUG_PACKETS)
359 tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes",
362 DROPPACKETn("send_data", 0);
364 pkt = (struct tftphdr *)buf;
366 pkt->th_opcode = htons((u_short)DATA);
367 pkt->th_block = htons((u_short)block);
368 memcpy(pkt->th_data, data, size);
370 n = send_packet(peer, block, (char *)pkt, size + 4);
378 static jmp_buf timeoutbuf;
381 timeout(int sig __unused)
384 /* tftp_log(LOG_DEBUG, "Timeout\n"); Inside a signal handler... */
385 longjmp(timeoutbuf, 1);
389 receive_packet(int peer, char *data, int size, struct sockaddr_storage *from,
393 struct sockaddr_storage from_local;
394 struct sockaddr_storage *pfrom;
399 if (debug&DEBUG_PACKETS)
401 "Waiting %d seconds for packet", timeoutpacket);
403 pkt = (struct tftphdr *)data;
406 signal(SIGALRM, timeout);
416 tftp_log(LOG_ERR, "receive_packet: timeout");
422 pfrom = (from == NULL) ? &from_local : from;
423 fromlen = sizeof(*pfrom);
424 n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
428 DROPPACKETn("receive_packet", RP_TIMEOUT);
431 tftp_log(LOG_ERR, "receive_packet: timeout");
438 /* No idea what could have happened if it isn't a timeout */
439 tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
440 return (RP_RECVFROM);
444 "receive_packet: packet too small (%d bytes)", n);
445 return (RP_TOOSMALL);
448 pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
449 if (pkt->th_opcode == DATA ||
450 pkt->th_opcode == ACK)
451 pkt->th_block = ntohs((u_short)pkt->th_block);
453 if (pkt->th_opcode == DATA && n > pktsize) {
454 tftp_log(LOG_ERR, "receive_packet: packet too big");
458 if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
459 ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
461 "receive_packet: received packet from wrong source");
462 return (RP_WRONGSOURCE);
465 if (pkt->th_opcode == ERROR) {
466 tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR,
467 "Got ERROR packet: %s", pkt->th_msg);
471 if (debug&DEBUG_PACKETS)
472 tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
473 n, packettype(pkt->th_opcode));