forked from mirrors/tftp-hpa-google
Add support for IPv6 in the server and client.
Add support for IPv6 in the server and client. You can force the use of IPv4 or IPv6 only with new -4 and -6 commandline options, if IPv6 support was compiled in. Signed-off-by: Karsten Keil <kkeil@suse.de> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
parent
7fe0fb941c
commit
28f22b6591
9 changed files with 574 additions and 185 deletions
135
tftp/main.c
135
tftp/main.c
|
@ -40,7 +40,6 @@
|
|||
*/
|
||||
#include <sys/file.h>
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
#ifdef WITH_READLINE
|
||||
#include <readline/readline.h>
|
||||
#ifdef HAVE_READLINE_HISTORY_H
|
||||
|
@ -72,8 +71,16 @@ static const struct modes modes[] = {
|
|||
#define MODE_NETASCII (&modes[0])
|
||||
#define MODE_DEFAULT MODE_NETASCII
|
||||
|
||||
struct sockaddr_in peeraddr;
|
||||
int f;
|
||||
#ifdef HAVE_IPV6
|
||||
int ai_fam = AF_UNSPEC;
|
||||
int ai_fam_sock = AF_UNSPEC;
|
||||
#else
|
||||
int ai_fam = AF_INET;
|
||||
int ai_fam_sock = AF_INET;
|
||||
#endif
|
||||
|
||||
union sock_addr peeraddr;
|
||||
int f = -1;
|
||||
u_short port;
|
||||
int trace;
|
||||
int verbose;
|
||||
|
@ -184,14 +191,18 @@ const char *program;
|
|||
static inline void usage(int errcode)
|
||||
{
|
||||
fprintf(stderr,
|
||||
#ifdef HAVE_IPV6
|
||||
"Usage: %s [-4][-6][-v][-l][-m mode] [host [port]] [-c command]\n",
|
||||
#else
|
||||
"Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n",
|
||||
#endif
|
||||
program);
|
||||
exit(errcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_in s_in;
|
||||
union sock_addr sa;
|
||||
int arg;
|
||||
static int pargc, peerargc;
|
||||
static int iscmd = 0;
|
||||
|
@ -210,6 +221,14 @@ int main(int argc, char *argv[])
|
|||
if (argv[arg][0] == '-') {
|
||||
for (optx = &argv[arg][1]; *optx; optx++) {
|
||||
switch (*optx) {
|
||||
#ifdef HAVE_IPV6
|
||||
case '4':
|
||||
ai_fam = AF_INET;
|
||||
break;
|
||||
case '6':
|
||||
ai_fam = AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
|
@ -268,6 +287,8 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
ai_fam_sock = ai_fam;
|
||||
|
||||
pargv = argv + arg;
|
||||
pargc = argc - arg;
|
||||
|
||||
|
@ -283,18 +304,7 @@ int main(int argc, char *argv[])
|
|||
sp->s_port = htons(IPPORT_TFTP);
|
||||
sp->s_proto = (char *)"udp";
|
||||
}
|
||||
port = sp->s_port; /* Default port */
|
||||
f = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (f < 0) {
|
||||
perror("tftp: socket");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
bzero((char *)&s_in, sizeof(s_in));
|
||||
s_in.sin_family = AF_INET;
|
||||
if (pick_port_bind(f, &s_in, portrange_from, portrange_to)) {
|
||||
perror("tftp: bind");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
bsd_signal(SIGINT, intr);
|
||||
|
||||
if (peerargc) {
|
||||
|
@ -304,6 +314,21 @@ int main(int argc, char *argv[])
|
|||
setpeer(peerargc, peerargv);
|
||||
}
|
||||
|
||||
if (ai_fam_sock == AF_UNSPEC)
|
||||
ai_fam_sock = AF_INET;
|
||||
|
||||
f = socket(ai_fam_sock, SOCK_DGRAM, 0);
|
||||
if (f < 0) {
|
||||
perror("tftp: socket");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sa.sa_family = ai_fam_sock;
|
||||
if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
|
||||
perror("tftp: bind");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
if (iscmd && pargc) {
|
||||
/* -c specified; execute command and exit */
|
||||
struct cmd *c;
|
||||
|
@ -375,7 +400,7 @@ static void getmoreargs(const char *partial, const char *mprompt)
|
|||
|
||||
void setpeer(int argc, char *argv[])
|
||||
{
|
||||
struct hostent *host;
|
||||
int err;
|
||||
|
||||
if (argc < 2) {
|
||||
getmoreargs("connect ", "(to) ");
|
||||
|
@ -388,16 +413,34 @@ void setpeer(int argc, char *argv[])
|
|||
return;
|
||||
}
|
||||
|
||||
host = gethostbyname(argv[1]);
|
||||
if (host == 0) {
|
||||
peeraddr.sa.sa_family = ai_fam;
|
||||
err = set_sock_addr(argv[1], &peeraddr, &hostname);
|
||||
if (err) {
|
||||
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);
|
||||
hostname = xstrdup(host->h_name);
|
||||
ai_fam = peeraddr.sa.sa_family;
|
||||
if (f == -1) { /* socket not open */
|
||||
ai_fam_sock = ai_fam;
|
||||
} else { /* socket was already open */
|
||||
if (ai_fam_sock != ai_fam) { /* need reopen socken for new family */
|
||||
union sock_addr sa;
|
||||
|
||||
close(f);
|
||||
ai_fam_sock = ai_fam;
|
||||
f = socket(ai_fam_sock, SOCK_DGRAM, 0);
|
||||
if (f < 0) {
|
||||
perror("tftp: socket");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
bzero((char *)&sa, sizeof (sa));
|
||||
sa.sa.sa_family = ai_fam_sock;
|
||||
if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
|
||||
perror("tftp: bind");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
port = sp->s_port;
|
||||
if (argc == 3) {
|
||||
struct servent *usp;
|
||||
|
@ -418,9 +461,13 @@ void setpeer(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if (verbose) {
|
||||
char tmp[INET6_ADDRSTRLEN], *tp;
|
||||
tp = (char *)inet_ntop(peeraddr.sa.sa_family, SOCKADDR_P(&peeraddr),
|
||||
tmp, INET6_ADDRSTRLEN);
|
||||
if (!tp)
|
||||
tp = (char *)"???";
|
||||
printf("Connected to %s (%s), port %u\n",
|
||||
hostname, inet_ntoa(peeraddr.sin_addr),
|
||||
(unsigned int)ntohs(port));
|
||||
hostname, tp, (unsigned int)ntohs(port));
|
||||
}
|
||||
connected = 1;
|
||||
}
|
||||
|
@ -484,7 +531,7 @@ static void settftpmode(const struct modes *newmode)
|
|||
void put(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int n;
|
||||
int n, err;
|
||||
char *cp, *targ;
|
||||
|
||||
if (argc < 2) {
|
||||
|
@ -499,8 +546,6 @@ void put(int argc, char *argv[])
|
|||
}
|
||||
targ = argv[argc - 1];
|
||||
if (!literal && strchr(argv[argc - 1], ':')) {
|
||||
struct hostent *hp;
|
||||
|
||||
for (n = 1; n < argc - 1; n++)
|
||||
if (strchr(argv[n], ':')) {
|
||||
putusage(argv[0]);
|
||||
|
@ -509,16 +554,14 @@ void put(int argc, char *argv[])
|
|||
cp = argv[argc - 1];
|
||||
targ = strchr(cp, ':');
|
||||
*targ++ = 0;
|
||||
hp = gethostbyname(cp);
|
||||
if (hp == NULL) {
|
||||
fprintf(stderr, "tftp: %s: ", cp);
|
||||
herror((char *)NULL);
|
||||
peeraddr.sa.sa_family = ai_fam;
|
||||
err = set_sock_addr(cp, &peeraddr,&hostname);
|
||||
if (err) {
|
||||
connected = 0;
|
||||
return;
|
||||
}
|
||||
bcopy(hp->h_addr, &peeraddr.sin_addr, hp->h_length);
|
||||
peeraddr.sin_family = hp->h_addrtype;
|
||||
ai_fam = peeraddr.sa.sa_family;
|
||||
connected = 1;
|
||||
hostname = xstrdup(hp->h_name);
|
||||
}
|
||||
if (!connected) {
|
||||
printf("No target machine specified.\n");
|
||||
|
@ -535,7 +578,7 @@ void put(int argc, char *argv[])
|
|||
if (verbose)
|
||||
printf("putting %s to %s:%s [%s]\n",
|
||||
cp, hostname, targ, mode->m_mode);
|
||||
peeraddr.sin_port = port;
|
||||
sa_set_port(&peeraddr, port);
|
||||
tftp_sendfile(fd, targ, mode->m_mode);
|
||||
return;
|
||||
}
|
||||
|
@ -554,7 +597,7 @@ void put(int argc, char *argv[])
|
|||
if (verbose)
|
||||
printf("putting %s to %s:%s [%s]\n",
|
||||
argv[n], hostname, targ, mode->m_mode);
|
||||
peeraddr.sin_port = port;
|
||||
sa_set_port(&peeraddr, port);
|
||||
tftp_sendfile(fd, targ, mode->m_mode);
|
||||
}
|
||||
}
|
||||
|
@ -597,19 +640,15 @@ void get(int argc, char *argv[])
|
|||
if (literal || src == NULL)
|
||||
src = argv[n];
|
||||
else {
|
||||
struct hostent *hp;
|
||||
int err;
|
||||
|
||||
*src++ = 0;
|
||||
hp = gethostbyname(argv[n]);
|
||||
if (hp == NULL) {
|
||||
fprintf(stderr, "tftp: %s: ", argv[n]);
|
||||
herror((char *)NULL);
|
||||
peeraddr.sa.sa_family = ai_fam;
|
||||
err = set_sock_addr(argv[n], &peeraddr, &hostname);
|
||||
if (err)
|
||||
continue;
|
||||
}
|
||||
bcopy(hp->h_addr, (caddr_t) & peeraddr.sin_addr, hp->h_length);
|
||||
peeraddr.sin_family = hp->h_addrtype;
|
||||
ai_fam = peeraddr.sa.sa_family;
|
||||
connected = 1;
|
||||
hostname = xstrdup(hp->h_name);
|
||||
}
|
||||
if (argc < 4) {
|
||||
cp = argc == 3 ? argv[2] : tail(src);
|
||||
|
@ -623,7 +662,7 @@ void get(int argc, char *argv[])
|
|||
if (verbose)
|
||||
printf("getting from %s:%s to %s [%s]\n",
|
||||
hostname, src, cp, mode->m_mode);
|
||||
peeraddr.sin_port = port;
|
||||
sa_set_port(&peeraddr, port);
|
||||
tftp_recvfile(fd, src, mode->m_mode);
|
||||
break;
|
||||
}
|
||||
|
@ -638,7 +677,7 @@ void get(int argc, char *argv[])
|
|||
if (verbose)
|
||||
printf("getting from %s:%s to %s [%s]\n",
|
||||
hostname, src, cp, mode->m_mode);
|
||||
peeraddr.sin_port = port;
|
||||
sa_set_port(&peeraddr, port);
|
||||
tftp_recvfile(fd, src, mode->m_mode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
.br
|
||||
.SH DESCRIPTION
|
||||
.B tftp
|
||||
is a client for the IPv4 Trivial file Transfer Protocol, which can be
|
||||
is a client for the Trivial file Transfer Protocol, which can be
|
||||
used to transfer files to and from remote machines, including some
|
||||
very minimalistic, usually embedded, systems. The remote
|
||||
.I host
|
||||
|
@ -55,6 +55,11 @@ as the default host for future transfers (see the
|
|||
command below.)
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-4
|
||||
Connect with IPv4 only, if IPv6 support was compiled in.
|
||||
.TP
|
||||
.B \-6
|
||||
.TP
|
||||
\fB\-c\fP \fIcommand\fP
|
||||
Execute \fIcommand\fP as if it had been entered on the tftp prompt.
|
||||
Must be specified last on the command line.
|
||||
|
|
28
tftp/tftp.c
28
tftp/tftp.c
|
@ -38,8 +38,8 @@
|
|||
*/
|
||||
#include "extern.h"
|
||||
|
||||
extern struct sockaddr_in peeraddr; /* filled in by main */
|
||||
extern int f; /* the opened socket */
|
||||
extern union sock_addr peeraddr; /* filled in by main */
|
||||
extern int f; /* the opened socket */
|
||||
extern int trace;
|
||||
extern int verbose;
|
||||
extern int rexmtval;
|
||||
|
@ -71,7 +71,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
|
|||
volatile u_short block;
|
||||
volatile int size, convert;
|
||||
volatile off_t amount;
|
||||
struct sockaddr_in from;
|
||||
union sock_addr from;
|
||||
socklen_t fromlen;
|
||||
FILE *file;
|
||||
u_short ap_opcode, ap_block;
|
||||
|
@ -105,7 +105,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
|
|||
if (trace)
|
||||
tpacket("sent", dp, size + 4);
|
||||
n = sendto(f, dp, size + 4, 0,
|
||||
(struct sockaddr *)&peeraddr, sizeof(peeraddr));
|
||||
&peeraddr.sa, SOCKLEN(&peeraddr));
|
||||
if (n != size + 4) {
|
||||
perror("tftp: sendto");
|
||||
goto abort;
|
||||
|
@ -116,14 +116,14 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
|
|||
do {
|
||||
fromlen = sizeof(from);
|
||||
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
&from.sa, &fromlen);
|
||||
} while (n <= 0);
|
||||
alarm(0);
|
||||
if (n < 0) {
|
||||
perror("tftp: recvfrom");
|
||||
goto abort;
|
||||
}
|
||||
peeraddr.sin_port = from.sin_port; /* added */
|
||||
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */
|
||||
if (trace)
|
||||
tpacket("received", ap, n);
|
||||
/* should verify packet came from server */
|
||||
|
@ -176,7 +176,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
|
|||
volatile u_short block;
|
||||
volatile int size, firsttrip;
|
||||
volatile unsigned long amount;
|
||||
struct sockaddr_in from;
|
||||
union sock_addr from;
|
||||
socklen_t fromlen;
|
||||
FILE *file;
|
||||
volatile int convert; /* true if converting crlf -> lf */
|
||||
|
@ -207,8 +207,8 @@ void tftp_recvfile(int fd, const char *name, const char *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, &peeraddr.sa,
|
||||
SOCKLEN(&peeraddr)) != size) {
|
||||
alarm(0);
|
||||
perror("tftp: sendto");
|
||||
goto abort;
|
||||
|
@ -219,14 +219,14 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
|
|||
do {
|
||||
fromlen = sizeof(from);
|
||||
n = recvfrom(f, dp, PKTSIZE, 0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
&from.sa, &fromlen);
|
||||
} while (n <= 0);
|
||||
alarm(0);
|
||||
if (n < 0) {
|
||||
perror("tftp: recvfrom");
|
||||
goto abort;
|
||||
}
|
||||
peeraddr.sin_port = from.sin_port; /* added */
|
||||
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */
|
||||
if (trace)
|
||||
tpacket("received", dp, n);
|
||||
/* should verify client address */
|
||||
|
@ -266,7 +266,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
|
|||
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));
|
||||
SOCKLEN(&peeraddr));
|
||||
write_behind(file, convert); /* flush last buffer */
|
||||
fclose(file);
|
||||
stopclock();
|
||||
|
@ -341,8 +341,8 @@ static void nak(int error, const char *msg)
|
|||
|
||||
if (trace)
|
||||
tpacket("sent", tp, length);
|
||||
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
|
||||
sizeof(peeraddr)) != length)
|
||||
if (sendto(f, ackbuf, length, 0, &peeraddr.sa,
|
||||
SOCKLEN(&peeraddr)) != length)
|
||||
perror("nak");
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue