Browse Source

DNS config support on macOS

Grant Limberg 5 years ago
parent
commit
302ac8fefe
6 changed files with 166 additions and 2 deletions
  1. 6 2
      make-mac.mk
  2. 20 0
      osdep/MacDNSHelper.hpp
  3. 72 0
      osdep/MacDNSHelper.mm
  4. 62 0
      osdep/MacEthernetTap.cpp
  5. 3 0
      osdep/MacEthernetTap.hpp
  6. 3 0
      service/OneService.cpp

+ 6 - 2
make-mac.mk

@@ -25,10 +25,10 @@ TIMESTAMP=$(shell date +"%Y%m%d%H%M")
 DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE)
 
 include objects.mk
-ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o ext/http-parser/http_parser.o
+ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o osdep/MacDNSHelper.o ext/http-parser/http_parser.o
 
 ifeq ($(ZT_CONTROLLER),1)
-	LIBS+=-L/usr/local/opt/libpq/lib -lpq ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a
+	LIBS+=-L/usr/local/opt/libpq/lib -lpq ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a -framework SystemConfiguration -framework CoreFoundation
 	DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER_USE_REDIS -DZT_CONTROLLER 
 	INCLUDES+=-I/usr/local/opt/libpq/include -Iext/hiredis-0.14.1/include/ -Iext/redis-plus-plus-1.1.1/install/macos/include/sw/
 	
@@ -97,7 +97,11 @@ mac-agent: FORCE
 	$(CC) -Ofast -o MacEthernetTapAgent osdep/MacEthernetTapAgent.c
 	$(CODESIGN) -f -s $(CODESIGN_APP_CERT) MacEthernetTapAgent
 
+osdep/MacDNSHelper.o: osdep/MacDNSHelper.mm
+	$(CXX) $(CXXFLAGS) -c osdep/MacDNSHelper.mm -o osdep/MacDNSHelper.o 
+
 one:	$(CORE_OBJS) $(ONE_OBJS) one.o mac-agent
+	 
 	$(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS)
 	# $(STRIP) zerotier-one
 	ln -sf zerotier-one zerotier-idtool

+ 20 - 0
osdep/MacDNSHelper.hpp

@@ -0,0 +1,20 @@
+#ifndef MAC_DNS_HELPER
+#define MAC_DNS_HELPER
+
+#include <vector>
+#include "../node/InetAddress.hpp"
+
+namespace ZeroTier {
+
+class MacDNSHelper
+{
+public:
+    static void doTheThing();
+
+    static void setDNS(uint64_t nwid, const char *domain, const std::vector<InetAddress> &servers);
+    static void removeDNS(uint64_t nwid);
+};
+
+}
+
+#endif

+ 72 - 0
osdep/MacDNSHelper.mm

@@ -0,0 +1,72 @@
+#include "MacDNSHelper.hpp"
+
+#include <stdio.h>
+
+#include <SystemConfiguration/SystemConfiguration.h>
+
+namespace ZeroTier {
+
+void MacDNSHelper::doTheThing()
+{
+    fprintf(stderr, "\n\nDOING THE THING!!\n\n");
+}
+
+void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vector<InetAddress> &servers)
+{
+    SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL);
+
+    CFStringRef *s = new CFStringRef[4];
+    for (unsigned int i = 0; i < servers.size(); ++i) {
+        char buf[64];
+        ZeroTier::InetAddress a = servers[i];
+        const char *ipStr = a.toIpString(buf);
+        s[i] = CFStringCreateWithCString(NULL, ipStr, kCFStringEncodingUTF8);
+    }
+
+    CFArrayRef serverArray = CFArrayCreate(NULL, (const void**)s, servers.size(), &kCFTypeArrayCallBacks);
+
+    CFStringRef keys[2];
+    keys[0] = CFSTR("SupplementalMatchDomains");
+    keys[1] = CFSTR("ServerAddresses");
+
+    CFStringRef cfdomain = CFStringCreateWithCString(NULL, domain, kCFStringEncodingUTF8);
+    CFArrayRef domainArray = CFArrayCreate(NULL, (const void**)&cfdomain, 1, &kCFTypeArrayCallBacks);
+
+    CFTypeRef values[2];
+    values[0] = domainArray;
+    values[1] = serverArray;
+
+    CFDictionaryRef dict = CFDictionaryCreate(NULL,
+        (const void**)keys, (const void**)values, 2, &kCFCopyStringDictionaryKeyCallBacks,
+        &kCFTypeDictionaryValueCallBacks);
+    CFShow(dict);
+
+    char buf[256] = {0};
+    sprintf(buf, "State:/Network/Service/%.16llx/DNS", nwid);
+    CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
+    CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key);
+
+    CFIndex i = 0, j = CFArrayGetCount(list);
+    bool ret = TRUE;
+    if (j <= 0) {
+        fprintf(stderr, "Key '%s' does not exist.  Creating.\n", buf);
+        ret &= SCDynamicStoreAddValue(ds, key, dict);
+    } else {
+        fprintf(stderr, "Key '%s' already exists.  Updating DNS config.\n", buf);
+        ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict);
+    }
+    if (ret) {
+        fprintf(stderr, "DNS written successfully\n");
+    } else {
+        fprintf(stderr, "Error writing DNS configuration\n");
+    }
+
+    delete[] s;
+}
+    
+void MacDNSHelper::removeDNS(uint64_t nwid) 
+{
+
+}
+
+}

