[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug-inetutils] [PATCH] Make `tftpd' IPv6-compatible
From: |
Ludovic Courtès |
Subject: |
[bug-inetutils] [PATCH] Make `tftpd' IPv6-compatible |
Date: |
Tue, 07 Sep 2010 18:05:37 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) |
Hello!
The attached patch makes ‘tftpd’ IPv6-compatible. As a side effect, it
makes it usable (!) on current GNU/Linux when a client connects via an
address other than the loopback address (FROM is always AF_INET6 on my
machine.)
The patch assumes that IPv6 support is available. Besides, it’d be
better to import Gnulib’s ‘inet_ntop’ modules.
Comments?
Thanks,
Ludo’.
PS: My copyright assignment is now on file.
From 3be7f44305103b39a0e1bc79a9960feb5d142485 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <address@hidden>
Date: Tue, 7 Sep 2010 17:53:23 +0200
Subject: [PATCH] Make `tftpd' IPv6-compatible.
* src/tftpd.c (from): Change from `sockaddr_in' to `sockaddr_storage'.
(main): Likewise for `sin'. Have PEER and SIN have the same family as
FROM.
(verifyhost): Rename to...
(verify_host): ... this. Rewrite to handle both IPv6 and IPv4.
Update callers.
* tests/Makefile.am (dist_check_SCRIPTS)[ENABLE_inetd && ENABLE_tftpd &&
ENABLE_tftp]: Add `tftp.sh'.
* tests/tftp.sh: New file.
---
src/tftpd.c | 48 +++++++++++++++++++++-----------
tests/Makefile.am | 9 ++++++
tests/tftp.sh | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 119 insertions(+), 16 deletions(-)
create mode 100755 tests/tftp.sh
diff --git a/src/tftpd.c b/src/tftpd.c
index 70602fa..719db81 100644
--- a/src/tftpd.c
+++ b/src/tftpd.c
@@ -101,7 +101,7 @@ static int maxtimeout = 5 * TIMEOUT;
#define PKTSIZE SEGSIZE+4
static char buf[PKTSIZE];
static char ackbuf[PKTSIZE];
-static struct sockaddr_in from;
+static struct sockaddr_storage from;
static socklen_t fromlen;
void tftp (struct tftphdr *, int);
@@ -124,7 +124,8 @@ static int logging;
static const char *errtomsg (int);
static void nak (int);
-static const char *verifyhost (struct sockaddr_in *);
+static char *verify_host (struct sockaddr_storage *, socklen_t,
+ char *, size_t);
@@ -172,7 +173,7 @@ main (int argc, char *argv[])
int index;
register struct tftphdr *tp;
int on, n;
- struct sockaddr_in sin;
+ struct sockaddr_storage sin;
set_program_name (argv[0]);
iu_argp_init ("tftpd", default_program_authors);
@@ -268,18 +269,19 @@ main (int argc, char *argv[])
exit (EXIT_SUCCESS);
}
}
- from.sin_family = AF_INET;
+
alarm (0);
close (0);
close (1);
- peer = socket (AF_INET, SOCK_DGRAM, 0);
+
+ peer = socket (from.ss_family, SOCK_DGRAM, 0);
if (peer < 0)
{
syslog (LOG_ERR, "socket: %m\n");
exit (EXIT_FAILURE);
}
memset (&sin, 0, sizeof (sin));
- sin.sin_family = AF_INET;
+ sin.ss_family = from.ss_family;
if (bind (peer, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
syslog (LOG_ERR, "bind: %m\n");
@@ -360,8 +362,10 @@ again:
ecode = (*pf->f_validate) (&filename, tp->th_opcode);
if (logging)
{
+ char node[1024];
syslog (LOG_INFO, "%s: %s request for %s: %s",
- verifyhost (&from),
+ verify_host (&from, sizeof from,
+ node, sizeof node),
tp->th_opcode == WRQ ? "write" : "read",
filename, errtomsg (ecode));
}
@@ -736,17 +740,29 @@ nak (int error)
syslog (LOG_ERR, "nak: %m\n");
}
-static const char *
-verifyhost (struct sockaddr_in *fromp)
+static char *
+verify_host (struct sockaddr_storage *addr, socklen_t addr_len,
+ char *host_and_service, size_t len)
{
- struct hostent *hp;
-
- hp = gethostbyaddr ((char *) &fromp->sin_addr, sizeof (fromp->sin_addr),
- fromp->sin_family);
- if (hp)
- return hp->h_name;
+ int err;
+ char host[512], service[256];
+
+ err = getnameinfo ((struct sockaddr *) addr, addr_len,
+ host, sizeof host,
+ service, sizeof service,
+ 0);
+
+ if (err)
+ inet_ntop (addr->ss_family,
+ addr->ss_family == AF_INET
+ ? (void *) &((struct sockaddr_in *) addr)->sin_addr
+ : (void *) &((struct sockaddr_in6 *) addr)->sin6_addr,
+ host_and_service, len);
else
- return inet_ntoa (fromp->sin_addr);
+ snprintf (host_and_service, len, "%s%s%s",
+ host, *service ? "/" : "", service);
+
+ return host_and_service;
}
static const char usage_str[] =
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f64a066..4f4610a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -28,6 +28,15 @@ endif
if ENABLE_traceroute
dist_check_SCRIPTS += traceroute-localhost.sh
endif
+
+if ENABLE_inetd
+if ENABLE_tftpd
+if ENABLE_tftp
+dist_check_SCRIPTS += tftp.sh
+endif
+endif
+endif
+
TESTS = $(check_PROGRAMS) $(dist_check_SCRIPTS)
TESTS_ENVIRONMENT = EXEEXT=$(EXEEXT)
diff --git a/tests/tftp.sh b/tests/tftp.sh
new file mode 100755
index 0000000..08d5d86
--- /dev/null
+++ b/tests/tftp.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+# Copyright (C) 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Inetutils.
+#
+# GNU Inetutils is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or (at
+# your option) any later version.
+#
+# GNU Inetutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see `http://www.gnu.org/licenses/'.
+
+# Run `inetd' with `tftpd' and try to fetch a file from there using `tftp'.
+
+TFTP="${TFTP:-../src/tftp$EXEEXT}"
+TFTPD="${TFTPD:-../src/tftpd$EXEEXT}"
+INETD="${INETD:-../src/inetd$EXEEXT}"
+IFCONFIG="${IFCONFIG:-../ifconfig/ifconfig$EXEEXT}"
+
+PORT=7777
+INETD_CONF="inetd.conf.tmp"
+
+ADDRESSES="`$IFCONFIG | grep 'inet addr:' | \
+ sed -e's/inet addr:\([^ ]\+\)[[:blank:]].*$/\1/g'`"
+
+if [ "$VERBOSE" ]; then
+ set -x
+ "$TFTP" --version
+ "$TFTPD" --version
+ "$INETD" --version
+fi
+
+cat > "$INETD_CONF" <<EOF
+$PORT dgram udp wait $USER $TFTPD tftpd -l `pwd`/tftp-test
+EOF
+
+# Launch `inetd', assuming it's reachable at all $ADDRESSES.
+$INETD "${VERBOSE:+-d}" "$INETD_CONF" &
+inetd_pid="$!"
+
+if [ -f /dev/urandom ]; then
+ input="/dev/urandom"
+else
+ input="/dev/zero"
+fi
+
+rm -fr tftp-test tftp-test-file
+mkdir tftp-test && \
+ dd if="$input" of="tftp-test/tftp-test-file" bs=1024 count=170
+
+for addr in $ADDRESSES
+do
+ echo "trying with address \`$addr'..." >&2
+
+ rm -f tftp-test-file
+ echo "get tftp-test-file" | "$TFTP" $addr $PORT
+
+ cmp tftp-test/tftp-test-file tftp-test-file
+ result=$?
+
+ if [ "$result" -ne 0 ]; then
+ # Failure.
+ break
+ fi
+done
+
+kill "$inetd_pid"
+
+rm -rf tftp-test tftp-test-file "$INETD_CONF"
+
+exit $result
--
1.7.0
pgpq5_2Lpq8ar.pgp
Description: PGP signature
- [bug-inetutils] [PATCH] Make `tftpd' IPv6-compatible,
Ludovic Courtès <=