Index: tftp-hpa-5.2/tftpd/recvfrom.c =================================================================== --- tftp-hpa-5.2.orig/tftpd/recvfrom.c 2015-04-30 11:04:45.994568260 +0200 +++ tftp-hpa-5.2/tftpd/recvfrom.c 2015-05-14 16:02:28.104576816 +0200 @@ -148,17 +148,17 @@ myrecvfrom(int s, void *buf, int len, un #endif /* Try to enable getting the return address */ + /* Before the first packet we don't know the address family of the + * connection, so we set both ipv4 and ipv6 socket options + */ #ifdef IP_RECVDSTADDR - if (from->sa_family == AF_INET) setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)); #endif #ifdef IP_PKTINFO - if (from->sa_family == AF_INET) setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); #endif #ifdef HAVE_IPV6 #ifdef IPV6_RECVPKTINFO - if (from->sa_family == AF_INET6) setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); #endif #endif @@ -190,7 +190,7 @@ myrecvfrom(int s, void *buf, int len, un for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; cmptr = CMSG_NXTHDR(&msg, cmptr)) { - if (from->sa_family == AF_INET) { + if (cmptr->cmsg_level == IPPROTO_IP) { myaddr->sa.sa_family = AF_INET; #ifdef IP_RECVDSTADDR if (cmptr->cmsg_level == IPPROTO_IP && @@ -209,15 +209,26 @@ myrecvfrom(int s, void *buf, int len, un sizeof(struct in_addr)); } #endif + if (from->sa_family == AF_INET6) { + from->sa_family = AF_INET; + /* Unmap the ipv4 address from ipv6. + * The ipv6 mapped address is in format: + * 10 0x0 bytes, 2 0xff bytes, 4 bytes of the ipv4 address + * so we cut out the first 12 bytes of the ipv6 and + * interpret the rest as the ipv4 + */ + ((struct sockaddr_in *)from)->sin_addr = *((struct in_addr *)(((struct sockaddr_in6 *)from)->sin6_addr.s6_addr+12)); + } } #ifdef HAVE_IPV6 - else if (from->sa_family == AF_INET6) { + else if (cmptr->cmsg_level == IPPROTO_IPV6) { myaddr->sa.sa_family = AF_INET6; #ifdef IP6_RECVDSTADDR if (cmptr->cmsg_level == IPPROTO_IPV6 && - cmptr->cmsg_type == IPV6_RECVDSTADDR ) + cmptr->cmsg_type == IPV6_RECVDSTADDR ) { memcpy(&myaddr->s6.sin6_addr, CMSG_DATA(cmptr), sizeof(struct in6_addr)); + } #endif #ifdef HAVE_STRUCT_IN6_PKTINFO