summaryrefslogtreecommitdiffstats
path: root/libexec/tftpd/tftp-utils.c
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2010-05-04 13:07:40 +0000
committerimp <imp@FreeBSD.org>2010-05-04 13:07:40 +0000
commita5f9262d67ae99e9ce1468b626a63c5c9cafbb26 (patch)
tree77ff5caa24e36e652c7ab79f0b44f9bdef373e20 /libexec/tftpd/tftp-utils.c
parent249847477313ecfdf314f47b62fb935897c2a5f4 (diff)
downloadFreeBSD-src-a5f9262d67ae99e9ce1468b626a63c5c9cafbb26.zip
FreeBSD-src-a5f9262d67ae99e9ce1468b626a63c5c9cafbb26.tar.gz
Bring in new files from edwin's tftp
Diffstat (limited to 'libexec/tftpd/tftp-utils.c')
-rw-r--r--libexec/tftpd/tftp-utils.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/libexec/tftpd/tftp-utils.c b/libexec/tftpd/tftp-utils.c
new file mode 100644
index 0000000..da58064
--- /dev/null
+++ b/libexec/tftpd/tftp-utils.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "tftp-utils.h"
+#include "tftp-io.h"
+
+/*
+ * Default values, can be changed later via the TFTP Options
+ */
+int timeoutpacket = TIMEOUT;
+int timeoutnetwork = MAX_TIMEOUTS * TIMEOUT;
+int maxtimeouts = MAX_TIMEOUTS;
+uint16_t segsize = SEGSIZE;
+uint16_t pktsize = SEGSIZE + 4;
+
+int acting_as_client;
+
+
+/*
+ * Set timeout values for packet reception. The idea is that you
+ * get 'maxtimeouts' of 5 seconds between 'timeoutpacket' (i.e. the
+ * first timeout) to 'timeoutnetwork' (i.e. the last timeout)
+ */
+int
+settimeouts(int _timeoutpacket, int _timeoutnetwork, int _maxtimeouts)
+{
+ int i;
+
+ /* We cannot do impossible things */
+ if (_timeoutpacket >= _timeoutnetwork)
+ return (0);
+
+ maxtimeouts = 0;
+ i = _timeoutpacket;
+ while (i < _timeoutnetwork || maxtimeouts < MIN_TIMEOUTS) {
+ maxtimeouts++;
+ i += 5;
+ }
+
+ timeoutpacket = _timeoutpacket;
+ timeoutnetwork = i;
+ return (1);
+}
+
+/* translate IPv4 mapped IPv6 address to IPv4 address */
+void
+unmappedaddr(struct sockaddr_in6 *sin6)
+{
+ struct sockaddr_in *sin4;
+ u_int32_t addr;
+ int port;
+
+ if (sin6->sin6_family != AF_INET6 ||
+ !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ return;
+ sin4 = (struct sockaddr_in *)sin6;
+ addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
+ port = sin6->sin6_port;
+ memset(sin4, 0, sizeof(struct sockaddr_in));
+ sin4->sin_addr.s_addr = addr;
+ sin4->sin_port = port;
+ sin4->sin_family = AF_INET;
+ sin4->sin_len = sizeof(struct sockaddr_in);
+}
+
+/* Get a field from a \0 seperated string */
+ssize_t
+get_field(int peer, char *buffer, ssize_t size)
+{
+ char *cp = buffer;
+
+ while (cp < buffer + size) {
+ if (*cp == '\0') break;
+ cp++;
+ }
+ if (*cp != '\0') {
+ tftp_log(LOG_ERR, "Bad option - no trailing \\0 found");
+ send_error(peer, EBADOP);
+ exit(1);
+ }
+ return (cp - buffer + 1);
+}
+
+/*
+ * Logging functions
+ */
+int _tftp_logtostdout = 1;
+
+void
+tftp_openlog(const char *ident, int logopt, int facility)
+{
+
+ _tftp_logtostdout = (ident == NULL);
+ if (_tftp_logtostdout == 0)
+ openlog(ident, logopt, facility);
+}
+
+void
+tftp_closelog(void)
+{
+
+ if (_tftp_logtostdout == 0)
+ closelog();
+}
+
+void
+tftp_log(int priority, const char *message, ...)
+{
+ va_list ap;
+ char *s;
+
+ va_start(ap, message);
+ if (_tftp_logtostdout == 0) {
+ vasprintf(&s, message, ap);
+ syslog(priority, "%s", s);
+ } else {
+ vprintf(message, ap);
+ printf("\n");
+ }
+ va_end(ap);
+}
+
+/*
+ * Packet types
+ */
+struct packettypes packettypes[] = {
+ { RRQ, "RRQ" },
+ { WRQ, "WRQ" },
+ { DATA, "DATA" },
+ { ACK, "ACK" },
+ { ERROR, "ERROR" },
+ { OACK, "OACK" },
+ { 0, NULL },
+};
+
+char *
+packettype(int type)
+{
+ static char failed[100];
+ int i = 0;
+
+ while (packettypes[i].name != NULL) {
+ if (packettypes[i].value == type)
+ break;
+ i++;
+ }
+ if (packettypes[i].name != NULL)
+ return packettypes[i].name;
+ sprintf(failed, "unknown (type: %d)", type);
+ return (failed);
+}
+
+/*
+ * Debugs
+ */
+int debug = DEBUG_NONE;
+struct debugs debugs[] = {
+ { DEBUG_PACKETS, "packet", "Packet debugging" },
+ { DEBUG_SIMPLE, "simple", "Simple debugging" },
+ { DEBUG_OPTIONS, "options", "Options debugging" },
+ { DEBUG_ACCESS, "access", "TCPd access debugging" },
+ { DEBUG_NONE, NULL, "No debugging" },
+};
+int packetdroppercentage = 0;
+
+int
+debug_find(char *s)
+{
+ int i = 0;
+
+ while (debugs[i].name != NULL) {
+ if (strcasecmp(debugs[i].name, s) == 0)
+ break;
+ i++;
+ }
+ return (debugs[i].value);
+}
+
+int
+debug_finds(char *s)
+{
+ int i = 0;
+ char *ps = s;
+
+ while (s != NULL) {
+ ps = strchr(s, ' ');
+ if (ps != NULL)
+ *ps = '\0';
+ i += debug_find(s);
+ if (ps != NULL)
+ *ps = ' ';
+ s = ps;
+ }
+ return (i);
+}
+
+char *
+debug_show(int d)
+{
+ static char s[100];
+ int i = 0;
+
+ s[0] = '\0';
+ while (debugs[i].name != NULL) {
+ if (d&debugs[i].value) {
+ if (s[0] != '\0')
+ strcat(s, " ");
+ strcat(s, debugs[i].name);
+ }
+ i++;
+ }
+ if (s[0] != '\0')
+ return (s);
+ return ("none");
+}
+
+/*
+ * RP_
+ */
+struct rp_errors rp_errors[] = {
+ { RP_TIMEOUT, "Network timeout" },
+ { RP_TOOSMALL, "Not enough data bytes" },
+ { RP_WRONGSOURCE, "Invalid IP address of UDP port" },
+ { RP_ERROR, "Error packet" },
+ { RP_RECVFROM, "recvfrom() complained" },
+ { RP_TOOBIG, "Too many data bytes" },
+ { RP_NONE, NULL }
+};
+
+char *
+rp_strerror(int error)
+{
+ static char s[100];
+ int i = 0;
+
+ while (rp_errors[i].desc != NULL) {
+ if (rp_errors[i].error == error) {
+ strcpy(s, rp_errors[i].desc);
+ }
+ i++;
+ }
+ if (s[0] == '\0')
+ sprintf(s, "unknown (error=%d)", error);
+ return (s);
+}
+
+/*
+ * Performance figures
+ */
+
+void
+stats_init(struct tftp_stats *ts)
+{
+
+ ts->amount = 0;
+ ts->rollovers = 0;
+ ts->retries = 0;
+ ts->blocks = 0;
+ ts->amount = 0;
+ gettimeofday(&(ts->tstart), NULL);
+}
+
+void
+printstats(const char *direction, int verbose, struct tftp_stats *ts)
+{
+ double delta; /* compute delta in 1/10's second units */
+
+ delta = ((ts->tstop.tv_sec*10.)+(ts->tstop.tv_usec/100000)) -
+ ((ts->tstart.tv_sec*10.)+(ts->tstart.tv_usec/100000));
+ delta = delta/10.; /* back to seconds */
+
+ printf("%s %zu bytes during %.1f seconds in %u blocks",
+ direction, ts->amount, delta, ts->blocks);
+
+ if (ts->rollovers != 0)
+ printf(" with %d rollover%s",
+ ts->rollovers, ts->rollovers != 1 ? "s" : "");
+
+ if (verbose)
+ printf(" [%.0f bits/sec]", (ts->amount*8.)/delta);
+ putchar('\n');
+}
+
OpenPOWER on IntegriCloud