Simon Kelley schrieb:
> Adding IPv6 support would be fairly simple: the DNS part of dnsmasq does
> do IPv6, so all the bits are already in place, there just need to be an
> IPv6 socket listening as well as an IPv4 one, and a couple of address
> fields in structures need to be extended to hold IPv6 addresses.
> 

step one:
widen the addresses used in tftp.c for use with IPv4 & IPv6

only compile tested, i do not have any netboot stuff.

> Cheers,
> 
> Simon.
> 

Greetings
        Jan

-- 
// Replaces with spaces the braces in cases where
// braces in places cause stasis
   $str = str_replace(array("\{","\}")," ",$str);
=== modified file 'src/dnsmasq.h'
--- upstream/src/dnsmasq.h      2010-05-21 10:12:20 +0000
+++ ipv6_tftp/src/dnsmasq.h     2010-06-18 16:23:46 +0000
@@ -601,7 +601,7 @@
   int backoff;
   unsigned int block, blocksize, expansion;
   off_t offset;
-  struct sockaddr_in peer;
+  union mysockaddr peer;
   char opt_blocksize, opt_transize, netascii, carrylf;
   struct tftp_file *file;
   struct tftp_transfer *next;
@@ -790,6 +790,7 @@
 char *print_mac(char *buff, unsigned char *mac, int len);
 void bump_maxfd(int fd, int *max);
 int read_write(int fd, unsigned char *packet, int size, int rw);
+const char *mysockaddr_print(const union mysockaddr *src, char *dst, unsigned 
cnt);
 
 /* log.c */
 void die(char *message, char *arg1, int exit_code);
@@ -824,6 +825,7 @@
 struct listener *create_wildcard_listeners(void);
 struct listener *create_bound_listeners(void);
 int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
+int iface_check_mysockaddr(union mysockaddr *addr, char *name, int *indexp);
 int fix_fd(int fd);
 struct in_addr get_ifaddr(char *intr);
 

=== modified file 'src/network.c'
--- upstream/src/network.c      2010-06-18 14:22:05 +0000
+++ ipv6_tftp/src/network.c     2010-06-18 16:23:49 +0000
@@ -186,6 +186,17 @@
   
   return ret; 
 }
+
+int iface_check_mysockaddr(union mysockaddr *addr, char *name, int *indexp)
+{
+  if (AF_INET == addr->sa.sa_family)
+    return iface_check(addr->sa.sa_family, (struct all_addr 
*)&addr->in.sin_addr, name, indexp);
+#ifdef HAVE_IPV6
+  else if (AF_INET6 == addr->sa.sa_family)
+    return iface_check(addr->sa.sa_family, (struct all_addr 
*)&addr->in6.sin6_addr, name, indexp);
+#endif
+  return 0;
+}
       
 static int iface_allowed(struct irec **irecp, int if_index, 
                         union mysockaddr *addr, struct in_addr netmask) 

=== modified file 'src/tftp.c'
--- upstream/src/tftp.c 2010-05-21 10:10:06 +0000
+++ ipv6_tftp/src/tftp.c        2010-06-18 16:33:32 +0000
@@ -20,7 +20,7 @@
 
 static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int 
special);
 static void free_transfer(struct tftp_transfer *transfer);
-static ssize_t tftp_err(int err, char *packet, char *mess, char *file);
+static ssize_t tftp_err(int err, char *packet, const char *mess, const char 
*file);
 static ssize_t tftp_err_oops(char *packet, char *file);
 static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
 static char *next(char **p, char *end);
@@ -43,7 +43,7 @@
   ssize_t len;
   char *packet = daemon->packet;
   char *filename, *mode, *p, *end, *opt;
-  struct sockaddr_in addr, peer;
+  union mysockaddr addr, peer;
   struct msghdr msg;
   struct iovec iov;
   struct ifreq ifr;
@@ -89,10 +89,16 @@
 
   if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
     return;
-  
+
+  memset(&addr, 0, sizeof(addr));
+// TODO: get proper address family
+  addr.sa.sa_family = AF_INET;
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.sa.sa_len = sizeof(addr);
+#endif
   if (daemon->options & OPT_NOWILD)
     {
-      addr = listen->iface->addr.in;
+      addr.in = listen->iface->addr.in;
       mtu = listen->iface->mtu;
       name = listen->iface->name;
     }
@@ -102,8 +108,8 @@
       int check;
       struct interface_list *ir;
 
-      addr.sin_addr.s_addr = 0;
-      
+// TODO: this looks like recvfromto
+      /* and needs to be pimped for IPv6 */
 #if defined(HAVE_LINUX_NETWORK)
       for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, 
cmptr))
        if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
@@ -113,10 +119,10 @@
              struct in_pktinfo *p;
            } p;
            p.c = CMSG_DATA(cmptr);
-           addr.sin_addr = p.p->ipi_spec_dst;
+           addr.in.sin_addr = p.p->ipi_spec_dst;
            if_index = p.p->ipi_ifindex;
          }
-      
+
 #elif defined(HAVE_SOLARIS_NETWORK)
       for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, 
