NetBSD Problem Report #49868

From buhrow@lothlorien.nfbcal.org  Thu Apr 30 17:08:26 2015
Return-Path: <buhrow@lothlorien.nfbcal.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id E1E7FA5864
	for <gnats-bugs@gnats.NetBSD.org>; Thu, 30 Apr 2015 17:08:26 +0000 (UTC)
Message-Id: <201504301708.t3UH8Ow1028631@lothlorien.nfbcal.org>
Date: Thu, 30 Apr 2015 10:08:24 -0700 (PDT)
From: buhrow@nfbcal.org
Reply-To: buhrow@nfbcal.org
To: gnats-bugs@gnats.NetBSD.org
Subject: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
X-Send-Pr-Version: 3.95

>Number:         49868
>Category:       bin
>Synopsis:       Clients that return acks to the brodcast address can't talk to our tftpd(8) server
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Apr 30 17:10:00 +0000 2015
>Last-Modified:  Sun Oct 11 03:25:00 +0000 2015
>Originator:     Brian Buhrow
>Release:        NetBSd-current and all prior releases
>Organization:
NFB of California

>Environment:


System: NetBSD lothlorien.nfbcal.org 5.2_STABLE NetBSD 5.2_STABLE (RBL) #0: Thu Mar 27 10:15:56 PDT 2014 buhrow@lothlorien.nfbcal.org:/usr/src/sys/arch/i386/compile/RBL i386
Architecture: i386
Machine: i386
>Description:


Some Cisco equipment have firmware recovery software in them that includes
a tftp client which can be used to reflash the device with fresh firmware
in the event that the original firmware became unusable.
This tftp client is broken in the sense that when it returns
acknowledgements to the tftp server as its receiving data, rather than
sending those acks to the unicast address representing the server's IP
address, it sends them to the broadcast address.  To illustrate, here is a
tcpdump showing the problem in action.

	The tftp client is IP address 10.0.0.1 and the tftp server is IP
address 10.0.0.2.  Notice how the 10.0.0.1 client returns its
acknowledgements to the correct port number for the  tftp session, but
sends those acks to 255.255.255.255, the broadcast address.  In this trace,
you can see both sides retrying to talk to each other, and missing each
other.  

03:25:36.200156 IP 10.0.0.1.1024 > 255.255.255.255.69:  31 RRQ "c1240-k9w7-tar.default" octet 
03:25:36.243033 arp who-has 10.0.0.1 tell 10.0.0.2
03:25:36.243448 arp reply 10.0.0.1 is-at 00:1a:6d:3e:1a:aa
03:25:36.243455 IP 10.0.0.2.63484 > 10.0.0.1.1024: UDP, length 516
03:25:36.315783 IP 10.0.0.1.1024 > 255.255.255.255.63484: UDP, length 4
03:25:40.121059 IP 10.0.0.1.1024 > 255.255.255.255.63484: UDP, length 4
03:25:41.254158 IP 10.0.0.2.63484 > 10.0.0.1.1024: UDP, length 516
03:25:45.060073 IP 10.0.0.1.1024 > 255.255.255.255.63484: UDP, length 4
03:25:46.266457 IP 10.0.0.2.63484 > 10.0.0.1.1024: UDP, length 516
03:25:50.072412 IP 10.0.0.1.1024 > 255.255.255.255.63484: UDP, length 4
03:25:51.278758 IP 10.0.0.2.63484 > 10.0.0.1.1024: UDP, length 516
03:25:55.084701 IP 10.0.0.1.1024 > 255.255.255.255.63484: UDP, length 4
03:25:56.291059 IP 10.0.0.2.63484 > 10.0.0.1.1024: UDP, length 516
03:26:00.096881 IP 10.0.0.1.1024 > 255.255.255.255.63484: UDP, length 4
03:26:03.902150 IP 10.0.0.1.1024 > 255.255.255.255.63484: UDP, length 4


