Browse Source

make it compilable

Daniel Skowroński 8 years ago
parent
commit
f09eedbd7a

+ 4 - 4
make-netbsd.mk

@@ -6,7 +6,7 @@ DEFS=
 LIBS=
 
 include objects.mk
-OBJS+=osdep/BSDEthernetTap.o ext/lz4/lz4.o ext/json-parser/json.o ext/http-parser/http_parser.o
+OBJS+=osdep/NetBSDEthernetTap.o ext/lz4/lz4.o ext/json-parser/json.o ext/http-parser/http_parser.o
 
 # "make official" is a shortcut for this
 ifeq ($(ZT_OFFICIAL_RELEASE),1)
@@ -29,17 +29,17 @@ ifeq ($(ZT_DEBUG),1)
 ext/lz4/lz4.o node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS)
 else
 	CFLAGS?=-O3 -fstack-protector
-	CFLAGS+=-Wall -fPIE -fvisibility=hidden -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS)
+	CFLAGS+=-fPIE -fvisibility=hidden -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS)
 	LDFLAGS+=-pie -Wl,-z,relro,-z,now
 	STRIP=strip --strip-all
 endif
 
-CXXFLAGS+=$(CFLAGS) -fno-rtti
+CXXFLAGS+=$(CFLAGS) -fno-rtti -fpermissive -w
 
 all:	one
 
 one:	$(OBJS) service/OneService.o one.o
-	$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS)
+	$(CXX) $(CXXFLAGS) $(LDFLAGS)  -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS)
 	$(STRIP) zerotier-one
 	ln -sf zerotier-one zerotier-idtool
 	ln -sf zerotier-one zerotier-cli

+ 464 - 0
osdep/NetBSDEthernetTap.cpp

@@ -0,0 +1,464 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016  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/>.
+ */
+
+#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/if.h>
+#include <ifaddrs.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/route.h>
+
+#include <sys/sysctl.h>
+
+#include "freebsd_getifmaddrs.h"
+
+#include <string>
+#include <map>
+#include <set>
+#include <algorithm>
+#include <utility>
+
+#include "../node/Constants.hpp"
+#include "../node/Utils.hpp"
+#include "../node/Mutex.hpp"
+#include "OSUtils.hpp"
+#include "NetBSDEthernetTap.hpp"
+
+#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv"
+
+// ff:ff:ff:ff:ff:ff with no ADI
+static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
+
+namespace ZeroTier {
+
+NetBSDEthernetTap::NetBSDEthernetTap(
+	const char *homePath,
+	const MAC &mac,
+	unsigned int mtu,
+	unsigned int metric,
+	uint64_t nwid,
+	const char *friendlyName,
+	void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
+	void *arg) :
+	_handler(handler),
+	_arg(arg),
+	_nwid(nwid),
+	_mtu(mtu),
+	_metric(metric),
+	_fd(0),
+	_enabled(true)
+{
+	static Mutex globalTapCreateLock;
+	char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32];
+	struct stat stattmp;
+
+	// On FreeBSD at least we can rename, so use nwid to generate a deterministic unique zt#### name using base32
+	// As a result we don't use desiredDevice
+	_dev = "zt";
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 60) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 55) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 50) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 45) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 40) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 35) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 30) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 25) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 20) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 15) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 10) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 5) & 0x1f)]);
+	_dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]);
+
+	Mutex::Lock _gl(globalTapCreateLock);
+
+	if (mtu > 2800)
+		throw std::runtime_error("max tap MTU is 2800");
+
+	// On BSD we create taps and they can have high numbers, so use ones starting
+	// at 9993 to not conflict with other stuff. Then we rename it to zt<base32 of nwid>
+	std::vector<std::string> devFiles(OSUtils::listDirectory("/dev"));
+	for(int i=9993;i<(9993+128);++i) {
+		Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
+		Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
+		if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) {
+			long cpid = (long)vfork();
+			if (cpid == 0) {
+				::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0);
+				::_exit(-1);
+			} else if (cpid > 0) {
+				int exitcode = -1;
+				::waitpid(cpid,&exitcode,0);
+			} else throw std::runtime_error("fork() failed");
+
+			if (!stat(devpath,&stattmp)) {
+				cpid = (long)vfork();
+				if (cpid == 0) {
+					::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0);
+					::_exit(-1);
+				} else if (cpid > 0) {
+					int exitcode = -1;
+					::waitpid(cpid,&exitcode,0);
+					if (exitcode)
+						throw std::runtime_error("ifconfig rename operation failed");
+				} else throw std::runtime_error("fork() failed");
+
+				_fd = ::open(devpath,O_RDWR);
+				if (_fd > 0)
+					break;
+				else throw std::runtime_error("unable to open created tap device");
+			} else {
+				throw std::runtime_error("cannot find /dev node for newly created tap device");
+			}
+		}
+	}
+
+	if (_fd <= 0)
+		throw std::runtime_error("unable to open TAP device or no more devices available");
+
+	if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
+		::close(_fd);
+		throw std::runtime_error("unable to set flags on file descriptor for TAP device");
+	}
+
+	// Configure MAC address and MTU, bring interface up
+	Utils::snprintf(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]);
+	Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu);
+	Utils::snprintf(metstr,sizeof(metstr),"%u",_metric);
+	long cpid = (long)vfork();
+	if (cpid == 0) {
+		::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
+		::_exit(-1);
+	} else if (cpid > 0) {
+		int exitcode = -1;
+		::waitpid(cpid,&exitcode,0);
+		if (exitcode) {
+			::close(_fd);
+			throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
+		}
+	}
+
+	// Set close-on-exec so that devices cannot persist if we fork/exec for update
+	fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
+
+	::pipe(_shutdownSignalPipe);
+
+	_thread = Thread::start(this);
+}
+
+NetBSDEthernetTap::~NetBSDEthernetTap()
+{
+	::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
+	Thread::join(_thread);
+	::close(_fd);
+	::close(_shutdownSignalPipe[0]);
+	::close(_shutdownSignalPipe[1]);
+
+	long cpid = (long)vfork();
+	if (cpid == 0) {
+		::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0);
+		::_exit(-1);
+	} else if (cpid > 0) {
+		int exitcode = -1;
+		::waitpid(cpid,&exitcode,0);
+	}
+}
+
+void NetBSDEthernetTap::setEnabled(bool en)
+{
+	_enabled = en;
+}
+
+bool NetBSDEthernetTap::enabled() const
+{
+	return _enabled;
+}
+
+static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
+{
+	long cpid = (long)vfork();
+	if (cpid == 0) {
+		execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0);
+		_exit(-1);
+	} else if (cpid > 0) {
+		int exitcode = -1;
+		waitpid(cpid,&exitcode,0);
+		return (exitcode == 0);
+	}
+	return false; // never reached, make compiler shut up about return value
+}
+
+bool NetBSDEthernetTap::addIp(const InetAddress &ip)
+{
+	if (!ip)
+		return false;
+
+	std::vector<InetAddress> allIps(ips());
+	if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end())
+		return true; // IP/netmask already assigned
+
+	// Remove and reconfigure if address is the same but netmask is different
+	for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
+		if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
+			if (___removeIp(_dev,*i))
+				break;
+		}
+	}
+
+	long cpid = (long)vfork();
+	if (cpid == 0) {
+		::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0);
+		::_exit(-1);
+	} else if (cpid > 0) {
+		int exitcode = -1;
+		::waitpid(cpid,&exitcode,0);
+		return (exitcode == 0);
+	}
+	return false;
+}
+
+bool NetBSDEthernetTap::removeIp(const InetAddress &ip)
+{
+	if (!ip)
+		return false;
+	std::vector<InetAddress> allIps(ips());
+	if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) {
+		if (___removeIp(_dev,ip))
+			return true;
+	}
+	return false;
+}
+
+std::vector<InetAddress> NetBSDEthernetTap::ips() const
+{
+	struct ifaddrs *ifa = (struct ifaddrs *)0;
+	if (getifaddrs(&ifa))
+		return std::vector<InetAddress>();
+
+	std::vector<InetAddress> r;
+
+	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;
+	}
+
+	if (ifa)
+		freeifaddrs(ifa);
+
+	std::sort(r.begin(),r.end());
+	std::unique(r.begin(),r.end());
+
+	return r;
+}
+
+void NetBSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
+{
+	char putBuf[4096];
+	if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
+		to.copyTo(putBuf,6);
+		from.copyTo(putBuf + 6,6);
+		*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
+		memcpy(putBuf + 14,data,len);
+		len += 14;
+		::write(_fd,putBuf,len);
+	}
+}
+
+std::string NetBSDEthernetTap::deviceName() const
+{
+	return _dev;
+}
+
+void NetBSDEthernetTap::setFriendlyName(const char *friendlyName)
+{
+}
+
+void NetBSDEthernetTap::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);
+}
+
+/*
+bool NetBSDEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
+{
+	std::set<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.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
+			}
+			p = p->ifma_next;
+		}
+		freeifmaddrs(ifmap);
+	}
+
+	{
+		std::set<InetAddress> allIps(ips());
+		for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i)
+			newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
+	}
+
+	bool changed = false;
+
+	for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) {
+		if (!groups.count(*mg)) {
+			groups.insert(*mg);
+			changed = true;
+		}
+	}
+	for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
+		if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
+			groups.erase(mg++);
+			changed = true;
+		} else ++mg;
+	}
+
+	return changed;
+}
+*/
+
+void NetBSDEthernetTap::threadMain()
+	throw()
+{
+	fd_set readfds,nullfds;
+	MAC to,from;
+	int n,nfds,r;
+	char getBuf[8194];
+
+	// Wait for a moment after startup -- wait for Network to finish
+	// constructing itself.
+	Thread::sleep(500);
+
+	FD_ZERO(&readfds);
+	FD_ZERO(&nullfds);
+	nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
+
+	r = 0;
+	for(;;) {
+		FD_SET(_shutdownSignalPipe[0],&readfds);
+		FD_SET(_fd,&readfds);
+		select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
+
+		if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
+			break;
+
+		if (FD_ISSET(_fd,&readfds)) {
+			n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
+			if (n < 0) {
+				if ((errno != EINTR)&&(errno != ETIMEDOUT))
+					break;
+			} else {
+				// Some tap drivers like to send the ethernet frame and the
+				// payload in two chunks, so handle that by accumulating
+				// data until we have at least a frame.
+				r += n;
+				if (r > 14) {
+					if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
+						r = _mtu + 14;
+
+					if (_enabled) {
+						to.setTo(getBuf,6);
+						from.setTo(getBuf + 6,6);
+						unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
+						// TODO: VLAN support
+						_handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14);
+					}
+
+					r = 0;
+				}
+			}
+		}
+	}
+}
+
+} // namespace ZeroTier

+ 84 - 0
osdep/NetBSDEthernetTap.hpp

@@ -0,0 +1,84 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016  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/>.
+ */
+
+#ifndef ZT_NetBSDEthernetTap_HPP
+#define ZT_NetBSDEthernetTap_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+#include <stdexcept>
+
+#include "../node/Constants.hpp"
+#include "../node/MulticastGroup.hpp"
+#include "../node/MAC.hpp"
+#include "Thread.hpp"
+
+
+
+
+
+namespace ZeroTier {
+
+class NetBSDEthernetTap
+{
+public:
+	NetBSDEthernetTap(
+		const char *homePath,
+		const MAC &mac,
+		unsigned int mtu,
+		unsigned int metric,
+		uint64_t nwid,
+		const char *friendlyName,
+		void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
+		void *arg);
+
+	~NetBSDEthernetTap();
+
+	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 threadMain()
+		throw();
+
+private:
+	void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
+	void *_arg;
+	uint64_t _nwid;
+	Thread _thread;
+	std::string _dev;
+	std::vector<MulticastGroup> _multicastGroups;
+	unsigned int _mtu;
+	unsigned int _metric;
+	int _fd;
+	int _shutdownSignalPipe[2];
+	volatile bool _enabled;
+};
+
+} // namespace ZeroTier
+
+#endif

