mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-19 21:17:52 +00:00
OSX no longer requires the kext due to feth black magic! The MacEthernetTapAgent must be installed in /Library/Application Support/ZeroTier/One for ZT to work now. Eventually this can let us do an app bundle, get rid of the pkg, and have ZT itself run with normal or reduced privileges. Also fixes GitHub issue #870 (at least for me) and may be faster than the old kext.
This commit is contained in:
parent
7c72653385
commit
2e44b90f63
1
.gitignore
vendored
1
.gitignore
vendored
@ -51,6 +51,7 @@ enc_temp_folder
|
||||
/world/mkworld
|
||||
/world/*.c25519
|
||||
zt1-src.tar.gz
|
||||
/MacEthernetTapAgent
|
||||
|
||||
# Miscellaneous temporaries, build files, etc.
|
||||
*.log
|
||||
|
20
make-mac.mk
20
make-mac.mk
@ -19,7 +19,7 @@ ZT_VERSION_BUILD=$(shell cat version.h | grep -F VERSION_BUILD | cut -d ' ' -f 3
|
||||
DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE)
|
||||
|
||||
include objects.mk
|
||||
ONE_OBJS+=osdep/OSXEthernetTap.o ext/http-parser/http_parser.o
|
||||
ONE_OBJS+=osdep/MacEthernetTap.o ext/http-parser/http_parser.o
|
||||
|
||||
# Official releases are signed with our Apple cert and apply software updates by default
|
||||
ifeq ($(ZT_OFFICIAL_RELEASE),1)
|
||||
@ -78,7 +78,11 @@ all: one macui
|
||||
ext/x64-salsa2012-asm/salsa2012.o:
|
||||
$(CC) $(CFLAGS) -c ext/x64-salsa2012-asm/salsa2012.s -o ext/x64-salsa2012-asm/salsa2012.o
|
||||
|
||||
one: $(CORE_OBJS) $(ONE_OBJS) one.o
|
||||
mac-agent: FORCE
|
||||
$(CC) -O -s -o MacEthernetTapAgent osdep/MacEthernetTapAgent.c
|
||||
$(CODESIGN) -f -s $(CODESIGN_APP_CERT) MacEthernetTapAgent
|
||||
|
||||
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
|
||||
@ -128,17 +132,17 @@ official: FORCE
|
||||
make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg
|
||||
|
||||
clean:
|
||||
rm -rf *.dSYM build-* *.a *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier doc/node_modules macui/build zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_*
|
||||
rm -rf MacEthernetTapAgent *.dSYM build-* *.a *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier doc/node_modules macui/build zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_*
|
||||
|
||||
distclean: clean
|
||||
|
||||
realclean: clean
|
||||
|
||||
# For those building from source -- installs signed binary tap driver in system ZT home
|
||||
install-mac-tap: FORCE
|
||||
mkdir -p /Library/Application\ Support/ZeroTier/One
|
||||
rm -rf /Library/Application\ Support/ZeroTier/One/tap.kext
|
||||
cp -R ext/bin/tap-mac/tap.kext /Library/Application\ Support/ZeroTier/One
|
||||
chown -R root:wheel /Library/Application\ Support/ZeroTier/One/tap.kext
|
||||
#install-mac-tap: FORCE
|
||||
# mkdir -p /Library/Application\ Support/ZeroTier/One
|
||||
# rm -rf /Library/Application\ Support/ZeroTier/One/tap.kext
|
||||
# cp -R ext/bin/tap-mac/tap.kext /Library/Application\ Support/ZeroTier/One
|
||||
# chown -R root:wheel /Library/Application\ Support/ZeroTier/One/tap.kext
|
||||
|
||||
FORCE:
|
||||
|
404
osdep/MacEthernetTap.cpp
Normal file
404
osdep/MacEthernetTap.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../node/Dictionary.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "MacEthernetTap.hpp"
|
||||
#include "MacEthernetTapAgent.h"
|
||||
|
||||
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
static Mutex globalTapCreateLock;
|
||||
|
||||
MacEthernetTap::MacEthernetTap(
|
||||
const char *homePath,
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len),
|
||||
void *arg) :
|
||||
_handler(handler),
|
||||
_arg(arg),
|
||||
_nwid(nwid),
|
||||
_homePath(homePath),
|
||||
_mtu(mtu),
|
||||
_metric(metric),
|
||||
_agentStdin(-1),
|
||||
_agentStdout(-1),
|
||||
_agentStderr(-1),
|
||||
_agentStdin2(-1),
|
||||
_agentStdout2(-1),
|
||||
_agentStderr2(-1),
|
||||
_agentPid(-1),
|
||||
_enabled(true)
|
||||
{
|
||||
char ethaddr[64],mtustr[16],devnostr[16],devstr[16],metricstr[16];
|
||||
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]);
|
||||
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",mtu);
|
||||
OSUtils::ztsnprintf(metricstr,sizeof(metricstr),"%u",metric);
|
||||
|
||||
struct ifaddrs *ifa = (struct ifaddrs *)0;
|
||||
std::set<std::string> ifns;
|
||||
if (!getifaddrs(&ifa)) {
|
||||
struct ifaddrs *p = ifa;
|
||||
while (p) {
|
||||
ifns.insert(std::string(p->ifa_name));
|
||||
p = p->ifa_next;
|
||||
}
|
||||
freeifaddrs(ifa);
|
||||
}
|
||||
|
||||
Mutex::Lock _gl(globalTapCreateLock); // only make one at a time
|
||||
|
||||
unsigned int devNo = (nwid ^ (nwid >> 32) ^ (nwid >> 48)) % 5000;
|
||||
for(int tries=0;tries<16;++tries) {
|
||||
OSUtils::ztsnprintf(devstr,sizeof(devstr),"feth%u",devNo);
|
||||
_dev = devstr;
|
||||
if (!ifns.count(_dev))
|
||||
break;
|
||||
devNo = (devNo + 1) % 5000;
|
||||
}
|
||||
OSUtils::ztsnprintf(devnostr,sizeof(devnostr),"%u",devNo);
|
||||
|
||||
if (::pipe(_shutdownSignalPipe)) {
|
||||
throw std::runtime_error("pipe creation failed");
|
||||
}
|
||||
|
||||
int agentStdin[2];
|
||||
int agentStdout[2];
|
||||
int agentStderr[2];
|
||||
if (::pipe(agentStdin)) {
|
||||
throw std::runtime_error("pipe creation failed");
|
||||
}
|
||||
if (::pipe(agentStdout)) {
|
||||
throw std::runtime_error("pipe creation failed");
|
||||
}
|
||||
if (::pipe(agentStderr)) {
|
||||
throw std::runtime_error("pipe creation failed");
|
||||
}
|
||||
_agentStdin = agentStdin[1];
|
||||
_agentStdout = agentStdout[0];
|
||||
_agentStderr = agentStderr[0];
|
||||
_agentStdin2 = agentStdin[0];
|
||||
_agentStdout2 = agentStdout[1];
|
||||
_agentStderr2 = agentStderr[1];
|
||||
long apid = (long)vfork();
|
||||
if (apid < 0) {
|
||||
throw std::runtime_error("fork failed");
|
||||
} else if (apid == 0) {
|
||||
::dup2(agentStdin[0],STDIN_FILENO);
|
||||
::dup2(agentStdout[1],STDOUT_FILENO);
|
||||
::dup2(agentStderr[1],STDERR_FILENO);
|
||||
::close(agentStdin[0]);
|
||||
::close(agentStdout[1]);
|
||||
::close(agentStderr[1]);
|
||||
::execl(ZT_MACETHERNETTAPAGENT_DEFAULT_SYSTEM_PATH,ZT_MACETHERNETTAPAGENT_DEFAULT_SYSTEM_PATH,devnostr,ethaddr,mtustr,metricstr,(char *)0);
|
||||
::exit(-1);
|
||||
} else {
|
||||
_agentPid = apid;
|
||||
}
|
||||
Thread::sleep(100); // this causes them to come up in a more user-friendly order on launch
|
||||
|
||||
_thread = Thread::start(this);
|
||||
}
|
||||
|
||||
MacEthernetTap::~MacEthernetTap()
|
||||
{
|
||||
Mutex::Lock _gl(globalTapCreateLock);
|
||||
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
|
||||
Thread::join(_thread);
|
||||
::close(_shutdownSignalPipe[0]);
|
||||
::close(_shutdownSignalPipe[1]);
|
||||
int ec = 0;
|
||||
::kill(_agentPid,SIGTERM);
|
||||
::waitpid(_agentPid,&ec,0);
|
||||
::close(_agentStdin);
|
||||
::close(_agentStdout);
|
||||
::close(_agentStderr);
|
||||
::close(_agentStdin2);
|
||||
::close(_agentStdout2);
|
||||
::close(_agentStderr2);
|
||||
}
|
||||
|
||||
void MacEthernetTap::setEnabled(bool en) { _enabled = en; }
|
||||
bool MacEthernetTap::enabled() const { return _enabled; }
|
||||
|
||||
bool MacEthernetTap::addIp(const InetAddress &ip)
|
||||
{
|
||||
char tmp[128];
|
||||
|
||||
if (!ip)
|
||||
return false;
|
||||
|
||||
std::string cmd;
|
||||
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
|
||||
cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet");
|
||||
cmd.push_back(0);
|
||||
cmd.append(ip.toString(tmp));
|
||||
cmd.push_back(0);
|
||||
cmd.append("alias");
|
||||
cmd.push_back(0);
|
||||
|
||||
uint16_t l = (uint16_t)cmd.length();
|
||||
write(_agentStdin,&l,2);
|
||||
write(_agentStdin,cmd.data(),cmd.length());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacEthernetTap::removeIp(const InetAddress &ip)
|
||||
{
|
||||
char tmp[128];
|
||||
|
||||
if (!ip)
|
||||
return false;
|
||||
|
||||
std::string cmd;
|
||||
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
|
||||
cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet");
|
||||
cmd.push_back(0);
|
||||
cmd.append(ip.toString(tmp));
|
||||
cmd.push_back(0);
|
||||
cmd.append("-alias");
|
||||
cmd.push_back(0);
|
||||
|
||||
uint16_t l = (uint16_t)cmd.length();
|
||||
write(_agentStdin,&l,2);
|
||||
write(_agentStdin,cmd.data(),cmd.length());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<InetAddress> MacEthernetTap::ips() const
|
||||
{
|
||||
struct ifaddrs *ifa = (struct ifaddrs *)0;
|
||||
std::vector<InetAddress> r;
|
||||
if (!getifaddrs(&ifa)) {
|
||||
struct ifaddrs *p = ifa;
|
||||
while (p) {
|
||||
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
|
||||
switch(p->ifa_addr->sa_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
|
||||
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
|
||||
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
|
||||
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
|
||||
uint32_t b[4];
|
||||
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
|
||||
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
p = p->ifa_next;
|
||||
}
|
||||
freeifaddrs(ifa);
|
||||
}
|
||||
std::sort(r.begin(),r.end());
|
||||
r.erase(std::unique(r.begin(),r.end()),r.end());
|
||||
return r;
|
||||
}
|
||||
|
||||
void MacEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
|
||||
{
|
||||
struct iovec iov[3];
|
||||
unsigned char hdr[15];
|
||||
uint16_t l;
|
||||
if ((_agentStdin > 0)&&(len <= _mtu)&&(_enabled)) {
|
||||
hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET;
|
||||
to.copyTo(hdr + 1,6);
|
||||
from.copyTo(hdr + 7,6);
|
||||
hdr[13] = (char)((etherType >> 8) & 0xff);
|
||||
hdr[14] = (char)(etherType & 0xff);
|
||||
l = (uint16_t)(len + 15);
|
||||
iov[0].iov_base = &l;
|
||||
iov[0].iov_len = 2;
|
||||
iov[1].iov_base = hdr;
|
||||
iov[1].iov_len = 15;
|
||||
iov[2].iov_base = const_cast<void *>(data);
|
||||
iov[2].iov_len = len;
|
||||
writev(_agentStdin,iov,3);
|
||||
}
|
||||
}
|
||||
|
||||
std::string MacEthernetTap::deviceName() const { return _dev; }
|
||||
void MacEthernetTap::setFriendlyName(const char *friendlyName) {}
|
||||
|
||||
void MacEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
|
||||
{
|
||||
std::vector<MulticastGroup> newGroups;
|
||||
|
||||
struct ifmaddrs *ifmap = (struct ifmaddrs *)0;
|
||||
if (!getifmaddrs(&ifmap)) {
|
||||
struct ifmaddrs *p = ifmap;
|
||||
while (p) {
|
||||
if (p->ifma_addr->sa_family == AF_LINK) {
|
||||
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
|
||||
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
|
||||
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
|
||||
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
|
||||
}
|
||||
p = p->ifma_next;
|
||||
}
|
||||
freeifmaddrs(ifmap);
|
||||
}
|
||||
|
||||
std::vector<InetAddress> allIps(ips());
|
||||
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
|
||||
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
|
||||
|
||||
std::sort(newGroups.begin(),newGroups.end());
|
||||
std::unique(newGroups.begin(),newGroups.end());
|
||||
|
||||
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
|
||||
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
|
||||
added.push_back(*m);
|
||||
}
|
||||
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
|
||||
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
|
||||
removed.push_back(*m);
|
||||
}
|
||||
|
||||
_multicastGroups.swap(newGroups);
|
||||
}
|
||||
|
||||
void MacEthernetTap::setMtu(unsigned int mtu)
|
||||
{
|
||||
char tmp[16];
|
||||
std::string cmd;
|
||||
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
|
||||
cmd.append("mtu");
|
||||
cmd.push_back(0);
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu);
|
||||
cmd.append(tmp);
|
||||
cmd.push_back(0);
|
||||
uint16_t l = (uint16_t)cmd.length();
|
||||
write(_agentStdin,&l,2);
|
||||
write(_agentStdin,cmd.data(),cmd.length());
|
||||
_mtu = mtu;
|
||||
}
|
||||
|
||||
void MacEthernetTap::threadMain()
|
||||
throw()
|
||||
{
|
||||
char agentReadBuf[262144];
|
||||
fd_set readfds,nullfds;
|
||||
MAC to,from;
|
||||
|
||||
Thread::sleep(250);
|
||||
|
||||
const int nfds = std::max(std::max(_shutdownSignalPipe[0],_agentStdout),_agentStderr) + 1;
|
||||
long agentReadPtr = 0;
|
||||
fcntl(_agentStdout,F_SETFL,O_NONBLOCK);
|
||||
fcntl(_agentStderr,F_SETFL,O_NONBLOCK);
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&nullfds);
|
||||
for(;;) {
|
||||
FD_SET(_shutdownSignalPipe[0],&readfds);
|
||||
FD_SET(_agentStdout,&readfds);
|
||||
FD_SET(_agentStderr,&readfds);
|
||||
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
|
||||
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) {
|
||||
break;
|
||||
}
|
||||
if (FD_ISSET(_agentStdout,&readfds)) {
|
||||
long n = (long)read(_agentStdout,agentReadBuf + agentReadPtr,sizeof(agentReadBuf) - agentReadPtr);
|
||||
if (n > 0) {
|
||||
agentReadPtr += n;
|
||||
while (agentReadPtr >= 2) {
|
||||
long len = *((uint16_t *)agentReadBuf);
|
||||
if (agentReadPtr >= (len + 2)) {
|
||||
char *msg = agentReadBuf + 2;
|
||||
|
||||
if ((len > 14)&&(_enabled)) {
|
||||
to.setTo(msg,6);
|
||||
from.setTo(msg + 6,6);
|
||||
_handler(_arg,(void *)0,_nwid,from,to,ntohs(((const uint16_t *)msg)[6]),0,(const void *)(msg + 14),(unsigned int)len - 14);
|
||||
}
|
||||
|
||||
if (agentReadPtr > (len + 2)) {
|
||||
memmove(agentReadBuf,agentReadBuf + len + 2,agentReadPtr -= (len + 2));
|
||||
} else {
|
||||
agentReadPtr = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(_agentStderr,&readfds)) {
|
||||
read(_agentStderr,agentReadBuf,sizeof(agentReadBuf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
93
osdep/MacEthernetTap.hpp
Normal file
93
osdep/MacEthernetTap.hpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_OSXETHERNETTAP_HPP
|
||||
#define ZT_OSXETHERNETTAP_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/MAC.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/MulticastGroup.hpp"
|
||||
|
||||
#include "Thread.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class MacEthernetTap
|
||||
{
|
||||
public:
|
||||
MacEthernetTap(
|
||||
const char *homePath,
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
|
||||
void *arg);
|
||||
|
||||
~MacEthernetTap();
|
||||
|
||||
void setEnabled(bool en);
|
||||
bool enabled() const;
|
||||
bool addIp(const InetAddress &ip);
|
||||
bool removeIp(const InetAddress &ip);
|
||||
std::vector<InetAddress> ips() const;
|
||||
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
||||
std::string deviceName() const;
|
||||
void setFriendlyName(const char *friendlyName);
|
||||
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
|
||||
void setMtu(unsigned int mtu);
|
||||
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
|
||||
void *_arg;
|
||||
uint64_t _nwid;
|
||||
Thread _thread;
|
||||
std::string _homePath;
|
||||
std::string _dev;
|
||||
std::vector<MulticastGroup> _multicastGroups;
|
||||
unsigned int _mtu;
|
||||
unsigned int _metric;
|
||||
int _shutdownSignalPipe[2];
|
||||
int _agentStdin,_agentStdout,_agentStderr,_agentStdin2,_agentStdout2,_agentStderr2;
|
||||
long _agentPid;
|
||||
volatile bool _enabled;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
404
osdep/MacEthernetTapAgent.c
Normal file
404
osdep/MacEthernetTapAgent.c
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
/* This is the agent program that is executed with setuid privileges to
|
||||
* actually manage feth pairs. Its execution in this manner allows ZT
|
||||
* itself to drop privileges on Mac. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/ndrv.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet6/nd6.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include "../version.h"
|
||||
#include "MacEthernetTapAgent.h"
|
||||
|
||||
#ifndef SIOCAUTOCONF_START
|
||||
#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
|
||||
#endif
|
||||
#ifndef SIOCAUTOCONF_STOP
|
||||
#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
|
||||
#endif
|
||||
|
||||
#define P_IFCONFIG "/sbin/ifconfig"
|
||||
|
||||
static unsigned char s_pktReadBuf[262144] __attribute__ ((__aligned__(16)));
|
||||
static unsigned char s_stdinReadBuf[262144] __attribute__ ((__aligned__(16)));
|
||||
static char s_deviceName[IFNAMSIZ];
|
||||
static char s_peerDeviceName[IFNAMSIZ];
|
||||
static int s_bpffd = -1;
|
||||
static pid_t s_parentPid;
|
||||
|
||||
static void configureIpv6Parameters(const char *ifname,int performNUD,int acceptRouterAdverts)
|
||||
{
|
||||
struct in6_ndireq nd;
|
||||
struct in6_ifreq ifr;
|
||||
|
||||
int s = socket(AF_INET6,SOCK_DGRAM,0);
|
||||
if (s <= 0)
|
||||
return;
|
||||
|
||||
memset(&nd,0,sizeof(nd));
|
||||
strncpy(nd.ifname,ifname,sizeof(nd.ifname));
|
||||
|
||||
if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
|
||||
close(s);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long oldFlags = (unsigned long)nd.ndi.flags;
|
||||
|
||||
if (performNUD)
|
||||
nd.ndi.flags |= ND6_IFF_PERFORMNUD;
|
||||
else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
|
||||
|
||||
if (oldFlags != (unsigned long)nd.ndi.flags) {
|
||||
if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) {
|
||||
close(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&ifr,0,sizeof(ifr));
|
||||
strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
|
||||
if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) {
|
||||
close(s);
|
||||
return;
|
||||
}
|
||||
|
||||
close(s);
|
||||
}
|
||||
|
||||
static int run(const char *path,...)
|
||||
{
|
||||
va_list ap;
|
||||
char *args[16];
|
||||
int argNo = 1;
|
||||
|
||||
va_start(ap,path);
|
||||
args[0] = (char *)path;
|
||||
for(;argNo<15;++argNo) {
|
||||
args[argNo] = va_arg(ap,char *);
|
||||
if (!args[argNo]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
args[argNo++] = (char *)0;
|
||||
va_end(ap);
|
||||
|
||||
pid_t pid = vfork();
|
||||
if (pid < 0) {
|
||||
return -1;
|
||||
} else if (pid == 0) {
|
||||
dup2(STDERR_FILENO,STDOUT_FILENO);
|
||||
execv(args[0],args);
|
||||
exit(-1);
|
||||
}
|
||||
int rv = 0;
|
||||
waitpid(pid,&rv,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void die()
|
||||
{
|
||||
if (s_bpffd >= 0)
|
||||
close(s_bpffd);
|
||||
if (s_deviceName[0])
|
||||
run("/sbin/ifconfig",s_deviceName,"destroy",(char *)0);
|
||||
if (s_peerDeviceName[0])
|
||||
run("/sbin/ifconfig",s_peerDeviceName,"destroy",(char *)0);
|
||||
}
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
char buf[128];
|
||||
struct ifreq ifr;
|
||||
u_int fl;
|
||||
fd_set rfds,wfds,efds;
|
||||
struct iovec iov[2];
|
||||
|
||||
s_deviceName[0] = 0;
|
||||
s_peerDeviceName[0] = 0;
|
||||
s_parentPid = getppid();
|
||||
|
||||
atexit(&die);
|
||||
signal(SIGIO,SIG_IGN);
|
||||
signal(SIGCHLD,SIG_IGN);
|
||||
signal(SIGPIPE,SIG_IGN);
|
||||
signal(SIGUSR1,SIG_IGN);
|
||||
signal(SIGUSR2,SIG_IGN);
|
||||
signal(SIGALRM,SIG_IGN);
|
||||
signal(SIGQUIT,&exit);
|
||||
signal(SIGTERM,&exit);
|
||||
signal(SIGKILL,&exit);
|
||||
signal(SIGINT,&exit);
|
||||
signal(SIGPIPE,&exit);
|
||||
|
||||
if (getuid() != 0) {
|
||||
if (setuid(0) != 0) {
|
||||
fprintf(stderr,"E must be run as root or with root setuid bit on executable\n");
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 5) {
|
||||
fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> <mac> <mtu> <metric>)\n");
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
|
||||
}
|
||||
const int deviceNo = atoi(argv[1]);
|
||||
if ((deviceNo < 0)||(deviceNo > 4999)) {
|
||||
fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> <mac> <mtu> <metric>)\n");
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
|
||||
}
|
||||
const char *mac = argv[2];
|
||||
const char *mtu = argv[3];
|
||||
const char *metric = argv[4];
|
||||
|
||||
int ndrvSocket = socket(AF_NDRV,SOCK_RAW,0);
|
||||
if (ndrvSocket < 0) {
|
||||
fprintf(stderr,"E unable to open AF_NDRV socket\n");
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
|
||||
snprintf(s_peerDeviceName,sizeof(s_peerDeviceName),"feth%d",deviceNo+5000);
|
||||
if (run(P_IFCONFIG,s_peerDeviceName,"create",(char *)0) != 0) {
|
||||
fprintf(stderr,"E unable to create %s\n",s_deviceName);
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
usleep(10);
|
||||
snprintf(s_deviceName,sizeof(s_deviceName),"feth%d",deviceNo);
|
||||
if (run(P_IFCONFIG,s_deviceName,"create",(char *)0) != 0) {
|
||||
fprintf(stderr,"E unable to create %s\n",s_deviceName);
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
run(P_IFCONFIG,s_deviceName,"lladdr",mac,(char *)0);
|
||||
usleep(10);
|
||||
run(P_IFCONFIG,s_peerDeviceName,"peer",s_deviceName,(char *)0);
|
||||
usleep(10);
|
||||
run(P_IFCONFIG,s_peerDeviceName,"mtu","10000","up",(char *)0);
|
||||
usleep(10);
|
||||
run(P_IFCONFIG,s_deviceName,"mtu",mtu,"metric",metric,"up",(char *)0);
|
||||
usleep(10);
|
||||
configureIpv6Parameters(s_deviceName,1,0);
|
||||
usleep(10);
|
||||
|
||||
struct sockaddr_ndrv nd;
|
||||
nd.snd_len = sizeof(struct sockaddr_ndrv);
|
||||
nd.snd_family = AF_NDRV;
|
||||
memcpy(nd.snd_name,s_peerDeviceName,sizeof(nd.snd_name));
|
||||
if (bind(ndrvSocket,(struct sockaddr *)&nd,sizeof(nd)) != 0) {
|
||||
fprintf(stderr,"E unable to bind AF_NDRV socket\n");
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
if (connect(ndrvSocket,(struct sockaddr *)&nd,sizeof(nd)) != 0) {
|
||||
fprintf(stderr,"E unable to connect AF_NDRV socket\n");
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
|
||||
/* Start at /dev/bpf1 since some simple bpf-using net utilities hard-code /dev/bpf0.
|
||||
* Things like libpcap are smart enough to search. */
|
||||
for(int bpfno=1;bpfno<5000;++bpfno) {
|
||||
char tmp[32];
|
||||
snprintf(tmp,sizeof(tmp),"/dev/bpf%d",bpfno);
|
||||
s_bpffd = open(tmp,O_RDWR);
|
||||
if (s_bpffd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s_bpffd < 0) {
|
||||
fprintf(stderr,"E unable to open bpf device\n");
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
|
||||
fl = sizeof(s_pktReadBuf);
|
||||
if (ioctl(s_bpffd,BIOCSBLEN,&fl) != 0) {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
const size_t readPktSize = (size_t)fl;
|
||||
fl = 1;
|
||||
if (ioctl(s_bpffd,BIOCIMMEDIATE,&fl) != 0) {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
fl = 0;
|
||||
if (ioctl(s_bpffd,BIOCSSEESENT,&fl) != 0) {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
memset(&ifr,0,sizeof(ifr));
|
||||
memcpy(ifr.ifr_name,s_peerDeviceName,IFNAMSIZ);
|
||||
if (ioctl(s_bpffd,BIOCSETIF,&ifr) != 0) {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
fl = 1;
|
||||
if (ioctl(s_bpffd,BIOCSHDRCMPLT,&fl) != 0) {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
fl = 1;
|
||||
if (ioctl(s_bpffd,BIOCPROMISC,&fl) != 0) {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
|
||||
}
|
||||
|
||||
fcntl(STDIN_FILENO,F_SETFL,fcntl(STDIN_FILENO,F_GETFL)|O_NONBLOCK);
|
||||
fcntl(ndrvSocket,F_SETFL,fcntl(ndrvSocket,F_GETFL)|O_NONBLOCK);
|
||||
fcntl(s_bpffd,F_SETFL,fcntl(s_bpffd,F_GETFL)|O_NONBLOCK);
|
||||
|
||||
fprintf(stderr,"I %s %s %d.%d.%d.%d\n",s_deviceName,s_peerDeviceName,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD);
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&efds);
|
||||
long stdinReadPtr = 0;
|
||||
for(;;) {
|
||||
FD_SET(STDIN_FILENO,&rfds);
|
||||
FD_SET(s_bpffd,&rfds);
|
||||
if (select(s_bpffd+1,&rfds,&wfds,&efds,(struct timeval *)0) < 0) {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR;
|
||||
}
|
||||
|
||||
if (FD_ISSET(s_bpffd,&rfds)) {
|
||||
long n = (long)read(s_bpffd,s_pktReadBuf,readPktSize);
|
||||
if (n > 0) {
|
||||
for(unsigned char *p=s_pktReadBuf,*eof=p+n;p<eof;) {
|
||||
struct bpf_hdr *h = (struct bpf_hdr *)p;
|
||||
if ((h->bh_caplen > 0)&&((p + h->bh_hdrlen + h->bh_caplen) <= eof)) {
|
||||
uint16_t len = (uint16_t)h->bh_caplen;
|
||||
iov[0].iov_base = &len;
|
||||
iov[0].iov_len = 2;
|
||||
iov[1].iov_base = p + h->bh_hdrlen;
|
||||
iov[1].iov_len = h->bh_caplen;
|
||||
writev(STDOUT_FILENO,iov,2);
|
||||
}
|
||||
p += BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen);
|
||||
}
|
||||
} else {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO,&rfds)) {
|
||||
long n = (long)read(STDIN_FILENO,s_stdinReadBuf + stdinReadPtr,sizeof(s_stdinReadBuf) - stdinReadPtr);
|
||||
if (n > 0) {
|
||||
stdinReadPtr += n;
|
||||
while (stdinReadPtr >= 2) {
|
||||
long len = *((uint16_t *)s_stdinReadBuf);
|
||||
if (stdinReadPtr >= (len + 2)) {
|
||||
if (len > 0) {
|
||||
unsigned char *msg = s_stdinReadBuf + 2;
|
||||
|
||||
switch(msg[0]) {
|
||||
case ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET:
|
||||
if (len > 1) {
|
||||
if (write(ndrvSocket,msg+1,len-1) < 0) {
|
||||
fprintf(stderr,"E inject failed size==%ld errno==%d\n",len-1,errno);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG: {
|
||||
char *args[16];
|
||||
args[0] = P_IFCONFIG;
|
||||
args[1] = s_deviceName;
|
||||
int argNo = 2;
|
||||
for(int argPtr=0,k=1,l=(int)len;k<l;++k) {
|
||||
if (!msg[k]) {
|
||||
if (argPtr > 0) {
|
||||
argPtr = 0;
|
||||
++argNo;
|
||||
if (argNo >= 15) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (argPtr == 0) {
|
||||
args[argNo] = (char *)(msg + k);
|
||||
}
|
||||
argPtr++;
|
||||
}
|
||||
}
|
||||
args[argNo] = (char *)0;
|
||||
if (argNo > 2) {
|
||||
pid_t pid = vfork();
|
||||
if (pid < 0) {
|
||||
return -1;
|
||||
} else if (pid == 0) {
|
||||
dup2(STDERR_FILENO,STDOUT_FILENO);
|
||||
execv(args[0],args);
|
||||
exit(-1);
|
||||
}
|
||||
int rv = 0;
|
||||
waitpid(pid,&rv,0);
|
||||
}
|
||||
} break;
|
||||
case ZT_MACETHERNETTAPAGENT_STDIN_CMD_EXIT:
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (stdinReadPtr > (len + 2)) {
|
||||
memmove(s_stdinReadBuf,s_stdinReadBuf + len + 2,stdinReadPtr -= (len + 2));
|
||||
} else {
|
||||
stdinReadPtr = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS;
|
||||
}
|
41
osdep/MacEthernetTapAgent.h
Normal file
41
osdep/MacEthernetTapAgent.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MACETHERNETTAPAGENT_H
|
||||
#define ZT_MACETHERNETTAPAGENT_H
|
||||
|
||||
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS 0
|
||||
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST -1
|
||||
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE -2
|
||||
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR -3
|
||||
|
||||
#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET 0
|
||||
#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG 1
|
||||
#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_EXIT 2
|
||||
|
||||
#define ZT_MACETHERNETTAPAGENT_DEFAULT_SYSTEM_PATH "/Library/Application Support/ZeroTier/One/MacEthernetTapAgent"
|
||||
|
||||
#endif
|
@ -114,8 +114,8 @@ namespace ZeroTier { typedef VirtualTap EthernetTap; }
|
||||
#else
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "../osdep/OSXEthernetTap.hpp"
|
||||
namespace ZeroTier { typedef OSXEthernetTap EthernetTap; }
|
||||
#include "../osdep/MacEthernetTap.hpp"
|
||||
namespace ZeroTier { typedef MacEthernetTap EthernetTap; }
|
||||
#endif // __APPLE__
|
||||
#ifdef __LINUX__
|
||||
#include "../osdep/LinuxEthernetTap.hpp"
|
||||
|
Loading…
Reference in New Issue
Block a user