Re: [Dnsmasq-discuss] TFTP for IPv6

2010-06-24 Thread Simon Kelley
Thanks to Jan 'RedBully' Seiffert, dnsmasq now has IPv6 support in the
TFTP server. To use this, you'll need a client which also knows about
IPv6, I found that current versions of tftp-hpa do.

A test release with this functionality is available at:

http://www.thekelleys.org.uk/dnsmasq/test-releases/dnsmasq-2.56test4.tar.gz


Cheers,

Simon.



Re: [Dnsmasq-discuss] TFTP for IPv6

2010-06-18 Thread richardvo...@gmail.com
Not totally sure, but I seem to recall that IPv6 support in dnsmasq
means it supports handling  DNS records which are mappings to IPv6
addresses, and perhaps PTRv6 records.  Not IPv6 sockets.

On Thu, Jun 17, 2010 at 4:43 PM, Ean Houts eho...@edgewaternetworks.com wrote:
 Hello - I'm attempting to use dnsmasq mainly for it's tftp server.  My
 requirements are a multi-homed tftp server that serves both ipv4 and
 ipv6 tftp clients.

 I'm using fedora core 11, and the box as two NICs, both of which have
 ipv4 and ipv6 addresses.  One of the NICs has multiple aliases with
 distinct subnets (this is a test environment that needs to exercise alot
 of different functionality).

 Anyway, I have the dnsmasq tftp server running, but it won't respond to
 any ipv6 addresses.  dnsmasq reports ipv6 support :
 Compile time options IPv6 GNU-getopt DBus no-I18N DHCP TFTP

 And I've tried to enable this in the config - the uncommented settings
 are :
 no-resolv
 no-poll
 enable-tftp
 tftp-root=/export/test_data/tftpboot
 tftp-no-blocksize
 conf-dir=/etc/dnsmasq.d

 Unfortunately, tftp starts only listening for ipv4 :
 sudo lsof | grep tftp
 dnsmasq   24942    nobody    8u     IPv4           11864044
 0t0        UDP *:tftp

 using the fedora core standard tftpd server, I have no problem
 configuring it for ipv6.  Unfortunately, it doesn't seem to work very
 well with multi-homed hosts :-(

 Any pointers or tips would be greatly appreciated.
 thanks,
 Ean

 ___
 Dnsmasq-discuss mailing list
 Dnsmasq-discuss@lists.thekelleys.org.uk
 http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss




Re: [Dnsmasq-discuss] TFTP for IPv6

2010-06-18 Thread Ean Houts
Ah, ok, I'll pursue patching tftpd-hpa.
Thanks,
Ean




Re: [Dnsmasq-discuss] TFTP for IPv6

2010-06-18 Thread Simon Kelley
Ean Houts wrote:
 Hello - I'm attempting to use dnsmasq mainly for it's tftp server.  My 
 requirements are a multi-homed tftp server that serves both ipv4 and 
 ipv6 tftp clients.
 
 I'm using fedora core 11, and the box as two NICs, both of which have 
 ipv4 and ipv6 addresses.  One of the NICs has multiple aliases with 
 distinct subnets (this is a test environment that needs to exercise alot 
 of different functionality).
 
 Anyway, I have the dnsmasq tftp server running, but it won't respond to 
 any ipv6 addresses.  dnsmasq reports ipv6 support :
 Compile time options IPv6 GNU-getopt DBus no-I18N DHCP TFTP
 
 And I've tried to enable this in the config - the uncommented settings 
 are :
 no-resolv
 no-poll
 enable-tftp
 tftp-root=/export/test_data/tftpboot
 tftp-no-blocksize
 conf-dir=/etc/dnsmasq.d
 
 Unfortunately, tftp starts only listening for ipv4 :
 sudo lsof | grep tftp
 dnsmasq   24942nobody8u IPv4   11864044   
 0t0UDP *:tftp
 
 using the fedora core standard tftpd server, I have no problem 
 configuring it for ipv6.  Unfortunately, it doesn't seem to work very 
 well with multi-homed hosts :-(
 
 Any pointers or tips would be greatly appreciated.
 thanks,

The TFTP server doesn't support IPv6 - my design criteria were to make
the simplest, smallest TFTP server needed to support netboot, and since
I'm not aware of any netboot infrastructure which runs over IPv6, I
didn't include that.

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.

Cheers,

Simon.



Re: [Dnsmasq-discuss] TFTP for IPv6

2010-06-18 Thread Jan 'RedBully' Seiffert
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 +
+++ ipv6_tftp/src/dnsmasq.h 2010-06-18 16:23:46 +
@@ -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 +
+++ ipv6_tftp/src/network.c 2010-06-18 16:23:49 +
@@ -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 +
+++ ipv6_tftp/src/tftp.c2010-06-18 16:33:32 +
@@ -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 == 

Re: [Dnsmasq-discuss] TFTP for IPv6

2010-06-18 Thread Jan 'RedBully' Seiffert
Jan 'RedBully' Seiffert schrieb:
 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
 
 

step two:
tell the udpfromto copy how to deal with ipv6

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

same, but i tested code like that in another project of mine, so should work,
minus bugs...

Greetings
Jan

-- 
Every program in development at MIT expands until it can read mail.
=== modified file 'src/tftp.c'
--- upstream/src/tftp.c 2010-06-18 16:34:34 +
+++ ipv6_tftp/src/tftp.c2010-06-18 17:09:35 +
@@ -90,15 +90,9 @@
   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.in = listen-iface-addr.in;
+  addr = listen-iface-addr;
   mtu = listen-iface-mtu;
   name = listen-iface-name;
 }
@@ -108,8 +102,13 @@
   int check;
   struct interface_list *ir;
 
+  memset(addr, 0, sizeof(addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.sa.sa_len = sizeof(addr);
+#endif
+  addr.sa.sa_family = AF_INET;
+
 // 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)
@@ -122,6 +121,19 @@
addr.in.sin_addr = p.p-ipi_spec_dst;
if_index = p.p-ipi_ifindex;
  }
+#ifdef HAVE_IPV6
+   else if (cmptr-cmsg_level == SOL_IPV6  cmptr-cmsg_type == 
daemon-v6pktinfo)
+ {
+   union {
+ unsigned char *c;
+ struct in6_pktinfo *p;
+   } p;
+   p.c = CMSG_DATA(cmptr);
+   addr.in6.sin6_family = AF_INET6;
+   memcpy(addr.in6.sin6_addr, p.p-ipi6_addr, 
sizeof(addr.in6.sin6_addr));
+   if_index = p.p-ipi6_ifindex;
+ }
+#endif
 
 #elif defined(HAVE_SOLARIS_NETWORK)
   for (cmptr = CMSG_FIRSTHDR(msg); cmptr; cmptr = CMSG_NXTHDR(msg, 
cmptr))
@@ -136,6 +148,14 @@
addr.in.sin_addr = *(p.a);
  else if (cmptr-cmsg_level == IPPROTO_IP  cmptr-cmsg_type == 
IP_RECVIF)
if_index = *(p.i);
+#ifdef HAVE_IPV6
+ /* Solaris does not have IPV6_RECVDSTADDR AFAIK, */
+ else if (cmptr-cmsg_level == IPPROTO_IPV6  cmptr-cmsg_type == 
IP_RECVIF)
+   {
+ addr.in6.sin6_family = AF_INET6;
+ if_index = p.s-sdl_index;
+   }
+#endif
}
 
 #elif defined(IP_RECVDSTADDR)  defined(IP_RECVIF)
@@ -144,6 +164,9 @@
  union {
unsigned char *c;
struct in_addr *a;
+#ifdef HAVE_IPV6
+   struct in6_addr *b;
+#endif
struct sockaddr_dl *s;
  } p;
  p.c = CMSG_DATA(cmptr);
@@ -151,6 +174,18 @@
addr.in.sin_addr = *(p.a);
  else if (cmptr-cmsg_level == IPPROTO_IP  cmptr-cmsg_type == 
IP_RECVIF)
if_index = p.s-sdl_index;
+#ifdef HAVE_IPV6
+ else if (cmptr-cmsg_level == IPPROTO_IPV6  cmptr-cmsg_type == 
IPV6_RECVDSTADDR)
+   {
+ addr.in6.sin6_family = AF_INET6;
+ memcpy(addr.in6.sin6_addr, p.b, sizeof(addr.in6.sin6_addr));
+   }
+ else if (cmptr-cmsg_level == IPPROTO_IPV6  cmptr-cmsg_type == 
IP_RECVIF)
+   {
+ addr.in6.sin6_family = AF_INET6;
+ if_index = p.s-sdl_index;
+   }
+#endif
}
 
 #endif
@@ -172,13 +207,13 @@
   for (ir = daemon-tftp_interfaces; ir; ir = ir-next)
if (strcmp(ir-interface, name) == 0)
  break;
-   
+
   if (!ir)
{
  if (!daemon-tftp_unlimited || !check)
return;
- 
-#ifdef HAVE_DHCP  
+
+#ifdef HAVE_DHCP
  /* allowed interfaces are the same as for DHCP */
  for (tmp = daemon-dhcp_except; tmp; tmp = tmp-next)
if (tmp-name  (strcmp(tmp-name, name) == 0))



Re: [Dnsmasq-discuss] TFTP for IPv6

2010-06-18 Thread Jan 'RedBully' Seiffert
Jan 'RedBully' Seiffert schrieb:
 Jan 'RedBully' Seiffert schrieb:
 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


 
 step two:
 tell the udpfromto copy how to deal with ipv6
 

and the final stepp three:
Add tftp IPv6 listener, a little bit CP, but...

And then a little cleanup of things i saw for myself.

only compile tested

Greetings
Jan

-- 
Every bug you find is the last one.
=== modified file 'src/network.c'
--- upstream/src/network.c  2010-06-18 16:34:34 +
+++ ipv6_tftp/src/network.c 2010-06-18 17:41:40 +
@@ -400,7 +400,8 @@
   !fix_fd(tcpfd) ||
   bind(tcpfd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
   listen(tcpfd, 5) == -1 ||
-  bind(fd, (struct sockaddr *)addr, sa_len(addr)) == -1) 
+  bind(fd, (struct sockaddr *)addr, sa_len(addr)) == -1)
+// TODO: we leak fd  tcpfd here
 return 0;
 
   /* The API changed around Linux 2.6.14 but the old ABI is still supported:
@@ -437,6 +438,80 @@
   
   return 1;
 }
+
+/* cp ... bad */
+static int create_ipv6_listener_tftp(struct listener **link, int port)
+{
+  union mysockaddr addr;
+  int fd;
+  struct listener *l;
+  int opt = 1;
+
+  memset(addr, 0, sizeof(addr));
+  addr.in6.sin6_family = AF_INET6;
+  addr.in6.sin6_addr = in6addr_any;
+  addr.in6.sin6_port = htons(port);
+#ifdef HAVE_SOCKADDR_SA_LEN
+  addr.in6.sin6_len = sizeof(addr.in6);
+#endif
+
+  /* No error of the kernel doesn't support IPv6 */
+  if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
+return (errno == EPROTONOSUPPORT ||
+   errno == EAFNOSUPPORT ||
+   errno == EINVAL);
+
+  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt)) == -1 ||
+  setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, opt, sizeof(opt)) == -1 ||
+  !fix_fd(fd) ||
+  bind(fd, (struct sockaddr *)addr, sa_len(addr)) == -1)
+{
+  close(fd);
+  return 0;
+}
+
+  /* The API changed around Linux 2.6.14 but the old ABI is still supported:
+ handle all combinations of headers and kernel.
+ OpenWrt note that this fixes the problem addressed by your very broken 
patch. */
+
+  daemon-v6pktinfo = IPV6_PKTINFO;
+
+#ifdef IPV6_RECVPKTINFO
+#  ifdef IPV6_2292PKTINFO
+  if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, opt, sizeof(opt)) == -1)
+{
+  if (errno == ENOPROTOOPT  setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, 
opt, sizeof(opt)) != -1)
+   daemon-v6pktinfo = IPV6_2292PKTINFO;
+  else
+   return 0;
+}
+#  else
+  if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, opt, sizeof(opt)) == -1)
+return 0;
+#  endif
+#else
+  if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, opt, sizeof(opt)) == -1)
+return 0;
+#endif
+
+  if(*link)
+{
+  l = *link;
+  l-tftpfd = fd;
+}
+  else
+{
+  l = safe_malloc(sizeof(struct listener));
+  l-fd = -1;
+  l-tcpfd = -1;
+  l-tftpfd = fd;
+  l-family = AF_INET6;
+  l-next = NULL;
+  *link = l;
+}
+
+  return 1;
+}
 #endif
 
 struct listener *create_wildcard_listeners(void)
@@ -456,11 +531,11 @@
 
   if (daemon-port != 0)
 {
-  
+
   if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
  (tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return NULL;
-  
+
   if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt)) == -1 
||
  bind(tcpfd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
  listen(tcpfd, 5) == -1 ||
@@ -475,30 +550,33 @@
 #elif defined(IP_RECVDSTADDR)  defined(IP_RECVIF)
  setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, opt, sizeof(opt)) == -1 ||
  setsockopt(fd, IPPROTO_IP, IP_RECVIF, opt, sizeof(opt)) == -1 ||
-#endif 
+#endif
  bind(fd, (struct sockaddr *)addr, sa_len(addr)) == -1)
return NULL;
 }
-  
+
 #ifdef HAVE_TFTP
   if (daemon-tftp_unlimited || daemon-tftp_interfaces)
 {
   addr.in.sin_port = htons(TFTP_PORT);
   if ((tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
return NULL;
-  
+
   if (!fix_fd(tftpfd) ||
+#ifdef HAVE_IPV6
+ !create_ipv6_listener_tftp(l6, TFTP_PORT) ||
+#endif
 #if defined(HAVE_LINUX_NETWORK) 
  setsockopt(tftpfd, SOL_IP, IP_PKTINFO, opt, sizeof(opt)) == -1 ||
 #elif defined(IP_RECVDSTADDR)  defined(IP_RECVIF)
  setsockopt(tftpfd, IPPROTO_IP, IP_RECVDSTADDR, opt, sizeof(opt)) == 
-1 ||
  setsockopt(tftpfd, IPPROTO_IP, IP_RECVIF, opt, sizeof(opt)) == -1 ||
-#endif 
+#endif
  bind(tftpfd, (struct sockaddr *)addr, sa_len(addr)) == -1)
return NULL;
 }
 #endif
-  
+
   l = safe_malloc(sizeof(struct listener));
   l-family = AF_INET;
   l-fd = fd;
@@ -590,6 +668,19 @@

[Dnsmasq-discuss] TFTP for IPv6

2010-06-17 Thread Ean Houts
Hello - I'm attempting to use dnsmasq mainly for it's tftp server.  My 
requirements are a multi-homed tftp server that serves both ipv4 and 
ipv6 tftp clients.


I'm using fedora core 11, and the box as two NICs, both of which have 
ipv4 and ipv6 addresses.  One of the NICs has multiple aliases with 
distinct subnets (this is a test environment that needs to exercise alot 
of different functionality).


Anyway, I have the dnsmasq tftp server running, but it won't respond to 
any ipv6 addresses.  dnsmasq reports ipv6 support :

Compile time options IPv6 GNU-getopt DBus no-I18N DHCP TFTP

And I've tried to enable this in the config - the uncommented settings 
are :

no-resolv
no-poll
enable-tftp
tftp-root=/export/test_data/tftpboot
tftp-no-blocksize
conf-dir=/etc/dnsmasq.d

Unfortunately, tftp starts only listening for ipv4 :
sudo lsof | grep tftp
dnsmasq   24942nobody8u IPv4   11864044   
0t0UDP *:tftp


using the fedora core standard tftpd server, I have no problem 
configuring it for ipv6.  Unfortunately, it doesn't seem to work very 
well with multi-homed hosts :-(


Any pointers or tips would be greatly appreciated.
thanks,
Ean