From 4a575cd3c466abfccf4516f5e9f6eacd534f4dc1 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 24 Apr 2020 23:28:24 +0200 Subject: Set MCAST_LOOP/IPV6_V6ONLY only on supported sockets, select outbound multicast interfaces properly --- backends/libmmbackend.c | 4 ++-- backends/rtpmidi.c | 44 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/backends/libmmbackend.c b/backends/libmmbackend.c index 186cc66..bad048c 100644 --- a/backends/libmmbackend.c +++ b/backends/libmmbackend.c @@ -167,7 +167,7 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener, uin } yes = dualstack ? 0 : 1; - if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &yes, sizeof(yes)) < 0){ + if(addr_it->ai_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &yes, sizeof(yes)) < 0){ LOGPF("Failed to %s dualstack operations on socket: %s", dualstack ? "enable" : "disable", mmbackend_socket_strerror(errno)); } @@ -178,7 +178,7 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener, uin } yes = 0; - if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*) &yes, sizeof(yes)) < 0){ + if(setsockopt(fd, addr_it->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6, addr_it->ai_family == AF_INET ? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP, (void*) &yes, sizeof(yes)) < 0){ LOGPF("Failed to disable IP_MULTICAST_LOOP on socket: %s", mmbackend_socket_strerror(errno)); } } diff --git a/backends/rtpmidi.c b/backends/rtpmidi.c index eb08e8d..7c5aa69 100644 --- a/backends/rtpmidi.c +++ b/backends/rtpmidi.c @@ -1,5 +1,5 @@ #define BACKEND_NAME "rtpmidi" -#define DEBUG +//#define DEBUG #include #include @@ -15,6 +15,7 @@ #include #else #include +#include #include #include #endif @@ -47,6 +48,10 @@ static struct /*_rtpmidi_global*/ { char* mdns_name; char* mdns_interface; + #ifdef _WIN32 + unsigned mdns_adapter; + unsigned mdns6_adapter; + #endif uint8_t detect; uint64_t last_service; @@ -283,6 +288,13 @@ static int rtpmidi_announce_addrs(){ continue; } + //for exact matches, use exactly this interface for multicasts + if(!strcmp(iface, cfg.mdns_interface)){ + LOGPF("Using interface %s for mDNS discovery", iface); + cfg.mdns_adapter = iter->IfIndex; + cfg.mdns6_adapter = iter->Ipv6IfIndex; + } + for(unicast_addr = (IP_ADAPTER_UNICAST_ADDRESS_LH*) iter->FirstUnicastAddress; unicast_addr; unicast_addr = unicast_addr->Next){ addr.in = unicast_addr->Address.lpSockaddr; #else @@ -1437,7 +1449,7 @@ static int rtpmidi_apple_peermatch(uint8_t* session_raw, struct sockaddr* peer, for(n = 0; n < cfg.invite[u].invites; n++){ if(!strcmp(cfg.invite[u].name[n], "*")){ done = 1; - DBGPF("Peer %.*s implicitly invited on instance %s, converting to explicit invitation", session_name[0], session_name + 1, cfg.invite[u].inst->name); + DBGPF("Peer %s implicitly invited on instance %s, converting to explicit invitation", session_name, cfg.invite[u].inst->name); if(rtpmidi_push_invite(cfg.invite[u].inst, session_name)){ return 1; } @@ -1524,6 +1536,9 @@ static int rtpmidi_handle_mdns(int fd){ ssize_t bytes = 0; struct sockaddr_storage peer_addr; socklen_t peer_len = sizeof(peer_addr); + #ifdef DEBUG + char peer_name[INET6_ADDRSTRLEN + 1]; + #endif for(bytes = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr*) &peer_addr, &peer_len); bytes > 0; @@ -1542,10 +1557,11 @@ static int rtpmidi_handle_mdns(int fd){ //rfc6762 18.3: opcode != 0 -> ignore //rfc6762 18.11: response code != 0 -> ignore - DBGPF("%" PRIsize_t " bytes on v%c, ID %d, Opcode %d, %s, %d questions, %d answers, %d servers, %d additional", + DBGPF("%" PRIsize_t " bytes on v%c, ID %d, Opcode %d, %s, %d questions, %d answers, %d servers, %d additional, src %s", bytes, (fd == cfg.mdns_fd ? '6' : '4'), hdr->id, DNS_OPCODE(hdr->flags[0]), DNS_RESPONSE(hdr->flags[0]) ? "response" : "query", - hdr->questions, hdr->answers, hdr->servers, hdr->additional); + hdr->questions, hdr->answers, hdr->servers, hdr->additional, + mmbackend_sockaddr_ntop((struct sockaddr*) &peer_addr, peer_name, sizeof(peer_name))); rtpmidi_parse_announce(buffer, bytes, hdr, &name, &host, (struct sockaddr*) &peer_addr, peer_len); peer_len = sizeof(peer_addr); @@ -1605,9 +1621,15 @@ static int rtpmidi_handle(size_t num, managed_fd* fds){ } static int rtpmidi_start_mdns(){ + //use ip_mreqn where possible, but that renames the interface member + #ifdef _WIN32 struct ip_mreq mcast_req = { - .imr_multiaddr.s_addr = htobe32(((uint32_t) 0xe00000fb)), - .imr_interface.s_addr = INADDR_ANY + .imr_interface.s_addr = INADDR_ANY, + #else + struct ip_mreqn mcast_req = { + .imr_address.s_addr = INADDR_ANY, + #endif + .imr_multiaddr.s_addr = htobe32(((uint32_t) 0xe00000fb)) }; struct ipv6_mreq mcast6_req = { @@ -1623,6 +1645,16 @@ static int rtpmidi_start_mdns(){ return 0; } + if(cfg.mdns_interface){ + #ifdef _WIN32 + mcast6_req.ipv6mr_interface = cfg.mdns6_adapter; + mcast_req.imr_interface.s_addr = htobe32(cfg.mdns_adapter); + #else + mcast6_req.ipv6mr_interface = if_nametoindex(cfg.mdns_interface); + mcast_req.imr_ifindex = if_nametoindex(cfg.mdns_interface); + #endif + } + //FIXME might try passing NULL as host here to work around possible windows ipv6 handicaps cfg.mdns_fd = mmbackend_socket(RTPMIDI_DEFAULT_HOST, RTPMIDI_MDNS_PORT, SOCK_DGRAM, 1, 1, 0); cfg.mdns4_fd = mmbackend_socket(RTPMIDI_DEFAULT4_HOST, RTPMIDI_MDNS_PORT, SOCK_DGRAM, 1, 1, 0); -- cgit v1.2.3