+/*
+ discovery.c -- local network discovery
+ Copyright (C) 2014-2021 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
#define __APPLE_USE_RFC_3542
#include "system.h"
struct cmsghdr align;
} u;
+ memset(&u, 0, sizeof(u));
+
struct msghdr msg = {
.msg_name = (struct sockaddr *) &dest->sa,
.msg_namelen = SALEN(dest->sa),
.msg_controllen = sizeof(u.buf),
};
-
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
memmove(p, p + 1, (mesh->discovery.addresses + --mesh->discovery.address_count - p) * sizeof(*p));
}
-#if !defined(__linux) && (defined(RTM_NEWADDR) || defined(__APPLE__))
-static void scan_ifaddrs(meshlink_handle_t *mesh) {
+void scan_ifaddrs(meshlink_handle_t *mesh) {
+#ifdef HAVE_GETIFADDRS
struct ifaddrs *ifa = NULL;
if(getifaddrs(&ifa) == -1) {
}
freeifaddrs(ifa);
-}
+#else
+ (void)mesh;
#endif
+}
#if defined(__linux)
static void netlink_getlink(int fd) {
if(loop->now.tv_sec > mesh->discovery.last_update + 5) {
mesh->discovery.last_update = loop->now.tv_sec;
- handle_network_change(mesh, 1);
+ handle_network_change(mesh, true);
}
}
}
}
#elif defined(__APPLE__)
-static void network_change_callback(SCDynamicStoreRef store, CFArrayRef keys, void *info) {
- (void)store;
- (void)keys;
+static void reachability_change_callback(SCNetworkReachabilityRef reachability, SCNetworkReachabilityFlags flags, void *info) {
+ (void)reachability;
+ (void)flags;
meshlink_handle_t *mesh = info;
pthread_mutex_lock(&mesh->mutex);
- logger(mesh, MESHLINK_ERROR, "Network change detected!");
scan_ifaddrs(mesh);
if(mesh->loop.now.tv_sec > mesh->discovery.last_update + 5) {
+ logger(mesh, MESHLINK_INFO, "Network change detected");
mesh->discovery.last_update = mesh->loop.now.tv_sec;
- handle_network_change(mesh, 1);
+ handle_network_change(mesh, true);
}
pthread_mutex_unlock(&mesh->mutex);
mesh->discovery.runloop = CFRunLoopGetCurrent();
- SCDynamicStoreContext context = {0, mesh, NULL, NULL, NULL};
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("network_change_handler"), network_change_callback, &context);
- CFStringRef interfaces = SCDynamicStoreKeyCreate(NULL, CFSTR("State:/Network/Interface"), kCFStringEncodingUTF8);
- CFStringRef ipv4 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
- CFStringRef ipv6 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
- CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFRunLoopSourceRef runloop_source = NULL;
-
- if(!store) {
- logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError()));
- goto exit;
- }
-
- if(!interfaces || !ipv4 || !ipv6 || !keys || !patterns) {
- logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError()));
- goto exit;
- }
+ SCNetworkReachabilityRef reach_v4 = SCNetworkReachabilityCreateWithName(NULL, "93.184.216.34");
+ SCNetworkReachabilityRef reach_v6 = SCNetworkReachabilityCreateWithName(NULL, "2606:2800:220:1:248:1893:25c8:1946");
- CFArrayAppendValue(keys, interfaces);
- CFArrayAppendValue(patterns, ipv4);
- CFArrayAppendValue(patterns, ipv6);
+ SCNetworkReachabilityContext context;
+ memset(&context, 0, sizeof(context));
+ context.info = mesh;
- if(!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) {
- logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError()));
- goto exit;
+ if(reach_v4) {
+ SCNetworkReachabilitySetCallback(reach_v4, reachability_change_callback, &context);
+ SCNetworkReachabilityScheduleWithRunLoop(reach_v4, mesh->discovery.runloop, kCFRunLoopDefaultMode);
+ } else {
+ logger(mesh, MESHLINK_ERROR, "Could not create IPv4 network reachability watcher");
}
- runloop_source = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
-
- if(!runloop_source) {
- logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError()));
- goto exit;
+ if(reach_v6) {
+ SCNetworkReachabilitySetCallback(reach_v6, reachability_change_callback, &context);
+ SCNetworkReachabilityScheduleWithRunLoop(reach_v6, mesh->discovery.runloop, kCFRunLoopDefaultMode);
+ } else {
+ logger(mesh, MESHLINK_ERROR, "Could not create IPv6 network reachability watcher");
}
- CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_source, kCFRunLoopDefaultMode);
CFRunLoopRun();
-exit:
-
- if(runloop_source) {
- CFRelease(runloop_source);
- }
-
- if(interfaces) {
- CFRelease(interfaces);
- }
-
- if(ipv4) {
- CFRelease(ipv4);
- }
-
- if(ipv6) {
- CFRelease(ipv6);
- }
-
- if(keys) {
- CFRelease(keys);
- }
+ mesh->discovery.runloop = NULL;
- if(patterns) {
- CFRelease(patterns);
+ if(reach_v4) {
+ SCNetworkReachabilityUnscheduleFromRunLoop(reach_v4, mesh->discovery.runloop, kCFRunLoopDefaultMode);
+ CFRelease(reach_v4);
}
- if(store) {
- CFRelease(store);
+ if(reach_v6) {
+ SCNetworkReachabilityUnscheduleFromRunLoop(reach_v6, mesh->discovery.runloop, kCFRunLoopDefaultMode);
+ CFRelease(reach_v6);
}
- mesh->discovery.runloop = NULL;
-
return NULL;
-
}
#elif defined(RTM_NEWADDR)
static void pfroute_parse_iface(meshlink_handle_t *mesh, const struct rt_msghdr *rtm) {
.in.sin_port = ntohs(5353),
};
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+#ifdef SO_REUSEPORT
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
+#endif
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one8, sizeof(one8));
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl8, sizeof(ttl8));
}
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+#ifdef SO_REUSEPORT
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
+#endif
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
netlink_getlink(sock);
} else {
logger(mesh, MESHLINK_WARNING, "Could not bind AF_NETLINK socket: %s", strerror(errno));
+ scan_ifaddrs(mesh);
}
} else {
logger(mesh, MESHLINK_WARNING, "Could not open AF_NETLINK socket: %s", strerror(errno));
+ scan_ifaddrs(mesh);
}
#elif defined(__APPLE__)