diff options
author | Gleydson Soares <gsoares@cvs.openbsd.org> | 2012-05-01 04:23:22 +0000 |
---|---|---|
committer | Gleydson Soares <gsoares@cvs.openbsd.org> | 2012-05-01 04:23:22 +0000 |
commit | c857126767e7c723f236a643ac2166ea71fbb530 (patch) | |
tree | c5d15e587540e72973b3951e1b7cf80e6d87a7cc /usr.bin/tftp | |
parent | 6fb575d2c3daf3def4e179b9795f497c735d9340 (diff) |
IPv6 support; mostly a sync with netbsd code done by itojun@
tweaks/OK henning@ sthen@ jmc@ jasper@
feedback/tests weerd@ brad@ (thanks)
Diffstat (limited to 'usr.bin/tftp')
-rw-r--r-- | usr.bin/tftp/main.c | 169 | ||||
-rw-r--r-- | usr.bin/tftp/tftp.1 | 10 | ||||
-rw-r--r-- | usr.bin/tftp/tftp.c | 78 | ||||
-rw-r--r-- | usr.bin/tftp/tftpsubs.c | 4 |
4 files changed, 160 insertions, 101 deletions
diff --git a/usr.bin/tftp/main.c b/usr.bin/tftp/main.c index fca97b45f15..5df3dfa8df6 100644 --- a/usr.bin/tftp/main.c +++ b/usr.bin/tftp/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.30 2009/10/27 23:59:44 deraadt Exp $ */ +/* $OpenBSD: main.c,v 1.31 2012/05/01 04:23:21 gsoares Exp $ */ /* $NetBSD: main.c,v 1.6 1995/05/21 16:54:10 mycroft Exp $ */ /* @@ -68,7 +68,8 @@ void put(int, char **); void quit(int, char **); void setascii(int, char **); void setbinary(int, char **); -void setpeer(int, char **); +void setpeer(char *, char *); +void parsearg(int, char **); void setrexmt(int, char **); void settimeout(int, char **); void settrace(int, char **); @@ -86,9 +87,8 @@ static __dead void command(void); 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 @@ int margc; char *margv[MAXARGV+1]; char *prompt = "tftp"; void intr(int); -struct servent *sp; int rexmtval = TIMEOUT; int maxtimeout = 5 * TIMEOUT; char hostname[MAXHOSTNAMELEN]; @@ -134,7 +133,7 @@ struct cmd { }; struct cmd cmdtab[] = { - { "connect", chelp, setpeer }, + { "connect", chelp, parsearg }, { "mode", mhelp, modecmd }, { "put", shelp, put }, { "get", rhelp, get }, @@ -170,26 +169,14 @@ struct modes { 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)); /* set peer if given */ if (argc > 1) - setpeer(argc, argv); + parsearg(argc, argv); /* catch SIGINT */ signal(SIGINT, intr); @@ -205,11 +192,73 @@ main(int argc, char *argv[]) } void -setpeer(int argc, char *argv[]) +setpeer(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) { + if (res->ai_addrlen > sizeof(peeraddr)) + continue; + 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 { + /* res->ai_addr <= sizeof(peeraddr) is guaranteed */ + 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; + } + freeaddrinfo(res0); +} + +void +parsearg(int argc, char *argv[]) +{ if (argc < 2) { strlcpy(line, "Connect ", sizeof(line)); printf("(to) "); @@ -223,32 +272,10 @@ setpeer(int argc, char *argv[]) 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 == 2) + setpeer(argv[1], NULL); + else + setpeer(argv[1], argv[2]); } void @@ -331,8 +358,7 @@ put(int argc, char *argv[]) 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 +366,13 @@ put(int argc, char *argv[]) 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)); + setpeer(cp, NULL); } if (!connected) { printf("No target machine specified.\n"); @@ -367,7 +388,6 @@ put(int argc, char *argv[]) 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 +408,6 @@ put(int argc, char *argv[]) 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 +447,27 @@ get(int argc, char *argv[]) } 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)); + setpeer(cp, NULL); + if (!connected) + continue; } if (argc < 4) { cp = argc == 3 ? argv[2] : tail(src); @@ -462,7 +479,6 @@ get(int argc, char *argv[]) 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 +491,6 @@ get(int argc, char *argv[]) if (verbose) printf("getting from %s:%s to %s [%s]\n", hostname, src, cp, mode); - peeraddr.sin_port = port; recvfile(fd, src, mode); } } diff --git a/usr.bin/tftp/tftp.1 b/usr.bin/tftp/tftp.1 index bf9fa831f7f..0a9704ea8d0 100644 --- a/usr.bin/tftp/tftp.1 +++ b/usr.bin/tftp/tftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tftp.1,v 1.19 2012/03/01 03:47:19 dlg Exp $ +.\" $OpenBSD: tftp.1,v 1.20 2012/05/01 04:23:21 gsoares Exp $ .\" $NetBSD: tftp.1,v 1.5 1995/08/18 14:45:44 pk Exp $ .\" .\" Copyright (c) 1990, 1993, 1994 @@ -30,7 +30,7 @@ .\" .\" @(#)tftp.1 8.2 (Berkeley) 4/18/94 .\" -.Dd $Mdocdate: March 1 2012 $ +.Dd $Mdocdate: May 1 2012 $ .Dt TFTP 1 .Os .Sh NAME @@ -119,6 +119,9 @@ When using the argument, the .Ar host will be used as the default host for future transfers. +IPv6 addresses can be specified by enclosing +.Ar host +in square brackets. If .Ar localname is specified, @@ -156,6 +159,9 @@ When using the argument, the .Ar host will be used as the default host for future transfers. +IPv6 addresses can be specified by enclosing +.Ar host +in square brackets. If .Ar remotename is specified, the file is stored remotely as diff --git a/usr.bin/tftp/tftp.c b/usr.bin/tftp/tftp.c index d28e9435ab0..53c59b813b9 100644 --- a/usr.bin/tftp/tftp.c +++ b/usr.bin/tftp/tftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tftp.c,v 1.22 2009/10/27 23:59:44 deraadt Exp $ */ +/* $OpenBSD: tftp.c,v 1.23 2012/05/01 04:23:21 gsoares Exp $ */ /* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $ */ /* @@ -53,12 +53,14 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <netdb.h> #include "extern.h" #include "tftpsubs.h" +static int cmpport(struct sockaddr *, struct sockaddr *); 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 +69,7 @@ static void printtimeout(void); 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 +126,8 @@ void sendfile(int fd, char *name, char *mode) { struct tftphdr *dp, *ap; /* data and ack packets */ - struct sockaddr_in from; + struct sockaddr_storage from, peer; + struct sockaddr_storage serv; /* valid server port number */ struct pollfd pfd[1]; unsigned long amount; socklen_t fromlen; @@ -138,6 +141,8 @@ sendfile(int fd, char *name, char *mode) convert = !strcmp(mode, "netascii"); block = 0; amount = 0; + memcpy(&peer, &peeraddr, peeraddr.ss_len); + memset(&serv, 0, sizeof(serv)); do { /* read data from file */ @@ -146,7 +151,7 @@ sendfile(int fd, char *name, char *mode) 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 +169,8 @@ sendfile(int fd, char *name, char *mode) 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 +207,14 @@ sendfile(int fd, char *name, char *mode) warn("recvfrom"); goto abort; } - peeraddr.sin_port = from.sin_port; /* added */ + if (!serv.ss_family) + serv = from; + else if (!cmpport((struct sockaddr *)&serv, + (struct sockaddr *)&from)) { + warn("server port mismatch"); + goto abort; + } + peer = from; if (trace) tpacket("received", ap, n); @@ -256,7 +268,8 @@ void recvfile(int fd, char *name, char *mode) { struct tftphdr *dp, *ap; /* data and ack packets */ - struct sockaddr_in from; + struct sockaddr_storage from, peer; + struct sockaddr_storage serv; /* valid server port number */ struct pollfd pfd[1]; unsigned long amount; socklen_t fromlen; @@ -273,6 +286,8 @@ recvfile(int fd, char *name, char *mode) block = 1; amount = 0; firsttrip = 1; + memcpy(&peer, &peeraddr, peeraddr.ss_len); + memset(&serv, 0, sizeof(serv)); options: do { @@ -298,8 +313,8 @@ options: 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 +350,14 @@ options: warn("recvfrom"); goto abort; } - peeraddr.sin_port = from.sin_port; /* added */ + if (!serv.ss_family) + serv = from; + else if (!cmpport((struct sockaddr *)&serv, + (struct sockaddr *)&from)) { + warn("server port mismatch"); + goto abort; + } + peer = from; if (trace) tpacket("received", dp, n); @@ -371,7 +393,7 @@ options: /* 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 +403,8 @@ abort: /* 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); @@ -395,6 +417,20 @@ abort: } static int +cmpport(struct sockaddr *sa, struct sockaddr *sb) +{ + char a[NI_MAXSERV], b[NI_MAXSERV]; + if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) + return (0); + if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) + return (0); + if (strcmp(a, b) != 0) + return (0); + + return (1); +} + +static int makerequest(int request, const char *name, struct tftphdr *tp, const char *mode) { @@ -436,7 +472,7 @@ makerequest(int request, const char *name, struct tftphdr *tp, * offset by 100. */ static void -nak(int error) +nak(int error, struct sockaddr *peer) { struct errmsg *pe; struct tftphdr *tp; @@ -457,8 +493,8 @@ nak(int error) 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 +624,8 @@ oack_set(const char *option, const char *value) { 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 +638,7 @@ oack_set(const char *option, const char *value) &errstr); if (errstr || rexmtval != n || opt_tout == 0) { - nak(EOPTNEG); + nak(EOPTNEG, (struct sockaddr *)&peer); intrflag = 1; return (-1); } @@ -612,7 +650,7 @@ oack_set(const char *option, const char *value) &errstr); if (errstr || opt_blksize != n || opt_blksize == 0) { - nak(EOPTNEG); + nak(EOPTNEG, (struct sockaddr *)&peer); intrflag = 1; return (-1); } diff --git a/usr.bin/tftp/tftpsubs.c b/usr.bin/tftp/tftpsubs.c index 9cc615efdcb..85c2e372849 100644 --- a/usr.bin/tftp/tftpsubs.c +++ b/usr.bin/tftp/tftpsubs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tftpsubs.c,v 1.14 2009/10/27 23:59:44 deraadt Exp $ */ +/* $OpenBSD: tftpsubs.c,v 1.15 2012/05/01 04:23:21 gsoares Exp $ */ /* $NetBSD: tftpsubs.c,v 1.3 1994/12/08 09:51:31 jtc Exp $ */ /* @@ -258,7 +258,7 @@ synchnet(int f) { int i, j = 0; char rbuf[SEGSIZE_MIN]; - struct sockaddr_in from; + struct sockaddr_storage from; socklen_t fromlen; for (;;) { |