Bug#759534: [libapr1] apr_mcast_interface does not work for IPv6
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;
}
Reply to: