From 696669406987bcac30aa66c232b7747e69f3d181 Mon Sep 17 00:00:00 2001
From: Mats Erik Andersson
Date: Fri, 24 Sep 2010 11:57:42 +0200
Subject: [PATCH] Implement IPv6 capability for the TFTP server.
---
ChangeLog | 14 ++++++++++
libinetutils/tftpsubs.c | 2 +-
src/tftpd.c | 61 +++++++++++++++++++++++++++++++++-------------
3 files changed, 59 insertions(+), 18 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 1ff6282..1465b13 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2010-09-24 Mats Erik Andersson
+
+ * libinetutils/tftpsubs.c (synchnet): Changed type of FROM
+ to be "struct sockaddr_storage".
+
+ * src/tftpd.c: Changed all uses of "struct sockaddr_in"
+ to be "struct sockaddr_storage".
+ (fromlen): Meticulously tracks length of address structure FROM
+ in every function.
+ (verifyhost): Expanded declaration signature to be
+ "(struct sockaddr_storage *, socklen_t)". Use getnameinfo(3)
+ as resolver.
+ (tftp) : Now displays address family "IPv4", "IPv6", or "?".
+
2010-09-15 Mats Erik Andersson
* telnetd/telnetd.c (login_invocation, argp_options):
diff --git a/libinetutils/tftpsubs.c b/libinetutils/tftpsubs.c
index bc1f84a..6fa78bc 100644
--- a/libinetutils/tftpsubs.c
+++ b/libinetutils/tftpsubs.c
@@ -285,7 +285,7 @@ synchnet (int f)
{
int i, j = 0;
char rbuf[PKTSIZE];
- struct sockaddr_in from;
+ struct sockaddr_storage from;
socklen_t fromlen;
while (1)
diff --git a/src/tftpd.c b/src/tftpd.c
index 70602fa..b8bbe8d 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,7 @@ static int logging;
static const char *errtomsg (int);
static void nak (int);
-static const char *verifyhost (struct sockaddr_in *);
+static const char *verifyhost (struct sockaddr_storage *, socklen_t);
@@ -172,7 +172,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,24 +268,29 @@ 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);
+
+ /* The peer's address 'from' is valid at this point.
+ * 'from.ss_family' contains the correct address
+ * family for any callback connection, and 'fromlen'
+ * is the length of the corresponding address structure. */
+ 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;
- if (bind (peer, (struct sockaddr *) &sin, sizeof (sin)) < 0)
+ sin.ss_family = from.ss_family;
+ if (bind (peer, (struct sockaddr *) &sin, fromlen) < 0)
{
syslog (LOG_ERR, "bind: %m\n");
exit (EXIT_FAILURE);
}
- if (connect (peer, (struct sockaddr *) &from, sizeof (from)) < 0)
+ if (connect (peer, (struct sockaddr *) &from, fromlen) < 0)
{
syslog (LOG_ERR, "connect: %m\n");
exit (EXIT_FAILURE);
@@ -360,8 +365,22 @@ again:
ecode = (*pf->f_validate) (&filename, tp->th_opcode);
if (logging)
{
- syslog (LOG_INFO, "%s: %s request for %s: %s",
- verifyhost (&from),
+ char *family;
+
+ switch (from.ss_family)
+ {
+ case AF_INET:
+ family = "IPv4";
+ break;
+ case AF_INET6:
+ /* Should mapped IPv4 addresses be reported? */
+ family = "IPv6";
+ break;
+ default:
+ family = "?";
+ }
+ syslog (LOG_INFO, "%s (%s): %s request for %s: %s",
+ verifyhost (&from, fromlen), family,
tp->th_opcode == WRQ ? "write" : "read",
filename, errtomsg (ecode));
}
@@ -737,16 +756,24 @@ nak (int error)
}
static const char *
-verifyhost (struct sockaddr_in *fromp)
+verifyhost (struct sockaddr_storage *fromp, socklen_t frlen)
{
- struct hostent *hp;
+ int rc;
+#ifdef NI_MAXHOST
+ static char host[NI_MAXHOST];
+#else
+ static char host[64];
+#endif
- hp = gethostbyaddr ((char *) &fromp->sin_addr, sizeof (fromp->sin_addr),
- fromp->sin_family);
- if (hp)
- return hp->h_name;
+ rc = getnameinfo ((struct sockaddr *) fromp, frlen,
+ host, sizeof (host), NULL, 0, 0);
+ if (rc == 0)
+ return host;
else
- return inet_ntoa (fromp->sin_addr);
+ {
+ syslog (LOG_ERR, "getnameinfo: %s\n", gai_strerror(rc));
+ return "0.0.0.0";
+ }
}
static const char usage_str[] =
--
1.7.0