>How-To-Repeat:


	The Cisco Aironet 1240 boot loader, as well as other Cisco Aironet
boot loaders demonstrates this behavior.  I believe the boot loader on
older Cisco 1900 switches exhibits this behavior as well.  If you have such
a device, you can:

1.  addan alias to your tftp serving  network interface:
i.e. ifconfig nfe0 inet 10.0.0.2 netmask 255.255.255.224 alias

2.  Perform the required steps to put your device into recovery mode and
get it to try and retrieve an image via tftp from your server.

3.  Watch it fail.

>Fix:


Here is a patch that allows our tftpd(8) utility to work with such broken
tftp clients.  This patch does not break any existing functionality that I
can detect.  Essentially it enables the reception of traffic to the
broadcast address, but only the currently active ephemeral port number, in
addition to receiving the usual unicast traffic during a session.


Here is the patch:

Index: tftpd.c
===================================================================
RCS file: /cvsroot/src/libexec/tftpd/tftpd.c,v
retrieving revision 1.43
diff -u -r1.43 tftpd.c
--- tftpd.c	4 Oct 2013 07:51:48 -0000	1.43
+++ tftpd.c	30 Apr 2015 16:35:36 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD$	*/
+/*	$NetBSD: tftpd.c,v 1.31.4.1 2011/11/02 19:58:23 riz Exp $	*/

 /*
  * Copyright (c) 1983, 1993
@@ -36,7 +36,7 @@
 #if 0
 static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD$");
+__RCSID("$NetBSD: tftpd.c,v 1.43 2013/10/04 07:51:48 jnemeth Exp $");
 #endif
 #endif /* not lint */

@@ -393,12 +393,13 @@
 		syslog(LOG_ERR, "socket: %m");
 		exit(1);
 	}
-	if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
-		syslog(LOG_ERR, "bind: %m");
+	soopt = 1;
+	if (setsockopt(peer, SOL_SOCKET, SO_BROADCAST, (void *) &soopt, sizeof(soopt)) < 0) {
+		syslog(LOG_ERR, "set SO_BROADCAST: %m");
 		exit(1);
 	}
-	if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
-		syslog(LOG_ERR, "connect: %m");
+	if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
+		syslog(LOG_ERR, "bind: %m");
 		exit(1);
 	}
 	soopt = 65536;	/* larger than we'll ever need */
@@ -955,7 +956,7 @@
 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 +964,8 @@
 			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 +1051,15 @@
 		(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 +1111,16 @@
 	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 +1188,7 @@
 		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");
 }


>Audit-Trail:
From: christos@zoulas.com (Christos Zoulas)
To: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Cc: 
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 13:59:36 -0400

 On Apr 30,  5:10pm, buhrow@nfbcal.org (buhrow@nfbcal.org) wrote:
 -- Subject: bin/49868: tftpd(8) doesn't play well with clients that return ac


 Shouldn't we make this optional with a -b flag? I think it can be abused
 otherwise...

 christos

From: Brian Buhrow <buhrow@nfbcal.org>
To: gnats-bugs@NetBSD.org, gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 11:18:04 -0700

 	Hello.   Sure, I can add a -b flag to permit this new functionality.
 Patches to follow.

 -thanks
 -Brian

