Add a -b flag so that clients that return their acknowledgements to the
broadcast address can inter-operate with the tftpd server. Discussed in bin/49868
This commit is contained in:
parent
58ba35d88f
commit
3a2e9669fe
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: tftpd.8,v 1.28 2010/04/29 21:34:04 wiz Exp $
|
||||
.\" $NetBSD: tftpd.8,v 1.29 2015/05/05 05:50:31 buhrow Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
|
@ -39,7 +39,7 @@
|
|||
Internet Trivial File Transfer Protocol server
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl cdln
|
||||
.Op Fl bcdln
|
||||
.Op Fl g Ar group
|
||||
.Op Fl p Ar pathsep
|
||||
.Op Fl s Ar directory
|
||||
|
@ -95,6 +95,12 @@ relative filename requests.
|
|||
.Pp
|
||||
The options are:
|
||||
.Bl -tag -width "XsXdirectoryX"
|
||||
.It Fl b
|
||||
Allow clients which return acknowledgements to the broadcast address to
|
||||
communicate with the tftp server.
|
||||
Some tftp clients, notably ones resident in the ROMs of older Cisco
|
||||
equipment, return their acknowledgements to the broadcast address rather
|
||||
than the server's unicast address.
|
||||
.It Fl c
|
||||
Allow unrestricted creation of new files.
|
||||
Without this flag, only existing publicly writable files can be overwritten.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: tftpd.c,v 1.43 2013/10/04 07:51:48 jnemeth Exp $ */
|
||||
/* $NetBSD: tftpd.c,v 1.44 2015/05/05 05:50:31 buhrow Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
|
@ -36,7 +36,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: tftpd.c,v 1.43 2013/10/04 07:51:48 jnemeth Exp $");
|
||||
__RCSID("$NetBSD: tftpd.c,v 1.44 2015/05/05 05:50:31 buhrow Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -110,6 +110,7 @@ static int secure;
|
|||
static char pathsep = '\0';
|
||||
static char *securedir;
|
||||
static int unrestricted_writes; /* uploaded files don't have to exist */
|
||||
static int broadcast_client = 0; /* Some clients ack to the broadcast address */
|
||||
|
||||
struct formats;
|
||||
|
||||
|
@ -142,7 +143,7 @@ usage(void)
|
|||
{
|
||||
|
||||
syslog(LOG_ERR,
|
||||
"Usage: %s [-cdln] [-g group] [-p pathsep] [-s directory] [-u user] [directory ...]",
|
||||
"Usage: %s [-bcdln] [-g group] [-p pathsep] [-s directory] [-u user] [directory ...]",
|
||||
getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
@ -172,8 +173,30 @@ main(int argc, char *argv[])
|
|||
curuid = getuid();
|
||||
curgid = getgid();
|
||||
|
||||
while ((ch = getopt(argc, argv, "cdg:lnp:s:u:")) != -1)
|
||||
while ((ch = getopt(argc, argv, "bcdg:lnp:s:u:")) != -1)
|
||||
switch (ch) {
|
||||
case 'b':
|
||||
/*
|
||||
* Some clients, notably older Cisco boot loaders,
|
||||
* send their acknowledgements to the broadcast address
|
||||
* rather than the unicast address of the server.
|
||||
* Allow those clients to inter-operate with us.
|
||||
* It's worth noting that this interaction doesn't cause the
|
||||
* server to change where it sends the responses, meaning
|
||||
* servers that have this flag enabled are no more
|
||||
* susceptible to magnifcation DOS attacks than those
|
||||
* servers that don't use this flag. This flag merely
|
||||
* permits the reception of acknowledgement traffic to the
|
||||
* broadcast address/specific port number that's being used for
|
||||
* this session as well as the unicast address/specific port
|
||||
* number for this session. For example, if the session is
|
||||
* expecting acks on 192.168.1.40:50201, then this flag
|
||||
* would also allow acks to be returned to
|
||||
* 192.168.1.255:50201, assuming that 192.168.1.255 is the
|
||||
* broadcast address for the subnet containing 192.168.1.40.
|
||||
*/
|
||||
broadcast_client = 1;
|
||||
break;
|
||||
case 'c':
|
||||
unrestricted_writes = 1;
|
||||
break;
|
||||
|
@ -393,14 +416,17 @@ main(int argc, char *argv[])
|
|||
syslog(LOG_ERR, "socket: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (broadcast_client) {
|
||||
soopt = 1;
|
||||
if (setsockopt(peer, SOL_SOCKET, SO_BROADCAST, (void *) &soopt, sizeof(soopt)) < 0) {
|
||||
syslog(LOG_ERR, "set SO_BROADCAST: %m");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
|
||||
syslog(LOG_ERR, "bind: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
|
||||
syslog(LOG_ERR, "connect: %m");
|
||||
exit(1);
|
||||
}
|
||||
soopt = 65536; /* larger than we'll ever need */
|
||||
if (setsockopt(peer, SOL_SOCKET, SO_SNDBUF, (void *) &soopt, sizeof(soopt)) < 0) {
|
||||
syslog(LOG_ERR, "set SNDBUF: %m");
|
||||
|
@ -955,7 +981,7 @@ sendfile(struct formats *pf, volatile int etftp, int acklength)
|
|||
send_data:
|
||||
if (!etftp && debug)
|
||||
syslog(LOG_DEBUG, "Send DATA %u", block);
|
||||
if ((n = send(peer, dp, size + 4, 0)) != size + 4) {
|
||||
if ((n = sendto(peer, dp, size + 4, 0, (struct sockaddr *)&from, fromlen)) != size + 4) {
|
||||
syslog(LOG_ERR, "tftpd: write: %m");
|
||||
goto abort;
|
||||
}
|
||||
|
@ -963,7 +989,8 @@ send_data:
|
|||
read_ahead(file, tftp_blksize, pf->f_convert);
|
||||
for ( ; ; ) {
|
||||
alarm(rexmtval); /* read the ack */
|
||||
n = recv(peer, ackbuf, tftp_blksize, 0);
|
||||
n = recvfrom(peer, ackbuf, tftp_blksize, 0,(struct sockaddr
|
||||
*)&from, &fromlen );
|
||||
alarm(0);
|
||||
if (n < 0) {
|
||||
syslog(LOG_ERR, "tftpd: read: %m");
|
||||
|
@ -1049,14 +1076,15 @@ recvfile(struct formats *pf, volatile int etftp, volatile int acklength)
|
|||
(void) setjmp(timeoutbuf);
|
||||
send_ack:
|
||||
ap = (struct tftphdr *) (etftp ? oackbuf : ackbuf);
|
||||
if (send(peer, ap, acklength, 0) != acklength) {
|
||||
if (sendto(peer, ap, acklength, 0, (struct sockaddr *)&from, fromlen) != acklength) {
|
||||
syslog(LOG_ERR, "tftpd: write: %m");
|
||||
goto abort;
|
||||
}
|
||||
write_behind(file, pf->f_convert);
|
||||
for ( ; ; ) {
|
||||
alarm(rexmtval);
|
||||
n = recv(peer, dp, tftp_blksize + 4, 0);
|
||||
n = recvfrom(peer, dp, tftp_blksize + 4, 0, (struct sockaddr
|
||||
*)&from, &fromlen);
|
||||
alarm(0);
|
||||
if (n < 0) { /* really? */
|
||||
syslog(LOG_ERR, "tftpd: read: %m");
|
||||
|
@ -1108,16 +1136,16 @@ done:
|
|||
ap->th_block = htons((u_short)(block));
|
||||
if (debug)
|
||||
syslog(LOG_DEBUG, "Send final ACK %u", block);
|
||||
(void) send(peer, ackbuf, 4, 0);
|
||||
(void) sendto(peer, ackbuf, 4, 0, (struct sockaddr *)&from, fromlen);
|
||||
|
||||
signal(SIGALRM, justquit); /* just quit on timeout */
|
||||
alarm(rexmtval);
|
||||
n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
|
||||
n = recvfrom(peer, buf, sizeof (buf), 0, (struct sockaddr *)&from, &fromlen); /* normally times out and quits */
|
||||
alarm(0);
|
||||
if (n >= 4 && /* if read some data */
|
||||
dp->th_opcode == DATA && /* and got a data block */
|
||||
block == dp->th_block) { /* then my last ack was lost */
|
||||
(void) send(peer, ackbuf, 4, 0); /* resend final ack */
|
||||
(void) sendto(peer, ackbuf, 4, 0, (struct sockaddr *)&from, fromlen); /* resend final ack */
|
||||
}
|
||||
abort:
|
||||
return;
|
||||
|
@ -1185,7 +1213,7 @@ nak(int error)
|
|||
syslog(LOG_DEBUG, "Send NACK %s", tp->th_msg);
|
||||
length = strlen(tp->th_msg);
|
||||
msglen = &tp->th_msg[length + 1] - buf;
|
||||
if (send(peer, buf, msglen, 0) != (ssize_t)msglen)
|
||||
if (sendto(peer, buf, msglen, 0, (struct sockaddr *)&from, fromlen) != (ssize_t)msglen)
|
||||
syslog(LOG_ERR, "nak: %m");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue