bug-inetutils
[Top][All Lists]
Advanced

[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

Attachment: pgpq5_2Lpq8ar.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]