MacDNSHelper.mm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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[3];
  21. keys[0] = CFSTR("SupplementalMatchDomains");
  22. keys[1] = CFSTR("ServerAddresses");
  23. keys[2] = CFSTR("SearchDomains");
  24. CFStringRef cfdomain = CFStringCreateWithCString(NULL, domain, kCFStringEncodingUTF8);
  25. CFStringRef cfdomain2 = CFStringCreateWithCString(NULL, domain, kCFStringEncodingUTF8);
  26. CFArrayRef domainArray = CFArrayCreate(NULL, (const void**)&cfdomain, 1, &kCFTypeArrayCallBacks);
  27. CFArrayRef domainArray2 = CFArrayCreate(NULL, (const void**)&cfdomain2, 1, &kCFTypeArrayCallBacks);
  28. CFTypeRef values[3];
  29. values[0] = domainArray;
  30. values[1] = serverArray;
  31. values[2] = domainArray2;
  32. CFDictionaryRef dict = CFDictionaryCreate(NULL,
  33. (const void**)keys, (const void**)values, 3, &kCFCopyStringDictionaryKeyCallBacks,
  34. &kCFTypeDictionaryValueCallBacks);
  35. char buf[256] = {0};
  36. sprintf(buf, "State:/Network/Service/%.16llx/DNS", nwid);
  37. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  38. CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key);
  39. CFIndex i = 0, j = CFArrayGetCount(list);
  40. bool dnsServersChanged = true;
  41. CFPropertyListRef oldDNSServers = NULL;
  42. if (j > 0) {
  43. oldDNSServers = SCDynamicStoreCopyValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i));
  44. dnsServersChanged = !CFEqual(oldDNSServers,dict);
  45. }
  46. if (dnsServersChanged) {
  47. bool ret = TRUE;
  48. if (j <= 0) {
  49. ret &= SCDynamicStoreAddValue(ds, key, dict);
  50. } else {
  51. ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict);
  52. }
  53. if (!ret) {
  54. fprintf(stderr, "Error writing DNS configuration\n");
  55. }
  56. }
  57. if (oldDNSServers != NULL) {
  58. CFRelease(oldDNSServers);
  59. }
  60. CFRelease(list);
  61. CFRelease(key);
  62. CFRelease(dict);
  63. CFRelease(domainArray);
  64. CFRelease(domainArray2);
  65. CFRelease(cfdomain);
  66. CFRelease(cfdomain2);
  67. CFRelease(serverArray);
  68. for (int i = 0; i < servers.size(); ++i) {
  69. CFRelease(s[i]);
  70. }
  71. delete[] s;
  72. CFRelease(ds);
  73. }
  74. void MacDNSHelper::removeDNS(uint64_t nwid)
  75. {
  76. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  77. char buf[256] = {0};
  78. sprintf(buf, "State:/Network/Service/%.16llx/DNS", nwid);
  79. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  80. SCDynamicStoreRemoveValue(ds, key);
  81. CFRelease(key);
  82. CFRelease(ds);
  83. }
  84. // Make macOS believe we do in fact have ipv6 connectivity and that it should resolve dns names
  85. // over ipv6 if we ask for them.
  86. // Originally I planned to put all the v6 ip addresses from the network into the config.
  87. // But only the link local address is necessary and sufficient. Added other v6 addresses
  88. // doesn't do anything.
  89. //
  90. // As of Monterey we need IPv4 set up too.
  91. bool MacDNSHelper::addIps4(uint64_t nwid, const MAC mac, const char *dev, const std::vector<InetAddress>& addrs)
  92. {
  93. const char* ipStr = {0};
  94. char buf2[256] = {0};
  95. bool hasV4 = false;
  96. for (unsigned int i = 0; i < addrs.size(); ++i) {
  97. if (addrs[i].isV4()) {
  98. hasV4 = true;
  99. ipStr = addrs[i].toIpString(buf2);
  100. break;
  101. }
  102. }
  103. if (!hasV4) {
  104. MacDNSHelper::removeIps4(nwid);
  105. return true;
  106. }
  107. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  108. char buf[256] = { 0 };
  109. sprintf(buf, "State:/Network/Service/%.16llx/IPv4", nwid);
  110. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  111. CFStringRef cfaddr = CFStringCreateWithCString(NULL, ipStr, kCFStringEncodingUTF8);
  112. CFArrayRef addrArray = CFArrayCreate(NULL, (const void**)&cfaddr, 1, &kCFTypeArrayCallBacks);
  113. CFStringRef cfdev = CFStringCreateWithCString(NULL, dev, kCFStringEncodingUTF8);
  114. CFStringRef cfserver = CFStringCreateWithCString(NULL, "127.0.0.1", kCFStringEncodingUTF8);
  115. // using the ip from the zerotier network breaks routing on the mac
  116. CFStringRef cfrouter = CFStringCreateWithCString(NULL, "127.0.0.1", kCFStringEncodingUTF8);
  117. const int SIZE = 4;
  118. CFStringRef keys[SIZE];
  119. keys[0] = CFSTR("Addresses");
  120. keys[1] = CFSTR("InterfaceName");
  121. keys[2] = CFSTR("ServerAddress");
  122. keys[3] = CFSTR("Router");
  123. CFTypeRef values[SIZE];
  124. values[0] = addrArray;
  125. values[1] = cfdev;
  126. values[2] = cfserver;
  127. values[3] = cfrouter;
  128. CFDictionaryRef dict = CFDictionaryCreate(NULL,
  129. (const void**)keys, (const void**)values, SIZE, &kCFCopyStringDictionaryKeyCallBacks,
  130. &kCFTypeDictionaryValueCallBacks);
  131. // CFDictionaryApplyFunction(dict, printKeys, NULL);
  132. CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key);
  133. CFIndex i = 0, j = CFArrayGetCount(list);
  134. bool addrsChanged = true;
  135. CFPropertyListRef oldAddrs = NULL;
  136. bool ret = TRUE;
  137. if (j > 0) {
  138. oldAddrs = SCDynamicStoreCopyValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i));
  139. addrsChanged = !CFEqual(oldAddrs,dict);
  140. }
  141. if (addrsChanged) {
  142. if (j <= 0) {
  143. ret &= SCDynamicStoreAddValue(ds, key, dict);
  144. } else {
  145. ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict);
  146. }
  147. if (!ret) {
  148. fprintf(stderr, "Error writing IPv6 configuration\n");
  149. }
  150. }
  151. if (oldAddrs != NULL) {
  152. CFRelease(oldAddrs);
  153. }
  154. CFRelease(cfaddr);
  155. CFRelease(addrArray);
  156. CFRelease(cfdev);
  157. CFRelease(cfserver);
  158. CFRelease(cfrouter);
  159. CFRelease(ds);
  160. CFRelease(key);
  161. // for (unsigned int i = 0; i < SIZE; ++i) {
  162. // values[i] = NULL;
  163. // }
  164. CFRelease(list);
  165. CFRelease(dict);
  166. return ret;
  167. }
  168. bool MacDNSHelper::addIps6(uint64_t nwid, const MAC mac, const char *dev, const std::vector<InetAddress>& addrs)
  169. {
  170. bool hasV6 = false;
  171. for (unsigned int i = 0; i < addrs.size(); ++i) {
  172. if (addrs[i].isV6()) {
  173. hasV6 = true;
  174. break;
  175. }
  176. }
  177. if (!hasV6) {
  178. MacDNSHelper::removeIps6(nwid);
  179. return true;
  180. }
  181. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  182. char buf[256] = { 0 };
  183. sprintf(buf, "State:/Network/Service/%.16llx/IPv6", nwid);
  184. InetAddress ll = InetAddress::makeIpv6LinkLocal(mac);
  185. char buf2[256] = {0};
  186. const char* llStr = ll.toIpString(buf2);
  187. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  188. CFStringRef cfaddr = CFStringCreateWithCString(NULL, llStr, kCFStringEncodingUTF8);
  189. CFStringRef cfprefixes = CFStringCreateWithCString(NULL, "64", kCFStringEncodingUTF8);
  190. CFStringRef cfdestaddrs = CFStringCreateWithCString(NULL, "::ffff:ffff:ffff:ffff:0:0", kCFStringEncodingUTF8);
  191. CFStringRef cfflags = CFStringCreateWithCString(NULL, "0", kCFStringEncodingUTF8);
  192. CFArrayRef addrArray = CFArrayCreate(NULL, (const void**)&cfaddr, 1, &kCFTypeArrayCallBacks);
  193. CFArrayRef prefixArray = CFArrayCreate(NULL, (const void**)&cfprefixes, 1, &kCFTypeArrayCallBacks);
  194. CFArrayRef destArray = CFArrayCreate(NULL, (const void**)&cfdestaddrs, 1, &kCFTypeArrayCallBacks);
  195. CFArrayRef flagsArray = CFArrayCreate(NULL, (const void**)&cfflags, 1, &kCFTypeArrayCallBacks);
  196. CFStringRef cfdev = CFStringCreateWithCString(NULL, dev, kCFStringEncodingUTF8);
  197. const int SIZE = 5;
  198. CFStringRef keys[SIZE];
  199. keys[0] = CFSTR("Addresses");
  200. keys[1] = CFSTR("DestAddresses");
  201. keys[2] = CFSTR("Flags");
  202. keys[3] = CFSTR("InterfaceName");
  203. keys[4] = CFSTR("PrefixLength");
  204. CFTypeRef values[SIZE];
  205. values[0] = addrArray;
  206. values[1] = destArray;
  207. values[2] = flagsArray;
  208. // values[3] = devArray;
  209. values[3] = cfdev;
  210. values[4] = prefixArray;
  211. CFDictionaryRef dict = CFDictionaryCreate(NULL,
  212. (const void**)keys, (const void**)values, SIZE, &kCFCopyStringDictionaryKeyCallBacks,
  213. &kCFTypeDictionaryValueCallBacks);
  214. // CFDictionaryApplyFunction(dict, printKeys, NULL);
  215. CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key);
  216. CFIndex i = 0, j = CFArrayGetCount(list);
  217. bool addrsChanged = true;
  218. CFPropertyListRef oldAddrs = NULL;
  219. bool ret = TRUE;
  220. if (j > 0) {
  221. oldAddrs = SCDynamicStoreCopyValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i));
  222. addrsChanged = !CFEqual(oldAddrs,dict);
  223. }
  224. if (addrsChanged) {
  225. if (j <= 0) {
  226. ret &= SCDynamicStoreAddValue(ds, key, dict);
  227. } else {
  228. ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict);
  229. }
  230. if (!ret) {
  231. fprintf(stderr, "Error writing IPv6 configuration\n");
  232. }
  233. }
  234. if (oldAddrs != NULL) {
  235. CFRelease(oldAddrs);
  236. }
  237. CFRelease(cfaddr);
  238. CFRelease(cfprefixes);
  239. CFRelease(cfdestaddrs);
  240. CFRelease(cfflags);
  241. CFRelease(addrArray);
  242. CFRelease(prefixArray);
  243. CFRelease(destArray);
  244. CFRelease(flagsArray);
  245. CFRelease(cfdev);
  246. CFRelease(ds);
  247. CFRelease(key);
  248. // for (unsigned int i = 0; i < SIZE; ++i) {
  249. // values[i] = NULL;
  250. // }
  251. CFRelease(list);
  252. CFRelease(dict);
  253. return ret;
  254. }
  255. bool MacDNSHelper::removeIps6(uint64_t nwid)
  256. {
  257. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  258. char buf[256] = {0};
  259. sprintf(buf, "State:/Network/Service/%.16llx/IPv6", nwid);
  260. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  261. bool res = SCDynamicStoreRemoveValue(ds, key);
  262. CFRelease(key);
  263. CFRelease(ds);
  264. return res;
  265. }
  266. bool MacDNSHelper::removeIps4(uint64_t nwid)
  267. {
  268. SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
  269. char buf[256] = {0};
  270. sprintf(buf, "State:/Network/Service/%.16llx/IPv4", nwid);
  271. CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
  272. bool res = SCDynamicStoreRemoveValue(ds, key);
  273. CFRelease(key);
  274. CFRelease(ds);
  275. return res;
  276. }
  277. }