summaryrefslogtreecommitdiff
path: root/usr.bin/tftp
diff options
context:
space:
mode:
authorGleydson Soares <gsoares@cvs.openbsd.org>2012-05-01 04:23:22 +0000
committerGleydson Soares <gsoares@cvs.openbsd.org>2012-05-01 04:23:22 +0000
commitc857126767e7c723f236a643ac2166ea71fbb530 (patch)
treec5d15e587540e72973b3951e1b7cf80e6d87a7cc /usr.bin/tftp
parent6fb575d2c3daf3def4e179b9795f497c735d9340 (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.c169
-rw-r--r--usr.bin/tftp/tftp.110
-rw-r--r--usr.bin/tftp/tftp.c78
-rw-r--r--usr.bin/tftp/tftpsubs.c4
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 (;;) {