+ 202 - 0
osdep/freebsd_getifmaddrs.c

@@ -0,0 +1,202 @@
+#define	NET_RT_IFMALIST	4		/* return multicast address list */
+#define	RTM_NEWMADDR	0xf    /* mcast group membership being added to if */
+
+
+/*
+ * Copyright (c) 2003 Bruce M. Simpson.
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+/*
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"*/
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+//#include "un-namespace.h"
+
+#define	SALIGN	(sizeof(long) - 1)
+#define	SA_RLEN(sa)	((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
+			    (SALIGN + 1))
+#define	MAX_SYSCTL_TRY	5
+#define	RTA_MASKS	(RTA_GATEWAY | RTA_IFP | RTA_IFA)
+
+int
+getifmaddrs(struct ifmaddrs **pif)
+{
+	int icnt = 1;
+	int dcnt = 0;
+	int ntry = 0;
+	size_t len;
+	size_t needed;
+	int mib[6];
+	int i;
+	char *buf;
+	char *data;
+	char *next;
+	char *p;
+	struct ifma_msghdr *ifmam;
+	struct ifmaddrs *ifa, *ift;
+	struct rt_msghdr *rtm;
+	struct sockaddr *sa;
+
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;             /* protocol */
+	mib[3] = 0;             /* wildcard address family */
+	mib[4] = NET_RT_IFMALIST;
+	mib[5] = 0;             /* no flags */
+	do {
+		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+			return (-1);
+		if ((buf = malloc(needed)) == NULL)
+			return (-1);
+		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+				free(buf);
+				return (-1);
+			}
+			free(buf);
+			buf = NULL;
+		}
+	} while (buf == NULL);
+
+	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+		rtm = (struct rt_msghdr *)(void *)next;
+		if (rtm->rtm_version != RTM_VERSION)
+			continue;
+		switch (rtm->rtm_type) {
+		case RTM_NEWMADDR:
+			ifmam = (struct ifma_msghdr *)(void *)rtm;
+			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+				break;
+			icnt++;
+			p = (char *)(ifmam + 1);
+			for (i = 0; i < RTAX_MAX; i++) {
+				if ((RTA_MASKS & ifmam->ifmam_addrs &
+				    (1 << i)) == 0)
+					continue;
+				sa = (struct sockaddr *)(void *)p;
+				len = SA_RLEN(sa);
+				dcnt += len;
+				p += len;
+			}
+			break;
+		}
+	}
+
+	data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
+	if (data == NULL) {
+		free(buf);
+		return (-1);
+	}
+
+	ifa = (struct ifmaddrs *)(void *)data;
+	data += sizeof(struct ifmaddrs) * icnt;
+
+	memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
+	ift = ifa;
+
+	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+		rtm = (struct rt_msghdr *)(void *)next;
+		if (rtm->rtm_version != RTM_VERSION)
+			continue;
+
+		switch (rtm->rtm_type) {
+		case RTM_NEWMADDR:
+			ifmam = (struct ifma_msghdr *)(void *)rtm;
+			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+				break;
+
+			p = (char *)(ifmam + 1);
+			for (i = 0; i < RTAX_MAX; i++) {
+				if ((RTA_MASKS & ifmam->ifmam_addrs &
+				    (1 << i)) == 0)
+					continue;
+				sa = (struct sockaddr *)(void *)p;
+				len = SA_RLEN(sa);
+				switch (i) {
+				case RTAX_GATEWAY:
+					ift->ifma_lladdr =
+					    (struct sockaddr *)(void *)data;
+					memcpy(data, p, len);
+					data += len;
+					break;
+
+				case RTAX_IFP:
+					ift->ifma_name =
+					    (struct sockaddr *)(void *)data;
+					memcpy(data, p, len);
+					data += len;
+					break;
+
+				case RTAX_IFA:
+					ift->ifma_addr =
+					    (struct sockaddr *)(void *)data;
+					memcpy(data, p, len);
+					data += len;
+					break;
+
+				default:
+					data += len;
+					break;
+				}
+				p += len;
+			}
+			ift->ifma_next = ift + 1;
+			ift = ift->ifma_next;
+			break;
+		}
+	}
+
+	free(buf);
+
+	if (ift > ifa) {
+		ift--;
+		ift->ifma_next = NULL;
+		*pif = ifa;
+	} else {
+		*pif = NULL;
+		free(ifa);
+	}
+	return (0);
+}
+
+void
+freeifmaddrs(struct ifmaddrs *ifmp)
+{
+
+	free(ifmp);
+}

