|
@@ -29,126 +29,43 @@
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
|
+#include <errno.h>
|
|
|
+
|
|
|
#include <unistd.h>
|
|
|
#include <signal.h>
|
|
|
+
|
|
|
#include <fcntl.h>
|
|
|
-#include <errno.h>
|
|
|
#include <sys/types.h>
|
|
|
#include <sys/stat.h>
|
|
|
#include <sys/ioctl.h>
|
|
|
#include <sys/wait.h>
|
|
|
#include <sys/select.h>
|
|
|
-#include <netinet/in.h>
|
|
|
-#include <net/if_arp.h>
|
|
|
-#include <arpa/inet.h>
|
|
|
-
|
|
|
-#include <string>
|
|
|
-#include <map>
|
|
|
-#include <set>
|
|
|
-#include <algorithm>
|
|
|
-
|
|
|
-#include "Constants.hpp"
|
|
|
-#include "UnixEthernetTap.hpp"
|
|
|
-#include "Logger.hpp"
|
|
|
-#include "RuntimeEnvironment.hpp"
|
|
|
-#include "Utils.hpp"
|
|
|
-#include "Mutex.hpp"
|
|
|
-
|
|
|
-// ff:ff:ff:ff:ff:ff with no ADI
|
|
|
-static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
|
|
|
-
|
|
|
-// Command identifiers used with command finder static (on various *nixes)
|
|
|
-#define ZT_UNIX_IP_COMMAND 1
|
|
|
-#define ZT_UNIX_IFCONFIG_COMMAND 2
|
|
|
-#define ZT_MAC_KEXTLOAD_COMMAND 3
|
|
|
-#define ZT_MAC_KEXTUNLOAD_COMMAND 4
|
|
|
-
|
|
|
-// Finds external commands on startup ----------------------------------------
|
|
|
-class _CommandFinder
|
|
|
-{
|
|
|
-public:
|
|
|
- _CommandFinder()
|
|
|
- {
|
|
|
- _findCmd(ZT_UNIX_IFCONFIG_COMMAND,"ifconfig");
|
|
|
-#ifdef __LINUX__
|
|
|
- _findCmd(ZT_UNIX_IP_COMMAND,"ip");
|
|
|
-#endif
|
|
|
-#ifdef __APPLE__
|
|
|
- _findCmd(ZT_MAC_KEXTLOAD_COMMAND,"kextload");
|
|
|
- _findCmd(ZT_MAC_KEXTUNLOAD_COMMAND,"kextunload");
|
|
|
-#endif
|
|
|
- }
|
|
|
- inline const char *operator[](int id) const
|
|
|
- throw()
|
|
|
- {
|
|
|
- std::map<int,std::string>::const_iterator c(_paths.find(id));
|
|
|
- if (c == _paths.end())
|
|
|
- return (const char *)0;
|
|
|
- return c->second.c_str();
|
|
|
- }
|
|
|
-private:
|
|
|
- inline void _findCmd(int id,const char *name)
|
|
|
- {
|
|
|
- char tmp[4096];
|
|
|
- ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/sbin/%s",name);
|
|
|
- if (ZeroTier::Utils::fileExists(tmp)) {
|
|
|
- _paths[id] = tmp;
|
|
|
- return;
|
|
|
- }
|
|
|
- ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/usr/sbin/%s",name);
|
|
|
- if (ZeroTier::Utils::fileExists(tmp)) {
|
|
|
- _paths[id] = tmp;
|
|
|
- return;
|
|
|
- }
|
|
|
- ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/bin/%s",name);
|
|
|
- if (ZeroTier::Utils::fileExists(tmp)) {
|
|
|
- _paths[id] = tmp;
|
|
|
- return;
|
|
|
- }
|
|
|
- ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/usr/bin/%s",name);
|
|
|
- if (ZeroTier::Utils::fileExists(tmp)) {
|
|
|
- _paths[id] = tmp;
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- std::map<int,std::string> _paths;
|
|
|
-};
|
|
|
-static const _CommandFinder UNIX_COMMANDS;
|
|
|
-// ---------------------------------------------------------------------------
|
|
|
-
|
|
|
-#ifdef __LINUX__
|
|
|
-#include <linux/if.h>
|
|
|
-#include <linux/if_tun.h>
|
|
|
-#include <linux/if_addr.h>
|
|
|
-#include <linux/if_ether.h>
|
|
|
-#include <ifaddrs.h>
|
|
|
-#endif // __LINUX__
|
|
|
-
|
|
|
-#ifdef __APPLE__
|
|
|
-
|
|
|
#include <sys/cdefs.h>
|
|
|
#include <sys/uio.h>
|
|
|
#include <sys/param.h>
|
|
|
#include <sys/sysctl.h>
|
|
|
#include <sys/ioctl.h>
|
|
|
-#include <sys/types.h>
|
|
|
#include <sys/socket.h>
|
|
|
+#include <netinet/in.h>
|
|
|
+#include <arpa/inet.h>
|
|
|
#include <net/route.h>
|
|
|
#include <net/if.h>
|
|
|
+#include <net/if_arp.h>
|
|
|
#include <net/if_dl.h>
|
|
|
#include <net/if_media.h>
|
|
|
-struct prf_ra { // stupid OSX compile fix... in6_var defines this in a struct which namespaces it for C++
|
|
|
- u_char onlink : 1;
|
|
|
- u_char autonomous : 1;
|
|
|
- u_char reserved : 6;
|
|
|
-} prf_ra;
|
|
|
#include <netinet6/in6_var.h>
|
|
|
-#include <netinet/in.h>
|
|
|
#include <netinet/in_var.h>
|
|
|
#include <netinet/icmp6.h>
|
|
|
#include <netinet6/nd6.h>
|
|
|
#include <ifaddrs.h>
|
|
|
|
|
|
+// OSX compile fix... in6_var defines this in a struct which namespaces it for C++
|
|
|
+struct prf_ra {
|
|
|
+ u_char onlink : 1;
|
|
|
+ u_char autonomous : 1;
|
|
|
+ u_char reserved : 6;
|
|
|
+} prf_ra;
|
|
|
+
|
|
|
// These are KERNEL_PRIVATE... why?
|
|
|
#ifndef SIOCAUTOCONF_START
|
|
|
#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
|
|
@@ -157,8 +74,198 @@ struct prf_ra { // stupid OSX compile fix... in6_var defines this in a struct wh
|
|
|
#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
|
|
|
#endif
|
|
|
|
|
|
-static volatile int EthernetTap_instances = 0;
|
|
|
-static ZeroTier::Mutex EthernetTap_instances_m;
|
|
|
+// --------------------------------------------------------------------------
|
|
|
+// --------------------------------------------------------------------------
|
|
|
+// This source is from:
|
|
|
+// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt
|
|
|
+// It's here because OSX 10.6 does not have this convenience function.
|
|
|
+
|
|
|
+#define SALIGN (sizeof(uint32_t) - 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)
|
|
|
+
|
|
|
+/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */
|
|
|
+/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */
|
|
|
+//#define DARWIN_COMPAT
|
|
|
+
|
|
|
+//#ifdef DARWIN_COMPAT
|
|
|
+#define GIM_SYSCTL_MIB NET_RT_IFLIST2
|
|
|
+#define GIM_RTM_ADDR RTM_NEWMADDR2
|
|
|
+//#else
|
|
|
+//#define GIM_SYSCTL_MIB NET_RT_IFMALIST
|
|
|
+//#define GIM_RTM_ADDR RTM_NEWMADDR
|
|
|
+//#endif
|
|
|
+
|
|
|
+// Not in 10.6 includes so use our own
|
|
|
+struct _intl_ifmaddrs {
|
|
|
+ struct _intl_ifmaddrs *ifma_next;
|
|
|
+ struct sockaddr *ifma_name;
|
|
|
+ struct sockaddr *ifma_addr;
|
|
|
+ struct sockaddr *ifma_lladdr;
|
|
|
+};
|
|
|
+
|
|
|
+static inline int _intl_getifmaddrs(struct _intl_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_msghdr2 *ifmam;
|
|
|
+ struct _intl_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] = GIM_SYSCTL_MIB;
|
|
|
+ mib[5] = 0; /* no flags */
|
|
|
+ do {
|
|
|
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
|
|
|
+ return (-1);
|
|
|
+ if ((buf = (char *)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 GIM_RTM_ADDR:
|
|
|
+ ifmam = (struct ifma_msghdr2 *)(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 = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
|
|
|
+ if (data == NULL) {
|
|
|
+ free(buf);
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+
|
|
|
+ ifa = (struct _intl_ifmaddrs *)(void *)data;
|
|
|
+ data += sizeof(struct _intl_ifmaddrs) * icnt;
|
|
|
+
|
|
|
+ memset(ifa, 0, sizeof(struct _intl_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 GIM_RTM_ADDR:
|
|
|
+ ifmam = (struct ifma_msghdr2 *)(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);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
|
|
|
+{
|
|
|
+ free(ifmp);
|
|
|
+}
|
|
|
+
|
|
|
+// --------------------------------------------------------------------------
|
|
|
+// --------------------------------------------------------------------------
|
|
|
+
|
|
|
+#include <string>
|
|
|
+#include <map>
|
|
|
+#include <set>
|
|
|
+#include <algorithm>
|
|
|
+
|
|
|
+#include "../Constants.hpp"
|
|
|
+#include "../Utils.hpp"
|
|
|
+#include "../Mutex.hpp"
|
|
|
+#include "OSXEthernetTap.hpp"
|
|
|
+
|
|
|
+// ff:ff:ff:ff:ff:ff with no ADI
|
|
|
+static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
|
|
|
|
|
|
static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts)
|
|
|
{
|
|
@@ -201,126 +308,12 @@ static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptR
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-#endif // __APPLE__
|
|
|
-
|
|
|
namespace ZeroTier {
|
|
|
|
|
|
// Only permit one tap to be opened concurrently across the entire process
|
|
|
-static Mutex __tapCreateLock;
|
|
|
-
|
|
|
-#ifdef __LINUX__
|
|
|
-UnixEthernetTap::UnixEthernetTap(
|
|
|
- const RuntimeEnvironment *renv,
|
|
|
- const char *tryToGetDevice,
|
|
|
- const MAC &mac,
|
|
|
- unsigned int mtu,
|
|
|
- void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
|
|
- void *arg)
|
|
|
- throw(std::runtime_error) :
|
|
|
- EthernetTap("UnixEthernetTap",mac,mtu),
|
|
|
- _r(renv),
|
|
|
- _handler(handler),
|
|
|
- _arg(arg),
|
|
|
- _fd(0),
|
|
|
- _enabled(true)
|
|
|
-{
|
|
|
- char procpath[128];
|
|
|
- struct stat sbuf;
|
|
|
- Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
|
|
|
-
|
|
|
- if (mtu > 4096)
|
|
|
- throw std::runtime_error("max tap MTU is 4096");
|
|
|
-
|
|
|
- _fd = ::open("/dev/net/tun",O_RDWR);
|
|
|
- if (_fd <= 0)
|
|
|
- throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno));
|
|
|
-
|
|
|
- struct ifreq ifr;
|
|
|
- memset(&ifr,0,sizeof(ifr));
|
|
|
-
|
|
|
- // Try to recall our last device name, or pick an unused one if that fails.
|
|
|
- bool recalledDevice = false;
|
|
|
- if ((tryToGetDevice)&&(tryToGetDevice[0])) {
|
|
|
- Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),tryToGetDevice);
|
|
|
- Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
|
|
|
- recalledDevice = (stat(procpath,&sbuf) != 0);
|
|
|
- }
|
|
|
- if (!recalledDevice) {
|
|
|
- int devno = 0;
|
|
|
- do {
|
|
|
- Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++);
|
|
|
- Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
|
|
|
- } while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist
|
|
|
- }
|
|
|
-
|
|
|
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
|
|
- if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) {
|
|
|
- ::close(_fd);
|
|
|
- throw std::runtime_error("unable to configure TUN/TAP device for TAP operation");
|
|
|
- }
|
|
|
-
|
|
|
- _dev = ifr.ifr_name;
|
|
|
-
|
|
|
- ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here
|
|
|
-
|
|
|
- // Open an arbitrary socket to talk to netlink
|
|
|
- int sock = socket(AF_INET,SOCK_DGRAM,0);
|
|
|
- if (sock <= 0) {
|
|
|
- ::close(_fd);
|
|
|
- throw std::runtime_error("unable to open netlink socket");
|
|
|
- }
|
|
|
-
|
|
|
- // Set MAC address
|
|
|
- ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER;
|
|
|
- mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6);
|
|
|
- if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) {
|
|
|
- ::close(_fd);
|
|
|
- ::close(sock);
|
|
|
- throw std::runtime_error("unable to configure TAP hardware (MAC) address");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // Set MTU
|
|
|
- ifr.ifr_ifru.ifru_mtu = (int)mtu;
|
|
|
- if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) {
|
|
|
- ::close(_fd);
|
|
|
- ::close(sock);
|
|
|
- throw std::runtime_error("unable to configure TAP MTU");
|
|
|
- }
|
|
|
-
|
|
|
- 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");
|
|
|
- }
|
|
|
-
|
|
|
- /* Bring interface up */
|
|
|
- if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) {
|
|
|
- ::close(_fd);
|
|
|
- ::close(sock);
|
|
|
- throw std::runtime_error("unable to get TAP interface flags");
|
|
|
- }
|
|
|
- ifr.ifr_flags |= IFF_UP;
|
|
|
- if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) {
|
|
|
- ::close(_fd);
|
|
|
- ::close(sock);
|
|
|
- throw std::runtime_error("unable to set TAP interface flags");
|
|
|
- }
|
|
|
-
|
|
|
- ::close(sock);
|
|
|
-
|
|
|
- // 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);
|
|
|
-
|
|
|
- TRACE("tap %s created",_dev.c_str());
|
|
|
-
|
|
|
- _thread = Thread::start(this);
|
|
|
-}
|
|
|
-#endif // __LINUX__
|
|
|
+static Mutex __tapCreateLock;
|
|
|
|
|
|
-#ifdef __APPLE__
|
|
|
-UnixEthernetTap::UnixEthernetTap(
|
|
|
+OSXEthernetTap::OSXEthernetTap(
|
|
|
const RuntimeEnvironment *renv,
|
|
|
const char *tryToGetDevice,
|
|
|
const MAC &mac,
|
|
@@ -328,7 +321,7 @@ UnixEthernetTap::UnixEthernetTap(
|
|
|
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
|
|
void *arg)
|
|
|
throw(std::runtime_error) :
|
|
|
- EthernetTap("UnixEthernetTap",mac,mtu),
|
|
|
+ EthernetTap("OSXEthernetTap",mac,mtu,metric),
|
|
|
_r(renv),
|
|
|
_handler(handler),
|
|
|
_arg(arg),
|
|
@@ -339,8 +332,8 @@ UnixEthernetTap::UnixEthernetTap(
|
|
|
struct stat stattmp;
|
|
|
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
|
|
|
|
|
|
- if (mtu > 4096)
|
|
|
- throw std::runtime_error("max tap MTU is 4096");
|
|
|
+ if (mtu > 2800)
|
|
|
+ throw std::runtime_error("max tap MTU is 2800");
|
|
|
|
|
|
// Check for existence of ZT tap devices, try to load module if not there
|
|
|
const char *kextload = UNIX_COMMANDS[ZT_MAC_KEXTLOAD_COMMAND];
|
|
@@ -432,9 +425,8 @@ UnixEthernetTap::UnixEthernetTap(
|
|
|
++EthernetTap_instances;
|
|
|
EthernetTap_instances_m.unlock();
|
|
|
}
|
|
|
-#endif // __APPLE__
|
|
|
|
|
|
-UnixEthernetTap::~UnixEthernetTap()
|
|
|
+OSXEthernetTap::~OSXEthernetTap()
|
|
|
{
|
|
|
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
|
|
|
Thread::join(_thread);
|
|
@@ -442,7 +434,6 @@ UnixEthernetTap::~UnixEthernetTap()
|
|
|
::close(_shutdownSignalPipe[0]);
|
|
|
::close(_shutdownSignalPipe[1]);
|
|
|
|
|
|
-#ifdef __APPLE__
|
|
|
EthernetTap_instances_m.lock();
|
|
|
int instances = --EthernetTap_instances;
|
|
|
EthernetTap_instances_m.unlock();
|
|
@@ -463,82 +454,19 @@ UnixEthernetTap::~UnixEthernetTap()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-#endif // __APPLE__
|
|
|
}
|
|
|
|
|
|
-void UnixEthernetTap::setEnabled(bool en)
|
|
|
+void OSXEthernetTap::setEnabled(bool en)
|
|
|
{
|
|
|
_enabled = en;
|
|
|
// TODO: interface status change
|
|
|
}
|
|
|
|
|
|
-bool UnixEthernetTap::enabled() const
|
|
|
+bool OSXEthernetTap::enabled() const
|
|
|
{
|
|
|
return _enabled;
|
|
|
}
|
|
|
|
|
|
-void UnixEthernetTap::setDisplayName(const char *dn)
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef __LINUX__
|
|
|
-static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
|
|
|
-{
|
|
|
- const char *ipcmd = UNIX_COMMANDS[ZT_UNIX_IP_COMMAND];
|
|
|
- if (!ipcmd)
|
|
|
- return false;
|
|
|
- long cpid = (long)vfork();
|
|
|
- if (cpid == 0) {
|
|
|
- execl(ipcmd,ipcmd,"addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
|
|
|
- _exit(-1);
|
|
|
- } else {
|
|
|
- int exitcode = -1;
|
|
|
- waitpid(cpid,&exitcode,0);
|
|
|
- return (exitcode == 0);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-bool UnixEthernetTap::addIP(const InetAddress &ip)
|
|
|
-{
|
|
|
- const char *ipcmd = UNIX_COMMANDS[ZT_UNIX_IP_COMMAND];
|
|
|
- if (!ipcmd) {
|
|
|
- LOG("ERROR: could not configure IP address for %s: unable to find 'ip' command on system (checked /sbin, /bin, /usr/sbin, /usr/bin)",_dev.c_str());
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (!ip)
|
|
|
- return false;
|
|
|
-
|
|
|
- std::set<InetAddress> allIps(ips());
|
|
|
- if (allIps.count(ip) > 0)
|
|
|
- return true;
|
|
|
-
|
|
|
- // Remove and reconfigure if address is the same but netmask is different
|
|
|
- for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
|
|
|
- if (i->ipsEqual(ip)) {
|
|
|
- if (___removeIp(_dev,*i)) {
|
|
|
- break;
|
|
|
- } else {
|
|
|
- LOG("WARNING: failed to remove old IP/netmask %s to replace with %s",i->toString().c_str(),ip.toString().c_str());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- long cpid;
|
|
|
- if ((cpid = (long)vfork()) == 0) {
|
|
|
- execl(ipcmd,ipcmd,"addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
|
|
|
- _exit(-1);
|
|
|
- } else if (cpid > 0) {
|
|
|
- int exitcode = -1;
|
|
|
- waitpid(cpid,&exitcode,0);
|
|
|
- return (exitcode == 0);
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
-}
|
|
|
-#endif // __LINUX__
|
|
|
-
|
|
|
-#ifdef __APPLE__
|
|
|
static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
|
|
|
{
|
|
|
const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND];
|
|
@@ -556,7 +484,7 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
|
|
|
return false; // never reached, make compiler shut up about return value
|
|
|
}
|
|
|
|
|
|
-bool UnixEthernetTap::addIP(const InetAddress &ip)
|
|
|
+bool OSXEthernetTap::addIP(const InetAddress &ip)
|
|
|
{
|
|
|
const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND];
|
|
|
if (!ifconfig) {
|
|
@@ -594,9 +522,8 @@ bool UnixEthernetTap::addIP(const InetAddress &ip)
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
-#endif // __APPLE__
|
|
|
|
|
|
-bool UnixEthernetTap::removeIP(const InetAddress &ip)
|
|
|
+bool OSXEthernetTap::removeIP(const InetAddress &ip)
|
|
|
{
|
|
|
if (ips().count(ip) > 0) {
|
|
|
if (___removeIp(_dev,ip))
|
|
@@ -605,7 +532,7 @@ bool UnixEthernetTap::removeIP(const InetAddress &ip)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-std::set<InetAddress> UnixEthernetTap::ips() const
|
|
|
+std::set<InetAddress> OSXEthernetTap::ips() const
|
|
|
{
|
|
|
struct ifaddrs *ifa = (struct ifaddrs *)0;
|
|
|
if (getifaddrs(&ifa))
|
|
@@ -640,7 +567,7 @@ std::set<InetAddress> UnixEthernetTap::ips() const
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
-void UnixEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
|
|
|
+void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
|
|
|
{
|
|
|
char putBuf[4096 + 14];
|
|
|
if ((_fd > 0)&&(len <= _mtu)) {
|
|
@@ -661,252 +588,17 @@ void UnixEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,c
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-std::string UnixEthernetTap::deviceName() const
|
|
|
+std::string OSXEthernetTap::deviceName() const
|
|
|
{
|
|
|
return _dev;
|
|
|
}
|
|
|
|
|
|
-std::string UnixEthernetTap::persistentId() const
|
|
|
+std::string OSXEthernetTap::persistentId() const
|
|
|
{
|
|
|
return std::string();
|
|
|
}
|
|
|
|
|
|
-#ifdef __LINUX__
|
|
|
-bool UnixEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
|
|
|
-{
|
|
|
- char *ptr,*ptr2;
|
|
|
- unsigned char mac[6];
|
|
|
- std::set<MulticastGroup> newGroups;
|
|
|
-
|
|
|
- int fd = ::open("/proc/net/dev_mcast",O_RDONLY);
|
|
|
- if (fd > 0) {
|
|
|
- char buf[131072];
|
|
|
- int n = (int)::read(fd,buf,sizeof(buf));
|
|
|
- if ((n > 0)&&(n < (int)sizeof(buf))) {
|
|
|
- buf[n] = (char)0;
|
|
|
- for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) {
|
|
|
- int fno = 0;
|
|
|
- char *devname = (char *)0;
|
|
|
- char *mcastmac = (char *)0;
|
|
|
- for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) {
|
|
|
- if (fno == 1)
|
|
|
- devname = f;
|
|
|
- else if (fno == 4)
|
|
|
- mcastmac = f;
|
|
|
- ++fno;
|
|
|
- }
|
|
|
- if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6))
|
|
|
- newGroups.insert(MulticastGroup(MAC(mac,6),0));
|
|
|
- }
|
|
|
- }
|
|
|
- ::close(fd);
|
|
|
- }
|
|
|
-
|
|
|
- {
|
|
|
- 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;
|
|
|
-}
|
|
|
-#endif // __LINUX__
|
|
|
-
|
|
|
-#ifdef __APPLE__
|
|
|
-// --------------------------------------------------------------------------
|
|
|
-// This source is from:
|
|
|
-// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt
|
|
|
-// It's here because OSX 10.6 does not have this convenience function.
|
|
|
-
|
|
|
-#define SALIGN (sizeof(uint32_t) - 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)
|
|
|
-
|
|
|
-/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */
|
|
|
-/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */
|
|
|
-//#define DARWIN_COMPAT
|
|
|
-
|
|
|
-//#ifdef DARWIN_COMPAT
|
|
|
-#define GIM_SYSCTL_MIB NET_RT_IFLIST2
|
|
|
-#define GIM_RTM_ADDR RTM_NEWMADDR2
|
|
|
-//#else
|
|
|
-//#define GIM_SYSCTL_MIB NET_RT_IFMALIST
|
|
|
-//#define GIM_RTM_ADDR RTM_NEWMADDR
|
|
|
-//#endif
|
|
|
-
|
|
|
-// Not in 10.6 includes so use our own
|
|
|
-struct _intl_ifmaddrs {
|
|
|
- struct _intl_ifmaddrs *ifma_next;
|
|
|
- struct sockaddr *ifma_name;
|
|
|
- struct sockaddr *ifma_addr;
|
|
|
- struct sockaddr *ifma_lladdr;
|
|
|
-};
|
|
|
-
|
|
|
-static inline int _intl_getifmaddrs(struct _intl_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_msghdr2 *ifmam;
|
|
|
- struct _intl_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] = GIM_SYSCTL_MIB;
|
|
|
- mib[5] = 0; /* no flags */
|
|
|
- do {
|
|
|
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
|
|
|
- return (-1);
|
|
|
- if ((buf = (char *)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 GIM_RTM_ADDR:
|
|
|
- ifmam = (struct ifma_msghdr2 *)(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 = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
|
|
|
- if (data == NULL) {
|
|
|
- free(buf);
|
|
|
- return (-1);
|
|
|
- }
|
|
|
-
|
|
|
- ifa = (struct _intl_ifmaddrs *)(void *)data;
|
|
|
- data += sizeof(struct _intl_ifmaddrs) * icnt;
|
|
|
-
|
|
|
- memset(ifa, 0, sizeof(struct _intl_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 GIM_RTM_ADDR:
|
|
|
- ifmam = (struct ifma_msghdr2 *)(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);
|
|
|
-}
|
|
|
-
|
|
|
-static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
|
|
|
-{
|
|
|
- free(ifmp);
|
|
|
-}
|
|
|
-
|
|
|
-// --------------------------------------------------------------------------
|
|
|
-
|
|
|
-bool UnixEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
|
|
|
+bool OSXEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
|
|
|
{
|
|
|
std::set<MulticastGroup> newGroups;
|
|
|
struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0;
|
|
@@ -947,9 +639,8 @@ bool UnixEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
|
|
|
|
|
|
return changed;
|
|
|
}
|
|
|
-#endif // __APPLE__
|
|
|
|
|
|
-void UnixEthernetTap::threadMain()
|
|
|
+void OSXEthernetTap::threadMain()
|
|
|
throw()
|
|
|
{
|
|
|
fd_set readfds,nullfds;
|