From 56096be8b6e3f67e3bdce25bee73d0fc0534b0d5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 6 Apr 2016 16:28:40 -0700 Subject: [PATCH 1/5] Tweak new RX queue algorithm to "expire" old entries to prevent always needing to traverse the whole queue array. --- node/Constants.hpp | 5 +++++ node/Switch.cpp | 4 ++-- node/Switch.hpp | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index c9356da02..6c44a8dc2 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -169,6 +169,11 @@ */ #define ZT_RX_QUEUE_SIZE 64 +/** + * RX queue entries older than this do not "exist" + */ +#define ZT_RX_QUEUE_EXPIRE 4000 + /** * Length of secret key in bytes -- 256-bit -- do not change */ diff --git a/node/Switch.cpp b/node/Switch.cpp index 890a94652..968d1a4a8 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -138,7 +138,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // seeing a Packet::Fragment? Mutex::Lock _l(_rxQueue_m); - RXQueueEntry *const rq = _findRXQueueEntry(fragmentPacketId); + RXQueueEntry *const rq = _findRXQueueEntry(now,fragmentPacketId); if ((!rq->timestamp)||(rq->packetId != fragmentPacketId)) { // No packet found, so we received a fragment without its head. @@ -241,7 +241,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Packet is the head of a fragmented packet series Mutex::Lock _l(_rxQueue_m); - RXQueueEntry *const rq = _findRXQueueEntry(packetId); + RXQueueEntry *const rq = _findRXQueueEntry(now,packetId); if ((!rq->timestamp)||(rq->packetId != packetId)) { // If we have no other fragments yet, create an entry and save the head diff --git a/node/Switch.hpp b/node/Switch.hpp index 219bfb416..ce4f00a16 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -184,7 +184,7 @@ private: /* Returns the matching or oldest entry. Caller must check timestamp and * packet ID to determine which. */ - inline RXQueueEntry *_findRXQueueEntry(uint64_t packetId) + inline RXQueueEntry *_findRXQueueEntry(uint64_t now,uint64_t packetId) { RXQueueEntry *rq; RXQueueEntry *oldest = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]); @@ -193,6 +193,8 @@ private: rq = &(_rxQueue[--i]); if ((rq->packetId == packetId)&&(rq->timestamp)) return rq; + if ((now - rq->timestamp) >= ZT_RX_QUEUE_EXPIRE) + rq->timestamp = 0; if (rq->timestamp < oldest->timestamp) oldest = rq; } From 24469a7f438a166e289dad00839e5dce631cd3e0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 6 Apr 2016 16:47:11 -0700 Subject: [PATCH 2/5] . --- {attic/rtbl => osdep}/BSDRoutingTable.cpp | 0 {attic/rtbl => osdep}/BSDRoutingTable.hpp | 0 {attic/rtbl => osdep}/LinuxRoutingTable.cpp | 0 {attic/rtbl => osdep}/LinuxRoutingTable.hpp | 0 {attic/rtbl => osdep}/RoutingTable.cpp | 0 {attic/rtbl => osdep}/RoutingTable.hpp | 0 {attic/rtbl => osdep}/TestRoutingTable.cpp | 0 {attic/rtbl => osdep}/TestRoutingTable.hpp | 0 {attic/rtbl => osdep}/WindowsRoutingTable.cpp | 0 {attic/rtbl => osdep}/WindowsRoutingTable.hpp | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename {attic/rtbl => osdep}/BSDRoutingTable.cpp (100%) rename {attic/rtbl => osdep}/BSDRoutingTable.hpp (100%) rename {attic/rtbl => osdep}/LinuxRoutingTable.cpp (100%) rename {attic/rtbl => osdep}/LinuxRoutingTable.hpp (100%) rename {attic/rtbl => osdep}/RoutingTable.cpp (100%) rename {attic/rtbl => osdep}/RoutingTable.hpp (100%) rename {attic/rtbl => osdep}/TestRoutingTable.cpp (100%) rename {attic/rtbl => osdep}/TestRoutingTable.hpp (100%) rename {attic/rtbl => osdep}/WindowsRoutingTable.cpp (100%) rename {attic/rtbl => osdep}/WindowsRoutingTable.hpp (100%) diff --git a/attic/rtbl/BSDRoutingTable.cpp b/osdep/BSDRoutingTable.cpp similarity index 100% rename from attic/rtbl/BSDRoutingTable.cpp rename to osdep/BSDRoutingTable.cpp diff --git a/attic/rtbl/BSDRoutingTable.hpp b/osdep/BSDRoutingTable.hpp similarity index 100% rename from attic/rtbl/BSDRoutingTable.hpp rename to osdep/BSDRoutingTable.hpp diff --git a/attic/rtbl/LinuxRoutingTable.cpp b/osdep/LinuxRoutingTable.cpp similarity index 100% rename from attic/rtbl/LinuxRoutingTable.cpp rename to osdep/LinuxRoutingTable.cpp diff --git a/attic/rtbl/LinuxRoutingTable.hpp b/osdep/LinuxRoutingTable.hpp similarity index 100% rename from attic/rtbl/LinuxRoutingTable.hpp rename to osdep/LinuxRoutingTable.hpp diff --git a/attic/rtbl/RoutingTable.cpp b/osdep/RoutingTable.cpp similarity index 100% rename from attic/rtbl/RoutingTable.cpp rename to osdep/RoutingTable.cpp diff --git a/attic/rtbl/RoutingTable.hpp b/osdep/RoutingTable.hpp similarity index 100% rename from attic/rtbl/RoutingTable.hpp rename to osdep/RoutingTable.hpp diff --git a/attic/rtbl/TestRoutingTable.cpp b/osdep/TestRoutingTable.cpp similarity index 100% rename from attic/rtbl/TestRoutingTable.cpp rename to osdep/TestRoutingTable.cpp diff --git a/attic/rtbl/TestRoutingTable.hpp b/osdep/TestRoutingTable.hpp similarity index 100% rename from attic/rtbl/TestRoutingTable.hpp rename to osdep/TestRoutingTable.hpp diff --git a/attic/rtbl/WindowsRoutingTable.cpp b/osdep/WindowsRoutingTable.cpp similarity index 100% rename from attic/rtbl/WindowsRoutingTable.cpp rename to osdep/WindowsRoutingTable.cpp diff --git a/attic/rtbl/WindowsRoutingTable.hpp b/osdep/WindowsRoutingTable.hpp similarity index 100% rename from attic/rtbl/WindowsRoutingTable.hpp rename to osdep/WindowsRoutingTable.hpp From e9b2613d5facc5c3540eeb53be66a6becdfd347b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 6 Apr 2016 16:57:37 -0700 Subject: [PATCH 3/5] Put routing table code back in osdep/ --- osdep/BSDRoutingTable.cpp | 43 ++++++------ osdep/BSDRoutingTable.hpp | 19 ++++-- osdep/LinuxRoutingTable.cpp | 27 +++++--- osdep/LinuxRoutingTable.hpp | 30 ++++----- osdep/RoutingTable.cpp | 77 --------------------- osdep/RoutingTable.hpp | 122 ---------------------------------- osdep/RoutingTableEntry.hpp | 62 +++++++++++++++++ osdep/TestRoutingTable.cpp | 50 -------------- osdep/TestRoutingTable.hpp | 50 -------------- osdep/WindowsRoutingTable.cpp | 18 ++--- osdep/WindowsRoutingTable.hpp | 30 ++++----- 11 files changed, 153 insertions(+), 375 deletions(-) delete mode 100644 osdep/RoutingTable.cpp delete mode 100644 osdep/RoutingTable.hpp create mode 100644 osdep/RoutingTableEntry.hpp delete mode 100644 osdep/TestRoutingTable.cpp delete mode 100644 osdep/TestRoutingTable.hpp diff --git a/osdep/BSDRoutingTable.cpp b/osdep/BSDRoutingTable.cpp index 6d44c3ecd..5b24af96a 100644 --- a/osdep/BSDRoutingTable.cpp +++ b/osdep/BSDRoutingTable.cpp @@ -25,6 +25,10 @@ * LLC. Start here: http://www.zerotier.com/ */ +#include "../node/Constants.hpp" + +#ifdef __BSD__ + #include #include #include @@ -45,7 +49,6 @@ #include #include -#include "../node/Constants.hpp" #include "BSDRoutingTable.hpp" // All I wanted was the bloody rounting table. I didn't expect the Spanish inquisition. @@ -62,9 +65,9 @@ BSDRoutingTable::~BSDRoutingTable() { } -std::vector BSDRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const +std::vector BSDRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const { - std::vector entries; + std::vector entries; int mib[6]; size_t needed; @@ -88,7 +91,7 @@ std::vector BSDRoutingTable::get(bool includeLinkLocal,bool char *saend = next + rtm->rtm_msglen; if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { - RoutingTable::Entry e; + RoutingTableEntry e; e.deviceIndex = -9999; // unset int which = 0; @@ -202,14 +205,14 @@ std::vector BSDRoutingTable::get(bool includeLinkLocal,bool } } - for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { + for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { if ((!e1->device[0])&&(e1->deviceIndex >= 0)) if_indextoname(e1->deviceIndex,e1->device); } - for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { + for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { if ((!e1->device[0])&&(e1->gateway)) { int bestMetric = 9999999; - for(std::vector::iterator e2(entries.begin());e2!=entries.end();++e2) { + for(std::vector::iterator e2(entries.begin());e2!=entries.end();++e2) { if ((e1->gateway.within(e2->destination))&&(e2->metric <= bestMetric)) { bestMetric = e2->metric; Utils::scopy(e1->device,sizeof(e1->device),e2->device); @@ -223,14 +226,14 @@ std::vector BSDRoutingTable::get(bool includeLinkLocal,bool return entries; } -RoutingTable::Entry BSDRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) +RoutingTableEntry BSDRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) { if ((!gateway)&&((!device)||(!device[0]))) - return RoutingTable::Entry(); + return RoutingTableEntry(); - std::vector rtab(get(true,true)); + std::vector rtab(get(true,true)); - for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { + for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { if (e->destination == destination) { if (((!device)||(!device[0]))||(!strcmp(device,e->device))) { long p = (long)fork(); @@ -248,7 +251,7 @@ RoutingTable::Entry BSDRoutingTable::set(const InetAddress &destination,const In } if (metric < 0) - return RoutingTable::Entry(); + return RoutingTableEntry(); { char hcstr[64]; @@ -270,8 +273,8 @@ RoutingTable::Entry BSDRoutingTable::set(const InetAddress &destination,const In } rtab = get(true,true); - std::vector::iterator bestEntry(rtab.end()); - for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { + std::vector::iterator bestEntry(rtab.end()); + for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { if ((device)&&(device[0])) { if (!strcmp(device,e->device)) { @@ -286,7 +289,7 @@ RoutingTable::Entry BSDRoutingTable::set(const InetAddress &destination,const In if (bestEntry != rtab.end()) return *bestEntry; - return RoutingTable::Entry(); + return RoutingTableEntry(); } } // namespace ZeroTier @@ -299,8 +302,8 @@ int main(int argc,char **argv) BSDRoutingTable rt; printf(" \n"); - std::vector ents(rt.get()); - for(std::vector::iterator e(ents.begin());e!=ents.end();++e) + std::vector ents(rt.get()); + for(std::vector::iterator e(ents.begin());e!=ents.end();++e) printf("%s\n",e->toString().c_str()); printf("\n"); @@ -311,7 +314,7 @@ int main(int argc,char **argv) printf(" \n"); ents = rt.get(); - for(std::vector::iterator e(ents.begin());e!=ents.end();++e) + for(std::vector::iterator e(ents.begin());e!=ents.end();++e) printf("%s\n",e->toString().c_str()); printf("\n"); @@ -322,10 +325,12 @@ int main(int argc,char **argv) printf(" \n"); ents = rt.get(); - for(std::vector::iterator e(ents.begin());e!=ents.end();++e) + for(std::vector::iterator e(ents.begin());e!=ents.end();++e) printf("%s\n",e->toString().c_str()); printf("\n"); return 0; } #endif + +#endif // __BSD__ diff --git a/osdep/BSDRoutingTable.hpp b/osdep/BSDRoutingTable.hpp index 97969666a..ac0e47495 100644 --- a/osdep/BSDRoutingTable.hpp +++ b/osdep/BSDRoutingTable.hpp @@ -28,7 +28,13 @@ #ifndef ZT_BSDROUTINGTABLE_HPP #define ZT_BSDROUTINGTABLE_HPP -#include "../node/RoutingTable.hpp" +#include "../node/Constants.hpp" + +#ifdef __BSD__ + +#include + +#include "RoutingTableEntry.hpp" namespace ZeroTier { @@ -37,15 +43,18 @@ namespace ZeroTier { * * Has currently only been tested on OSX/Darwin. */ -class BSDRoutingTable : public RoutingTable +class BSDRoutingTable { public: BSDRoutingTable(); - virtual ~BSDRoutingTable(); - virtual std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; - virtual RoutingTable::Entry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); + ~BSDRoutingTable(); + + std::vector get(bool includeLinkLocal,bool includeLoopback) const; + RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); }; } // namespace ZeroTier +#endif // __BSD__ + #endif diff --git a/osdep/LinuxRoutingTable.cpp b/osdep/LinuxRoutingTable.cpp index 581054e26..dd866922c 100644 --- a/osdep/LinuxRoutingTable.cpp +++ b/osdep/LinuxRoutingTable.cpp @@ -25,6 +25,10 @@ * LLC. Start here: http://www.zerotier.com/ */ +#include "../node/Constants.hpp" + +#ifdef __LINUX__ + #include #include #include @@ -42,7 +46,6 @@ #include #include -#include "../node/Constants.hpp" #include "../node/Utils.hpp" #include "LinuxRoutingTable.hpp" @@ -58,11 +61,11 @@ LinuxRoutingTable::~LinuxRoutingTable() { } -std::vector LinuxRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const +std::vector LinuxRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const { char buf[131072]; char *stmp,*stmp2; - std::vector entries; + std::vector entries; { int fd = ::open("/proc/net/route",O_RDONLY); @@ -102,7 +105,7 @@ std::vector LinuxRoutingTable::get(bool includeLinkLocal,bo } if ((iface)&&(destination)) { - RoutingTable::Entry e; + RoutingTableEntry e; if (destination) e.destination.set(&destination,4,Utils::countBits(mask)); e.gateway.set(&gateway,4,0); @@ -149,7 +152,7 @@ std::vector LinuxRoutingTable::get(bool includeLinkLocal,bo if ((device)&&(destination)) { unsigned char tmp[16]; - RoutingTable::Entry e; + RoutingTableEntry e; Utils::unhex(destination,tmp,16); if ((!Utils::isZero(tmp,16))&&(tmp[0] != 0xff)) e.destination.set(tmp,16,destPrefixLen); @@ -167,12 +170,12 @@ std::vector LinuxRoutingTable::get(bool includeLinkLocal,bo return entries; } -RoutingTable::Entry LinuxRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) +RoutingTableEntry LinuxRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) { char metstr[128]; if ((!gateway)&&((!device)||(!device[0]))) - return RoutingTable::Entry(); + return RoutingTableEntry(); Utils::snprintf(metstr,sizeof(metstr),"%d",metric); @@ -212,9 +215,9 @@ RoutingTable::Entry LinuxRoutingTable::set(const InetAddress &destination,const } } - std::vector rtab(get(true,true)); - std::vector::iterator bestEntry(rtab.end()); - for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { + std::vector rtab(get(true,true)); + std::vector::iterator bestEntry(rtab.end()); + for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { if ((device)&&(device[0])) { if (!strcmp(device,e->device)) { @@ -229,7 +232,9 @@ RoutingTable::Entry LinuxRoutingTable::set(const InetAddress &destination,const if (bestEntry != rtab.end()) return *bestEntry; - return RoutingTable::Entry(); + return RoutingTableEntry(); } } // namespace ZeroTier + +#endif // __LINUX__ diff --git a/osdep/LinuxRoutingTable.hpp b/osdep/LinuxRoutingTable.hpp index 808ec7eab..205d7b7b7 100644 --- a/osdep/LinuxRoutingTable.hpp +++ b/osdep/LinuxRoutingTable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. + * 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 @@ -14,36 +14,36 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ */ #ifndef ZT_LINUXROUTINGTABLE_HPP #define ZT_LINUXROUTINGTABLE_HPP -#include "../node/RoutingTable.hpp" +#include "../node/Constants.hpp" + +#ifdef __LINUX__ + +#include + +#include "RoutingTableEntry.hpp" namespace ZeroTier { /** * Routing table interface via /proc/net/route, /proc/net/ipv6_route, and /sbin/route command */ -class LinuxRoutingTable : public RoutingTable +class LinuxRoutingTable { public: LinuxRoutingTable(); - virtual ~LinuxRoutingTable(); - virtual std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; - virtual RoutingTable::Entry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); + ~LinuxRoutingTable(); + + std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; + RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); }; } // namespace ZeroTier +#endif // __LINUX__ + #endif diff --git a/osdep/RoutingTable.cpp b/osdep/RoutingTable.cpp deleted file mode 100644 index bae4bea90..000000000 --- a/osdep/RoutingTable.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "RoutingTable.hpp" -#include "Utils.hpp" - -namespace ZeroTier { - -std::string RoutingTable::Entry::toString() const -{ - char tmp[1024]; - Utils::snprintf(tmp,sizeof(tmp),"%s %s %s %d",destination.toString().c_str(),((gateway) ? gateway.toIpString().c_str() : ""),device,metric); - return std::string(tmp); -} - -bool RoutingTable::Entry::operator==(const Entry &re) const -{ - return ((destination == re.destination)&&(gateway == re.gateway)&&(strcmp(device,re.device) == 0)&&(metric == re.metric)); -} - -bool RoutingTable::Entry::operator<(const Entry &re) const -{ - if (destination < re.destination) - return true; - else if (destination == re.destination) { - if (gateway < re.gateway) - return true; - else if (gateway == re.gateway) { - int tmp = (int)::strcmp(device,re.device); - if (tmp < 0) - return true; - else if (tmp == 0) - return (metric < re.metric); - } - } - return false; -} - -RoutingTable::RoutingTable() -{ -} - -RoutingTable::~RoutingTable() -{ -} - -} // namespace ZeroTier diff --git a/osdep/RoutingTable.hpp b/osdep/RoutingTable.hpp deleted file mode 100644 index e1c98984b..000000000 --- a/osdep/RoutingTable.hpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_ROUTINGTABLE_HPP -#define ZT_ROUTINGTABLE_HPP - -#include -#include - -#include "InetAddress.hpp" -#include "NonCopyable.hpp" - -namespace ZeroTier { - -/** - * Base class for OS routing table interfaces - */ -class RoutingTable : NonCopyable -{ -public: - class Entry - { - public: - Entry() throw() { device[0] = (char)0; } - - /** - * Destination IP and netmask bits (CIDR format) - */ - InetAddress destination; - - /** - * Gateway or null address if direct link-level route, netmask/port part of InetAddress not used - */ - InetAddress gateway; - - /** - * System device index or ID (not included in comparison operators, may not be set on all platforms) - */ - int deviceIndex; - - /** - * Metric or hop count -- higher = lower routing priority - */ - int metric; - - /** - * System device name - */ - char device[128]; - - /** - * @return Human-readable representation of this route - */ - std::string toString() const; - - /** - * @return True if at least one required field is present (object is not null) - */ - inline operator bool() const { return ((destination)||(gateway)||(device[0])); } - - bool operator==(const Entry &re) const; - inline bool operator!=(const Entry &re) const { return (!(*this == re)); } - bool operator<(const Entry &re) const; - inline bool operator>(const Entry &re) const { return (re < *this); } - inline bool operator<=(const Entry &re) const { return (!(re < *this)); } - inline bool operator>=(const Entry &re) const { return (!(*this < re)); } - }; - - RoutingTable(); - virtual ~RoutingTable(); - - /** - * Get routing table - * - * @param includeLinkLocal If true, include link-local address routes (default: false) - * @param includeLoopback Include loopback (default: false) - * @return Sorted routing table entries - */ - virtual std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const = 0; - - /** - * Add or update a routing table entry - * - * If there is no change, the existing entry is returned. Use a value of -1 - * for metric to delete a route. - * - * @param destination Destination IP/netmask - * @param gateway Gateway IP (netmask/port part unused) or NULL/zero for device-level route - * @param device Device name (can be null for gateway routes) - * @param metric Route metric or hop count (higher = lower priority) or negative to delete - * @return Entry or null entry on failure (or delete) - */ - virtual RoutingTable::Entry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) = 0; -}; - -} // namespace ZeroTier - -#endif diff --git a/osdep/RoutingTableEntry.hpp b/osdep/RoutingTableEntry.hpp new file mode 100644 index 000000000..578972dbb --- /dev/null +++ b/osdep/RoutingTableEntry.hpp @@ -0,0 +1,62 @@ +/* + * 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 . + */ + +#ifndef ZT_ROUTINGTABLEENTRY_HPP +#define ZT_ROUTINGTABLEENTRY_HPP + +#include "../node/InetAddress.hpp" + +namespace ZeroTier { + +class RoutingTableEntry +{ +public: + /** + * Destination IP and netmask bits (CIDR format) + */ + InetAddress destination; + + /** + * Gateway or null address if direct link-level route, netmask/port part of InetAddress not used + */ + InetAddress gateway; + + /** + * System device index or ID (not included in comparison operators, may not be set on all platforms) + */ + int deviceIndex; + + /** + * Metric or hop count -- higher = lower routing priority + */ + int metric; + + /** + * System device name + */ + char device[128]; + + /** + * @return True if at least one required field is present (object is not null) + */ + inline operator bool() const { return ((destination)||(gateway)); } +}; + +} // namespace ZeroTier + +#endif diff --git a/osdep/TestRoutingTable.cpp b/osdep/TestRoutingTable.cpp deleted file mode 100644 index fd61b3140..000000000 --- a/osdep/TestRoutingTable.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "TestRoutingTable.hpp" - -namespace ZeroTier { - -TestRoutingTable::TestRoutingTable() -{ -} - -TestRoutingTable::~TestRoutingTable() -{ -} - -std::vector TestRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const -{ - return std::vector(); -} - -RoutingTable::Entry TestRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) -{ - return RoutingTable::Entry(); -} - -} // namespace ZeroTier diff --git a/osdep/TestRoutingTable.hpp b/osdep/TestRoutingTable.hpp deleted file mode 100644 index 69bd3d9fb..000000000 --- a/osdep/TestRoutingTable.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_TESTROUTINGTABLE_HPP -#define ZT_TESTROUTINGTABLE_HPP - -#include "../node/RoutingTable.hpp" - -namespace ZeroTier { - -/** - * Dummy routing table -- right now this just does nothing - */ -class TestRoutingTable : public RoutingTable -{ -public: - TestRoutingTable(); - virtual ~TestRoutingTable(); - - virtual std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; - virtual RoutingTable::Entry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); -}; - -} // namespace ZeroTier - -#endif diff --git a/osdep/WindowsRoutingTable.cpp b/osdep/WindowsRoutingTable.cpp index 00674620f..20abf90fe 100644 --- a/osdep/WindowsRoutingTable.cpp +++ b/osdep/WindowsRoutingTable.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. + * 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 @@ -14,17 +14,12 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ */ +#include "../node/Constants.hpp" + +#ifdef __WINDOWS__ + #include #include #include @@ -35,7 +30,6 @@ #include -#include "../node/Constants.hpp" #include "WindowsRoutingTable.hpp" namespace ZeroTier { @@ -176,3 +170,5 @@ RoutingTable::Entry WindowsRoutingTable::set(const InetAddress &destination,cons } } // namespace ZeroTier + +#endif // __WINDOWS__ diff --git a/osdep/WindowsRoutingTable.hpp b/osdep/WindowsRoutingTable.hpp index 491c3424d..a36b4f663 100644 --- a/osdep/WindowsRoutingTable.hpp +++ b/osdep/WindowsRoutingTable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. + * 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 @@ -14,36 +14,36 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ */ #ifndef ZT_WINDOWSROUTINGTABLE_HPP #define ZT_WINDOWSROUTINGTABLE_HPP -#include "../node/RoutingTable.hpp" +#include "../node/Constants.hpp" + +#ifdef __WINDOWS__ + +#include + +#include "RoutingTableEntry.hpp" namespace ZeroTier { /** * Interface to Microsoft Windows (Vista or newer) routing table */ -class WindowsRoutingTable : public RoutingTable +class WindowsRoutingTable { public: WindowsRoutingTable(); - virtual ~WindowsRoutingTable(); - virtual std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; - virtual RoutingTable::Entry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); + ~WindowsRoutingTable(); + + std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; + RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); }; } // namespace ZeroTier +#endif // __WINDOWS__ + #endif From 61a9c27af08dcf1035854ead098566b644983c90 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 6 Apr 2016 17:14:05 -0700 Subject: [PATCH 4/5] Consolidate routing table code. --- osdep/BSDRoutingTable.cpp | 336 ------------------- osdep/BSDRoutingTable.hpp | 60 ---- osdep/LinuxRoutingTable.cpp | 240 ------------- osdep/LinuxRoutingTable.hpp | 49 --- osdep/RoutingTable.cpp | 612 ++++++++++++++++++++++++++++++++++ osdep/RoutingTable.hpp | 77 +++++ osdep/RoutingTableEntry.hpp | 62 ---- osdep/WindowsRoutingTable.cpp | 174 ---------- osdep/WindowsRoutingTable.hpp | 49 --- 9 files changed, 689 insertions(+), 970 deletions(-) delete mode 100644 osdep/BSDRoutingTable.cpp delete mode 100644 osdep/BSDRoutingTable.hpp delete mode 100644 osdep/LinuxRoutingTable.cpp delete mode 100644 osdep/LinuxRoutingTable.hpp create mode 100644 osdep/RoutingTable.cpp create mode 100644 osdep/RoutingTable.hpp delete mode 100644 osdep/RoutingTableEntry.hpp delete mode 100644 osdep/WindowsRoutingTable.cpp delete mode 100644 osdep/WindowsRoutingTable.hpp diff --git a/osdep/BSDRoutingTable.cpp b/osdep/BSDRoutingTable.cpp deleted file mode 100644 index 5b24af96a..000000000 --- a/osdep/BSDRoutingTable.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "../node/Constants.hpp" - -#ifdef __BSD__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "BSDRoutingTable.hpp" - -// All I wanted was the bloody rounting table. I didn't expect the Spanish inquisition. - -#define ZT_BSD_ROUTE_CMD "/sbin/route" - -namespace ZeroTier { - -BSDRoutingTable::BSDRoutingTable() -{ -} - -BSDRoutingTable::~BSDRoutingTable() -{ -} - -std::vector BSDRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const -{ - std::vector entries; - int mib[6]; - size_t needed; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = 0; - mib[4] = NET_RT_DUMP; - mib[5] = 0; - if (!sysctl(mib,6,NULL,&needed,NULL,0)) { - if (needed <= 0) - return entries; - - char *buf = (char *)::malloc(needed); - if (buf) { - if (!sysctl(mib,6,buf,&needed,NULL,0)) { - struct rt_msghdr *rtm; - for(char *next=buf,*end=buf+needed;nextrtm_msglen; - - if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { - RoutingTableEntry e; - e.deviceIndex = -9999; // unset - - int which = 0; - while (saptr < saend) { - struct sockaddr *sa = (struct sockaddr *)saptr; - unsigned int salen = sa->sa_len; - if (!salen) - break; - - // Skip missing fields in rtm_addrs bit field - while ((rtm->rtm_addrs & 1) == 0) { - rtm->rtm_addrs >>= 1; - ++which; - if (which > 6) - break; - } - if (which > 6) - break; - - rtm->rtm_addrs >>= 1; - switch(which++) { - case 0: - //printf("RTA_DST\n"); - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - // Nobody expects the Spanish inquisition! - if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { - // Our chief weapon is... in-band signaling! - // Seriously who in the living fuck thought this was a good idea and - // then had the sadistic idea to not document it anywhere? Of course it's - // not like there is any documentation on BSD sysctls anyway. - unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - if (!sin6->sin6_scope_id) - sin6->sin6_scope_id = interfaceIndex; - } - } - e.destination.set(sa); - break; - case 1: - //printf("RTA_GATEWAY\n"); - switch(sa->sa_family) { - case AF_LINK: - e.deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; - break; - case AF_INET: - case AF_INET6: - e.gateway.set(sa); - break; - } - break; - case 2: { - if (e.destination.isV6()) { - salen = sizeof(struct sockaddr_in6); // Confess! - unsigned int bits = 0; - for(int i=0;i<16;++i) { - unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i]; - if (c == 0xff) - bits += 8; - else break; - /* must they be multiples of 8? Most of the BSD source I can find says yes..? - else { - while ((c & 0x80) == 0x80) { - ++bits; - c <<= 1; - } - break; - } - */ - } - e.destination.setPort(bits); - } else { - salen = sizeof(struct sockaddr_in); // Confess! - e.destination.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr)); - } - //printf("RTA_NETMASK\n"); - } break; - /* - case 3: - //printf("RTA_GENMASK\n"); - break; - case 4: - //printf("RTA_IFP\n"); - break; - case 5: - //printf("RTA_IFA\n"); - break; - case 6: - //printf("RTA_AUTHOR\n"); - break; - */ - } - - saptr += salen; - } - - e.metric = (int)rtm->rtm_rmx.rmx_hopcount; - if (e.metric < 0) - e.metric = 0; - - if (((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())))) - entries.push_back(e); - } - - next = saend; - } - } - - ::free(buf); - } - } - - for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { - if ((!e1->device[0])&&(e1->deviceIndex >= 0)) - if_indextoname(e1->deviceIndex,e1->device); - } - for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { - if ((!e1->device[0])&&(e1->gateway)) { - int bestMetric = 9999999; - for(std::vector::iterator e2(entries.begin());e2!=entries.end();++e2) { - if ((e1->gateway.within(e2->destination))&&(e2->metric <= bestMetric)) { - bestMetric = e2->metric; - Utils::scopy(e1->device,sizeof(e1->device),e2->device); - } - } - } - } - - std::sort(entries.begin(),entries.end()); - - return entries; -} - -RoutingTableEntry BSDRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) -{ - if ((!gateway)&&((!device)||(!device[0]))) - return RoutingTableEntry(); - - std::vector rtab(get(true,true)); - - for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { - if (e->destination == destination) { - if (((!device)||(!device[0]))||(!strcmp(device,e->device))) { - long p = (long)fork(); - if (p > 0) { - int exitcode = -1; - ::waitpid(p,&exitcode,0); - } else if (p == 0) { - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"delete",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),(const char *)0); - ::_exit(-1); - } - } - } - } - - if (metric < 0) - return RoutingTableEntry(); - - { - char hcstr[64]; - Utils::snprintf(hcstr,sizeof(hcstr),"%d",metric); - long p = (long)fork(); - if (p > 0) { - int exitcode = -1; - ::waitpid(p,&exitcode,0); - } else if (p == 0) { - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - if (gateway) { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),gateway.toIpString().c_str(),"-hopcount",hcstr,(const char *)0); - } else if ((device)&&(device[0])) { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),"-interface",device,"-hopcount",hcstr,(const char *)0); - } - ::_exit(-1); - } - } - - rtab = get(true,true); - std::vector::iterator bestEntry(rtab.end()); - for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { - if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { - if ((device)&&(device[0])) { - if (!strcmp(device,e->device)) { - if (metric == e->metric) - bestEntry = e; - } - } - if (bestEntry == rtab.end()) - bestEntry = e; - } - } - if (bestEntry != rtab.end()) - return *bestEntry; - - return RoutingTableEntry(); -} - -} // namespace ZeroTier - -// Enable and build to test routing table interface -#if 0 -using namespace ZeroTier; -int main(int argc,char **argv) -{ - BSDRoutingTable rt; - - printf(" \n"); - std::vector ents(rt.get()); - for(std::vector::iterator e(ents.begin());e!=ents.end();++e) - printf("%s\n",e->toString().c_str()); - printf("\n"); - - printf("adding 1.1.1.0 and 2.2.2.0...\n"); - rt.set(InetAddress("1.1.1.0",24),InetAddress("1.2.3.4",0),(const char *)0,1); - rt.set(InetAddress("2.2.2.0",24),InetAddress(),"en0",1); - printf("\n"); - - printf(" \n"); - ents = rt.get(); - for(std::vector::iterator e(ents.begin());e!=ents.end();++e) - printf("%s\n",e->toString().c_str()); - printf("\n"); - - printf("deleting 1.1.1.0 and 2.2.2.0...\n"); - rt.set(InetAddress("1.1.1.0",24),InetAddress("1.2.3.4",0),(const char *)0,-1); - rt.set(InetAddress("2.2.2.0",24),InetAddress(),"en0",-1); - printf("\n"); - - printf(" \n"); - ents = rt.get(); - for(std::vector::iterator e(ents.begin());e!=ents.end();++e) - printf("%s\n",e->toString().c_str()); - printf("\n"); - - return 0; -} -#endif - -#endif // __BSD__ diff --git a/osdep/BSDRoutingTable.hpp b/osdep/BSDRoutingTable.hpp deleted file mode 100644 index ac0e47495..000000000 --- a/osdep/BSDRoutingTable.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_BSDROUTINGTABLE_HPP -#define ZT_BSDROUTINGTABLE_HPP - -#include "../node/Constants.hpp" - -#ifdef __BSD__ - -#include - -#include "RoutingTableEntry.hpp" - -namespace ZeroTier { - -/** - * Routing table interface for BSD with sysctl() and BSD /sbin/route - * - * Has currently only been tested on OSX/Darwin. - */ -class BSDRoutingTable -{ -public: - BSDRoutingTable(); - ~BSDRoutingTable(); - - std::vector get(bool includeLinkLocal,bool includeLoopback) const; - RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); -}; - -} // namespace ZeroTier - -#endif // __BSD__ - -#endif diff --git a/osdep/LinuxRoutingTable.cpp b/osdep/LinuxRoutingTable.cpp deleted file mode 100644 index dd866922c..000000000 --- a/osdep/LinuxRoutingTable.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "../node/Constants.hpp" - -#ifdef __LINUX__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../node/Utils.hpp" -#include "LinuxRoutingTable.hpp" - -#define ZT_LINUX_IP_COMMAND "/sbin/ip" - -namespace ZeroTier { - -LinuxRoutingTable::LinuxRoutingTable() -{ -} - -LinuxRoutingTable::~LinuxRoutingTable() -{ -} - -std::vector LinuxRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const -{ - char buf[131072]; - char *stmp,*stmp2; - std::vector entries; - - { - int fd = ::open("/proc/net/route",O_RDONLY); - if (fd <= 0) - buf[0] = (char)0; - else { - int n = (int)::read(fd,buf,sizeof(buf) - 1); - ::close(fd); - if (n < 0) n = 0; - buf[n] = (char)0; - } - } - - int lineno = 0; - for(char *line=Utils::stok(buf,"\r\n",&stmp);(line);line=Utils::stok((char *)0,"\r\n",&stmp)) { - if (lineno == 0) { - ++lineno; - continue; // skip header - } - - char *iface = (char *)0; - uint32_t destination = 0; - uint32_t gateway = 0; - int metric = 0; - uint32_t mask = 0; - - int fno = 0; - for(char *f=Utils::stok(line,"\t \r\n",&stmp2);(f);f=Utils::stok((char *)0,"\t \r\n",&stmp2)) { - switch(fno) { - case 0: iface = f; break; - case 1: destination = (uint32_t)Utils::hexStrToULong(f); break; - case 2: gateway = (uint32_t)Utils::hexStrToULong(f); break; - case 6: metric = (int)Utils::strToInt(f); break; - case 7: mask = (uint32_t)Utils::hexStrToULong(f); break; - } - ++fno; - } - - if ((iface)&&(destination)) { - RoutingTableEntry e; - if (destination) - e.destination.set(&destination,4,Utils::countBits(mask)); - e.gateway.set(&gateway,4,0); - e.deviceIndex = 0; // not used on Linux - e.metric = metric; - Utils::scopy(e.device,sizeof(e.device),iface); - if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())&&(strcmp(iface,"lo"))))) - entries.push_back(e); - } - - ++lineno; - } - - { - int fd = ::open("/proc/net/ipv6_route",O_RDONLY); - if (fd <= 0) - buf[0] = (char)0; - else { - int n = (int)::read(fd,buf,sizeof(buf) - 1); - ::close(fd); - if (n < 0) n = 0; - buf[n] = (char)0; - } - } - - for(char *line=Utils::stok(buf,"\r\n",&stmp);(line);line=Utils::stok((char *)0,"\r\n",&stmp)) { - char *destination = (char *)0; - unsigned int destPrefixLen = 0; - char *gateway = (char *)0; // next hop in ipv6 terminology - int metric = 0; - char *device = (char *)0; - - int fno = 0; - for(char *f=Utils::stok(line,"\t \r\n",&stmp2);(f);f=Utils::stok((char *)0,"\t \r\n",&stmp2)) { - switch(fno) { - case 0: destination = f; break; - case 1: destPrefixLen = (unsigned int)Utils::hexStrToULong(f); break; - case 4: gateway = f; break; - case 5: metric = (int)Utils::hexStrToLong(f); break; - case 9: device = f; break; - } - ++fno; - } - - if ((device)&&(destination)) { - unsigned char tmp[16]; - RoutingTableEntry e; - Utils::unhex(destination,tmp,16); - if ((!Utils::isZero(tmp,16))&&(tmp[0] != 0xff)) - e.destination.set(tmp,16,destPrefixLen); - Utils::unhex(gateway,tmp,16); - e.gateway.set(tmp,16,0); - e.deviceIndex = 0; // not used on Linux - e.metric = metric; - Utils::scopy(e.device,sizeof(e.device),device); - if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())&&(strcmp(device,"lo"))))) - entries.push_back(e); - } - } - - std::sort(entries.begin(),entries.end()); - return entries; -} - -RoutingTableEntry LinuxRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) -{ - char metstr[128]; - - if ((!gateway)&&((!device)||(!device[0]))) - return RoutingTableEntry(); - - Utils::snprintf(metstr,sizeof(metstr),"%d",metric); - - if (metric < 0) { - long pid = (long)vfork(); - if (pid == 0) { - if (gateway) { - if ((device)&&(device[0])) { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"via",gateway.toIpString().c_str(),"dev",device,(const char *)0); - } else { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"via",gateway.toIpString().c_str(),(const char *)0); - } - } else { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"dev",device,(const char *)0); - } - ::_exit(-1); - } else if (pid > 0) { - int exitcode = -1; - ::waitpid(pid,&exitcode,0); - } - } else { - long pid = (long)vfork(); - if (pid == 0) { - if (gateway) { - if ((device)&&(device[0])) { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"via",gateway.toIpString().c_str(),"dev",device,(const char *)0); - } else { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"via",gateway.toIpString().c_str(),(const char *)0); - } - } else { - ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"dev",device,(const char *)0); - } - ::_exit(-1); - } else if (pid > 0) { - int exitcode = -1; - ::waitpid(pid,&exitcode,0); - } - } - - std::vector rtab(get(true,true)); - std::vector::iterator bestEntry(rtab.end()); - for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { - if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { - if ((device)&&(device[0])) { - if (!strcmp(device,e->device)) { - if (metric == e->metric) - bestEntry = e; - } - } - if (bestEntry == rtab.end()) - bestEntry = e; - } - } - if (bestEntry != rtab.end()) - return *bestEntry; - - return RoutingTableEntry(); -} - -} // namespace ZeroTier - -#endif // __LINUX__ diff --git a/osdep/LinuxRoutingTable.hpp b/osdep/LinuxRoutingTable.hpp deleted file mode 100644 index 205d7b7b7..000000000 --- a/osdep/LinuxRoutingTable.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 . - */ - -#ifndef ZT_LINUXROUTINGTABLE_HPP -#define ZT_LINUXROUTINGTABLE_HPP - -#include "../node/Constants.hpp" - -#ifdef __LINUX__ - -#include - -#include "RoutingTableEntry.hpp" - -namespace ZeroTier { - -/** - * Routing table interface via /proc/net/route, /proc/net/ipv6_route, and /sbin/route command - */ -class LinuxRoutingTable -{ -public: - LinuxRoutingTable(); - ~LinuxRoutingTable(); - - std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; - RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); -}; - -} // namespace ZeroTier - -#endif // __LINUX__ - -#endif diff --git a/osdep/RoutingTable.cpp b/osdep/RoutingTable.cpp new file mode 100644 index 000000000..a639f630f --- /dev/null +++ b/osdep/RoutingTable.cpp @@ -0,0 +1,612 @@ +/* + * 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 . + */ + +#ifndef ZT_ROUTINGTABLE_HPP +#define ZT_ROUTINGTABLE_HPP + +#include "../node/Constants.hpp" + +#ifdef __WINDOWS__ +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef __UNIX_LIKE__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include "RoutingTable.hpp" + +#define ZT_BSD_ROUTE_CMD "/sbin/route" +#define ZT_LINUX_IP_COMMAND "/sbin/ip" + +namespace ZeroTier { + +// --------------------------------------------------------------------------- + +#ifdef __LINUX__ + +std::vector RoutingTable::get(bool includeLinkLocal,bool includeLoopback) +{ + char buf[131072]; + char *stmp,*stmp2; + std::vector entries; + + { + int fd = ::open("/proc/net/route",O_RDONLY); + if (fd <= 0) + buf[0] = (char)0; + else { + int n = (int)::read(fd,buf,sizeof(buf) - 1); + ::close(fd); + if (n < 0) n = 0; + buf[n] = (char)0; + } + } + + int lineno = 0; + for(char *line=Utils::stok(buf,"\r\n",&stmp);(line);line=Utils::stok((char *)0,"\r\n",&stmp)) { + if (lineno == 0) { + ++lineno; + continue; // skip header + } + + char *iface = (char *)0; + uint32_t destination = 0; + uint32_t gateway = 0; + int metric = 0; + uint32_t mask = 0; + + int fno = 0; + for(char *f=Utils::stok(line,"\t \r\n",&stmp2);(f);f=Utils::stok((char *)0,"\t \r\n",&stmp2)) { + switch(fno) { + case 0: iface = f; break; + case 1: destination = (uint32_t)Utils::hexStrToULong(f); break; + case 2: gateway = (uint32_t)Utils::hexStrToULong(f); break; + case 6: metric = (int)Utils::strToInt(f); break; + case 7: mask = (uint32_t)Utils::hexStrToULong(f); break; + } + ++fno; + } + + if ((iface)&&(destination)) { + RoutingTable::Entry e; + if (destination) + e.destination.set(&destination,4,Utils::countBits(mask)); + e.gateway.set(&gateway,4,0); + e.deviceIndex = 0; // not used on Linux + e.metric = metric; + Utils::scopy(e.device,sizeof(e.device),iface); + if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())&&(strcmp(iface,"lo"))))) + entries.push_back(e); + } + + ++lineno; + } + + { + int fd = ::open("/proc/net/ipv6_route",O_RDONLY); + if (fd <= 0) + buf[0] = (char)0; + else { + int n = (int)::read(fd,buf,sizeof(buf) - 1); + ::close(fd); + if (n < 0) n = 0; + buf[n] = (char)0; + } + } + + for(char *line=Utils::stok(buf,"\r\n",&stmp);(line);line=Utils::stok((char *)0,"\r\n",&stmp)) { + char *destination = (char *)0; + unsigned int destPrefixLen = 0; + char *gateway = (char *)0; // next hop in ipv6 terminology + int metric = 0; + char *device = (char *)0; + + int fno = 0; + for(char *f=Utils::stok(line,"\t \r\n",&stmp2);(f);f=Utils::stok((char *)0,"\t \r\n",&stmp2)) { + switch(fno) { + case 0: destination = f; break; + case 1: destPrefixLen = (unsigned int)Utils::hexStrToULong(f); break; + case 4: gateway = f; break; + case 5: metric = (int)Utils::hexStrToLong(f); break; + case 9: device = f; break; + } + ++fno; + } + + if ((device)&&(destination)) { + unsigned char tmp[16]; + RoutingTable::Entry e; + Utils::unhex(destination,tmp,16); + if ((!Utils::isZero(tmp,16))&&(tmp[0] != 0xff)) + e.destination.set(tmp,16,destPrefixLen); + Utils::unhex(gateway,tmp,16); + e.gateway.set(tmp,16,0); + e.deviceIndex = 0; // not used on Linux + e.metric = metric; + Utils::scopy(e.device,sizeof(e.device),device); + if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())&&(strcmp(device,"lo"))))) + entries.push_back(e); + } + } + + std::sort(entries.begin(),entries.end()); + return entries; +} + +RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope) +{ + char metstr[128]; + + if ((!gateway)&&((!device)||(!device[0]))) + return RoutingTable::Entry(); + + Utils::snprintf(metstr,sizeof(metstr),"%d",metric); + + if (metric < 0) { + long pid = (long)vfork(); + if (pid == 0) { + if (gateway) { + if ((device)&&(device[0])) { + ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"via",gateway.toIpString().c_str(),"dev",device,(const char *)0); + } else { + ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"via",gateway.toIpString().c_str(),(const char *)0); + } + } else { + ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"dev",device,(const char *)0); + } + ::_exit(-1); + } else if (pid > 0) { + int exitcode = -1; + ::waitpid(pid,&exitcode,0); + } + } else { + long pid = (long)vfork(); + if (pid == 0) { + if (gateway) { + if ((device)&&(device[0])) { + ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"via",gateway.toIpString().c_str(),"dev",device,(const char *)0); + } else { + ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"via",gateway.toIpString().c_str(),(const char *)0); + } + } else { + ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"dev",device,(const char *)0); + } + ::_exit(-1); + } else if (pid > 0) { + int exitcode = -1; + ::waitpid(pid,&exitcode,0); + } + } + + std::vector rtab(get(true,true)); + std::vector::iterator bestEntry(rtab.end()); + for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { + if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { + if ((device)&&(device[0])) { + if (!strcmp(device,e->device)) { + if (metric == e->metric) + bestEntry = e; + } + } + if (bestEntry == rtab.end()) + bestEntry = e; + } + } + if (bestEntry != rtab.end()) + return *bestEntry; + + return RoutingTable::Entry(); +} + +#endif // __LINUX__ + +// --------------------------------------------------------------------------- + +#ifdef __BSD__ + +std::vector RoutingTable::get(bool includeLinkLocal,bool includeLoopback) +{ + std::vector entries; + int mib[6]; + size_t needed; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (!sysctl(mib,6,NULL,&needed,NULL,0)) { + if (needed <= 0) + return entries; + + char *buf = (char *)::malloc(needed); + if (buf) { + if (!sysctl(mib,6,buf,&needed,NULL,0)) { + struct rt_msghdr *rtm; + for(char *next=buf,*end=buf+needed;nextrtm_msglen; + + if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { + RoutingTable::Entry e; + e.deviceIndex = -9999; // unset + + int which = 0; + while (saptr < saend) { + struct sockaddr *sa = (struct sockaddr *)saptr; + unsigned int salen = sa->sa_len; + if (!salen) + break; + + // Skip missing fields in rtm_addrs bit field + while ((rtm->rtm_addrs & 1) == 0) { + rtm->rtm_addrs >>= 1; + ++which; + if (which > 6) + break; + } + if (which > 6) + break; + + rtm->rtm_addrs >>= 1; + switch(which++) { + case 0: + //printf("RTA_DST\n"); + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + // Nobody expects the Spanish inquisition! + if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { + // Our chief weapon is... in-band signaling! + // Seriously who in the living fuck thought this was a good idea and + // then had the sadistic idea to not document it anywhere? Of course it's + // not like there is any documentation on BSD sysctls anyway. + unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + if (!sin6->sin6_scope_id) + sin6->sin6_scope_id = interfaceIndex; + } + } + e.destination.set(sa); + break; + case 1: + //printf("RTA_GATEWAY\n"); + switch(sa->sa_family) { + case AF_LINK: + e.deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; + break; + case AF_INET: + case AF_INET6: + e.gateway.set(sa); + break; + } + break; + case 2: { + if (e.destination.isV6()) { + salen = sizeof(struct sockaddr_in6); // Confess! + unsigned int bits = 0; + for(int i=0;i<16;++i) { + unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i]; + if (c == 0xff) + bits += 8; + else break; + /* must they be multiples of 8? Most of the BSD source I can find says yes..? + else { + while ((c & 0x80) == 0x80) { + ++bits; + c <<= 1; + } + break; + } + */ + } + e.destination.setPort(bits); + } else { + salen = sizeof(struct sockaddr_in); // Confess! + e.destination.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr)); + } + //printf("RTA_NETMASK\n"); + } break; + /* + case 3: + //printf("RTA_GENMASK\n"); + break; + case 4: + //printf("RTA_IFP\n"); + break; + case 5: + //printf("RTA_IFA\n"); + break; + case 6: + //printf("RTA_AUTHOR\n"); + break; + */ + } + + saptr += salen; + } + + e.metric = (int)rtm->rtm_rmx.rmx_hopcount; + if (e.metric < 0) + e.metric = 0; + + if (((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())))) + entries.push_back(e); + } + + next = saend; + } + } + + ::free(buf); + } + } + + for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { + if ((!e1->device[0])&&(e1->deviceIndex >= 0)) + if_indextoname(e1->deviceIndex,e1->device); + } + for(std::vector::iterator e1(entries.begin());e1!=entries.end();++e1) { + if ((!e1->device[0])&&(e1->gateway)) { + int bestMetric = 9999999; + for(std::vector::iterator e2(entries.begin());e2!=entries.end();++e2) { + if ((e1->gateway.within(e2->destination))&&(e2->metric <= bestMetric)) { + bestMetric = e2->metric; + Utils::scopy(e1->device,sizeof(e1->device),e2->device); + } + } + } + } + + std::sort(entries.begin(),entries.end()); + + return entries; +} + +RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope) +{ + if ((!gateway)&&((!device)||(!device[0]))) + return RoutingTable::Entry(); + + std::vector rtab(get(true,true)); + + for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { + if (e->destination == destination) { + if (((!device)||(!device[0]))||(!strcmp(device,e->device))) { + long p = (long)fork(); + if (p > 0) { + int exitcode = -1; + ::waitpid(p,&exitcode,0); + } else if (p == 0) { + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"delete",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),(const char *)0); + ::_exit(-1); + } + } + } + } + + if (metric < 0) + return RoutingTable::Entry(); + + { + char hcstr[64]; + Utils::snprintf(hcstr,sizeof(hcstr),"%d",metric); + long p = (long)fork(); + if (p > 0) { + int exitcode = -1; + ::waitpid(p,&exitcode,0); + } else if (p == 0) { + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + if (gateway) { + ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),gateway.toIpString().c_str(),"-hopcount",hcstr,(const char *)0); + } else if ((device)&&(device[0])) { + ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),"-interface",device,"-hopcount",hcstr,(const char *)0); + } + ::_exit(-1); + } + } + + rtab = get(true,true); + std::vector::iterator bestEntry(rtab.end()); + for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { + if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { + if ((device)&&(device[0])) { + if (!strcmp(device,e->device)) { + if (metric == e->metric) + bestEntry = e; + } + } + if (bestEntry == rtab.end()) + bestEntry = e; + } + } + if (bestEntry != rtab.end()) + return *bestEntry; + + return RoutingTable::Entry(); +} + +#endif // __BSD__ + +// --------------------------------------------------------------------------- + +#ifdef __WINDOWS__ + +static void _copyInetAddressToSockaddrInet(const InetAddress &a,SOCKADDR_INET &sinet) +{ + memset(&sinet,0,sizeof(sinet)); + if (a.isV4()) { + sinet.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)a.rawIpData()); + sinet.Ipv4.sin_family = AF_INET; + sinet.Ipv4.sin_port = htons(a.port()); + } else if (a.isV6()) { + memcpy(sinet.Ipv6.sin6_addr.u.Byte,a.rawIpData(),16); + sinet.Ipv6.sin6_family = AF_INET6; + sinet.Ipv6.sin6_port = htons(a.port()); + } +} + +std::vector RoutingTable::get(bool includeLinkLocal,bool includeLoopback) const +{ + std::vector entries; + PMIB_IPFORWARD_TABLE2 rtbl = NULL; + + if (GetIpForwardTable2(AF_UNSPEC,&rtbl) != NO_ERROR) + return entries; + if (!rtbl) + return entries; + + for(ULONG r=0;rNumEntries;++r) { + RoutingTable::Entry e; + switch(rtbl->Table[r].DestinationPrefix.Prefix.si_family) { + case AF_INET: + e.destination.set(&(rtbl->Table[r].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr),4,rtbl->Table[r].DestinationPrefix.PrefixLength); + break; + case AF_INET6: + e.destination.set(rtbl->Table[r].DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,16,rtbl->Table[r].DestinationPrefix.PrefixLength); + break; + } + switch(rtbl->Table[r].NextHop.si_family) { + case AF_INET: + e.gateway.set(&(rtbl->Table[r].NextHop.Ipv4.sin_addr.S_un.S_addr),4,0); + break; + case AF_INET6: + e.gateway.set(rtbl->Table[r].NextHop.Ipv6.sin6_addr.u.Byte,16,0); + break; + } + e.deviceIndex = (int)rtbl->Table[r].InterfaceIndex; + e.metric = (int)rtbl->Table[r].Metric; + ConvertInterfaceLuidToNameA(&(rtbl->Table[r].InterfaceLuid),e.device,sizeof(e.device)); + if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())))) + entries.push_back(e); + } + + FreeMibTable(rtbl); + std::sort(entries.begin(),entries.end()); + return entries; +} + +RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope) +{ + NET_LUID luid; + luid.Value = 0; + if (ConvertInterfaceNameToLuidA(device,&luid) != NO_ERROR) + return RoutingTable::Entry(); + + bool needCreate = true; + PMIB_IPFORWARD_TABLE2 rtbl = NULL; + if (GetIpForwardTable2(AF_UNSPEC,&rtbl) != NO_ERROR) + return RoutingTable::Entry(); + if (!rtbl) + return RoutingTable::Entry(); + for(ULONG r=0;rNumEntries;++r) { + if (rtbl->Table[r].InterfaceLuid.Value == luid.Value) { + InetAddress rdest; + switch(rtbl->Table[r].DestinationPrefix.Prefix.si_family) { + case AF_INET: + rdest.set(&(rtbl->Table[r].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr),4,rtbl->Table[r].DestinationPrefix.PrefixLength); + break; + case AF_INET6: + rdest.set(rtbl->Table[r].DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,16,rtbl->Table[r].DestinationPrefix.PrefixLength); + break; + } + if (rdest == destination) { + if (metric >= 0) { + _copyInetAddressToSockaddrInet(gateway,rtbl->Table[r].NextHop); + rtbl->Table[r].Metric = metric; + SetIpForwardEntry2(&(rtbl->Table[r])); + needCreate = false; + } else { + DeleteIpForwardEntry2(&(rtbl->Table[r])); + FreeMibTable(rtbl); + return RoutingTable::Entry(); + } + } + } + } + FreeMibTable(rtbl); + + if ((metric >= 0)&&(needCreate)) { + MIB_IPFORWARD_ROW2 nr; + InitializeIpForwardEntry(&nr); + nr.InterfaceLuid.Value = luid.Value; + _copyInetAddressToSockaddrInet(destination,nr.DestinationPrefix.Prefix); + nr.DestinationPrefix.PrefixLength = destination.netmaskBits(); + _copyInetAddressToSockaddrInet(gateway,nr.NextHop); + nr.Metric = metric; + nr.Protocol = MIB_IPPROTO_NETMGMT; + DWORD result = CreateIpForwardEntry2(&nr); + if (result != NO_ERROR) + return RoutingTable::Entry(); + } + + std::vector rtab(get(true,true)); + std::vector::iterator bestEntry(rtab.end()); + for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { + if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { + if ((device)&&(device[0])) { + if (!strcmp(device,e->device)) { + if (metric == e->metric) + bestEntry = e; + } + } + if (bestEntry == rtab.end()) + bestEntry = e; + } + } + if (bestEntry != rtab.end()) + return *bestEntry; + return RoutingTable::Entry(); +} + +#endif // __WINDOWS__ + +// --------------------------------------------------------------------------- + +} // namespace ZeroTier + +#endif diff --git a/osdep/RoutingTable.hpp b/osdep/RoutingTable.hpp new file mode 100644 index 000000000..6fcff9678 --- /dev/null +++ b/osdep/RoutingTable.hpp @@ -0,0 +1,77 @@ +/* + * 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 . + */ + +#ifndef ZT_ROUTINGTABLE_HPP +#define ZT_ROUTINGTABLE_HPP + +#include + +#include "../node/Constants.hpp" +#include "../node/InetAddress.hpp" + +namespace ZeroTier { + +class RoutingTable +{ +public: + struct Entry + { + /** + * Destination IP and netmask bits (CIDR format) + */ + InetAddress destination; + + /** + * Gateway or null address if direct link-level route, netmask/port part of InetAddress not used + */ + InetAddress gateway; + + /** + * System device index or ID (not included in comparison operators, may not be set on all platforms) + */ + int deviceIndex; + + /** + * Metric or hop count -- higher = lower routing priority + */ + int metric; + + /** + * Interface scoped route? (always false if not meaningful on this OS) + */ + bool ifscope; + + /** + * System device name (may be empty if it doesn't exist or isn't important on this OS) + */ + char device[128]; + + /** + * @return True if at least one required field is present (object is not null) + */ + inline operator bool() const { return ((destination)||(gateway)); } + }; + + static std::vector get(bool includeLinkLocal,bool includeLoopback); + + static RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope); +}; + +} // namespace ZeroTier + +#endif diff --git a/osdep/RoutingTableEntry.hpp b/osdep/RoutingTableEntry.hpp deleted file mode 100644 index 578972dbb..000000000 --- a/osdep/RoutingTableEntry.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 . - */ - -#ifndef ZT_ROUTINGTABLEENTRY_HPP -#define ZT_ROUTINGTABLEENTRY_HPP - -#include "../node/InetAddress.hpp" - -namespace ZeroTier { - -class RoutingTableEntry -{ -public: - /** - * Destination IP and netmask bits (CIDR format) - */ - InetAddress destination; - - /** - * Gateway or null address if direct link-level route, netmask/port part of InetAddress not used - */ - InetAddress gateway; - - /** - * System device index or ID (not included in comparison operators, may not be set on all platforms) - */ - int deviceIndex; - - /** - * Metric or hop count -- higher = lower routing priority - */ - int metric; - - /** - * System device name - */ - char device[128]; - - /** - * @return True if at least one required field is present (object is not null) - */ - inline operator bool() const { return ((destination)||(gateway)); } -}; - -} // namespace ZeroTier - -#endif diff --git a/osdep/WindowsRoutingTable.cpp b/osdep/WindowsRoutingTable.cpp deleted file mode 100644 index 20abf90fe..000000000 --- a/osdep/WindowsRoutingTable.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 . - */ - -#include "../node/Constants.hpp" - -#ifdef __WINDOWS__ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "WindowsRoutingTable.hpp" - -namespace ZeroTier { - -static void _copyInetAddressToSockaddrInet(const InetAddress &a,SOCKADDR_INET &sinet) -{ - memset(&sinet,0,sizeof(sinet)); - if (a.isV4()) { - sinet.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)a.rawIpData()); - sinet.Ipv4.sin_family = AF_INET; - sinet.Ipv4.sin_port = htons(a.port()); - } else if (a.isV6()) { - memcpy(sinet.Ipv6.sin6_addr.u.Byte,a.rawIpData(),16); - sinet.Ipv6.sin6_family = AF_INET6; - sinet.Ipv6.sin6_port = htons(a.port()); - } -} - -WindowsRoutingTable::WindowsRoutingTable() -{ -} - -WindowsRoutingTable::~WindowsRoutingTable() -{ -} - -std::vector WindowsRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const -{ - std::vector entries; - PMIB_IPFORWARD_TABLE2 rtbl = NULL; - - if (GetIpForwardTable2(AF_UNSPEC,&rtbl) != NO_ERROR) - return entries; - if (!rtbl) - return entries; - - for(ULONG r=0;rNumEntries;++r) { - RoutingTable::Entry e; - switch(rtbl->Table[r].DestinationPrefix.Prefix.si_family) { - case AF_INET: - e.destination.set(&(rtbl->Table[r].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr),4,rtbl->Table[r].DestinationPrefix.PrefixLength); - break; - case AF_INET6: - e.destination.set(rtbl->Table[r].DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,16,rtbl->Table[r].DestinationPrefix.PrefixLength); - break; - } - switch(rtbl->Table[r].NextHop.si_family) { - case AF_INET: - e.gateway.set(&(rtbl->Table[r].NextHop.Ipv4.sin_addr.S_un.S_addr),4,0); - break; - case AF_INET6: - e.gateway.set(rtbl->Table[r].NextHop.Ipv6.sin6_addr.u.Byte,16,0); - break; - } - e.deviceIndex = (int)rtbl->Table[r].InterfaceIndex; - e.metric = (int)rtbl->Table[r].Metric; - ConvertInterfaceLuidToNameA(&(rtbl->Table[r].InterfaceLuid),e.device,sizeof(e.device)); - if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())))) - entries.push_back(e); - } - - FreeMibTable(rtbl); - std::sort(entries.begin(),entries.end()); - return entries; -} - -RoutingTable::Entry WindowsRoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric) -{ - NET_LUID luid; - luid.Value = 0; - if (ConvertInterfaceNameToLuidA(device,&luid) != NO_ERROR) - return RoutingTable::Entry(); - - bool needCreate = true; - PMIB_IPFORWARD_TABLE2 rtbl = NULL; - if (GetIpForwardTable2(AF_UNSPEC,&rtbl) != NO_ERROR) - return RoutingTable::Entry(); - if (!rtbl) - return RoutingTable::Entry(); - for(ULONG r=0;rNumEntries;++r) { - if (rtbl->Table[r].InterfaceLuid.Value == luid.Value) { - InetAddress rdest; - switch(rtbl->Table[r].DestinationPrefix.Prefix.si_family) { - case AF_INET: - rdest.set(&(rtbl->Table[r].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr),4,rtbl->Table[r].DestinationPrefix.PrefixLength); - break; - case AF_INET6: - rdest.set(rtbl->Table[r].DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,16,rtbl->Table[r].DestinationPrefix.PrefixLength); - break; - } - if (rdest == destination) { - if (metric >= 0) { - _copyInetAddressToSockaddrInet(gateway,rtbl->Table[r].NextHop); - rtbl->Table[r].Metric = metric; - SetIpForwardEntry2(&(rtbl->Table[r])); - needCreate = false; - } else { - DeleteIpForwardEntry2(&(rtbl->Table[r])); - FreeMibTable(rtbl); - return RoutingTable::Entry(); - } - } - } - } - FreeMibTable(rtbl); - - if ((metric >= 0)&&(needCreate)) { - MIB_IPFORWARD_ROW2 nr; - InitializeIpForwardEntry(&nr); - nr.InterfaceLuid.Value = luid.Value; - _copyInetAddressToSockaddrInet(destination,nr.DestinationPrefix.Prefix); - nr.DestinationPrefix.PrefixLength = destination.netmaskBits(); - _copyInetAddressToSockaddrInet(gateway,nr.NextHop); - nr.Metric = metric; - nr.Protocol = MIB_IPPROTO_NETMGMT; - DWORD result = CreateIpForwardEntry2(&nr); - if (result != NO_ERROR) - return RoutingTable::Entry(); - } - - std::vector rtab(get(true,true)); - std::vector::iterator bestEntry(rtab.end()); - for(std::vector::iterator e(rtab.begin());e!=rtab.end();++e) { - if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) { - if ((device)&&(device[0])) { - if (!strcmp(device,e->device)) { - if (metric == e->metric) - bestEntry = e; - } - } - if (bestEntry == rtab.end()) - bestEntry = e; - } - } - if (bestEntry != rtab.end()) - return *bestEntry; - return RoutingTable::Entry(); -} - -} // namespace ZeroTier - -#endif // __WINDOWS__ diff --git a/osdep/WindowsRoutingTable.hpp b/osdep/WindowsRoutingTable.hpp deleted file mode 100644 index a36b4f663..000000000 --- a/osdep/WindowsRoutingTable.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 . - */ - -#ifndef ZT_WINDOWSROUTINGTABLE_HPP -#define ZT_WINDOWSROUTINGTABLE_HPP - -#include "../node/Constants.hpp" - -#ifdef __WINDOWS__ - -#include - -#include "RoutingTableEntry.hpp" - -namespace ZeroTier { - -/** - * Interface to Microsoft Windows (Vista or newer) routing table - */ -class WindowsRoutingTable -{ -public: - WindowsRoutingTable(); - ~WindowsRoutingTable(); - - std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; - RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric); -}; - -} // namespace ZeroTier - -#endif // __WINDOWS__ - -#endif From c278f051817719fc3c4bbda0e13c279ce44f0966 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 6 Apr 2016 17:29:38 -0700 Subject: [PATCH 5/5] RoutingTable build fixes. --- osdep/RoutingTable.cpp | 14 +++++--------- osdep/RoutingTable.hpp | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/osdep/RoutingTable.cpp b/osdep/RoutingTable.cpp index a639f630f..40523898e 100644 --- a/osdep/RoutingTable.cpp +++ b/osdep/RoutingTable.cpp @@ -16,9 +16,6 @@ * along with this program. If not, see . */ -#ifndef ZT_ROUTINGTABLE_HPP -#define ZT_ROUTINGTABLE_HPP - #include "../node/Constants.hpp" #ifdef __WINDOWS__ @@ -308,7 +305,7 @@ std::vector RoutingTable::get(bool includeLinkLocal,bool in sin6->sin6_scope_id = interfaceIndex; } } - e.destination.set(sa); + e.destination = *sa; break; case 1: //printf("RTA_GATEWAY\n"); @@ -318,7 +315,7 @@ std::vector RoutingTable::get(bool includeLinkLocal,bool in break; case AF_INET: case AF_INET6: - e.gateway.set(sa); + e.gateway = *sa; break; } break; @@ -371,7 +368,8 @@ std::vector RoutingTable::get(bool includeLinkLocal,bool in if (e.metric < 0) e.metric = 0; - if (((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())))) + InetAddress::IpScope dscope = e.destination.ipScope(); + if ( ((includeLinkLocal)||(dscope != InetAddress::IP_SCOPE_LINK_LOCAL)) && ((includeLoopback)||((dscope != InetAddress::IP_SCOPE_LOOPBACK) && (e.gateway.ipScope() != InetAddress::IP_SCOPE_LOOPBACK) ))) entries.push_back(e); } @@ -391,7 +389,7 @@ std::vector RoutingTable::get(bool includeLinkLocal,bool in if ((!e1->device[0])&&(e1->gateway)) { int bestMetric = 9999999; for(std::vector::iterator e2(entries.begin());e2!=entries.end();++e2) { - if ((e1->gateway.within(e2->destination))&&(e2->metric <= bestMetric)) { + if ((e2->destination.containsAddress(e1->gateway))&&(e2->metric <= bestMetric)) { bestMetric = e2->metric; Utils::scopy(e1->device,sizeof(e1->device),e2->device); } @@ -608,5 +606,3 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA // --------------------------------------------------------------------------- } // namespace ZeroTier - -#endif diff --git a/osdep/RoutingTable.hpp b/osdep/RoutingTable.hpp index 6fcff9678..6f4301363 100644 --- a/osdep/RoutingTable.hpp +++ b/osdep/RoutingTable.hpp @@ -67,9 +67,24 @@ public: inline operator bool() const { return ((destination)||(gateway)); } }; - static std::vector get(bool includeLinkLocal,bool includeLoopback); + /** + * Get routing table + * + * @param includeLinkLocal Include link-local IPs? + * @param includeLoopback Include loopback routes? + */ + static std::vector get(bool includeLinkLocal,bool includeLoopback); - static RoutingTableEntry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope); + /** + * Add or replace a routing table entry + * + * @param destination Route destination + * @param gateway Gateway or null if local + * @param device Device name (if applicable) + * @param metric Route metric (if applicable) + * @param ifscope Interface bound route? If so, device must be set. (only applicable on some OSes) + */ + static RoutingTable::Entry set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope); }; } // namespace ZeroTier