aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/tftp/tftp.c
diff options
context:
space:
mode:
authorHajimu UMEMOTO <ume@FreeBSD.org>2002-04-11 17:14:22 +0000
committerHajimu UMEMOTO <ume@FreeBSD.org>2002-04-11 17:14:22 +0000
commit4dac6235cf2718f6c383b6bda1dc346bb357e886 (patch)
tree17221edddfe751134988e362f0829a38aa1ab240 /usr.bin/tftp/tftp.c
parent0d36f49e63b15762fcde4fcf8fa088ab2e0838b2 (diff)
IPv6 support for tftp/tftpd.
Obtained from: KAME MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=94443
Diffstat (limited to 'usr.bin/tftp/tftp.c')
-rw-r--r--usr.bin/tftp/tftp.c73
1 files changed, 57 insertions, 16 deletions
diff --git a/usr.bin/tftp/tftp.c b/usr.bin/tftp/tftp.c
index 7b4eb95032ca..b2cc8683b7b7 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;
+}