bug-inetutils
[Top][All Lists]
Advanced

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

[bug-inetutils] [RFC]: Tftpd fails with IPv4 mapped as IPv6.


From: Mats Erik Andersson
Subject: [bug-inetutils] [RFC]: Tftpd fails with IPv4 mapped as IPv6.
Date: Sun, 11 Sep 2011 02:02:44 +0200
User-agent: Mutt/1.5.18 (2008-05-17)

Hello there,

what can I do to activate you all, to wake you from lethargy?
If you are tired of coding, get going with testing. Rest assured
that it is still needed.

This message is primarily caused by the observation that the
present implementation 'src/tftpd.c' fails in GNU/kFreeBSD
when the inetd server (our version 1.8) is running dual stacked,
in the sense of mapping IPv4 to IPv6.

The only solution I have found as of yet is a deviation from
the legacy mode of using a connected UDP socketr:

  * remove server side call to connect(),

  * replace all send() by sendto().

Since these will potentially make the forging of diagrams easier,
I would like to discuss this code change before pushing it to the
repository.

However, with the patch applied, our TFTP server is correctly
handling dual stacked as well as pairs of single-stacked sockets
for GNU/Linux, GNU/kFreeBSD, OpenBSD, FreeBSD, and OpenSolaris.
Without the patch GNU/kFreeBSD is certainly failing all IPv6-mapped
cases of IPv4 calls.

I have also an unpushed patch to make the TFTP client fully IPv6
enabled, verified to be correct for all the five OSes mention above,
but I will proof read it some more before pushing the content.


You will see a smaller conditional insertion to handle a deviating
definition of "struct tftphdr", present in OpenSolaris. This is
elementary, but needed.

To be exact the mention of OpenSolaris for the TFTP server is only
true for transfers not exceeding on SEGSIZE in size, since the code
in 'libinetutils/tftpsubs.c' fails for the second segment in Open-
Solaris. I am working on a solution, but I do not understand the
causes just yet. (The second segment roughly returns the pointer
content instead of the size when leaving readit()! Ideas welcome.)

Side note our 'syslogd' is so far behaving well in OpenBSD and GNU/kFreeBSD.


Best regards,
  Mats


diff --git a/src/tftpd.c b/src/tftpd.c
index 49e7ae6..c17e6d3 100644
--- a/src/tftpd.c
+++ b/src/tftpd.c
@@ -285,16 +285,15 @@ main (int argc, char *argv[])
     }
   memset (&sin, 0, sizeof (sin));
   sin.ss_family = from.ss_family;
+#if HAVE_STRUCT_SOCKADDR_SA_LEN
+  sin.ss_len = from.ss_len;
+#endif
   if (bind (peer, (struct sockaddr *) &sin, fromlen) < 0)
     {
       syslog (LOG_ERR, "bind: %m\n");
       exit (EXIT_FAILURE);
     }
-  if (connect (peer, (struct sockaddr *) &from, fromlen) < 0)
-    {
-      syslog (LOG_ERR, "connect: %m\n");
-      exit (EXIT_FAILURE);
-    }
+
   tp = (struct tftphdr *) buf;
   tp->th_opcode = ntohs (tp->th_opcode);
   if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
@@ -332,7 +331,12 @@ tftp (struct tftphdr *tp, int size)
   register struct formats *pf;
   char *filename, *mode;
 
+#if !defined __sun__
   filename = cp = tp->th_stuff;
+#else /* __sun__ */
+  filename = cp = (char *) &(tp->th_stuff);
+#endif /* __sun__ */
+
 again:
   while (cp < buf + size)
     {
@@ -557,7 +561,8 @@ send_file (struct formats *pf)
       sigsetjmp (timeoutbuf, SIGALRM);
 
     send_data:
-      if (send (peer, (const char *) dp, size + 4, 0) != size + 4)
+      if (sendto (peer, (const char *) dp, size + 4, 0,
+                 (struct sockaddr *) &from, fromlen) != size + 4)
        {
          syslog (LOG_ERR, "tftpd: write: %m\n");
          goto abort;
@@ -627,7 +632,7 @@ recvfile (struct formats *pf)
       block++;
       sigsetjmp (timeoutbuf, SIGALRM);
     send_ack:
-      if (send (peer, ackbuf, 4, 0) != 4)
+      if (sendto (peer, ackbuf, 4, 0, (struct sockaddr *) &from, fromlen) != 4)
        {
          syslog (LOG_ERR, "tftpd: write: %m\n");
          goto abort;
@@ -676,7 +681,7 @@ recvfile (struct formats *pf)
 
   ap->th_opcode = htons ((u_short) ACK);       /* send the "final" ack */
   ap->th_block = htons ((u_short) (block));
-  send (peer, ackbuf, 4, 0);
+  sendto (peer, ackbuf, 4, 0, (struct sockaddr *) &from, fromlen);
 
   signal (SIGALRM, justquit);  /* just quit on timeout */
   alarm (rexmtval);
@@ -686,7 +691,7 @@ recvfile (struct formats *pf)
       dp->th_opcode == DATA && /* and got a data block */
       block == dp->th_block)
     {                          /* then my last ack was lost */
-      send (peer, ackbuf, 4, 0);       /* resend final ack */
+      sendto (peer, ackbuf, 4, 0, (struct sockaddr *) &from, fromlen); /* 
resend final ack */
     }
 abort:
   return;
@@ -751,7 +756,7 @@ nak (int error)
   length = strlen (pe->e_msg);
   tp->th_msg[length] = '\0';
   length += 5;
-  if (send (peer, buf, length, 0) != length)
+  if (sendto (peer, buf, length, 0, (struct sockaddr *) &from, fromlen) != 
length)
     syslog (LOG_ERR, "nak: %m\n");
 }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]