Module Name:    src
Committed By:   buhrow
Date:           Tue May  5 05:50:32 UTC 2015

Modified Files:
        src/libexec/tftpd: tftpd.8 tftpd.c

Log Message:
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


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/libexec/tftpd/tftpd.8
cvs rdiff -u -r1.43 -r1.44 src/libexec/tftpd/tftpd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/libexec/tftpd/tftpd.8
diff -u src/libexec/tftpd/tftpd.8:1.28 src/libexec/tftpd/tftpd.8:1.29
--- src/libexec/tftpd/tftpd.8:1.28	Thu Apr 29 21:34:04 2010
+++ src/libexec/tftpd/tftpd.8	Tue May  5 05:50:31 2015
@@ -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.

Index: src/libexec/tftpd/tftpd.c
diff -u src/libexec/tftpd/tftpd.c:1.43 src/libexec/tftpd/tftpd.c:1.44
--- src/libexec/tftpd/tftpd.c:1.43	Fri Oct  4 07:51:48 2013
+++ src/libexec/tftpd/tftpd.c	Tue May  5 05:50:31 2015
@@ -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, 19
 #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 in
 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 in
 		(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");
 }
 

Reply via email to