[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: