Re: [Dnsmasq-discuss] TFTP for IPv6
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
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
Ah, ok, I'll pursue patching tftpd-hpa. Thanks, Ean
Re: [Dnsmasq-discuss] TFTP for IPv6
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
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
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
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
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