rpms/tftp/F-9 tftp-hpa-0.48-ipv6.patch, NONE, 1.1 tftp.spec, 1.46, 1.47

Jiri Skala jskala at fedoraproject.org
Fri Nov 21 10:04:50 UTC 2008


Author: jskala

Update of /cvs/extras/rpms/tftp/F-9
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv24607

Modified Files:
	tftp.spec 
Added Files:
	tftp-hpa-0.48-ipv6.patch 
Log Message:
* Fri Nov 21 2008 Jiri Skala <jskala at redhat.com> - 0.48-7
- #461525 - tftp server and client support IPv6 now


tftp-hpa-0.48-ipv6.patch:

--- NEW FILE tftp-hpa-0.48-ipv6.patch ---
diff -up tftp-hpa-0.48/common/tftpsubs.c.ipv6 tftp-hpa-0.48/common/tftpsubs.c
--- tftp-hpa-0.48/common/tftpsubs.c.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/common/tftpsubs.c	2008-11-21 10:37:18.000000000 +0100
@@ -37,6 +37,7 @@
  */
 
 #include "tftpsubs.h"
+#include "tftpd/tftpd.h"
 
 #ifndef lint
 /* static char sccsid[] = "@(#)tftpsubs.c	8.1 (Berkeley) 6/6/93"; */
@@ -249,7 +250,7 @@ synchnet(int f)		/* socket to flush */
 {
   int pktcount = 0;
   char rbuf[PKTSIZE];
-  struct sockaddr_in from;
+  union sockaddr_uni from;
   socklen_t fromlen;
   fd_set socketset;
   struct timeval notime;
@@ -265,7 +266,7 @@ synchnet(int f)		/* socket to flush */
 	
     /* Otherwise drain the packet */
     pktcount++;
-    fromlen = sizeof from;
+    fromlen = SA_ADDRLEN(&from);
     (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
 		    (struct sockaddr *)&from, &fromlen);
   }
@@ -274,10 +275,11 @@ synchnet(int f)		/* socket to flush */
 }
 
 