From: John Nemeth <jnemeth@cue.bc.ca>
To: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Cc: 
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 10:52:55 -0700

 On Apr 30,  5:10pm, buhrow@nfbcal.org wrote:
 }
 } >Number:         49868
 } >Category:       bin
 } >Synopsis:       Clients that return acks to the brodcast address can't talk to our tftpd(8) server
 } >Responsible:    bin-bug-people
 } >State:          open
 } >Class:          sw-bug
 } >Arrival-Date:   Thu Apr 30 17:10:00 +0000 2015
 } >Originator:     Brian Buhrow
 } >Release:        NetBSd-current and all prior releases
 } >Environment:
 } 	
 } System: NetBSD lothlorien.nfbcal.org 5.2_STABLE NetBSD 5.2_STABLE (RBL) #0: Thu Mar 27 10:15:56 PDT 2014 buhrow@lothlorien.nfbcal.org:/usr/src/sys/arch/i386/compile/RBL i386
 } Architecture: i386
 } Machine: i386
 } >Description:
 } 
 } Some Cisco equipment have firmware recovery software in them that includes
 } a tftp client which can be used to reflash the device with fresh firmware
 } in the event that the original firmware became unusable.
 } This tftp client is broken in the sense that when it returns
 } acknowledgements to the tftp server as its receiving data, rather than
 } sending those acks to the unicast address representing the server's IP
 } address, it sends them to the broadcast address.  To illustrate, here is a
 } tcpdump showing the problem in action.

      I would say the bug is that tftpd responds to broadcast at
 all.  What happens if you have more then one tftpd on a network
 segment?

 }-- End of excerpt from buhrow@nfbcal.org

From: mlelstv@serpens.de (Michael van Elst)
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 19:02:32 +0000 (UTC)

 jnemeth@cue.bc.ca (John Nemeth) writes:

 >     I would say the bug is that tftpd responds to broadcast at
 >all.  What happens if you have more then one tftpd on a network
 >segment?

 RFC1123 explicitely says that TFTP requests direct to a
 broadcast address SHOULD be silently ignored.

 This means that TFTP on a broadcast address might be useful in
 some cases, but you should understand the full implications of
 using TFTP this way.

 -- 
 -- 
                                 Michael van Elst
 Internet: mlelstv@serpens.de
                                 "A potential Snark may lurk in every tree."

From: Brian Buhrow <buhrow@nfbcal.org>
To: gnats-bugs@NetBSD.org, gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 12:20:10 -0700

 	Hello.  Here are  patches which implement Christos request, as well as
 documenting the change.  Any reason I shouldn't commit these?

 -thanks
 -Brian

 Index: tftpd.8
 ===================================================================
 RCS file: /cvsroot/src/libexec/tftpd/tftpd.8,v
 retrieving revision 1.28
 diff -u -r1.28 tftpd.8
 --- tftpd.8	29 Apr 2010 21:34:04 -0000	1.28
 +++ tftpd.8	30 Apr 2015 18:57:10 -0000
 @@ -1,4 +1,4 @@
 -.\"	$NetBSD$
 +.\"	$NetBSD: tftpd.8,v 1.28 2010/04/29 21:34:04 wiz 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 @@
  .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: tftpd.c
 ===================================================================
 RCS file: /cvsroot/src/libexec/tftpd/tftpd.c,v
 retrieving revision 1.43
 diff -u -r1.43 tftpd.c
 --- tftpd.c	4 Oct 2013 07:51:48 -0000	1.43
 +++ tftpd.c	30 Apr 2015 18:57:30 -0000
 @@ -1,4 +1,4 @@
 -/*	$NetBSD$	*/
 +/*	$NetBSD: tftpd.c,v 1.31.4.1 2011/11/02 19:58:23 riz Exp $	*/

  /*
   * Copyright (c) 1983, 1993
 @@ -36,7 +36,7 @@
  #if 0
  static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
  #else
 -__RCSID("$NetBSD$");
 +__RCSID("$NetBSD: tftpd.c,v 1.43 2013/10/04 07:51:48 jnemeth Exp $");
  #endif
  #endif /* not lint */

 @@ -110,6 +110,7 @@
  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 @@
  {

  	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,11 @@
  	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':
 +			broadcast_client = 1;
 +			break;
  		case 'c':
  			unrestricted_writes = 1;
  			break;
 @@ -393,14 +397,17 @@
  		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 +962,7 @@
  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 +970,8 @@
  			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 +1057,15 @@
  		(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 +1117,16 @@
  	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 +1194,7 @@
  		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");
  }


From: Brian Buhrow <buhrow@nfbcal.org>
To: gnats-bugs@NetBSD.org, gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 12:15:39 -0700

 }       I would say the bug is that tftpd responds to broadcast at
 }  all.  What happens if you have more then one tftpd on a network
 }  segment?

 	Nothing.  The initial request comes into inetd, which launches tftpd
 in the usual way.  Once the session begins, the server forks and begins
 serving files from ephemeral port numbers.  This patch only allows the
 reception of acknowledgements on the same ephemeral port number that the
 tftp server is serving from.  For example, an initial request comes in on
 port 69 for the file named "foo".  The tftp server forks and begins
 returning the contents of "foo" to the client, sourcing the data from port
 50102.  The client then acknowledges that data by replying to the unicast
 address of the server on port 50102.  This change allows the tftp server to
 receive those acknowledgements on the server's unicast address, port 50102,
 as well as the broadcast address, port 50102.  Any additional requests that
 come in on port 69 to the server would be considered new requests and would
 be handled by a new instance of the server.  It's worth noting that the
 current behavior of the system would cause any tftp servers listening on
 the network segment in question to respond to the initial request which
 came in to the broadcast address.  However, none of them would be able to
 complete the request because they are unable to communicate with the client
 after the initial request is received.  

 -Brian

