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.