2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/tftp.h>
43 #include "tftp-utils.h"
47 * Default values, can be changed later via the TFTP Options
49 int timeoutpacket = TIMEOUT;
50 int timeoutnetwork = MAX_TIMEOUTS * TIMEOUT;
51 int maxtimeouts = MAX_TIMEOUTS;
52 uint16_t segsize = SEGSIZE;
53 uint16_t pktsize = SEGSIZE + 4;
59 * Set timeout values for packet reception. The idea is that you
60 * get 'maxtimeouts' of 5 seconds between 'timeoutpacket' (i.e. the
61 * first timeout) to 'timeoutnetwork' (i.e. the last timeout)
64 settimeouts(int _timeoutpacket, int _timeoutnetwork, int _maxtimeouts __unused)
68 /* We cannot do impossible things */
69 if (_timeoutpacket >= _timeoutnetwork)
74 while (i < _timeoutnetwork || maxtimeouts < MIN_TIMEOUTS) {
79 timeoutpacket = _timeoutpacket;
84 /* translate IPv4 mapped IPv6 address to IPv4 address */
86 unmappedaddr(struct sockaddr_in6 *sin6)
88 struct sockaddr_in *sin4;
92 if (sin6->sin6_family != AF_INET6 ||
93 !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
95 sin4 = (struct sockaddr_in *)sin6;
96 memcpy(&addr, &sin6->sin6_addr.s6_addr[12], sizeof(addr));
97 port = sin6->sin6_port;
98 memset(sin4, 0, sizeof(struct sockaddr_in));
99 sin4->sin_addr.s_addr = addr;
100 sin4->sin_port = port;
101 sin4->sin_family = AF_INET;
102 sin4->sin_len = sizeof(struct sockaddr_in);
105 /* Get a field from a \0 separated string */
107 get_field(int peer, char *buffer, ssize_t size)
111 while (cp < buffer + size) {
112 if (*cp == '\0') break;
116 tftp_log(LOG_ERR, "Bad option - no trailing \\0 found");
117 send_error(peer, EBADOP);
120 return (cp - buffer + 1);
126 static int _tftp_logtostdout = 1;
129 tftp_openlog(const char *ident, int logopt, int facility)
132 _tftp_logtostdout = (ident == NULL);
133 if (_tftp_logtostdout == 0)
134 openlog(ident, logopt, facility);
141 if (_tftp_logtostdout == 0)
146 tftp_log(int priority, const char *message, ...)
151 va_start(ap, message);
152 if (_tftp_logtostdout == 0) {
153 vasprintf(&s, message, ap);
154 syslog(priority, "%s", s);
156 vprintf(message, ap);
165 struct packettypes packettypes[] = {
178 static char failed[100];
181 while (packettypes[i].name != NULL) {
182 if (packettypes[i].value == type)
186 if (packettypes[i].name != NULL)
187 return packettypes[i].name;
188 sprintf(failed, "unknown (type: %d)", type);
195 int debug = DEBUG_NONE;
196 struct debugs debugs[] = {
197 { DEBUG_PACKETS, "packet", "Packet debugging" },
198 { DEBUG_SIMPLE, "simple", "Simple debugging" },
199 { DEBUG_OPTIONS, "options", "Options debugging" },
200 { DEBUG_ACCESS, "access", "TCPd access debugging" },
201 { DEBUG_NONE, NULL, "No debugging" },
203 int packetdroppercentage = 0;
210 while (debugs[i].name != NULL) {
211 if (strcasecmp(debugs[i].name, s) == 0)
215 return (debugs[i].value);
243 while (debugs[i].name != NULL) {
244 if (d&debugs[i].value) {
247 strcat(s, debugs[i].name);
259 struct rp_errors rp_errors[] = {
260 { RP_TIMEOUT, "Network timeout" },
261 { RP_TOOSMALL, "Not enough data bytes" },
262 { RP_WRONGSOURCE, "Invalid IP address of UDP port" },
263 { RP_ERROR, "Error packet" },
264 { RP_RECVFROM, "recvfrom() complained" },
265 { RP_TOOBIG, "Too many data bytes" },
270 rp_strerror(int error)
275 while (rp_errors[i].desc != NULL) {
276 if (rp_errors[i].error == error) {
277 strcpy(s, rp_errors[i].desc);
282 sprintf(s, "unknown (error=%d)", error);
287 * Performance figures
291 stats_init(struct tftp_stats *ts)
299 gettimeofday(&(ts->tstart), NULL);
303 printstats(const char *direction, int verbose, struct tftp_stats *ts)
305 double delta; /* compute delta in 1/10's second units */
307 delta = ((ts->tstop.tv_sec*10.)+(ts->tstop.tv_usec/100000)) -
308 ((ts->tstart.tv_sec*10.)+(ts->tstart.tv_usec/100000));
309 delta = delta/10.; /* back to seconds */
311 printf("%s %zu bytes during %.1f seconds in %u blocks",
312 direction, ts->amount, delta, ts->blocks);
314 if (ts->rollovers != 0)
315 printf(" with %d rollover%s",
316 ts->rollovers, ts->rollovers != 1 ? "s" : "");
319 printf(" [%.0f bits/sec]", (ts->amount*8.)/delta);