From: Brian Buhrow <buhrow@nfbcal.org>
To: <Paul_Koning@dell.com>, <gnats-bugs@NetBSD.org>
Cc: <gnats-admin@NetBSD.org>, <netbsd-bugs@NetBSD.org>, buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 13:37:54 -0700

 	Hello.  I think Christos' suggestion of turning on this functionality
 with a  command line option and documenting that option is a good idea.  While
 I don't think doing things just because Linux does them is a good reason,
 I'll note that Linux's in.tftpd has the -a option which can be used to
 implement this same functionality.  I think we should implement this
 functionality because our users are pretty network savvy, they often work
 with older broken equipment where they are likely to encounter this bug and
 because having it will make it very convenient for our users to  work
 around issues like this.  Before I figured out what was going on and how to
 fix it, I was considering installing Linux or firing up my Windows
 machine to deal with this piece of hardware.  Finally, given the fact that
 this change only permits the reception of broadcast traffic on an ephemeral
 port, not the main tftp port, it's unclear to me how much abuse potential
 this change really introduces.  For most users, this addition will mostly
 go unused.But, for those that need it, they'll be glad to have it in a
 pinch!  I think that makes it worth doing.
 -thanks
 -Brian

 On Apr 30,  7:46pm, <Paul_Koning@dell.com> wrote:
 } Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that retur
 } SXMgdGhlcmUgYW55IHJlYXNvbiB3aHkgdGZ0cGQgc2hvdWxkIG9wZXJhdGUgd2l0aCBzdWNoIGNs
 } aWVudHM/ICBJdCBzb3VuZHMgbGlrZSBhIHByb3RvY29sIHZpb2xhdGlvbiwgYW5kIGdpdmVuIHRo
 } ZSBwb3RlbnRpYWwgZm9yIGFidXNlIGl0IGRvZXNu4oCZdCBzZWVtIGxpa2Ug4oCcYmUgdG9sZXJh
 } bnTigJ0gc2hvdWxkIGFwcGx5Lg0KDQoJcGF1bA0K
 >-- End of excerpt from <Paul_Koning@dell.com>


From: christos@zoulas.com (Christos Zoulas)
To: Brian Buhrow <buhrow@nfbcal.org>, <Paul_Koning@dell.com>, 
	<gnats-bugs@NetBSD.org>
Cc: <gnats-admin@NetBSD.org>, <netbsd-bugs@NetBSD.org>
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 17:00:12 -0400

 On Apr 30,  1:37pm, buhrow@nfbcal.org (Brian Buhrow) wrote:
 -- Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that retur

 | 	Hello.  I think Christos' suggestion of turning on this functionality
 | with a  command line option and documenting that option is a good idea.  While
 | I don't think doing things just because Linux does them is a good reason,
 | I'll note that Linux's in.tftpd has the -a option which can be used to
 | implement this same functionality.  I think we should implement this
 | functionality because our users are pretty network savvy, they often work
 | with older broken equipment where they are likely to encounter this bug and
 | because having it will make it very convenient for our users to  work
 | around issues like this.  Before I figured out what was going on and how to
 | fix it, I was considering installing Linux or firing up my Windows
 | machine to deal with this piece of hardware.  Finally, given the fact that
 | this change only permits the reception of broadcast traffic on an ephemeral
 | port, not the main tftp port, it's unclear to me how much abuse potential
 | this change really introduces.  For most users, this addition will mostly
 | go unused.But, for those that need it, they'll be glad to have it in a
 | pinch!  I think that makes it worth doing.

 I agree, but I am wondering if one can fake a packet coming coming from a
 broadcast address and cause tftpd send datagrams to the broadcast address
 too. If that's the case, then a warning should be added to the man page
 next to the option documentation. I have not really examined the code to
 see if that's possible though (inetd and tftpd). Otherwise I think it is
 fine to commit this.

 christos

From: <Paul_Koning@Dell.com>
To: <gnats-bugs@NetBSD.org>
Cc: <gnats-admin@netbsd.org>, <netbsd-bugs@netbsd.org>, <buhrow@nfbcal.org>
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return
 acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 19:46:57 +0000

 SXMgdGhlcmUgYW55IHJlYXNvbiB3aHkgdGZ0cGQgc2hvdWxkIG9wZXJhdGUgd2l0aCBzdWNoIGNs
 aWVudHM/ICBJdCBzb3VuZHMgbGlrZSBhIHByb3RvY29sIHZpb2xhdGlvbiwgYW5kIGdpdmVuIHRo
 ZSBwb3RlbnRpYWwgZm9yIGFidXNlIGl0IGRvZXNu4oCZdCBzZWVtIGxpa2Ug4oCcYmUgdG9sZXJh
 bnTigJ0gc2hvdWxkIGFwcGx5Lg0KDQoJcGF1bA0K

From: Brian Buhrow <buhrow@via.net>
To: gnats-bugs@NetBSD.org, gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 14:40:38 -0700

 On Apr 30,  9:05pm, Christos Zoulas wrote:
 } Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that retur
 } The following reply was made to PR bin/49868; it has been noted by GNATS.
 } 
 }  I agree, but I am wondering if one can fake a packet coming coming from a
 }  broadcast address and cause tftpd send datagrams to the broadcast address
 }  too. If that's the case, then a warning should be added to the man page
 }  next to the option documentation. I have not really examined the code to
 }  see if that's possible though (inetd and tftpd). Otherwise I think it is
 }  fine to commit this.
 }  
 }  christos
 }  

 	Hello.  The only way to get the tftpd to return packets to the
 broadcast address is if inetd can be tricked into initiating a connection
 with a broadcast address.  In looking at the inetd(8) source code, it looks
 like there are checks in there to assure that this doesn't happen.  The
 change I'm making won't allow traffic to be redirected to a broadcast
 address after the fact even if a reply comes from a broadcast address
 in the midle of a session.  That's because tftpd(8) only sets the client's
 source address from the socket passed to it by inetd(8).  Once that's done,
 it doesn't change for the life of the session.
 -thanks
 -Brian

