Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/tftpd/tftp-utils.c
34821 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (C) 2008 Edwin Groothuis. All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
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.
14
*
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
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/cdefs.h>
29
#include <sys/socket.h>
30
#include <sys/stat.h>
31
#include <sys/time.h>
32
33
#include <netinet/in.h>
34
#include <arpa/tftp.h>
35
36
#include <errno.h>
37
#include <stdarg.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <syslog.h>
42
43
#include "tftp-utils.h"
44
#include "tftp-io.h"
45
46
/*
47
* Default values, can be changed later via the TFTP Options
48
*/
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;
54
uint16_t windowsize = WINDOWSIZE;
55
56
int acting_as_client;
57
58
59
/*
60
* Set timeout values for packet reception. The idea is that you
61
* get 'maxtimeouts' of 5 seconds between 'timeoutpacket' (i.e. the
62
* first timeout) to 'timeoutnetwork' (i.e. the last timeout)
63
*/
64
int
65
settimeouts(int _timeoutpacket, int _timeoutnetwork, int _maxtimeouts __unused)
66
{
67
int i;
68
69
/* We cannot do impossible things */
70
if (_timeoutpacket >= _timeoutnetwork)
71
return (0);
72
73
maxtimeouts = 0;
74
i = _timeoutpacket;
75
while (i < _timeoutnetwork || maxtimeouts < MIN_TIMEOUTS) {
76
maxtimeouts++;
77
i += 5;
78
}
79
80
timeoutpacket = _timeoutpacket;
81
timeoutnetwork = i;
82
return (1);
83
}
84
85
/* translate IPv4 mapped IPv6 address to IPv4 address */
86
void
87
unmappedaddr(struct sockaddr_in6 *sin6)
88
{
89
struct sockaddr_in *sin4;
90
u_int32_t addr;
91
int port;
92
93
if (sin6->sin6_family != AF_INET6 ||
94
!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
95
return;
96
sin4 = (struct sockaddr_in *)sin6;
97
memcpy(&addr, &sin6->sin6_addr.s6_addr[12], sizeof(addr));
98
port = sin6->sin6_port;
99
memset(sin4, 0, sizeof(struct sockaddr_in));
100
sin4->sin_addr.s_addr = addr;
101
sin4->sin_port = port;
102
sin4->sin_family = AF_INET;
103
sin4->sin_len = sizeof(struct sockaddr_in);
104
}
105
106
/* Get a field from a \0 separated string */
107
size_t
108
get_field(int peer, char *buffer, size_t size)
109
{
110
char *cp = buffer;
111
112
while (cp < buffer + size) {
113
if (*cp == '\0') break;
114
cp++;
115
}
116
if (*cp != '\0') {
117
tftp_log(LOG_ERR, "Bad option - no trailing \\0 found");
118
send_error(peer, EBADOP);
119
exit(1);
120
}
121
return (cp - buffer + 1);
122
}
123
124
/*
125
* Logging functions
126
*/
127
static int _tftp_logtostdout = 1;
128
129
void
130
tftp_openlog(const char *ident, int logopt, int facility)
131
{
132
133
_tftp_logtostdout = (ident == NULL);
134
if (_tftp_logtostdout == 0)
135
openlog(ident, logopt, facility);
136
}
137
138
void
139
tftp_closelog(void)
140
{
141
142
if (_tftp_logtostdout == 0)
143
closelog();
144
}
145
146
void
147
tftp_log(int priority, const char *message, ...)
148
{
149
va_list ap;
150
int serrno;
151
char *s;
152
153
serrno = errno;
154
va_start(ap, message);
155
if (_tftp_logtostdout == 0) {
156
vasprintf(&s, message, ap);
157
syslog(priority, "%s", s);
158
} else {
159
vprintf(message, ap);
160
printf("\n");
161
}
162
va_end(ap);
163
errno = serrno;
164
}
165
166
/*
167
* Packet types
168
*/
169
struct packettypes packettypes[] = {
170
{ RRQ, "RRQ" },
171
{ WRQ, "WRQ" },
172
{ DATA, "DATA" },
173
{ ACK, "ACK" },
174
{ ERROR, "ERROR" },
175
{ OACK, "OACK" },
176
{ 0, NULL },
177
};
178
179
const char *
180
packettype(int type)
181
{
182
static char failed[100];
183
int i = 0;
184
185
while (packettypes[i].name != NULL) {
186
if (packettypes[i].value == type)
187
break;
188
i++;
189
}
190
if (packettypes[i].name != NULL)
191
return packettypes[i].name;
192
sprintf(failed, "unknown (type: %d)", type);
193
return (failed);
194
}
195
196
/*
197
* Debugs
198
*/
199
int debug = DEBUG_NONE;
200
struct debugs debugs[] = {
201
{ DEBUG_PACKETS, "packet", "Packet debugging" },
202
{ DEBUG_SIMPLE, "simple", "Simple debugging" },
203
{ DEBUG_OPTIONS, "options", "Options debugging" },
204
{ DEBUG_ACCESS, "access", "TCPd access debugging" },
205
{ DEBUG_NONE, NULL, "No debugging" },
206
};
207
unsigned int packetdroppercentage = 0;
208
209
int
210
debug_find(char *s)
211
{
212
int i = 0;
213
214
while (debugs[i].name != NULL) {
215
if (strcasecmp(debugs[i].name, s) == 0)
216
break;
217
i++;
218
}
219
return (debugs[i].value);
220
}
221
222
int
223
debug_finds(char *s)
224
{
225
int i = 0;
226
char *ps = s;
227
228
while (s != NULL) {
229
ps = strchr(s, ' ');
230
if (ps != NULL)
231
*ps = '\0';
232
i += debug_find(s);
233
if (ps != NULL)
234
*ps = ' ';
235
s = ps;
236
}
237
return (i);
238
}
239
240
const char *
241
debug_show(int d)
242
{
243
static char s[100];
244
size_t space = sizeof(s);
245
int i = 0;
246
247
s[0] = '\0';
248
while (debugs[i].name != NULL) {
249
if (d&debugs[i].value) {
250
if (s[0] != '\0')
251
strlcat(s, " ", space);
252
strlcat(s, debugs[i].name, space);
253
}
254
i++;
255
}
256
if (s[0] != '\0')
257
return (s);
258
return ("none");
259
}
260
261
/*
262
* RP_
263
*/
264
struct rp_errors rp_errors[] = {
265
{ RP_TIMEOUT, "Network timeout" },
266
{ RP_TOOSMALL, "Not enough data bytes" },
267
{ RP_WRONGSOURCE, "Invalid IP address of UDP port" },
268
{ RP_ERROR, "Error packet" },
269
{ RP_RECVFROM, "recvfrom() complained" },
270
{ RP_TOOBIG, "Too many data bytes" },
271
{ RP_NONE, NULL }
272
};
273
274
char *
275
rp_strerror(int error)
276
{
277
static char s[100];
278
size_t space = sizeof(s);
279
int i = 0;
280
281
while (rp_errors[i].desc != NULL) {
282
if (rp_errors[i].error == error) {
283
strlcpy(s, rp_errors[i].desc, space);
284
space -= strlen(rp_errors[i].desc);
285
}
286
i++;
287
}
288
if (s[0] == '\0')
289
sprintf(s, "unknown (error=%d)", error);
290
return (s);
291
}
292
293
/*
294
* Performance figures
295
*/
296
297
void
298
stats_init(struct tftp_stats *ts)
299
{
300
301
ts->amount = 0;
302
ts->rollovers = 0;
303
ts->retries = 0;
304
ts->blocks = 0;
305
ts->amount = 0;
306
gettimeofday(&(ts->tstart), NULL);
307
}
308
309
void
310
printstats(const char *direction, int verbose, struct tftp_stats *ts)
311
{
312
double delta; /* compute delta in 1/10's second units */
313
314
delta = ((ts->tstop.tv_sec*10.)+(ts->tstop.tv_usec/100000)) -
315
((ts->tstart.tv_sec*10.)+(ts->tstart.tv_usec/100000));
316
delta = delta/10.; /* back to seconds */
317
318
printf("%s %zu bytes during %.1f seconds in %u blocks",
319
direction, ts->amount, delta, ts->blocks);
320
321
if (ts->rollovers != 0)
322
printf(" with %d rollover%s",
323
ts->rollovers, ts->rollovers != 1 ? "s" : "");
324
325
if (verbose)
326
printf(" [%.0f bits/sec]", (ts->amount*8.)/delta);
327
putchar('\n');
328
}
329
330