-int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int port_range_from, unsigned int port_range_to)
+int pick_port_bind(int sockfd, union sockaddr_uni *myaddr, unsigned int port_range_from, unsigned int port_range_to)
 {
   unsigned int port, firstport;
   int port_range = 0;
+	int addrlen;
 
   if (port_range_from != 0 && port_range_to != 0) {
       port_range = 1;
@@ -290,9 +292,9 @@ int pick_port_bind(int sockfd, struct so
   port = firstport;
 
   do {
-    myaddr->sin_port = htons(port);
-    
-    if (bind(sockfd, (struct sockaddr *)myaddr, sizeof *myaddr) < 0) {
+		SA_PORT(myaddr) = htons(port);
+		addrlen = IS_IPv6(myaddr) ? sizeof(myaddr->s_in6) : sizeof(myaddr->s_in);
+    if (bind(sockfd, (struct sockaddr *)myaddr, addrlen) < 0) {
       /* Some versions of Linux return EINVAL instead of EADDRINUSE */
       if ( !(port_range && (errno == EINVAL || errno == EADDRINUSE)) )
 	return -1;
diff -up tftp-hpa-0.48/common/tftpsubs.h.ipv6 tftp-hpa-0.48/common/tftpsubs.h
--- tftp-hpa-0.48/common/tftpsubs.h.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/common/tftpsubs.h	2008-11-21 10:37:18.000000000 +0100
@@ -46,6 +46,7 @@
 #define TFTPSUBS_H
 
 #include "config.h"
+#include "tftpd/tftpd.h"
 
 struct tftphdr;
 
@@ -62,6 +63,6 @@ int	writeit(FILE *, struct tftphdr **, i
 extern int segsize;
 #define MAX_SEGSIZE	65464
 
-int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int from, unsigned int to);
+int pick_port_bind(int sockfd, union sockaddr_uni *myaddr, unsigned int from, unsigned int to);
 
 #endif
diff -up tftp-hpa-0.48/tftpd/recvfrom.c.ipv6 tftp-hpa-0.48/tftpd/recvfrom.c
--- tftp-hpa-0.48/tftpd/recvfrom.c.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/tftpd/recvfrom.c	2008-11-21 10:37:18.000000000 +0100
@@ -34,8 +34,10 @@
 /* Assume this version of glibc simply lacks the definition */
 struct in_pktinfo {
   int ipi_ifindex;
-  struct in_addr ipi_spec_dst;
-  struct in_addr ipi_addr;
+	union {
+  	struct in_addr  sin_addr;
+  	struct in6_addr sin6_addr;
+	} ipi_spec_dst, ipi_addr;
 };
 #  else
 #   undef IP_PKTINFO		/* No definition, no way to get it */
@@ -55,30 +57,38 @@ struct in_pktinfo {
  * end up having the same local and remote address when trying to
  * bind to it.
  */
-static int address_is_local(const struct sockaddr_in *addr)
+static int address_is_local(const union sockaddr_uni *addr)
 {
-  struct sockaddr_in sin;
+  union sockaddr_uni sin;
   int sockfd = -1;
   int e;
   int rv = 0;
   socklen_t addrlen;
 
   /* Multicast or universal broadcast address? */
-  if (ntohl(addr->sin_addr.s_addr) >= (224UL << 24))
-    return 0;
+	if (ipv6) {
+		if (addr->s_in6.sin6_addr.s6_addr[0] == 255)
+			return 0;
+	} else {
+  	if (ntohl(addr->s_in.sin_addr.s_addr) >= (224UL << 24))
+    	return 0;
+	}
 
-  sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+  sockfd = socket(SA_FAMILY(addr), SOCK_DGRAM, 0);
   if (sockfd < 0)
     goto err;
 
-  if (connect(sockfd, (const struct sockaddr *)addr, sizeof *addr))
+  addrlen = ipv6 ? sizeof(sin.s_in6) : sizeof(sin.s_in);
+  if (connect(sockfd, (const struct sockaddr *)addr, addrlen))
     goto err;
 
-  addrlen = sizeof sin;
+  addrlen = ipv6 ? sizeof(sin.s_in6) : sizeof(sin.s_in);
   if (getsockname(sockfd, (struct sockaddr *)&sin, &addrlen))
     goto err;
 
-  rv = sin.sin_addr.s_addr == addr->sin_addr.s_addr;
+	if (ipv6)
+		rv = !memcmp(&sin.s_in6.sin6_addr, &addr->s_in6.sin6_addr, sizeof(struct in6_addr));
+  else rv = sin.s_in.sin_addr.s_addr == addr->s_in.sin_addr.s_addr;
 
  err:
   e = errno;
@@ -93,8 +103,8 @@ static int address_is_local(const struct
 
 int
 myrecvfrom(int s, void *buf, int len, unsigned int flags,
-	   struct sockaddr *from, socklen_t *fromlen,
-	   struct sockaddr_in *myaddr)
+	   union sockaddr_uni *from, socklen_t *fromlen,
+	   union sockaddr_uni *myaddr)
 {
   struct msghdr msg;
   struct iovec iov;
@@ -103,10 +113,10 @@ myrecvfrom(int s, void *buf, int len, un
   union {
     struct cmsghdr cm;
 #ifdef IP_PKTINFO
-    char control[CMSG_SPACE(sizeof(struct in_addr)) +
+    char control[CMSG_SPACE(sizeof(struct in6_addr)) +
 		CMSG_SPACE(sizeof(struct in_pktinfo))];
 #else
-    char control[CMSG_SPACE(sizeof(struct in_addr))];
+    char control[CMSG_SPACE(sizeof(struct in6_addr))];
 #endif
   } control_un;
   int on = 1;
@@ -140,8 +150,8 @@ myrecvfrom(int s, void *buf, int len, un
   *fromlen = msg.msg_namelen;
 
   if ( myaddr ) {
-    bzero(myaddr, sizeof(struct sockaddr_in));
-    myaddr->sin_family = AF_INET;
+    bzero(myaddr, sizeof(union sockaddr_uni));
+    SA_FAMILY(myaddr) = ipv6 ? AF_INET6 : AF_INET;
 
     if ( msg.msg_controllen < sizeof(struct cmsghdr) ||
 	 (msg.msg_flags & MSG_CTRUNC) )
@@ -151,27 +161,34 @@ myrecvfrom(int s, void *buf, int len, un
 	  cmptr = CMSG_NXTHDR(&msg, cmptr) ) {
 
 #ifdef IP_RECVDSTADDR
-      if ( cmptr->cmsg_level == IPPROTO_IP &&
-	   cmptr->cmsg_type == IP_RECVDSTADDR ) {
-	memcpy(&myaddr->sin_addr, CMSG_DATA(cmptr),
-	       sizeof(struct in_addr));
-      }
+		if ( cmptr->cmsg_level == IPPROTO_IP &&
+				 cmptr->cmsg_type == IP_RECVDSTADDR ) {
+				if (IS_IPv6(*myaddr)))
+					memcpy(&myaddr->s_sin6.sin6_addr, CMSG_DATA(cmptr), sizeof(struct in6_addr));
+				else memcpy(&myaddr->s_sin.sin_addr, CMSG_DATA(cmptr), sizeof(struct in_addr));
+		}
 #endif
 
 #ifdef IP_PKTINFO
-      if ( cmptr->cmsg_level == IPPROTO_IP &&
-	   cmptr->cmsg_type == IP_PKTINFO ) {
-	memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo));
-	memcpy(&myaddr->sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr));
-      }
+		if ( cmptr->cmsg_level == IPPROTO_IP &&
+				 cmptr->cmsg_type == IP_PKTINFO ) {
+			memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo));
+			if (ipv6)
+				memcpy(&myaddr->s_in6.sin6_addr, &pktinfo.ipi_addr, sizeof(struct in6_addr));
+			else memcpy(&myaddr->s_in.sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr));
+		}
 #endif
 
     }
   }
 
   /* If the address is not a valid local address, then bind to any address... */
-  if (address_is_local(myaddr) != 1)
-    myaddr->sin_addr.s_addr = INADDR_ANY;
+  if (address_is_local(myaddr) != 1) {
+    if (SA_FAMILY(myaddr) == AF_INET6)
+				memcpy(&myaddr->s_in6.sin6_addr, &in6addr_any, sizeof (struct in6_addr));
+		else myaddr->s_in.sin_addr.s_addr = INADDR_ANY;
+
+	}
 
   return n;
 }
@@ -180,16 +197,17 @@ myrecvfrom(int s, void *buf, int len, un
 
 int
 myrecvfrom(int s, void *buf, int len, unsigned int flags,
-	   struct sockaddr *from, int *fromlen,
-	   struct sockaddr_in *myaddr)
+	   union sockaddr_uni *from, int *fromlen,
+	   union sockaddr_uni *myaddr)
 {
   /* There is no way we can get the local address, fudge it */
+  bzero(myaddr, sizeof(union sockaddr_uni));
+	SA_FAMILY(myaddr) = ipv6 ? AF_INET6 : AF_INET;
 
-  bzero(myaddr, sizeof(struct sockaddr_in));
-  myaddr->sin_family = AF_INET;
-
-  myaddr->sin_port   = htons(IPPORT_TFTP);
-  bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr));
+  SA_PORT(myaddr)   = htons(IPPORT_TFTP);
+	if (SA_FAMILY(myaddr) == AF_INET6)
+ 		bzero(&myaddr->s_in6.sin6_addr, sizeof(struct in6_addr));
+ 	else myaddr->s_in.s_sin_addr.s_addr = 0L;
 
   return recvfrom(s,buf,len,flags,from,fromlen);
 }
diff -up tftp-hpa-0.48/tftpd/recvfrom.h.ipv6 tftp-hpa-0.48/tftpd/recvfrom.h
--- tftp-hpa-0.48/tftpd/recvfrom.h.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/tftpd/recvfrom.h	2008-11-21 10:37:18.000000000 +0100
@@ -16,8 +16,9 @@
  */
 
 #include "config.h"
+#include "tftpd.h"
 
 int
 myrecvfrom(int s, void *buf, int len, unsigned int flags,
-	   struct sockaddr *from, socklen_t *fromlen,
-	   struct sockaddr_in *myaddr);
+	   union sockaddr_uni *from, socklen_t *fromlen,
+	   union sockaddr_uni *myaddr);
diff -up tftp-hpa-0.48/tftpd/tftpd.8.in.ipv6 tftp-hpa-0.48/tftpd/tftpd.8.in
--- tftp-hpa-0.48/tftpd/tftpd.8.in.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/tftpd/tftpd.8.in	2008-11-21 10:37:18.000000000 +0100
@@ -173,6 +173,12 @@ specified range of port numbers.
 .B \-V
 Print the version number and configuration to standard output, then
 exit gracefully.
+.TP
+.B \-4
+support IPv4 only (by default)
+.TP
+.B \-6
+prefer IPv6
 .SH "RFC 2347 OPTION NEGOTIATION"
 This version of
 .B tftpd
diff -up tftp-hpa-0.48/tftpd/tftpd.c.ipv6 tftp-hpa-0.48/tftpd/tftpd.c
--- tftp-hpa-0.48/tftpd/tftpd.c.ipv6	2008-11-21 10:37:18.000000000 +0100
+++ tftp-hpa-0.48/tftpd/tftpd.c	2008-11-21 10:37:18.000000000 +0100
@@ -94,7 +94,7 @@ char		buf[PKTSIZE];
 char		ackbuf[PKTSIZE];
 unsigned int	max_blksize = MAX_SEGSIZE;
 
-struct sockaddr_in from;
+union sockaddr_uni from;
 socklen_t       fromlen;
 off_t	        tsize;
 int             tsize_ok;
@@ -108,6 +108,7 @@ int		unixperms = 0;
 int		portrange = 0;
 unsigned int	portrange_from, portrange_to;
 int		verbosity = 0;
+int		ipv6 = 0;
 
 struct formats;
 #ifdef WITH_REGEX
@@ -161,7 +162,7 @@ timer(int sig)
 static void
 usage(void)
 {
-  syslog(LOG_ERR, "Usage: %s [-vcl][-a address][-m mappings][-u user][-t inetd_timeout][-T pkt_timeout][-r option...] [-s] [directory ...]",
+  syslog(LOG_ERR, "Usage: %s [-vcl46][-a address][-m mappings][-u user][-t inetd_timeout][-T pkt_timeout][-r option...] [-s] [directory ...]",
 	 __progname);
   exit(EX_USAGE);
 }
@@ -278,8 +279,8 @@ main(int argc, char **argv)
   struct tftphdr *tp;
   struct passwd *pw;
   struct options *opt;
-  struct sockaddr_in myaddr;
-  struct sockaddr_in bindaddr;
+  union sockaddr_uni myaddr;
+  union sockaddr_uni bindaddr;
   int n;
   int fd = 0;
   int standalone = 0;		/* Standalone (listen) mode */
@@ -300,6 +301,7 @@ main(int argc, char **argv)
   time_t my_time = 0;
   struct tm* p_tm;
   char envtz[10];
+	char dbuf[INET6_ADDRSTRLEN];
   my_time = time(NULL);
   p_tm = localtime(&my_time);
   snprintf(envtz, sizeof(envtz) - 1, "UTC%+d", (p_tm->tm_gmtoff * -1)/3600);
@@ -314,7 +316,7 @@ main(int argc, char **argv)
 
   srand(time(NULL) ^ getpid());
   
-  while ((c = getopt(argc, argv, "cspvVlLa:B:u:U:r:t:T:R:m:")) != -1)
+  while ((c = getopt(argc, argv, "cspvVlL46a:B:u:U:r:t:T:R:m:")) != -1)
     switch (c) {
     case 'c':
       cancreate = 1;
@@ -338,6 +340,12 @@ main(int argc, char **argv)
     case 't':
       waittime = atoi(optarg);
       break;
+		case '4':
+			ipv6 = 0;
+			break;
+		case '6':
+			ipv6 = 1;
+			break;
     case 'B':
       {
 	char *vp;
@@ -459,31 +467,46 @@ main(int argc, char **argv)
 
   /* If we're running standalone, set up the input port */
   if ( standalone ) {
-    fd = socket(PF_INET, SOCK_DGRAM, 0);
+    fd = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
     
-    memset(&bindaddr, 0, sizeof bindaddr);
-    bindaddr.sin_family = AF_INET;
-    bindaddr.sin_addr.s_addr = INADDR_ANY;
-    bindaddr.sin_port = htons(IPPORT_TFTP);
+    bzero(&bindaddr, sizeof bindaddr);
+		SA_FAMILY(&bindaddr) = ipv6 ? AF_INET6 : AF_INET;
+		SA_PORT(&bindaddr) = htons(IPPORT_TFTP);
+		if (IS_IPv4(&bindaddr))
+			bindaddr.s_in.sin_addr.s_addr = INADDR_ANY;
+		else bindaddr.s_in6.sin6_addr = in6addr_any;
 
     if ( address ) {
       char *portptr, *eportptr;
-      struct hostent *hostent;
+      struct addrinfo hints, *res;
+			int error;
       struct servent *servent;
       unsigned long port;
 
-      address = tfstrdup(address);
-      portptr = strrchr(address, ':');
-      if ( portptr )
-	*portptr++ = '\0';
+			address = tfstrdup(address);
+			portptr = strrchr(address, ':');
+  	  if ( portptr )
+				*portptr++ = '\0';
       
       if ( *address ) {
-	hostent = gethostbyname(address);
-	if ( !hostent || hostent->h_addrtype != AF_INET ) {
-	  syslog(LOG_ERR, "cannot resolve local bind address: %s", address);
-	  exit(EX_NOINPUT);
-	}
-	memcpy(&bindaddr.sin_addr, hostent->h_addr, hostent->h_length);
+				memset(&hints, 0, sizeof (struct addrinfo));
+				hints.ai_family = SA_FAMILY(&bindaddr);
+				hints.ai_flags = AI_CANONNAME;
+				hints.ai_socktype = SOCK_DGRAM;
+
+				error = getaddrinfo(address, portptr, &hints, &res);
+				if (error != 0) {
+      		syslog(LOG_ERR, "%s unknown host", address);
+		      exit(EX_NOHOST);
+				}
+
+				for (; res; res = res->ai_next) {
+					fd = socket(SA_FAMILY(res), res->ai_socktype, 0);	
+					if (fd > -1) {
+						memcpy(&bindaddr, res->ai_addr, res->ai_addrlen);
+						break;
+					}
+				}
       } else {
 	/* Default to using INADDR_ANY */
       }
@@ -491,9 +514,9 @@ main(int argc, char **argv)
       if ( portptr && *portptr ) {
 	servent = getservbyname(portptr, "udp");
 	if ( servent ) {
-	  bindaddr.sin_port = servent->s_port;
+	  SA_PORT(&bindaddr) = servent->s_port;
 	} else if ( (port = strtoul(portptr, &eportptr, 0)) && !*eportptr ) {
-	  bindaddr.sin_port = htons(port);
+	  SA_PORT(&bindaddr) = htons(port);
 	} else if ( !strcmp(portptr, "tftp") ) {
 	  /* It's TFTP, we're OK */
 	} else {
@@ -595,15 +618,20 @@ main(int argc, char **argv)
       }
     }
 
-    if ( from.sin_family != AF_INET ) {
+    if ( SA_FAMILY(&from) != AF_INET && SA_FAMILY(&from) != AF_INET6 ) {
       syslog(LOG_ERR, "received address was not AF_INET, please check your inetd config");
       exit(EX_PROTOCOL);
     }
 
-    if ( standalone && myaddr.sin_addr.s_addr == INADDR_ANY ) {
+    if (standalone && IS_IPv4(&myaddr) &&
+				myaddr.s_in.sin_addr.s_addr == INADDR_ANY ) {
       /* myrecvfrom() didn't capture the source address; but we might
 	 have bound to a specific address, if so we should use it */
-      memcpy(&myaddr.sin_addr, &bindaddr.sin_addr, sizeof bindaddr.sin_addr);
+      memcpy(&myaddr.s_in.sin_addr, &bindaddr.s_in.sin_addr, sizeof bindaddr.s_in.sin_addr);
+    }
+    if (standalone && IS_IPv6(&myaddr) &&
+				!memcmp(&myaddr.s_in6.sin6_addr, &in6addr_any, sizeof(struct in6_addr)) ) {
+      memcpy(&myaddr.s_in6.sin6_addr, &bindaddr.s_in6.sin6_addr, sizeof bindaddr.s_in6.sin6_addr);
     }
 
     /*
@@ -636,11 +664,11 @@ main(int argc, char **argv)
   if ( hosts_access(&wrap_request) == 0 ) {
     if ( deny_severity != -1 )
       syslog(deny_severity, "connection refused from %s",
-	     inet_ntoa(from.sin_addr));
+	     inet_ntop(SA_FAMILY(&from), pSA_ADDR(&from), dbuf, INET6_ADDRSTRLEN));
     exit(EX_NOPERM);	/* Access denied */
   } else if ( allow_severity != -1 ) {
     syslog(allow_severity, "connect from %s",
-	   inet_ntoa(from.sin_addr));
+	   inet_ntop(SA_FAMILY(&from), pSA_ADDR(&from), dbuf, INET6_ADDRSTRLEN));
   }
 #endif
 
@@ -650,7 +678,7 @@ main(int argc, char **argv)
   /* Get a socket.  This has to be done before the chroot(), since
      some systems require access to /dev to create a socket. */
   
-  peer = socket(AF_INET, SOCK_DGRAM, 0);
+  peer = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
   if (peer < 0) {
     syslog(LOG_ERR, "socket: %m");
     exit(EX_IOERR);
@@ -703,7 +731,7 @@ main(int argc, char **argv)
   }
   
   /* Other basic setup */
-  from.sin_family = AF_INET;
+  SA_FAMILY(&from) = ipv6 ? AF_INET6 : AF_INET;
   
   /* Process the request... */
   if (pick_port_bind(peer, &myaddr, portrange_from, portrange_to) < 0) {
@@ -760,6 +788,7 @@ tftp(struct tftphdr *tp, int size)
   
   char *val = NULL, *opt = NULL;
   char *ap = ackbuf + 2;
+	char dbuf[INET6_ADDRSTRLEN];
 
   ((struct tftphdr *)ackbuf)->th_opcode = htons(OACK);
   
@@ -801,11 +830,11 @@ tftp(struct tftphdr *tp, int size)
 	if ( filename == origfilename || !strcmp(filename, origfilename) )
 	  syslog(LOG_NOTICE, "%s from %s filename %s\n",
 		 tp_opcode == WRQ ? "WRQ" : "RRQ",
-		 inet_ntoa(from.sin_addr), filename);
+		 inet_ntop(SA_FAMILY(&from), pSA_ADDR(&from), dbuf, INET6_ADDRSTRLEN), filename);
 	else
 	  syslog(LOG_NOTICE, "%s from %s filename %s remapped to %s\n",
 		 tp_opcode == WRQ ? "WRQ" : "RRQ",
-		 inet_ntoa(from.sin_addr), origfilename, filename);
+		 inet_ntop(SA_FAMILY(&from), pSA_ADDR(&from), dbuf, INET6_ADDRSTRLEN), origfilename, filename);
       }		   
       ecode = (*pf->f_validate)(filename, tp_opcode, pf, &errmsgptr);
       if (ecode) {
@@ -1024,18 +1053,23 @@ int
 rewrite_macros(char macro, char *output)
 {
   char *p;
+	int i;
+	char dbuf[INET6_ADDRSTRLEN];
 
   switch (macro) {
   case 'i':
-    p = inet_ntoa(from.sin_addr);
+    p = inet_ntop(SA_FAMILY(&from), pSA_ADDR(&from), dbuf, INET6_ADDRSTRLEN);
     if ( output )
       strcpy(output, p);
     return strlen(p);
     
   case 'x':
-    if ( output )
-      sprintf(output, "%08lX", (unsigned long)ntohl(from.sin_addr.s_addr));
-    return 8;
+    if ( output && ipv6 ) {
+			for (i=0; i < sizeof (from.s_in6.sin6_addr.s6_addr); i++)
+				sprintf(output+2*i, "%02x", from.s_in6.sin6_addr.s6_addr[i]);
+		} else if ( output )
+      sprintf(output, "%08lX", (unsigned long)ntohl(from.s_in.sin_addr.s_addr));
+    return ipv6 ? 32 : 8;
 
   default:
     return -1;
@@ -1403,6 +1437,7 @@ nak(int error, const char *msg)
 {
   struct tftphdr *tp;
   int length;
+	char dbuf[INET6_ADDRSTRLEN];
   
   tp = (struct tftphdr *)buf;
   tp->th_opcode = htons((u_short)ERROR);
@@ -1428,7 +1463,7 @@ nak(int error, const char *msg)
   
   if ( verbosity >= 2 ) {
     syslog(LOG_INFO, "sending NAK (%d, %s) to %s",
-	   error, tp->th_msg, inet_ntoa(from.sin_addr));
+	   error, tp->th_msg, inet_ntop(SA_FAMILY(&from), pSA_ADDR(&from), dbuf, INET6_ADDRSTRLEN));
   }
   
   if (send(peer, buf, length, 0) != length)
diff -up tftp-hpa-0.48/tftpd/tftpd.h.ipv6 tftp-hpa-0.48/tftpd/tftpd.h
--- tftp-hpa-0.48/tftpd/tftpd.h.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/tftpd/tftpd.h	2008-11-21 10:37:18.000000000 +0100
@@ -18,10 +18,32 @@
 #ifndef TFTPD_TFTPD_H
 #define TFTPD_TFTPD_H
 
+#include <netinet/in.h>
+
+union sockaddr_uni
+{
+	struct {
+		sa_family_t	si_family;
+		in_port_t		si_port;
+	}										s_si;
+  struct sockaddr     s_sa;
+  struct sockaddr_in  s_in;
+  struct sockaddr_in6 s_in6;
+};
+
+#define SCK(p)					((union sockaddr_uni *)p)
+#define IS_IPv4(p)			(SCK(p)->s_si.si_family == AF_INET)
+#define IS_IPv6(p)			(SCK(p)->s_si.si_family == AF_INET6)
+#define SA_FAMILY(p)		SCK(p)->s_si.si_family
+#define SA_PORT(p)			SCK(p)->s_si.si_port
+#define pSA_ADDR(p)			((void *)(IS_IPv4(p) ? &(SCK(p)->s_in.sin_addr) : &(SCK(p)->s_in6.sin6_addr)))
+#define SA_ADDRLEN(p)		(IS_IPv4(p) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
+
 void set_signal(int, void (*)(int), int);
 void *tfmalloc(size_t);
 char *tfstrdup(const char *);
 
 extern int verbosity;
+extern int ipv6;
 
 #endif
diff -up tftp-hpa-0.48/tftp/main.c.ipv6 tftp-hpa-0.48/tftp/main.c
--- tftp-hpa-0.48/tftp/main.c.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/tftp/main.c	2008-11-21 10:37:18.000000000 +0100
@@ -35,6 +35,7 @@
  */
 
 #include "common/tftpsubs.h"
+#include "tftpd/tftpd.h"
 
 #ifndef lint
 static const char *copyright UNUSED =
@@ -84,7 +85,7 @@ static const struct modes modes[] = {
 #define MODE_NETASCII (&modes[0])
 #define MODE_DEFAULT  MODE_NETASCII
 
-struct	sockaddr_in peeraddr;
+union 	sockaddr_uni peeraddr;
 int	f;
 u_short port;
 int	trace;
@@ -202,7 +203,6 @@ static inline void usage(int errcode)
 int
 main(int argc, char *argv[])
 {
-  struct sockaddr_in s_in;
   int arg;
   static int pargc, peerargc;
   static int iscmd = 0;
@@ -290,17 +290,6 @@ main(int argc, char *argv[])
     sp->s_proto   = (char *)"udp";
   }
   port = sp->s_port;		/* Default port */
-  f = socket(AF_INET, SOCK_DGRAM, 0);
-  if (f < 0) {
-    perror("tftp: socket");
-    exit(EX_OSERR);
-  }
-  bzero((char *)&s_in, sizeof (s_in));
-  s_in.sin_family = AF_INET;
-  if (pick_port_bind(f, &s_in, portrange_from, portrange_to)) {
-    perror("tftp: bind");
-    exit(EX_OSERR);
-  }
   bsd_signal(SIGINT, intr);
 
   if ( peerargc ) {
@@ -380,10 +369,50 @@ getmoreargs(const char *partial, const c
 #endif
 }
 
+int
+getinfo(char *host)
+{
+	struct addrinfo hints, *res;
+  int error, ret = 0;
+  char pbuf[NI_MAXSERV];
+
+	sprintf(pbuf, "%d", ntohs(sp->s_port));
+	memset(&hints, 0, sizeof (struct addrinfo));
+	hints.ai_flags = AI_CANONNAME;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	error = getaddrinfo(host, pbuf, &hints, &res);
+	if (error != 0) {
+		printf("%s: unknown host\n", host);
+		return ret;	
+	}
+
+	for (; res; res = res->ai_next) {
+		f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+
+		if (f > -1) {
+			ret = 1;
+			bzero(&peeraddr, sizeof (union sockaddr_uni));
+			if (res->ai_family == AF_INET)
+				bcopy(res->ai_addr, &peeraddr.s_in, res->ai_addrlen);
+			else if (res->ai_family == AF_INET6)
+				bcopy(res->ai_addr, &peeraddr.s_in6, res->ai_addrlen);
+			else ret = 0;
+
+			if (ret)
+				hostname = xstrdup(res->ai_canonname ? res->ai_canonname : host);
+			break;
+		}
+	}
+	freeaddrinfo(res);
+	return ret;
+}
+
 void
 setpeer(int argc, char *argv[])
 {
-	struct hostent *host;
+	static union sockaddr_uni s_inx;
+	char dbuf[INET6_ADDRSTRLEN];
 
 	if (argc < 2) {
 		getmoreargs("connect ", "(to) ");
@@ -396,15 +425,20 @@ setpeer(int argc, char *argv[])
 		return;
 	}
 
-	host = gethostbyname(argv[1]);
-	if (host == 0) {
-		connected = 0;
-		printf("%s: unknown host\n", argv[1]);
-		return;
+	connected = getinfo(argv[1]);
+
+	// TODO correct this
+  if (f < 0) {
+    perror("tftp: socket");
+    exit(EX_OSERR);
+  }
+
+	bzero(&s_inx, sizeof (union sockaddr_uni));
+	SA_FAMILY(&s_inx) = SA_FAMILY(&peeraddr);
+  if (pick_port_bind(f, &s_inx, portrange_from, portrange_to)) {
+		perror("tftp: bind");
+    exit(EX_OSERR);
 	}
-	peeraddr.sin_family = host->h_addrtype;
-	bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
-	hostname = xstrdup(host->h_name);
 
 	port = sp->s_port;
 	if (argc == 3) {
@@ -427,8 +461,9 @@ setpeer(int argc, char *argv[])
 
 	if (verbose) {
 		printf("Connected to %s (%s), port %u\n",
-		       hostname, inet_ntoa(peeraddr.sin_addr),
-		       (unsigned int)ntohs(port));
+					hostname,
+					inet_ntop(SA_FAMILY(&peeraddr), pSA_ADDR(&peeraddr), dbuf, INET6_ADDRSTRLEN),
+					(unsigned int)ntohs(port));
 	}
 	connected = 1;
 }
@@ -521,16 +556,7 @@ put(int argc, char *argv[])
 		cp = argv[argc - 1];
 		targ = strchr(cp, ':');
 		*targ++ = 0;
-		hp = gethostbyname(cp);
-		if (hp == NULL) {
-			fprintf(stderr, "tftp: %s: ", cp);
-			herror((char *)NULL);
-			return;
-		}
-		bcopy(hp->h_addr, &peeraddr.sin_addr, hp->h_length);
-		peeraddr.sin_family = hp->h_addrtype;
-		connected = 1;
-		hostname = xstrdup(hp->h_name);
+		connected = getinfo(cp);
 	}
 	if (!connected) {
 		printf("No target machine specified.\n");
@@ -546,7 +572,7 @@ put(int argc, char *argv[])
 		if (verbose)
 			printf("putting %s to %s:%s [%s]\n",
 				cp, hostname, targ, mode->m_mode);
-		peeraddr.sin_port = port;
+		SA_PORT(&peeraddr) = port;
 		tftp_sendfile(fd, targ, mode->m_mode);
 		return;
 	}
@@ -564,7 +590,7 @@ put(int argc, char *argv[])
 		if (verbose)
 			printf("putting %s to %s:%s [%s]\n",
 				argv[n], hostname, targ, mode->m_mode);
-		peeraddr.sin_port = port;
+		SA_PORT(&peeraddr) = port;
 		tftp_sendfile(fd, targ, mode->m_mode);
 	}
 }
@@ -612,17 +638,7 @@ get(int argc, char *argv[])
 			struct hostent *hp;
 
 			*src++ = 0;
-			hp = gethostbyname(argv[n]);
-			if (hp == NULL) {
-				fprintf(stderr, "tftp: %s: ", argv[n]);
-				herror((char *)NULL);
-				continue;
-			}
-			bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
-			    hp->h_length);
-			peeraddr.sin_family = hp->h_addrtype;
-			connected = 1;
-			hostname = xstrdup(hp->h_name);
+			connected = getinfo(argv[n]);
 		}
 		if (argc < 4) {
 			cp = argc == 3 ? argv[2] : tail(src);
@@ -634,7 +650,7 @@ get(int argc, char *argv[])
 			if (verbose)
 				printf("getting from %s:%s to %s [%s]\n",
 					hostname, src, cp, mode->m_mode);
-			peeraddr.sin_port = port;
+			SA_PORT(&peeraddr) = port;
 			tftp_recvfile(fd, src, mode->m_mode);
 			break;
 		}
@@ -647,7 +663,7 @@ get(int argc, char *argv[])
 		if (verbose)
 			printf("getting from %s:%s to %s [%s]\n",
 				hostname, src, cp, mode->m_mode);
-		peeraddr.sin_port = port;
+		SA_PORT(&peeraddr) = port;
 		tftp_recvfile(fd, src, mode->m_mode);
 	}
 }
diff -up tftp-hpa-0.48/tftp/tftp.c.ipv6 tftp-hpa-0.48/tftp/tftp.c
--- tftp-hpa-0.48/tftp/tftp.c.ipv6	2007-01-31 00:51:05.000000000 +0100
+++ tftp-hpa-0.48/tftp/tftp.c	2008-11-21 10:37:18.000000000 +0100
@@ -35,6 +35,7 @@
  */
 
 #include "common/tftpsubs.h"
+#include "tftpd/tftpd.h"
 
 #ifndef lint
 /* static char sccsid[] = "@(#)tftp.c	8.1 (Berkeley) 6/6/93"; */
@@ -50,7 +51,7 @@ static const char *rcsid UNUSED =
  */
 #include "extern.h"
 
-extern  struct sockaddr_in peeraddr;	/* filled in by main */
+extern  union   sockaddr_uni peeraddr;	/* filled in by main */
 extern  int     f;			/* the opened socket */
 extern  int     trace;
 extern  int     verbose;
@@ -84,7 +85,7 @@ tftp_sendfile(int fd, const char *name, 
 	volatile u_short block;
 	volatile int size, convert;
 	volatile off_t amount;
-	struct sockaddr_in from;
+	union sockaddr_uni from;
 	socklen_t fromlen;
 	FILE *file;
 	u_short ap_opcode, ap_block;
@@ -118,16 +119,19 @@ tftp_sendfile(int fd, const char *name, 
 		if (trace)
 			tpacket("sent", dp, size + 4);
 		n = sendto(f, dp, size + 4, 0,
-		    (struct sockaddr *)&peeraddr, sizeof(peeraddr));
+		    (struct sockaddr *)&peeraddr, SA_ADDRLEN(&peeraddr));
+
 		if (n != size + 4) {
 			perror("tftp: sendto");
 			goto abort;
 		}
+
 		read_ahead(file, convert);
 		for ( ; ; ) {
 			alarm(rexmtval);
 			do {
-				fromlen = sizeof(from);
+				from.s_si.si_family = peeraddr.s_si.si_family;
+				fromlen = SA_ADDRLEN(&from);
 				n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
 				    (struct sockaddr *)&from, &fromlen);
 			} while (n <= 0);
@@ -136,7 +140,9 @@ tftp_sendfile(int fd, const char *name, 
 				perror("tftp: recvfrom");
 				goto abort;
 			}
-			peeraddr.sin_port = from.sin_port;	/* added */
+
+			SA_PORT(&peeraddr) = SA_PORT(&from);/* added */
+			
 			if (trace)
 				tpacket("received", ap, n);
 			/* should verify packet came from server */
@@ -192,7 +198,7 @@ tftp_recvfile(int fd, const char *name, 
 	volatile u_short block;
 	volatile int size, firsttrip;
 	volatile unsigned long amount;
-	struct sockaddr_in from;
+	union sockaddr_uni from;
 	socklen_t fromlen;
 	FILE *file;
 	volatile int convert;		/* true if converting crlf -> lf */
@@ -224,7 +230,7 @@ send_ack:
 		if (trace)
 			tpacket("sent", ap, size);
 		if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
-		    sizeof(peeraddr)) != size) {
+		    SA_ADDRLEN(&peeraddr)) != size) {
 			alarm(0);
 			perror("tftp: sendto");
 			goto abort;
@@ -233,7 +239,8 @@ send_ack:
 		for ( ; ; ) {
 			alarm(rexmtval);
 			do  {
-				fromlen = sizeof(from);
+				SA_FAMILY(&from) = SA_FAMILY(&peeraddr);
+				fromlen = SA_ADDRLEN(&from);
 				n = recvfrom(f, dp, PKTSIZE, 0,
 				    (struct sockaddr *)&from, &fromlen);
 			} while (n <= 0);
@@ -242,7 +249,9 @@ send_ack:
 				perror("tftp: recvfrom");
 				goto abort;
 			}
-			peeraddr.sin_port = from.sin_port;	/* added */
+
+			SA_PORT(&peeraddr) = SA_PORT(&from);/* added */
+
 			if (trace)
 				tpacket("received", dp, n);
 			/* should verify client address */
@@ -282,7 +291,7 @@ abort:						/* ok to ack, since user */
 	ap->th_opcode = htons((u_short)ACK);	/* has seen err msg */
 	ap->th_block = htons((u_short)block);
 	(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
-	    sizeof(peeraddr));
+	    SA_ADDRLEN(&peeraddr));
 	write_behind(file, convert);		/* flush last buffer */
 	fclose(file);
 	stopclock();
@@ -290,7 +299,6 @@ abort:						/* ok to ack, since user */
 		printstats("Received", amount);
 }
 
-static int
 makerequest(int request, const char *name,
 	    struct tftphdr *tp, const char *mode)
 {
@@ -359,7 +367,7 @@ nak(int error, const char *msg)
   if (trace)
     tpacket("sent", tp, length);
   if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
-	     sizeof(peeraddr)) != length)
+	     SA_ADDRLEN(&peeraddr)) != length)
     perror("nak");
 }
 
