Package: libapr1 Version: 1.5.1-2 Severity: normal Tags: patch --- Please enter the report below this line. ---
Hi. When trying to set the mcast interface with apr_mcast_interface(), apr goes through all interfaces and tries to match the given address to the interfaces address. This does not work as it is currently implemented in linux, since the match is tried by comparing (memcmp()) the sin6_addr field of the given struct sockaddr_in6 and sa_data from a generic struct sockaddr, which do not line up. The attached patch fix_ipv6_find_if_index.patch fixes this for me. Also attached is a test program, that does not work correctly without the patch applied. The program goes through all interfaces of a host, chooses the ipv6 ones, that are not the loopback device, and tries to send a multicast packet on each address. There has to be a second ipv6 interface, for this error to actually have any effect. Regards nautsch --- System information. --- Architecture: amd64 Kernel: Linux 3.14-2-amd64 Debian Release: jessie/sid 500 unstable ftp.de.debian.org 500 stable ftp.uni-kl.de --- Package information. --- Depends (Version) | Installed =======================-+-=========== libc6 (>= 2.15) | libuuid1 (>= 2.16) | Package's Recommends field is empty. Package's Suggests field is empty.
Index: apr-1.5.1/network_io/unix/multicast.c =================================================================== --- apr-1.5.1.orig/network_io/unix/multicast.c +++ apr-1.5.1/network_io/unix/multicast.c @@ -62,7 +62,7 @@ static unsigned int find_if_index(const for (ifp = ifs; ifp; ifp = ifp->ifa_next) { if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family == AF_INET6) { if (memcmp(&iface->sa.sin6.sin6_addr, - &ifp->ifa_addr->sa_data[0], + &((struct sockaddr_in6*)ifp->ifa_addr)->sin6_addr, sizeof(iface->sa.sin6.sin6_addr)) == 0) { index = if_nametoindex(ifp->ifa_name); break;
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <netdb.h> #include <sys/ioctl.h> #include <net/if.h> #include <ifaddrs.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> #include <apr.h> #include <apr_errno.h> #include <apr_network_io.h> #define BCADDR_SITE "ff15::1234" #define MC_PORT 30000 int main(int argc, char **argv) { apr_socket_t *s; apr_sockaddr_t *addr; apr_pool_t *pool; apr_status_t err; char buffer[1024]; apr_initialize(); atexit(apr_terminate); apr_pool_create(&pool, NULL); if ((err = apr_socket_create(&s, APR_INET6, SOCK_DGRAM, 0, pool)) != APR_SUCCESS) { fprintf(stderr, "failed to create socket\n"); return 1; } if ((err = apr_sockaddr_info_get(&addr, BCADDR_SITE, APR_INET6, MC_PORT, 0, pool)) != APR_SUCCESS) { fprintf(stderr, "could not create mcast addrinfo %s\n", apr_strerror(err, buffer, 1024)); return 1; } { struct ifaddrs *ifaddrs; struct ifaddrs *ia; getifaddrs(&ifaddrs); for (ia = ifaddrs; ia; ia = ia->ifa_next) { apr_sockaddr_t *src_addr; char addr_str[INET6_ADDRSTRLEN + 1]; apr_size_t len = 6; apr_status_t ret; if (!ia->ifa_addr) { continue; } switch (ia->ifa_addr->sa_family) { case AF_INET6: // we cannot send multicasts on the loopback interface if (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6*)ia->ifa_addr)->sin6_addr)) { continue; } if (inet_ntop(AF_INET6, &((struct sockaddr_in6*)ia->ifa_addr)->sin6_addr, addr_str, INET6_ADDRSTRLEN) == NULL) { fprintf(stderr, "failed to create string v6 address: %s\n", strerror(errno)); return 1; } fprintf(stderr, "v6 addr: %s belongs to device %d\n", addr_str, if_nametoindex(ia->ifa_name)); break; default: continue; } if ((ret = apr_sockaddr_info_get(&src_addr, addr_str, APR_INET6, MC_PORT, 0, pool)) != APR_SUCCESS) { fprintf(stderr, "could no create sockaddr for mcast_interface %s\n", apr_strerror(ret, buffer, 1024)); return 1; } if (apr_mcast_interface(s, src_addr) != APR_SUCCESS) { fprintf(stderr, "could not set mcast interface"); return 1; } if ((err = apr_socket_sendto(s, addr, 0, "hallo\n", &len)) != APR_SUCCESS) { fprintf(stderr, "failed to send %s\n", apr_strerror(err, buffer, 1024)); return 1; } fprintf(stderr, "sent\n"); } freeifaddrs(ifaddrs); } return 0; }