summaryrefslogtreecommitdiffstats
path: root/usr.bin/tftp
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2002-04-11 17:14:22 +0000
committerume <ume@FreeBSD.org>2002-04-11 17:14:22 +0000
commit4f51ffc3fede007b2d1c6ce56bdf217f700eb1c7 (patch)
tree17221edddfe751134988e362f0829a38aa1ab240 /usr.bin/tftp
parentf8786d960f554dc901bb184a3bf33ca3ebf0eea2 (diff)
downloadFreeBSD-src-4f51ffc3fede007b2d1c6ce56bdf217f700eb1c7.zip
FreeBSD-src-4f51ffc3fede007b2d1c6ce56bdf217f700eb1c7.tar.gz
IPv6 support for tftp/tftpd.
Obtained from: KAME MFC after: 2 weeks
Diffstat (limited to 'usr.bin/tftp')
-rw-r--r--usr.bin/tftp/main.c167
-rw-r--r--usr.bin/tftp/tftp.17
-rw-r--r--usr.bin/tftp/tftp.c73
-rw-r--r--usr.bin/tftp/tftpsubs.c2
4 files changed, 155 insertions, 94 deletions
diff --git a/usr.bin/tftp/main.c b/usr.bin/tftp/main.c
index 38b376c..251abf5 100644
--- a/usr.bin/tftp/main.c
+++ b/usr.bin/tftp/main.c
@@ -77,9 +77,8 @@ __FBSDID("$FreeBSD$");
#define MAXLINE 200
#define TIMEOUT 5 /* secs between rexmt's */
-struct sockaddr_in peeraddr;
+struct sockaddr_storage peeraddr;
int f;
-short port;
int trace;
int verbose;
int connected;
@@ -88,7 +87,6 @@ char line[MAXLINE];
int margc;
char *margv[20];
jmp_buf toplevel;
-struct servent *sp;
void get(int, char **);
void help(int, char **);
@@ -98,6 +96,7 @@ void put(int, char **);
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 **);
@@ -160,18 +159,7 @@ main(argc, argv)
int argc;
char *argv[];
{
- struct sockaddr_in lsin;
-
- 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 *)&lsin, sizeof(lsin));
- lsin.sin_family = AF_INET;
- if (bind(f, (struct sockaddr *)&lsin, sizeof(lsin)) < 0)
- err(1, "bind");
+ f = -1;
strcpy(mode, "netascii");
signal(SIGINT, intr);
if (argc > 1) {
@@ -187,11 +175,78 @@ main(argc, argv)
char hostname[MAXHOSTNAMELEN];
void
+setpeer0(host, port)
+ char *host;
+ char *port;
+{
+ 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
setpeer(argc, argv)
int argc;
char *argv[];
{
- struct hostent *host;
if (argc < 2) {
strcpy(line, "Connect ");
@@ -205,34 +260,10 @@ setpeer(argc, argv)
printf("usage: %s host-name [port]\n", argv[0]);
return;
}
- host = gethostbyname(argv[1]);
- if (host) {
- peeraddr.sin_family = host->h_addrtype;
- bcopy(host->h_addr, &peeraddr.sin_addr,
- MIN(sizeof(peeraddr.sin_addr), (size_t)host->h_length));
- strncpy(hostname, host->h_name, sizeof(hostname));
- } else {
- peeraddr.sin_family = AF_INET;
- peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
- if (peeraddr.sin_addr.s_addr == INADDR_NONE) {
- connected = 0;
- printf("%s: unknown host\n", argv[1]);
- return;
- }
- strncpy(hostname, argv[1], sizeof(hostname));
- }
- hostname[sizeof(hostname) - 1] = '\0';
- port = sp->s_port;
- if (argc == 3) {
- port = atoi(argv[2]);
- if (port < 0) {
- printf("%s: bad port number\n", argv[2]);
- connected = 0;
- return;
- }
- port = htons(port);
- }
- connected = 1;
+ if (argc == 3)
+ setpeer0(argv[1], NULL);
+ else
+ setpeer0(argv[1], argv[2]);
}
struct modes {
@@ -336,9 +367,8 @@ put(argc, argv)
return;
}
targ = argv[argc - 1];
- if (index(argv[argc - 1], ':')) {
+ if (rindex(argv[argc - 1], ':')) {
char *lcp;
- struct hostent *hp;
for (n = 1; n < argc - 1; n++)
if (index(argv[n], ':')) {
@@ -346,20 +376,13 @@ put(argc, argv)
return;
}
lcp = argv[argc - 1];
- targ = index(lcp, ':');
+ targ = rindex(lcp, ':');
*targ++ = 0;
- hp = gethostbyname(lcp);
- if (hp == NULL) {
- fprintf(stderr, "tftp: %s: ", lcp);
- herror((char *)NULL);
- return;
+ if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
+ lcp[strlen(lcp) - 1] = '\0';
+ lcp++;
}
- bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
- MIN(sizeof(peeraddr.sin_addr), (size_t)hp->h_length));
- peeraddr.sin_family = hp->h_addrtype;
- connected = 1;
- strncpy(hostname, hp->h_name, sizeof(hostname));
- hostname[sizeof(hostname) - 1] = '\0';
+ setpeer0(lcp, NULL);
}
if (!connected) {
printf("No target machine specified.\n");
@@ -375,7 +398,6 @@ put(argc, argv)
if (verbose)
printf("putting %s to %s:%s [%s]\n",
cp, hostname, targ, mode);
- peeraddr.sin_port = port;
xmitfile(fd, targ, mode);
return;
}
@@ -393,7 +415,6 @@ put(argc, argv)
if (verbose)
printf("putting %s to %s:%s [%s]\n",
argv[n], hostname, targ, mode);
- peeraddr.sin_port = port;
xmitfile(fd, targ, mode);
}
}
@@ -433,31 +454,27 @@ get(argc, argv)
}
if (!connected) {
for (n = 1; n < argc ; n++)
- if (index(argv[n], ':') == 0) {
+ if (rindex(argv[n], ':') == 0) {
getusage(argv[0]);
return;
}
}
for (n = 1; n < argc ; n++) {
- src = index(argv[n], ':');
+ src = rindex(argv[n], ':');
if (src == NULL)
src = argv[n];
else {
- struct hostent *hp;
+ char *lcp;
*src++ = 0;
- hp = gethostbyname(argv[n]);
- if (hp == NULL) {
- fprintf(stderr, "tftp: %s: ", argv[n]);
- herror((char *)NULL);
- continue;
+ lcp = argv[n];
+ if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
+ lcp[strlen(lcp) - 1] = '\0';
+ lcp++;
}
- bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
- MIN(sizeof(peeraddr.sin_addr), (size_t)hp->h_length));
- peeraddr.sin_family = hp->h_addrtype;
- connected = 1;
- strncpy(hostname, hp->h_name, sizeof(hostname));
- hostname[sizeof(hostname) - 1] = '\0';
+ setpeer0(lcp, NULL);
+ if (!connected)
+ continue;
}
if (argc < 4) {
cp = argc == 3 ? argv[2] : tail(src);
@@ -469,7 +486,6 @@ get(argc, 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;
}
@@ -482,7 +498,6 @@ get(argc, 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 a09cf37..7f21590 100644
--- a/usr.bin/tftp/tftp.1
+++ b/usr.bin/tftp/tftp.1
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1990, 1993, 1994
+.\" $NetBSD: tftp.1,v 1.11 1999/12/13 04:44:55 itojun Exp $
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -137,6 +137,11 @@ If the remote-directory form is used, the remote host is
assumed to be a
.Tn UNIX
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
.It Cm quit
Exit
diff --git a/usr.bin/tftp/tftp.c b/usr.bin/tftp/tftp.c
index 7b4eb95..b2cc868 100644
--- a/usr.bin/tftp/tftp.c
+++ b/usr.bin/tftp/tftp.c
@@ -61,11 +61,12 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <netdb.h>
#include "extern.h"
#include "tftpsubs.h"
-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;
@@ -78,13 +79,14 @@ int timeout;
jmp_buf toplevel;
jmp_buf timeoutbuf;
-static void nak(int);
+static void nak(int, struct sockaddr *);
static int makerequest(int, const char *, struct tftphdr *, const char *);
static void printstats(const char *, unsigned long);
static void startclock(void);
static void stopclock(void);
static void timer(int);
static void tpacket(const char *, struct tftphdr *, int);
+static int cmpport(struct sockaddr *, struct sockaddr *);
/*
* Send the requested file.
@@ -101,9 +103,11 @@ xmitfile(fd, name, mode)
volatile unsigned short block;
volatile int size, convert;
volatile unsigned long amount;
- struct sockaddr_in from;
+ struct sockaddr_storage from;
int fromlen;
FILE *file;
+ struct sockaddr_storage peer;
+ struct sockaddr_storage serv; /* valid server port number */
startclock(); /* start stat's clock */
dp = r_init(); /* reset fillbuf/read-ahead code */
@@ -112,6 +116,8 @@ xmitfile(fd, name, mode)
convert = !strcmp(mode, "netascii");
block = 0;
amount = 0;
+ memcpy(&peer, &peeraddr, peeraddr.ss_len);
+ memset(&serv, 0, sizeof(serv));
signal(SIGALRM, timer);
do {
@@ -121,7 +127,7 @@ xmitfile(fd, name, mode)
/* size = read(fd, dp->th_data, SEGSIZE); */
size = readit(file, &dp, convert);
if (size < 0) {
- nak(errno + 100);
+ nak(errno + 100, (struct sockaddr *)&peer);
break;
}
dp->th_opcode = htons((u_short)DATA);
@@ -133,7 +139,7 @@ send_data:
if (trace)
tpacket("sent", dp, size + 4);
n = sendto(f, dp, size + 4, 0,
- (struct sockaddr *)&peeraddr, sizeof(peeraddr));
+ (struct sockaddr *)&peer, peer.ss_len);
if (n != size + 4) {
warn("sendto");
goto abort;
@@ -151,7 +157,14 @@ send_data:
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);
/* should verify packet came from server */
@@ -207,10 +220,12 @@ recvfile(fd, name, mode)
volatile unsigned short block;
volatile int size, firsttrip;
volatile unsigned long amount;
- struct sockaddr_in from;
+ struct sockaddr_storage from;
int fromlen;
FILE *file;
volatile int convert; /* true if converting crlf -> lf */
+ struct sockaddr_storage peer;
+ struct sockaddr_storage serv; /* valid server port number */
startclock();
dp = w_init();
@@ -220,6 +235,8 @@ recvfile(fd, name, mode)
block = 1;
firsttrip = 1;
amount = 0;
+ memcpy(&peer, &peeraddr, peeraddr.ss_len);
+ memset(&serv, 0, sizeof(serv));
signal(SIGALRM, timer);
do {
@@ -237,8 +254,8 @@ recvfile(fd, name, mode)
send_ack:
if (trace)
tpacket("sent", ap, size);
- if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
- sizeof(peeraddr)) != size) {
+ if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer,
+ peer.ss_len) != size) {
alarm(0);
warn("sendto");
goto abort;
@@ -256,7 +273,14 @@ send_ack:
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);
/* should verify client address */
@@ -288,7 +312,7 @@ send_ack:
/* size = write(fd, dp->th_data, n - 4); */
size = writeit(file, &dp, n - 4, convert);
if (size < 0) {
- nak(errno + 100);
+ nak(errno + 100, (struct sockaddr *)&peer);
break;
}
amount += size;
@@ -296,8 +320,8 @@ send_ack:
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));
+ (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
+ peer.ss_len);
write_behind(file, convert); /* flush last buffer */
fclose(file);
stopclock();
@@ -347,8 +371,9 @@ struct errmsg {
* offset by 100.
*/
static void
-nak(error)
+nak(error, peer)
int error;
+ struct sockaddr *peer;
{
struct errmsg *pe;
struct tftphdr *tp;
@@ -368,8 +393,7 @@ nak(error)
length = strlen(pe->e_msg) + 4;
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");
}
@@ -457,3 +481,20 @@ timer(sig)
}
longjmp(timeoutbuf, 1);
}
+
+static int
+cmpport(sa, sb)
+ 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;
+}
diff --git a/usr.bin/tftp/tftpsubs.c b/usr.bin/tftp/tftpsubs.c
index 50ff82d..a3673d8 100644
--- a/usr.bin/tftp/tftpsubs.c
+++ b/usr.bin/tftp/tftpsubs.c
@@ -260,7 +260,7 @@ synchnet(f)
{
int i, j = 0;
char rbuf[PKTSIZE];
- struct sockaddr_in from;
+ struct sockaddr_storage from;
int fromlen;
while (1) {
OpenPOWER on IntegriCloud