diff -up tftp-hpa-0.48/tftp-xinetd.ipv6 tftp-hpa-0.48/tftp-xinetd
--- tftp-hpa-0.48/tftp-xinetd.ipv6	2008-11-21 10:37:18.000000000 +0100
+++ tftp-hpa-0.48/tftp-xinetd	2008-11-21 10:40:30.000000000 +0100
@@ -3,6 +3,11 @@
 #	protocol.  The tftp protocol is often used to boot diskless \
 #	workstations, download configuration files to network-aware printers, \
 #	and to start the installation process for some operating systems.
+#
+# IPv6 support
+# server = -6 -s /var/lib/tftpboot
+# flags  = IPv6
+#
 service tftp
 {
 	socket_type		= dgram


Index: tftp.spec
===================================================================
RCS file: /cvs/extras/rpms/tftp/F-9/tftp.spec,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -r1.46 -r1.47
--- tftp.spec	21 May 2008 21:35:39 -0000	1.46
+++ tftp.spec	21 Nov 2008 10:04:18 -0000	1.47
@@ -3,7 +3,7 @@
 Summary: The client for the Trivial File Transfer Protocol (TFTP)
 Name: tftp
 Version: %{tftp_hpa_version}
-Release: 6%{?dist}
+Release: 7%{?dist}
 License: BSD
 Group: Applications/Internet
 Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa-%{tftp_hpa_version}.tar.gz
@@ -12,6 +12,7 @@
 Patch0: tftp-0.40-remap.patch
 Patch2: tftp-hpa-0.39-tzfix.patch
 Patch3: tftp-0.42-tftpboot.patch
+Patch4: tftp-hpa-0.48-ipv6.patch
 
 BuildRequires: tcp_wrappers-devel readline-devel
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -43,6 +44,7 @@
 %patch0 -p1 -b .zero
 %patch2 -p1 -b .tzfix
 %patch3 -p1 -b .tftpboot
+%patch4 -p1 -b .ipv6
 
 %build
 
@@ -88,6 +90,9 @@
 %{_mandir}/man8/*
 
 %changelog
+* Fri Nov 21 2008 Jiri Skala <jskala at redhat.com> - 0.48-7
+- #461525 - tftp server and client support IPv6 now
+
 * Wed May 21 2008 Warren Togami <wtogami at redhat.com. - 0.48-6
 - undo symlink stuff completely because they are problematic
   See Bug #447135 for details.




More information about the fedora-extras-commits mailing list