+ 70 - 0
osdep/freebsd_getifmaddrs.h

@@ -0,0 +1,70 @@
+/*	$FreeBSD$	*/
+
+/*
+ * Copyright (c) 1995, 1999
+ *	Berkeley Software Design, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef	_freebsd_getifmaddrs.h_
+#define	_freebsd_getifmaddrs.h_
+
+/*
+ * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef	ifa_broadaddr
+#define	ifa_broadaddr	ifa_dstaddr	/* broadcast address interface */
+#endif
+
+struct ifmaddrs {
+	struct ifmaddrs	*ifma_next;
+	struct sockaddr	*ifma_name;
+	struct sockaddr	*ifma_addr;
+	struct sockaddr	*ifma_lladdr;
+};
+
+#include <sys/cdefs.h>
+
+
+/*
+ * Message format for use in obtaining information about multicast addresses
+ * from the routing socket
+ */
+struct ifma_msghdr {
+	int	ifmam_msglen;	/* to skip over non-understood messages */
+	int	ifmam_version;	/* future binary compatibility */
+	int	ifmam_type;	/* message type */
+	int	ifmam_addrs;	/* like rtm_addrs */
+	int	ifmam_flags;	/* value of ifa_flags */
+	int	ifmam_index;	/* index for associated ifp */
+};
+
+
+extern int getifaddrs(struct ifaddrs **);
+extern void freeifaddrs(struct ifaddrs *);
+extern int getifmaddrs(struct ifmaddrs **);
+extern void freeifmaddrs(struct ifmaddrs *);
+#include "freebsd_getifmaddrs.c"
+
+
+#endif

+ 6 - 2
service/OneService.cpp

@@ -114,6 +114,10 @@ namespace ZeroTier { typedef WindowsEthernetTap EthernetTap; }
 #include "../osdep/BSDEthernetTap.hpp"
 namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
 #endif // __FreeBSD__
+#ifdef __NetBSD__
+#include "../osdep/NetBSDEthernetTap.hpp"
+namespace ZeroTier { typedef NetBSDEthernetTap EthernetTap; }
+#endif // __FreeBSD__
 
 #endif // ZT_SERVICE_NETCON
 
@@ -1684,7 +1688,7 @@ public:
 	inline int nodePathCheckFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr)
 	{
 		Mutex::Lock _l(_nets_m);
-	
+
 		for(std::map<uint64_t,NetworkState>::const_iterator n(_nets.begin());n!=_nets.end();++n) {
 			if (n->second.tap) {
 				std::vector<InetAddress> ips(n->second.tap->ips());
@@ -1695,7 +1699,7 @@ public:
 				}
 			}
 		}
-	
+
 		/* Note: I do not think we need to scan for overlap with managed routes
 		 * because of the "route forking" and interface binding that we do. This
 		 * ensures (we hope) that ZeroTier traffic will still take the physical