Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/libexec/tftpd Add a -b flag so that clients that return thei...



details:   https://anonhg.NetBSD.org/src/rev/a38e7f9a3d1e
branches:  trunk
changeset: 337969:a38e7f9a3d1e
user:      buhrow <buhrow%NetBSD.org@localhost>
date:      Tue May 05 05:50:31 2015 +0000

description:
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

diffstat:

 libexec/tftpd/tftpd.8 |  10 ++++++-
 libexec/tftpd/tftpd.c |  60 +++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 52 insertions(+), 18 deletions(-)

diffs (186 lines):

diff -r 8215dc41f33f -r a38e7f9a3d1e libexec/tftpd/tftpd.8
--- a/libexec/tftpd/tftpd.8     Tue May 05 00:28:25 2015 +0000
+++ b/libexec/tftpd/tftpd.8     Tue May 05 05:50:31 2015 +0000
@@ -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 @@
 .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.
diff -r 8215dc41f33f -r a38e7f9a3d1e libexec/tftpd/tftpd.c
--- a/libexec/tftpd/tftpd.c     Tue May 05 00:28:25 2015 +0000
+++ b/libexec/tftpd/tftpd.c     Tue May 05 05:50:31 2015 +0000
@@ -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 @@
 #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 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,30 @@
        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 @@
                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 @@
 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 @@
                        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 @@
                (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 @@
        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 @@
                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");
 }
 



Home | Main Index | Thread Index | Old Index