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