From e6e971ba1b23bb67b43a909b486cbad5c6e96e06 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 18 Feb 2015 16:54:00 +0100 Subject: socket: Add functions for multicast group join/leave and IPv6 socket creation Add functions missed in previous commit, 069060cad6d9 ("llmnrd: Join IP multicast group on each new interface"). Also add socket_open_ipv6() to creat IPv6 sockets. Not used yet. Signed-off-by: Tobias Klauser --- socket.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 9 deletions(-) (limited to 'socket.c') diff --git a/socket.c b/socket.c index cca2fc3..2e2b28e 100644 --- a/socket.c +++ b/socket.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -35,11 +36,10 @@ static const int YES = 1; static const int NO = 0; -int socket_open_v4(uint16_t port) +int socket_open_ipv4(uint16_t port) { int sock; struct sockaddr_in sa; - struct ip_mreq mreq; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { @@ -49,7 +49,7 @@ int socket_open_v4(uint16_t port) /* pass pktinfo struct on received packets */ if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &YES, sizeof(YES)) < 0) { - log_err("Failed to set IP_PKTINFO option: %s\n", strerror(errno)); + log_err("Failed to set IPv4 packet info socket option: %s\n", strerror(errno)); goto err; } @@ -64,13 +64,41 @@ int socket_open_v4(uint16_t port) goto err; } - /* join the multicast group */ - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_interface.s_addr = INADDR_ANY; - inet_pton(AF_INET, LLMNR_IPV4_MCAST_ADDR, &mreq.imr_multiaddr); + return sock; +err: + close(sock); + return -1; +} + +int socket_open_ipv6(uint16_t port) +{ + int sock, opt_pktinfo; + struct sockaddr_in6 sa; - if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { - log_err("Failed to join multicast group: %s\n", strerror(errno)); + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) { + log_err("Failed to open UDP socket: %s\n", strerror(errno)); + return -1; + } + + /* pass pktinfo struct on received packets */ +#if defined(IPV6_RECVPKTINFO) + opt_pktinfo = IPV6_RECVPKTINFO; +#elif defined(IPV6_PKTINFO) + opt_pktinfo = IPV6_PKTINFO; +#endif + if (setsockopt(sock, IPPROTO_IPV6, opt_pktinfo, &YES, sizeof(YES)) < 0) { + log_err("Failed to set IPv4 packet info socket option: %s\n", strerror(errno)); + goto err; + } + + /* bind the socket */ + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(port); + + if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + log_err("Failed to bind() socket: %s\n", strerror(errno)); goto err; } @@ -111,3 +139,49 @@ err: close(sock); return -1; } + +int socket_mcast_group_ipv4(int sock, unsigned int ifindex, bool join) +{ + struct ip_mreqn mreq; + char ifname[IF_NAMESIZE]; + + /* silently ignore, we might not be listening on an IPv4 socket */ + if (sock < 0) + return -1; + + memset(&mreq, 0, sizeof(mreq)); + mreq.imr_ifindex = ifindex; + mreq.imr_address.s_addr = INADDR_ANY; + inet_pton(AF_INET, LLMNR_IPV4_MCAST_ADDR, &mreq.imr_multiaddr); + + if (setsockopt(sock, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + log_err("Failed to join multicast group on interface %s: %s\n", + if_indextoname(ifindex, ifname), strerror(errno)); + return -1; + } + + return 0; +} + +int socket_mcast_group_ipv6(int sock, unsigned int ifindex, bool join) +{ + struct ipv6_mreq mreq; + char ifname[IF_NAMESIZE]; + + /* silently ignore, we might not be listening on an IPv6 socket */ + if (sock < 0) + return -1; + + memset(&mreq, 0, sizeof(mreq)); + inet_pton(AF_INET6, LLMNR_IPV6_MCAST_ADDR, &mreq.ipv6mr_multiaddr); + + if (setsockopt(sock, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + log_err("Failed to join multicast group on interface %s: %s\n", + if_indextoname(ifindex, ifname), strerror(errno)); + return -1; + } + + return 0; +} -- cgit v1.2.3-54-g00ecf