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:
(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.