+ 62 - 0
osdep/MacEthernetTap.cpp

@@ -21,6 +21,7 @@
 #include "OSUtils.hpp"
 #include "MacEthernetTap.hpp"
 #include "MacEthernetTapAgent.h"
+#include "MacDNSHelper.hpp"
 
 #include <stdint.h>
 #include <stdio.h>
@@ -54,6 +55,7 @@
 #include <map>
 #include <set>
 #include <algorithm>
+#include <filesystem>
 
 static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
 
@@ -454,7 +456,67 @@ void MacEthernetTap::threadMain()
 
 void MacEthernetTap::setDns(const char *domain, const std::vector<InetAddress> &servers)
 {
+	MacDNSHelper::doTheThing();
+	MacDNSHelper::setDNS(this->_nwid, domain, servers);
+	// _removeDnsConfig(domain, servers);
+	// _addDnsConfig(domain, servers);
+}
+
+void MacEthernetTap::_removeDnsConfig(const char *domain, const std::vector<InetAddress> &servers)
+{
+	std::string tmpfile = std::tmpnam(nullptr);
+	std::FILE *remf = std::fopen(tmpfile.c_str(), "w");
+	char buf[4096] = {0};
+	sprintf(buf, "remove State:/Network/Service/%.16llx/DNS\n", _nwid);
+	std::fputs(buf, remf);
+	std::fflush(remf);
+	std::fclose(remf);
+	fprintf(stderr, "wrote tmpfile %s\n", tmpfile.c_str());
+	long cpid = (long)vfork();
+	if (cpid == 0) {
+		char cmd[1024] = {0};
+		sprintf(cmd, "/usr/sbin/scutil < %s", tmpfile.c_str());
+		::execl("/bin/sh", "-c", cmd);
+	} else if (cpid > 0) {
+		int exitcode = -1;
+		::waitpid(cpid, &exitcode,0);
+		if (exitcode) {
+			throw std::runtime_error("scutil dns config remove error");
+		}
+	}
+}
 
+void MacEthernetTap::_addDnsConfig(const char *domain, const std::vector<InetAddress> &servers)
+{
+	std::string tmpfile = std::tmpnam(nullptr);
+	std::FILE *addf = std::fopen(tmpfile.c_str(), "w");
+	char buf[4096] = {0};
+	sprintf(buf, "d.init\n");
+	sprintf(buf, "d.add ServerAddresses *");
+	for (auto it = servers.begin(); it != servers.end(); ++it) {
+		char ipbuf[128] = {0};
+		sprintf(buf, " %s", it->toIpString(buf));
+	}
+	sprintf(buf, "\n");
+	sprintf(buf, "d.add SupplementalMatchDomains * %s\n", domain);
+	sprintf(buf, "set State:/Network/Service/%.16llx/DNS", _nwid);
+	std::fputs(buf, addf);
+	std::fflush(addf);
+	std::fclose(addf);
+	fprintf(stderr, "wrote add tmpfile %s\n", tmpfile.c_str());
+	long cpid = (long)vfork();
+	if (cpid == 0) {
+		char cmd[1024];
+		sprintf(cmd, "'/usr/bin/scutil < %s'", tmpfile.c_str());
+		fprintf(stderr, "%s\n", cmd);
+		::execl("/bin/sh", "-c", cmd);
+	} else if (cpid > 0) {
+		int exitcode = -1;
+		::waitpid(cpid, &exitcode, 0);
+		if (exitcode) {
+			throw std::runtime_error("scutil dns config add error");
+		}
+	}
 }
 
 } // namespace ZeroTier

+ 3 - 0
osdep/MacEthernetTap.hpp

@@ -62,6 +62,9 @@ public:
 		throw();
 
 private:
+	void _removeDnsConfig(const char *domain, const std::vector<InetAddress> &servers);
+	void _addDnsConfig(const char *domain, const std::vector<InetAddress> &servers);
+
 	void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
 	void *_arg;
 	uint64_t _nwid;

+ 3 - 0
service/OneService.cpp

@@ -2011,12 +2011,15 @@ public:
 			for (int i = 0; i < n.config.dnsCount; ++i) {
 				if (strlen(n.config.dns[i].domain) != 0) {
 					fprintf(stderr, "Syncing DNS for domain: %s\n", n.config.dns[i].domain);
+					std::vector<InetAddress> servers;
 					for (int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
 						InetAddress a(n.config.dns[i].server_addr[j]);
 						if (a.isV4() || a.isV6()) {
 							fprintf(stderr, "\t Server %d: %s\n", j+1, a.toIpString(buf));
+							servers.push_back(a);
 						}
 					}
+					n.tap->setDns(n.config.dns[i].domain, servers);
 				}
 			}
 		}