cmptr))
        {
@@ -127,7 +133,7 @@
          } p;
          p.c = CMSG_DATA(cmptr);
          if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == 
IP_RECVDSTADDR)
-           addr.sin_addr = *(p.a);
+           addr.in.sin_addr = *(p.a);
          else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == 
IP_RECVIF)
            if_index = *(p.i);
        }
@@ -142,19 +148,25 @@
          } p;
          p.c = CMSG_DATA(cmptr);
          if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == 
IP_RECVDSTADDR)
-           addr.sin_addr = *(p.a);
+           addr.in.sin_addr = *(p.a);
          else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == 
IP_RECVIF)
            if_index = p.s->sdl_index;
        }
-         
-#endif
-      
-      if (!indextoname(listen->tftpfd, if_index, namebuff) ||
-         addr.sin_addr.s_addr == 0)
+
+#endif
+
+      if (!indextoname(listen->tftpfd, if_index, namebuff))
+       return;
+
+      if ((AF_INET == addr.sa.sa_family && addr.in.sin_addr.s_addr == 0)
+#ifdef HAVE_IPV6
+         || (AF_INET6 == addr.sa.sa_family && 
IN6_IS_ADDR_UNSPECIFIED(&addr.in6.sin6_addr))
+#endif
+        )
        return;
 
       name = namebuff;
-      check = iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, 
&if_index);
+      check = iface_check_mysockaddr(&addr, name, &if_index);
 
       /* wierd TFTP service override */
       for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
@@ -176,9 +188,9 @@
 
       strncpy(ifr.ifr_name, name, IF_NAMESIZE);
       if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
-       mtu = ifr.ifr_mtu;      
+       mtu = ifr.ifr_mtu;
     }
-  
+
   /* check for per-interface prefix */ 
   for (pref = daemon->if_prefix; pref; pref = pref->next)
     if (strcmp(pref->interface, name) == 0)
@@ -189,21 +201,22 @@
     if (strcmp(ir->interface, name) == 0)
       special = 1;
 
-  addr.sin_port = htons(port);
-  addr.sin_family = AF_INET;
-#ifdef HAVE_SOCKADDR_SA_LEN
-  addr.sin_len = sizeof(addr);
+  if (AF_INET == addr.in.sin_family)
+      addr.in.sin_port = htons(port);
+#ifdef HAVE_IPV6
+  else
+      addr.in6.sin6_port = htons(port);
 #endif
-  
+
   if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
     return;
-  
+
   if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
     {
       free(transfer);
       return;
     }
-  
+
   transfer->peer = peer;
   transfer->timeout = now + 2;
   transfer->backoff = 1;
@@ -227,7 +240,12 @@
            {
              if (++port <= daemon->end_tftp_port)
                { 
-                 addr.sin_port = htons(port);
+                 if (AF_INET == addr.sa.sa_family)
+                   addr.in.sin_port = htons(port);
+#ifdef HAVE_IPV6
+                 else
+                   addr.in6.sin6_port = htons(port);
+#endif
                  continue;
                }
              my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for 
TFTP"));
@@ -237,7 +255,7 @@
        }
       break;
     }
-  
+
   p = packet + 2;
   end = packet + len;
 
@@ -245,7 +263,11 @@
       !(filename = next(&p, end)) ||
       !(mode = next(&p, end)) ||
       (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
-    len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), 
inet_ntoa(peer.sin_addr));
+    {
+      char istr[46];
+      len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"),
+                    mysockaddr_print(&peer, istr, sizeof(istr)));
+    }
   else
     {
       if (strcasecmp(mode, "netascii") == 0)
@@ -294,15 +316,17 @@
            {
              size_t oldlen = strlen(daemon->namebuff);
              struct stat statbuf;
-             
-             strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), (MAXDNAME-1) 
- strlen(daemon->namebuff));
+
+// TODO: +-1 ???
+             mysockaddr_print(&peer, daemon->namebuff + 
strlen(daemon->namebuff),
+                              (MAXDNAME-1) - strlen(daemon->namebuff));
              strncat(daemon->namebuff, "/", (MAXDNAME-1) - 
strlen(daemon->namebuff));
-             
+
              /* remove unique-directory if it doesn't exist */
              if (stat(daemon->namebuff, &statbuf) == -1 || 
!S_ISDIR(statbuf.st_mode))
                daemon->namebuff[oldlen] = 0;
            }
-               
+
          /* Absolute pathnames OK if they match prefix */
          if (filename[0] == '/')
            {
@@ -325,20 +349,22 @@
            is_err = 0;
        }
     }
-  
+
   while (sendto(transfer->sockfd, packet, len, 0, 
                (struct sockaddr *)&peer, sizeof(peer)) == -1 && errno == 
EINTR);
-  
+
   if (is_err)
     free_transfer(transfer);
   else
     {
-      my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff, 
inet_ntoa(peer.sin_addr));
+      char istr[46];
+      my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff,
+               mysockaddr_print(&peer, istr, sizeof(istr)));
       transfer->next = daemon->tftp_trans;
       daemon->tftp_trans = transfer;
     }
 }
