can anyone test this diff? your feedback will be most welcome
On Wed, Sep 08, 2010 at 11:51:11AM -0300, Gleydson Soares wrote:
> hi,
> 
> - ipv6 support for tftp client.
> 
> based on an old itojun's diff.

Index: tftpsubs.c
===================================================================
RCS file: /cvs/src/usr.bin/tftp/tftpsubs.c,v
retrieving revision 1.14
diff -u -r1.14 tftpsubs.c
--- tftpsubs.c  27 Oct 2009 23:59:44 -0000      1.14
+++ tftpsubs.c  8 Sep 2010 14:01:19 -0000
@@ -258,7 +258,7 @@
 {
        int                     i, j = 0;
        char                    rbuf[SEGSIZE_MIN];
-       struct sockaddr_in      from;
+       struct sockaddr_storage from;
        socklen_t               fromlen;
 
        for (;;) {
Index: tftp.c
===================================================================
RCS file: /cvs/src/usr.bin/tftp/tftp.c,v
retrieving revision 1.22
diff -u -r1.22 tftp.c
--- tftp.c      27 Oct 2009 23:59:44 -0000      1.22
+++ tftp.c      8 Sep 2010 14:01:39 -0000
@@ -58,7 +58,7 @@
 #include "tftpsubs.h"
 
 static int     makerequest(int, const char *, struct tftphdr *, const char *);
-static void    nak(int);
+static void    nak(int, struct sockaddr *);
 static void    tpacket(const char *, struct tftphdr *, int);
 static void    startclock(void);
 static void    stopclock(void);
@@ -67,7 +67,7 @@
 static void    oack(struct tftphdr *, int, int);
 static int     oack_set(const char *, const char *);
 
-extern struct sockaddr_in       peeraddr;      /* filled in by main */
+extern struct sockaddr_storage  peeraddr;      /* filled in by main */
 extern int                      f;             /* the opened socket */
 extern int                      trace;
 extern int                      verbose;
@@ -124,7 +124,8 @@
 sendfile(int fd, char *name, char *mode)
 {
        struct tftphdr          *dp, *ap; /* data and ack packets */
-       struct sockaddr_in       from;
+       struct sockaddr_storage  from;
+       struct sockaddr_storage peer;
        struct pollfd            pfd[1];
        unsigned long            amount;
        socklen_t                fromlen;
@@ -138,6 +139,7 @@
        convert = !strcmp(mode, "netascii");
        block = 0;
        amount = 0;
+       memcpy(&peer, &peeraddr, peeraddr.ss_len);
 
        do {
                /* read data from file */
@@ -146,7 +148,7 @@
                else {
                        size = readit(file, &dp, convert, segment_size);
                        if (size < 0) {
-                               nak(errno + 100);
+                               nak(errno + 100, (struct sockaddr *)&peer);
                                break;
                        }
                        dp->th_opcode = htons((u_short)DATA);
@@ -164,8 +166,8 @@
                                if (trace)
                                        tpacket("sent", dp, size + 4);
                                if (sendto(f, dp, size + 4, 0,
-                                   (struct sockaddr *)&peeraddr,
-                                   sizeof(peeraddr)) != size + 4) {
+                                   (struct sockaddr *)&peer,
+                                   peer.ss_len) != size + 4) {
                                        warn("sendto");
                                        goto abort;
                                }
@@ -202,7 +204,19 @@
                                warn("recvfrom");
                                goto abort;
                        }
-                       peeraddr.sin_port = from.sin_port;      /* added */
+                       switch (peer.ss_family) {       /* added */
+                       case AF_INET:
+                               ((struct sockaddr_in *)&peer)->sin_port =
+                               ((struct sockaddr_in *)&from)->sin_port;
+                       break;
+                       case AF_INET6:
+                               ((struct sockaddr_in6 *)&peer)->sin6_port =
+                               ((struct sockaddr_in6 *)&from)->sin6_port;
+                       break;
+                       default:
+                               /* unsupported */
+                       break;
+                       }
                        if (trace)
                                tpacket("received", ap, n);
 
@@ -256,7 +270,8 @@
 recvfile(int fd, char *name, char *mode)
 {
        struct tftphdr          *dp, *ap; /* data and ack packets */
-       struct sockaddr_in       from;
+       struct sockaddr_storage  from;
+       struct sockaddr_storage peer;
        struct pollfd            pfd[1];
        unsigned long            amount;
        socklen_t                fromlen;
@@ -273,6 +288,7 @@
        block = 1;
        amount = 0;
        firsttrip = 1;
+       memcpy(&peer, &peeraddr, peeraddr.ss_len);
 
 options:
        do {
@@ -298,8 +314,8 @@
                                if (trace)
                                        tpacket("sent", ap, size);
                                if (sendto(f, ackbuf, size, 0,
-                                   (struct sockaddr *)&peeraddr,
-                                   sizeof(peeraddr)) != size) {
+                                   (struct sockaddr *)&peer,
+                                   peer.ss_len) != size) {
                                        warn("sendto");
                                        goto abort;
                                }
@@ -335,7 +351,19 @@
                                warn("recvfrom");
                                goto abort;
                        }
-                       peeraddr.sin_port = from.sin_port;      /* added */
+                       switch (peer.ss_family) {       /* added */
+                       case AF_INET:
+                               ((struct sockaddr_in *)&peer)->sin_port =
+                               ((struct sockaddr_in *)&from)->sin_port;
+                       break;
+                       case AF_INET6:
+                               ((struct sockaddr_in6 *)&peer)->sin6_port =
+                               ((struct sockaddr_in6 *)&from)->sin6_port;
+                       break;
+                       default:
+                               /* unsupported */
+                       break;
+                       }
                        if (trace)
                                tpacket("received", dp, n);
 
@@ -371,7 +399,7 @@
                /* write data to file */
                size = writeit(file, &dp, n - 4, convert);
                if (size < 0) {
-                       nak(errno + 100);
+                       nak(errno + 100, (struct sockaddr *)&peer);
                        break;
                }
                amount += size;
@@ -381,8 +409,8 @@
        /* ok to ack, since user has seen err msg */
        ap->th_opcode = htons((u_short)ACK);
        ap->th_block = htons((u_short)block);
-       (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
-           sizeof(peeraddr));
+       (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
+           peer.ss_len);
        write_behind(file, convert);    /* flush last buffer */
 
        fclose(file);
@@ -436,7 +464,7 @@
  * offset by 100.
  */
 static void
-nak(int error)
+nak(int error, struct sockaddr *peer)
 {
        struct errmsg   *pe;
        struct tftphdr  *tp;
@@ -457,8 +485,8 @@
                length = packet_size;
        if (trace)
                tpacket("sent", tp, length);
-       if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
-           sizeof(peeraddr)) != length)
+       if (sendto(f, ackbuf, length, 0, peer,
+           peer->sa_len) != length)
                warn("nak");
 }
 
@@ -588,6 +616,8 @@
 {
        int              i, n;
        const char      *errstr;
+       struct sockaddr_storage peer;
+       memcpy(&peer, &peeraddr, peeraddr.ss_len);
 
        for (i = 0; options[i].o_type != NULL; i++) {
                if (!strcasecmp(options[i].o_type, option)) {
@@ -600,7 +630,7 @@
                                    &errstr);
                                if (errstr || rexmtval != n ||
                                    opt_tout == 0) {
-                                       nak(EOPTNEG);
+                                       nak(EOPTNEG, (struct sockaddr *)&peer);
                                        intrflag = 1;
                                        return (-1);
                                }
@@ -612,7 +642,7 @@
                                    &errstr);
                                if (errstr || opt_blksize != n ||
                                    opt_blksize == 0) {
-                                       nak(EOPTNEG);   
+                                       nak(EOPTNEG, (struct sockaddr *)&peer);
                                        intrflag = 1;
                                        return (-1);
                                }
Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/tftp/main.c,v
retrieving revision 1.30
diff -u -r1.30 main.c
--- main.c      27 Oct 2009 23:59:44 -0000      1.30
+++ main.c      8 Sep 2010 14:02:04 -0000
@@ -68,6 +68,7 @@
 void                    quit(int, char **);
 void                    setascii(int, char **);
 void                    setbinary(int, char **);
+void                    setpeer0(char *, char *);
 void                    setpeer(int, char **);
 void                    setrexmt(int, char **);
 void                    settimeout(int, char **);
@@ -86,9 +87,8 @@
 struct cmd             *getcmd(char *);
 char                   *tail(char *);
 
-struct sockaddr_in      peeraddr;
+struct sockaddr_storage         peeraddr;
 int                     f;
-short                   port;
 int                     trace;
 int                     verbose;
 int                     connected;
@@ -98,7 +98,6 @@
 char                   *margv[MAXARGV+1];
 char                   *prompt = "tftp";
 void                    intr(int);
-struct servent         *sp;
 int                     rexmtval = TIMEOUT;
 int                     maxtimeout = 5 * TIMEOUT;
 char                    hostname[MAXHOSTNAMELEN];
@@ -170,19 +169,7 @@
 int
 main(int argc, char *argv[])
 {
-       struct sockaddr_in      s_in;
-
-       /* socket, bind */
-       sp = getservbyname("tftp", "udp");
-       if (sp == 0)
-               errx(1, "udp/tftp: unknown service");
-       f = socket(AF_INET, SOCK_DGRAM, 0);
-       if (f < 0)
-               err(3, "socket");
-       bzero((char *)&s_in, sizeof(s_in));
-       s_in.sin_family = AF_INET;
-       if (bind(f, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
-               err(1, "bind");
+       f = -1;
 
        /* set default transfer mode */
        strlcpy(mode, "netascii", sizeof(mode));
@@ -205,11 +192,69 @@
 }
 
 void
-setpeer(int argc, char *argv[])
+setpeer0(char *host, char *port)
 {
-       struct hostent  *host;
-       const char      *errstr;
+       struct addrinfo hints, *res0, *res;
+       int error;
+       struct sockaddr_storage ss;
+       char *cause = "unknown";
+
+       if (connected) {
+               close(f);
+               f = -1;
+               connected = 0;
+       }
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_DGRAM;
+       hints.ai_protocol = IPPROTO_UDP;
+       hints.ai_flags = AI_CANONNAME;
+       if (!port)
+               port = "tftp";
+       error = getaddrinfo(host, port, &hints, &res0);
+       if (error) {
+               warnx("%s", gai_strerror(error));
+               return;
+       }
+
+       for (res = res0; res; res = res->ai_next) {
+               f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+               if (f < 0) {
+                       cause = "socket";
+                       continue;
+               }
+
+               memset(&ss, 0, sizeof(ss));
+               ss.ss_family = res->ai_family;
+               ss.ss_len = res->ai_addrlen;
+               if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
+                       cause = "bind";
+                       close(f);
+                       f = -1;
+                       continue;
+               }
+
+               break;
+       }
+
+       if (f < 0)
+               warn("%s", cause);
+       else {
+               memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+               if (res->ai_canonname) {
+                       (void) strncpy(hostname, res->ai_canonname,
+                               sizeof(hostname));
+               } else
+                       (void) strncpy(hostname, host, sizeof(hostname));
+                       hostname[sizeof(hostname)-1] = 0;
+                       connected = 1;
+       }
+}
 
+void
+setpeer(int argc, char *argv[])
+{
        if (argc < 2) {
                strlcpy(line, "Connect ", sizeof(line));
                printf("(to) ");
@@ -223,32 +268,10 @@
                printf("usage: %s [host [port]]\n", argv[0]);
                return;
        }
-       if (inet_aton(argv[1], &peeraddr.sin_addr) != 0) {
-               peeraddr.sin_family = AF_INET;
-               (void)strncpy(hostname, argv[1], sizeof(hostname));
-               hostname[sizeof(hostname) - 1] = '\0';
-       } else {
-               host = gethostbyname(argv[1]);
-               if (host == 0) {
-                       connected = 0;
-                       printf("%s: unknown host\n", argv[1]);
-                       return;
-               }
-               peeraddr.sin_family = host->h_addrtype;
-               bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
-               (void)strlcpy(hostname, host->h_name, sizeof(hostname));
-       }
-       port = sp->s_port;
-       if (argc == 3) {
-               port = strtonum(argv[2], 1, 65535, &errstr);
-               if (errstr) {
-                       printf("%s: port number is %s\n", argv[2], errstr);
-                       connected = 0;
-                       return;
-               }
-               port = htons(port);
-       }
-       connected = 1;
+       if (argc == 3)
+               setpeer0(argv[1], NULL);
+       else
+               setpeer0(argv[1], argv[2]);
 }
 
 void
@@ -331,8 +354,7 @@
                return;
        }
        targ = argv[argc - 1];
-       if (strchr(argv[argc - 1], ':')) {
-               struct hostent  *hp;
+       if (strrchr(argv[argc - 1], ':')) {
 
                for (n = 1; n < argc - 1; n++)
                        if (strchr(argv[n], ':')) {
@@ -340,18 +362,13 @@
                                return;
                        }
                cp = argv[argc - 1];
-               targ = strchr(cp, ':');
+               targ = strrchr(cp, ':');
                *targ++ = 0;
-               hp = gethostbyname(cp);
-               if (hp == NULL) {
-                       warnx("%s: %s", cp, hstrerror(h_errno));
-                       return;
+               if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
+                       cp[strlen(cp) - 1] = '\0';
+                       cp++;
                }
-               bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
-               peeraddr.sin_family = hp->h_addrtype;
-               connected = 1;
-               port = sp->s_port;
-               strlcpy(hostname, hp->h_name, sizeof(hostname));
+               setpeer0(cp, NULL);
        }
        if (!connected) {
                printf("No target machine specified.\n");
@@ -367,7 +384,6 @@
                if (verbose)
                        printf("putting %s to %s:%s [%s]\n",
                            cp, hostname, targ, mode);
-               peeraddr.sin_port = port;
                sendfile(fd, targ, mode);
                return;
        }
@@ -388,7 +404,6 @@
                if (verbose)
                        printf("putting %s to %s:%s [%s]\n",
                            argv[n], hostname, cp, mode);
-               peeraddr.sin_port = port;
                sendfile(fd, cp, mode);
                free(cp);
        }
@@ -428,29 +443,27 @@
        }
        if (!connected) {
                for (n = 1; n < argc; n++)
-                       if (strchr(argv[n], ':') == 0) {
+                       if (strrchr(argv[n], ':') == 0) {
                                getusage(argv[0]);
                                return;
                        }
        }
        for (n = 1; n < argc; n++) {
-               src = strchr(argv[n], ':');
+               src = strrchr(argv[n], ':');
                if (src == NULL)
                        src = argv[n];
                else {
-                       struct hostent  *hp;
+                       char *cp;
 
                        *src++ = 0;
-                       hp = gethostbyname(argv[n]);
-                       if (hp == NULL) {
-                               warnx("%s: %s", argv[n], hstrerror(h_errno));
-                               continue;
+                       cp = argv[n];
+                       if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
+                               cp[strlen(cp) - 1] = '\0';
+                               cp++;
                        }
-                       bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
-                           hp->h_length);
-                       peeraddr.sin_family = hp->h_addrtype;
-                       connected = 1;
-                       strlcpy(hostname, hp->h_name, sizeof(hostname));
+                       setpeer0(cp, NULL);
+                       if (!connected)
+                               continue;
                }
                if (argc < 4) {
                        cp = argc == 3 ? argv[2] : tail(src);
@@ -462,7 +475,6 @@
                        if (verbose)
                                printf("getting from %s:%s to %s [%s]\n",
                                    hostname, src, cp, mode);
-                       peeraddr.sin_port = port;
                        recvfile(fd, src, mode);
                        break;
                }
@@ -475,7 +487,6 @@
                if (verbose)
                        printf("getting from %s:%s to %s [%s]\n",
                            hostname, src, cp, mode);
-               peeraddr.sin_port = port;
                recvfile(fd, src, mode);
        }
 }
Index: tftp.1
===================================================================
RCS file: /cvs/src/usr.bin/tftp/tftp.1,v
retrieving revision 1.18
diff -u -r1.18 tftp.1
--- tftp.1      22 Oct 2009 12:35:53 -0000      1.18
+++ tftp.1      8 Sep 2010 14:03:02 -0000
@@ -166,6 +166,11 @@
 argument is used, the remote host is assumed to be a
 .Ux
 machine.
+If you need to specify IPv6 numeric address to
+.Ar hosts ,
+wrap them using square bracket like
+.Ar [hosts]:filename
+to disambiguate the colon.
 .Pp
 Note that files may only be written to if they already exist on the
 remote host and are publicly writable.

Reply via email to