diff --git a/osdep/MacDNSHelper.hpp b/osdep/MacDNSHelper.hpp index 7a2902fa5..2fa283621 100644 --- a/osdep/MacDNSHelper.hpp +++ b/osdep/MacDNSHelper.hpp @@ -3,6 +3,7 @@ #include #include "../node/InetAddress.hpp" +#include "../node/MAC.hpp" namespace ZeroTier { @@ -11,6 +12,8 @@ class MacDNSHelper public: static void setDNS(uint64_t nwid, const char *domain, const std::vector &servers); static void removeDNS(uint64_t nwid); + static bool addIps(uint64_t nwid, const MAC mac, const char *dev, const std::vector &addrs); + static bool removeIps(uint64_t nwid); }; } diff --git a/osdep/MacDNSHelper.mm b/osdep/MacDNSHelper.mm index 38e74dc3f..8a5bebd92 100644 --- a/osdep/MacDNSHelper.mm +++ b/osdep/MacDNSHelper.mm @@ -6,6 +6,11 @@ namespace ZeroTier { +static void printKeys (const void* key, const void* value, void* context) { + CFShow(key); + CFShow(value); +} + void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vector &servers) { SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL); @@ -85,4 +90,130 @@ void MacDNSHelper::removeDNS(uint64_t nwid) CFRelease(ds); } -} \ No newline at end of file +// Make macOS believe we do in fact have ipv6 connectivity and that it should resolve dns names +// over ipv6 if we ask for them. +// Originally I planned to put all the v6 ip addresses from the network into the config. +// But only the link local address is necessary and sufficient. Added other v6 addresses +// doesn't do anything. +bool MacDNSHelper::addIps(uint64_t nwid, const MAC mac, const char *dev, const std::vector& addrs) +{ + + bool hasV6 = false; + for (unsigned int i = 0; i < addrs.size(); ++i) { + if (addrs[i].isV6()) { + hasV6 = true; + break; + } + } + + if (!hasV6) { + MacDNSHelper::removeIps(nwid); + return true; + } + + + SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL); + char buf[256] = { 0 }; + sprintf(buf, "State:/Network/Service/%.16llx/IPv6", nwid); + + InetAddress ll = InetAddress::makeIpv6LinkLocal(mac); + char buf2[256] = {0}; + const char* llStr = ll.toIpString(buf2); + + + CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); + CFStringRef* cfaddrs = new CFStringRef[1]; + CFStringRef* cfprefixes = new CFStringRef[1]; + CFStringRef* cfdestaddrs = new CFStringRef[1]; + CFStringRef* cfflags = new CFStringRef[1]; + + + cfaddrs[0] = CFStringCreateWithCString(NULL, llStr, kCFStringEncodingUTF8); + cfprefixes[0] = CFStringCreateWithCString(NULL, "64", kCFStringEncodingUTF8); + cfdestaddrs[0] = CFStringCreateWithCString(NULL, "::ffff:ffff:ffff:ffff:0:0", kCFStringEncodingUTF8); + cfflags[0] = CFStringCreateWithCString(NULL, "0", kCFStringEncodingUTF8); + + CFArrayRef addrArray = CFArrayCreate(NULL, (const void**)cfaddrs, 1, &kCFTypeArrayCallBacks); + CFArrayRef prefixArray = CFArrayCreate(NULL, (const void**)cfprefixes, 1, &kCFTypeArrayCallBacks); + CFArrayRef destArray = CFArrayCreate(NULL, (const void**)cfdestaddrs, 1, &kCFTypeArrayCallBacks); + CFArrayRef flagsArray = CFArrayCreate(NULL, (const void**)cfflags, 1, &kCFTypeArrayCallBacks); + CFStringRef cfdev = CFStringCreateWithCString(NULL, dev, kCFStringEncodingUTF8); + + const int SIZE = 5; + CFStringRef keys[SIZE]; + keys[0] = CFSTR("Addresses"); + keys[1] = CFSTR("DestAddresses"); + keys[2] = CFSTR("Flags"); + keys[3] = CFSTR("InterfaceName"); + keys[4] = CFSTR("PrefixLength"); + + CFTypeRef values[SIZE]; + values[0] = addrArray; + values[1] = destArray; + values[2] = flagsArray; + // values[3] = devArray; + values[3] = cfdev; + values[4] = prefixArray; + + + CFDictionaryRef dict = CFDictionaryCreate(NULL, + (const void**)keys, (const void**)values, SIZE, &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // CFDictionaryApplyFunction(dict, printKeys, NULL); + + CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key); + CFIndex i = 0, j = CFArrayGetCount(list); + bool addrsChanged = true; + CFPropertyListRef oldAddrs = NULL; + + bool ret = TRUE; + if (j > 0) { + oldAddrs = SCDynamicStoreCopyValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i)); + addrsChanged = !CFEqual(oldAddrs,dict); + } + if (addrsChanged) { + if (j <= 0) { + ret &= SCDynamicStoreAddValue(ds, key, dict); + } else { + ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict); + } + if (!ret) { + fprintf(stderr, "Error writing IPv6 configuration\n"); + } + } + + CFRelease(addrArray); + CFRelease(prefixArray); + CFRelease(destArray); + CFRelease(flagsArray); + CFRelease(cfdev); + + CFRelease(list); + CFRelease(dict); + + CFRelease(ds); + CFRelease(key); + + delete[] cfaddrs; + delete[] cfprefixes; + delete[] cfdestaddrs; + delete[] cfflags; + + return ret; +} +bool MacDNSHelper::removeIps(uint64_t nwid) +{ + SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL); + + char buf[256] = {0}; + sprintf(buf, "State:/Network/Service/%.16llx/IPv6", nwid); + CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); + bool res = SCDynamicStoreRemoveValue(ds, key); + CFRelease(key); + CFRelease(ds); + + return res; +} + +} diff --git a/osdep/MacEthernetTap.cpp b/osdep/MacEthernetTap.cpp index 1ba82dcb7..55822fd5a 100644 --- a/osdep/MacEthernetTap.cpp +++ b/osdep/MacEthernetTap.cpp @@ -244,6 +244,7 @@ MacEthernetTap::~MacEthernetTap() pid_t pid0,pid1; MacDNSHelper::removeDNS(_nwid); + MacDNSHelper::removeIps(_nwid); Mutex::Lock _gl(globalTapCreateLock); ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit diff --git a/service/OneService.cpp b/service/OneService.cpp index 255bad21e..68891b8e5 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2041,6 +2041,11 @@ public: fprintf(stderr,"ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString(ipbuf)); } } + +#ifdef __APPLE__ + if (!MacDNSHelper::addIps(n.config.nwid, n.config.mac, n.tap->deviceName().c_str(), newManagedIps)) + fprintf(stderr, "ERROR: unable to add v6 addresses to system configuration" ZT_EOL_S); +#endif #endif n.managedIps.swap(newManagedIps); }