From: christos@zoulas.com (Christos Zoulas)
To: Brian Buhrow <buhrow@via.net>, gnats-bugs@NetBSD.org, 
	gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 17:47:22 -0400

 On Apr 30,  2:40pm, buhrow@via.net (Brian Buhrow) wrote:
 -- Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that retur

 | 	Hello.  The only way to get the tftpd to return packets to the
 | broadcast address is if inetd can be tricked into initiating a connection
 | with a broadcast address.  In looking at the inetd(8) source code, it looks
 | like there are checks in there to assure that this doesn't happen.  The
 | change I'm making won't allow traffic to be redirected to a broadcast
 | address after the fact even if a reply comes from a broadcast address
 | in the midle of a session.  That's because tftpd(8) only sets the client's
 | source address from the socket passed to it by inetd(8).  Once that's done,
 | it doesn't change for the life of the session.
 | -thanks
 | -Brian

 Great!

 I'd still put a comment in the source where we turn broadcast on why this
 is done, and why it is ok (so people are not mystified in the future).

 christos

From: Brian Buhrow <buhrow@nfbcal.org>
To: gnats-bugs@NetBSD.org, gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 15:59:31 -0700

 	hello.  Ok.  I'll add a comment explaining the issue, do a build
 release to make sure all is good and commit.  This will take a day or two.
 -thanks
 -Brian

From: Robert Elz <kre@munnari.OZ.AU>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Fri, 01 May 2015 07:40:29 +0700

 The one issue I see with this change is that switching from a connect/send
 implementation to sendto (which happens in the patch independently of the new
 switch) means that netstat won't identify the clients any more.   It would be
 kind of nice if that didn't happen unconditionally - tftp isn't really
 performance critical, so perhaps packet sending could be in a new function
 which tests the switch, and the sendto variant is used only when the new option
 is given ... and perhaps even better, even if the option is there, after
 receiving a packet that was sent to the unicast address (ie: not communicating
 with one of these broken clients) connect() and revert to the send()
 method?    (But perhaps all that complication only if !SMALL if tftpd gets
 included in boot images for some reason).

 kre

From: Brian Buhrow <buhrow@nfbcal.org>
To: gnats-bugs@NetBSD.org, gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: buhrow@nfbcal.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 18:37:01 -0700

 On May 1, 12:45am, Robert Elz wrote:
 } Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that retur
 } The following reply was made to PR bin/49868; it has been noted by GNATS.
 } 
 } From: Robert Elz <kre@munnari.OZ.AU>
 } To: gnats-bugs@NetBSD.org
 } Cc: 
 } Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
 } 
 }  The one issue I see with this change is that switching from a connect/send
 }  implementation to sendto (which happens in the patch independently of the new
 }  switch) means that netstat won't identify the clients any more.   It would be
 }  kind of nice if that didn't happen unconditionally - tftp isn't really
 }  performance critical, so perhaps packet sending could be in a new function
 }  which tests the switch, and the sendto variant is used only when the new option
 }  is given ... and perhaps even better, even if the option is there, after
 }  receiving a packet that was sent to the unicast address (ie: not communicating
 }  with one of these broken clients) connect() and revert to the send()
 }  method?    (But perhaps all that complication only if !SMALL if tftpd gets
 }  included in boot images for some reason).
 }  
 }  kre

 	Well, I confess I didn't realize the netstat implication of the
 change.  How important is the output of netstat relative to tftp for folks?
 Implementing the connect/send versus sendto methods based on the new
 switch, is, as Robert points out, a fairly large patch.  The current patch
 is tested and is known to work.  If there's not a lot of strong feeling on
 this issue, I'm inclined to commit as is. 

 	As to Robert's second suggestion, I'm not sure it's a good idea since
 one can't tell if the client at the other end died or is just sending to
 the broadcast address.   Some of the timeouts on these tftp clients are
 such that I'm not sure you'd get things going if the tftp server was trying
 to decide which traffic it might or might not be receiving.  

 -thanks
 -Brian


From: christos@zoulas.com (Christos Zoulas)
To: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org, netbsd-bugs@netbsd.org, 
	buhrow@nfbcal.org
Cc: 
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Thu, 30 Apr 2015 21:58:14 -0400

 On May 1, 12:45am, kre@munnari.OZ.AU (Robert Elz) wrote:
 -- Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that retur

 | The following reply was made to PR bin/49868; it has been noted by GNATS.
 | 
 | From: Robert Elz <kre@munnari.OZ.AU>
 | To: gnats-bugs@NetBSD.org
 | Cc: 
 | Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
 | Date: Fri, 01 May 2015 07:40:29 +0700
 | 
 |  The one issue I see with this change is that switching from a connect/send
 |  implementation to sendto (which happens in the patch independently of the new
 |  switch) means that netstat won't identify the clients any more.   It would be
 |  kind of nice if that didn't happen unconditionally - tftp isn't really
 |  performance critical, so perhaps packet sending could be in a new function
 |  which tests the switch, and the sendto variant is used only when the new option
 |  is given ... and perhaps even better, even if the option is there, after
 |  receiving a packet that was sent to the unicast address (ie: not communicating
 |  with one of these broken clients) connect() and revert to the send()
 |  method?    (But perhaps all that complication only if !SMALL if tftpd gets
 |  included in boot images for some reason).

 I like that idea, and I was going to suggest that..

 christos

From: Robert Elz <kre@munnari.OZ.AU>
To: Brian Buhrow <buhrow@nfbcal.org>
Cc: gnats-bugs@NetBSD.org, netbsd-bugs@NetBSD.org
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return acknowledgements to the broadcast address
Date: Fri, 01 May 2015 18:07:26 +0700

     Date:        Thu, 30 Apr 2015 18:37:01 -0700
     From:        Brian Buhrow <buhrow@nfbcal.org>
     Message-ID:  <201505010137.t411b1YQ023322@lothlorien.nfbcal.org>

   | How important is the output of netstat relative to tftp for folks?

 I'll leave that for others to comment on.

   | Implementing the connect/send versus sendto methods based on the new
   | switch, is, as Robert points out, a fairly large patch.

 Not that large, surely, change send() to tftp_send() (or whatever), and put
 the necessary logic in a new function.

   | As to Robert's second suggestion, I'm not sure it's a good idea since
   | one can't tell if the client at the other end died or is just sending to
   | the broadcast address.

 Sorry, I don't see your point there?   At the relevant time, you're 
 communicating with a single client.  That client is either one of the
 broken ones, or it is not.  If it sends to your unicast address, rather
 than the broadcast address, it is not broken - and would be very unlikely,
 I'd think, to break itself in the middle of one session.   I'm not sure
 of the relevance of timeouts or missing packets to that - if you don't receive
 anything, you're not getting any info, and keep on with the possibility that
 the client, when it does send, will be a broken one.

 Doing this does mean that the code on receiving a packet (at least when the
 "allow for a broken client" flag remains set) must do the magic ioctl/sockioctl
 (or recvfrom or however it is done) to determine the address the client sent
 its packet to, which adds some extra mess (though there's no real reason to
 not do that for every packet, so conditional code is at least not required).

 Whether any of this complication is useful of course depends upon the outcome
 of your first question.

 kre

From: David Holland <dholland-bugs@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: bin/49868: tftpd(8) doesn't play well with clients that return
 acknowledgements to the broadcast address
Date: Sun, 11 Oct 2015 03:22:29 +0000

 On Fri, May 01, 2015 at 12:45:01AM +0000, Robert Elz wrote:
  > The one issue I see with this change is that switching from a
  > connect/send implementation to sendto (which happens in the patch
  > independently of the new switch) means that netstat won't identify
  > the clients any more.  It would be kind of nice if that didn't
  > happen unconditionally -

 There's another reason: as I recall if you have a multihomed machine
 serving tftp, bad things happen if you don't use UDP connect to
 deliver packets. That is: if you don't bind the source address of the
 send socket, the packets might come from the wrong address; and if you
 try to, you end up having to scan routing tables and other horrors to
 figure out which source address to use. Or something like that.

 Anyway I would suggest leaving the connect/send alone unless the
 broadcast stuff is specifically needd.

 -- 
 David A. Holland
 dholland@netbsd.org

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.