MacDNSHelper.mm 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. #include "MacDNSHelper.hpp"
  2. #include <stdio.h>
  3. #include <SystemConfiguration/SystemConfiguration.h>
  4. namespace ZeroTier {
  5. static void printKeys (const void* key, const void* value, void* context) {
  6. CFShow(key);
  7. CFShow(value);
  8. }
  9. void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vector<InetAddress> &servers)
  10. {
  11. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  12. CFStringRef *s = new CFStringRef[4];
  13. for (unsigned int i = 0; i < servers.size(); ++i) {
  14. char buf[64];
  15. ZeroTier::InetAddress a = servers[i];
  16. const char *ipStr = a.toIpString(buf);
  17. s[i] = CFStringCreateWithCString(NULL, ipStr, kCFStringEncodingUTF8);
  18. }
  19. CFArrayRef serverArray = CFArrayCreate(NULL, (const void**)s, servers.size(), &kCFTypeArrayCallBacks);
  20. CFStringRef keys[2];
  21. keys[0] = CFSTR("SupplementalMatchDomains");
  22. keys[1] = CFSTR("ServerAddresses");
  23. CFStringRef cfdomain = CFStringCreateWithCString(NULL, domain, kCFStringEncodingUTF8);
  24. CFArrayRef domainArray = CFArrayCreate(NULL, (const void**)&cfdomain, 1, &kCFTypeArrayCallBacks);
  25. CFTypeRef values[2];
  26. values[0] = domainArray;
  27. values[1] = serverArray;
  28. CFDictionaryRef dict = CFDictionaryCreate(NULL,
  29. (const void**)keys, (const void**)values, 2, &kCFCopyStringDictionaryKeyCallBacks,
  30. &kCFTypeDictionaryValueCallBacks);
  31. char buf[256] = {0};
  32. sprintf(buf, "State:/Network/Service/%.16llx/DNS", nwid);
  33. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  34. CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key);
  35. CFIndex i = 0, j = CFArrayGetCount(list);
  36. bool dnsServersChanged = true;
  37. CFPropertyListRef oldDNSServers = NULL;
  38. if (j > 0) {
  39. oldDNSServers = SCDynamicStoreCopyValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i));
  40. dnsServersChanged = !CFEqual(oldDNSServers,dict);
  41. }
  42. if (dnsServersChanged) {
  43. bool ret = TRUE;
  44. if (j <= 0) {
  45. ret &= SCDynamicStoreAddValue(ds, key, dict);
  46. } else {
  47. ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict);
  48. }
  49. if (!ret) {
  50. fprintf(stderr, "Error writing DNS configuration\n");
  51. }
  52. }
  53. if (oldDNSServers != NULL) {
  54. CFRelease(oldDNSServers);
  55. }
  56. CFRelease(list);
  57. CFRelease(key);
  58. CFRelease(dict);
  59. CFRelease(domainArray);
  60. CFRelease(cfdomain);
  61. CFRelease(serverArray);
  62. for (int i = 0; i < servers.size(); ++i) {
  63. CFRelease(s[i]);
  64. }
  65. delete[] s;
  66. CFRelease(ds);
  67. }
  68. void MacDNSHelper::removeDNS(uint64_t nwid)
  69. {
  70. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  71. char buf[256] = {0};
  72. sprintf(buf, "State:/Network/Service/%.16llx/DNS", nwid);
  73. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  74. SCDynamicStoreRemoveValue(ds, key);
  75. CFRelease(key);
  76. CFRelease(ds);
  77. }
  78. // Make macOS believe we do in fact have ipv6 connectivity and that it should resolve dns names
  79. // over ipv6 if we ask for them.
  80. // Originally I planned to put all the v6 ip addresses from the network into the config.
  81. // But only the link local address is necessary and sufficient. Added other v6 addresses
  82. // doesn't do anything.
  83. bool MacDNSHelper::addIps(uint64_t nwid, const MAC mac, const char *dev, const std::vector<InetAddress>& addrs)
  84. {
  85. bool hasV6 = false;
  86. for (unsigned int i = 0; i < addrs.size(); ++i) {
  87. if (addrs[i].isV6()) {
  88. hasV6 = true;
  89. break;
  90. }
  91. }
  92. if (!hasV6) {
  93. MacDNSHelper::removeIps(nwid);
  94. return true;
  95. }
  96. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  97. char buf[256] = { 0 };
  98. sprintf(buf, "State:/Network/Service/%.16llx/IPv6", nwid);
  99. InetAddress ll = InetAddress::makeIpv6LinkLocal(mac);
  100. char buf2[256] = {0};
  101. const char* llStr = ll.toIpString(buf2);
  102. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  103. CFStringRef* cfaddrs = new CFStringRef[1];
  104. CFStringRef* cfprefixes = new CFStringRef[1];
  105. CFStringRef* cfdestaddrs = new CFStringRef[1];
  106. CFStringRef* cfflags = new CFStringRef[1];
  107. cfaddrs[0] = CFStringCreateWithCString(NULL, llStr, kCFStringEncodingUTF8);
  108. cfprefixes[0] = CFStringCreateWithCString(NULL, "64", kCFStringEncodingUTF8);
  109. cfdestaddrs[0] = CFStringCreateWithCString(NULL, "::ffff:ffff:ffff:ffff:0:0", kCFStringEncodingUTF8);
  110. cfflags[0] = CFStringCreateWithCString(NULL, "0", kCFStringEncodingUTF8);
  111. CFArrayRef addrArray = CFArrayCreate(NULL, (const void**)cfaddrs, 1, &kCFTypeArrayCallBacks);
  112. CFArrayRef prefixArray = CFArrayCreate(NULL, (const void**)cfprefixes, 1, &kCFTypeArrayCallBacks);
  113. CFArrayRef destArray = CFArrayCreate(NULL, (const void**)cfdestaddrs, 1, &kCFTypeArrayCallBacks);
  114. CFArrayRef flagsArray = CFArrayCreate(NULL, (const void**)cfflags, 1, &kCFTypeArrayCallBacks);
  115. CFStringRef cfdev = CFStringCreateWithCString(NULL, dev, kCFStringEncodingUTF8);
  116. const int SIZE = 5;
  117. CFStringRef keys[SIZE];
  118. keys[0] = CFSTR("Addresses");
  119. keys[1] = CFSTR("DestAddresses");
  120. keys[2] = CFSTR("Flags");
  121. keys[3] = CFSTR("InterfaceName");
  122. keys[4] = CFSTR("PrefixLength");
  123. CFTypeRef values[SIZE];
  124. values[0] = addrArray;
  125. values[1] = destArray;
  126. values[2] = flagsArray;
  127. // values[3] = devArray;
  128. values[3] = cfdev;
  129. values[4] = prefixArray;
  130. CFDictionaryRef dict = CFDictionaryCreate(NULL,
  131. (const void**)keys, (const void**)values, SIZE, &kCFCopyStringDictionaryKeyCallBacks,
  132. &kCFTypeDictionaryValueCallBacks);
  133. // CFDictionaryApplyFunction(dict, printKeys, NULL);
  134. CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key);
  135. CFIndex i = 0, j = CFArrayGetCount(list);
  136. bool addrsChanged = true;
  137. CFPropertyListRef oldAddrs = NULL;
  138. bool ret = TRUE;
  139. if (j > 0) {
  140. oldAddrs = SCDynamicStoreCopyValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i));
  141. addrsChanged = !CFEqual(oldAddrs,dict);
  142. }
  143. if (addrsChanged) {
  144. if (j <= 0) {
  145. ret &= SCDynamicStoreAddValue(ds, key, dict);
  146. } else {
  147. ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict);
  148. }
  149. if (!ret) {
  150. fprintf(stderr, "Error writing IPv6 configuration\n");
  151. }
  152. }
  153. CFRelease(addrArray);
  154. CFRelease(prefixArray);
  155. CFRelease(destArray);
  156. CFRelease(flagsArray);
  157. CFRelease(cfdev);
  158. CFRelease(list);
  159. CFRelease(dict);
  160. CFRelease(ds);
  161. CFRelease(key);
  162. delete[] cfaddrs;
  163. delete[] cfprefixes;
  164. delete[] cfdestaddrs;
  165. delete[] cfflags;
  166. return ret;
  167. }
  168. bool MacDNSHelper::removeIps(uint64_t nwid)
  169. {
  170. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  171. char buf[256] = {0};
  172. sprintf(buf, "State:/Network/Service/%.16llx/IPv6", nwid);
  173. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  174. bool res = SCDynamicStoreRemoveValue(ds, key);
  175. CFRelease(key);
  176. CFRelease(ds);
  177. return res;
  178. }
  179. }