- 
+
 static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int 
special)
 {
   char *packet = daemon->packet, *namebuff = daemon->namebuff;
@@ -351,7 +377,7 @@
   /* trick to ban moving out of the subtree */
   if (prefix && strstr(namebuff, "/../"))
     goto perm;
-  
+
   if ((fd = open(namebuff, O_RDONLY)) == -1)
     {
       if (errno == ENOENT)
@@ -364,11 +390,11 @@
       else
        goto oops;
     }
-  
+
   /* stat the file descriptor to avoid stat->open races */
   if (fstat(fd, &statbuf) == -1)
     goto oops;
-  
+
   /* running as root, must be world-readable */
   if (uid == 0)
     {
@@ -378,7 +404,7 @@
   /* in secure mode, must be owned by user running dnsmasq */
   else if (!special && (daemon->options & OPT_TFTP_SECURE) && uid != 
statbuf.st_uid)
     goto perm;
-      
+
   /* If we're doing many tranfers from the same file, only 
      open it once this saves lots of file descriptors 
      when mass-booting a big cluster, for instance. 
@@ -426,24 +452,24 @@
 {
   struct tftp_transfer *transfer, *tmp, **up;
   ssize_t len;
-  
+
   struct ack {
     unsigned short op, block;
   } *mess = (struct ack *)daemon->packet;
-  
+
   /* Check for activity on any existing transfers */
   for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; 
transfer = tmp)
     {
       tmp = transfer->next;
-      
+
       if (FD_ISSET(transfer->sockfd, rset))
        {
          /* we overwrote the buffer... */
          daemon->srv_save = NULL;
-         
+
          if ((len = recv(transfer->sockfd, daemon->packet, 
daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
            {
-             if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned 
short)transfer->block) 
+             if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned 
short)transfer->block)
                {
                  /* Got ack, ensure we take the (re)transmit path */
                  transfer->timeout = now;
@@ -453,6 +479,7 @@
                }
              else if (ntohs(mess->op) == OP_ERR)
                {
+                 char istr[46];
                  char *p = daemon->packet + sizeof(struct ack);
                  char *end = daemon->packet + len;
                  char *err = next(&p, end);
@@ -468,26 +495,26 @@
                      *q = 0;
                    }
                  my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from 
%s"),
-                           (int)ntohs(mess->block), err, 
-                           inet_ntoa(transfer->peer.sin_addr));        
-                 
+                           (int)ntohs(mess->block), err,
+                           mysockaddr_print(&transfer->peer, istr, 
sizeof(istr)));
+
                  /* Got err, ensure we take abort */
                  transfer->timeout = now;
                  transfer->backoff = 100;
                }
            }
        }
-      
+
       if (difftime(now, transfer->timeout) >= 0.0)
        {
          int endcon = 0;
 
          /* timeout, retransmit */
          transfer->timeout += 1 + (1<<transfer->backoff);
-                 
+
          /* we overwrote the buffer... */
          daemon->srv_save = NULL;
-        
+
          if ((len = get_block(daemon->packet, transfer)) == -1)
            {
              len = tftp_err_oops(daemon->packet, transfer->file->filename);
@@ -498,15 +525,18 @@
              /* don't complain about timeout when we're awaiting the last
                 ACK, some clients never send it */
              if (len != 0)
-               my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"), 
-                         transfer->file->filename, 
inet_ntoa(transfer->peer.sin_addr));
+               {
+                 char istr[46];
+                 my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
+                           transfer->file->filename, 
mysockaddr_print(&transfer->peer, istr, sizeof(istr)));
+               }
              len = 0;
            }
-         
+
          if (len != 0)
            while(sendto(transfer->sockfd, daemon->packet, len, 0, 
                         (struct sockaddr *)&transfer->peer, 
sizeof(transfer->peer)) == -1 && errno == EINTR);
-         
+
          if (endcon || len == 0)
            {
              /* unlink */
@@ -545,7 +575,7 @@
   return ret;
 }
 
-static ssize_t tftp_err(int err, char *packet, char *message, char *file)
+static ssize_t tftp_err(int err, char *packet, const char *message, const char 
*file)
 {
   struct errmess {
     unsigned short op, err;

=== modified file 'src/util.c'
--- upstream/src/util.c 2010-01-23 19:48:37 +0000
+++ ipv6_tftp/src/util.c        2010-06-18 16:19:32 +0000
@@ -512,3 +512,16 @@
   return 1;
 }
 
+const char *mysockaddr_print(const union mysockaddr *src, char *dst, unsigned 
cnt)
+{
+#ifdef HAVE_IPV6
+  return inet_ntop(src->sa.sa_family,
+                  AF_INET == src->sa.sa_family ?
+                   (const void *)&src->in.sin_addr :
+                   (const void *)&src->in6.sin6_addr,
+                  dst, cnt);
+#else
+  char *tmp = inet_ntoa(src->in.sin_addr);
+  return strncpy(dst, tmp, cnt);
+#endif
+}

Reply via email to