diff --git a/node/BSDRoutingTable.cpp b/node/BSDRoutingTable.cpp index d886b60fc..d6b5c4886 100644 --- a/node/BSDRoutingTable.cpp +++ b/node/BSDRoutingTable.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,9 @@ #include #include #include +#include #include +#include #include #include @@ -55,7 +58,7 @@ BSDRoutingTable::~BSDRoutingTable() { } -std::vector BSDRoutingTable::get() const +std::vector BSDRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const { std::vector entries; int mib[6]; @@ -82,6 +85,7 @@ std::vector BSDRoutingTable::get() const 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) { @@ -120,7 +124,15 @@ std::vector BSDRoutingTable::get() const break; case 1: //printf("RTA_GATEWAY\n"); - e.gateway.set(sa); + 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()) { @@ -148,6 +160,7 @@ std::vector BSDRoutingTable::get() const } //printf("RTA_NETMASK\n"); } break; + /* case 3: //printf("RTA_GENMASK\n"); break; @@ -160,6 +173,7 @@ std::vector BSDRoutingTable::get() const case 6: //printf("RTA_AUTHOR\n"); break; + */ } saptr += salen; @@ -167,8 +181,8 @@ std::vector BSDRoutingTable::get() const e.metric = (int)rtm->rtm_rmx.rmx_hopcount; - entries.push_back(e); - printf("%s\n",e.toString().c_str()); + if (((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())))) + entries.push_back(e); } next = saend; @@ -179,7 +193,24 @@ std::vector BSDRoutingTable::get() const } } + 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; } @@ -196,6 +227,8 @@ int main(int argc,char **argv) { ZeroTier::BSDRoutingTable rt; std::vector ents(rt.get()); + for(std::vector::iterator e(ents.begin());e!=ents.end();++e) + printf("%s\n",e->toString().c_str()); return 0; } //*/ diff --git a/node/BSDRoutingTable.hpp b/node/BSDRoutingTable.hpp index 8947bddef..7c4c9dcb4 100644 --- a/node/BSDRoutingTable.hpp +++ b/node/BSDRoutingTable.hpp @@ -42,7 +42,7 @@ class BSDRoutingTable : public RoutingTable public: BSDRoutingTable(); virtual ~BSDRoutingTable(); - virtual std::vector get() const; + virtual std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const; virtual bool set(const RoutingTable::Entry &re); }; diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index 706d804ac..9ff5acea5 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -215,6 +215,36 @@ bool InetAddress::sameNetworkAs(const InetAddress &ipnet) const return ((*a >> bits) == (*b >> bits)); } +bool InetAddress::within(const InetAddress &ipnet) const + throw() +{ + if (_sa.saddr.sa_family != ipnet._sa.saddr.sa_family) + return false; + + unsigned int bits = ipnet.netmaskBits(); + switch(_sa.saddr.sa_family) { + case AF_INET: + if (bits > 32) return false; + break; + case AF_INET6: + if (bits > 128) return false; + break; + default: return false; + } + + const uint8_t *a = (const uint8_t *)rawIpData(); + const uint8_t *b = (const uint8_t *)ipnet.rawIpData(); + while (bits >= 8) { + if (*(a++) != *(b++)) + return false; + bits -= 8; + } + if (bits) { + uint8_t mask = ((0xff << (8 - bits)) & 0xff); + return ((*a & mask) == (*b & mask)); + } else return true; +} + bool InetAddress::operator==(const InetAddress &a) const throw() { diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 325c2de41..74e42670d 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -147,6 +147,15 @@ public: bool isLinkLocal() const throw(); + /** + * @return True if this is a loopback address + */ + inline bool isLoopback() const + throw() + { + return ((*this == LO4)||(*this == LO6)); + } + /** * @return ASCII IP/port format representation */ @@ -286,6 +295,15 @@ public: bool sameNetworkAs(const InetAddress &ipnet) const throw(); + /** + * Determine whether this address is within an ip/netmask + * + * @param ipnet IP/netmask + * @return True if this address is within this network + */ + bool within(const InetAddress &ipnet) const + throw(); + /** * Set to null/zero */ diff --git a/node/RoutingTable.cpp b/node/RoutingTable.cpp index 1f4c53277..9534b321d 100644 --- a/node/RoutingTable.cpp +++ b/node/RoutingTable.cpp @@ -39,7 +39,7 @@ 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() : "(link)"),device,metric); + Utils::snprintf(tmp,sizeof(tmp),"%s %s %s %d",destination.toString().c_str(),((gateway) ? gateway.toIpString().c_str() : ""),device,metric); return std::string(tmp); } diff --git a/node/RoutingTable.hpp b/node/RoutingTable.hpp index 8894018da..3a4a3ddee 100644 --- a/node/RoutingTable.hpp +++ b/node/RoutingTable.hpp @@ -50,7 +50,8 @@ public: InetAddress destination; InetAddress gateway; // port/netmaskBits field not used, should be 0 -- null if direct-to-device route char device[128]; - int metric; + int deviceIndex; // may not always be set, depending on OS -- for internal use only + int metric; // higher = lower priority -- on some OSes this is "hop count," etc. std::string toString() const; @@ -66,9 +67,13 @@ public: 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() const = 0; + virtual std::vector get(bool includeLinkLocal = false,bool includeLoopback = false) const = 0; /** * Add or update a routing table entry diff --git a/node/Utils.hpp b/node/Utils.hpp index 828372860..4298d0455 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -492,32 +492,6 @@ public: return true; } - /** - * Match two strings with bits masked netmask-style - * - * @param a First string - * @param abits Number of bits in first string - * @param b Second string - * @param bbits Number of bits in second string - * @return True if min(abits,bbits) match between a and b - */ - static inline bool matchNetmask(const void *a,unsigned int abits,const void *b,unsigned int bbits) - throw() - { - const unsigned char *aptr = (const unsigned char *)a; - const unsigned char *bptr = (const unsigned char *)b; - - while ((abits >= 8)&&(bbits >= 8)) { - if (*aptr++ != *bptr++) - return false; - abits -= 8; - bbits -= 8; - } - - unsigned char mask = 0xff << (8 - ((abits > bbits) ? bbits : abits)); - return ((*aptr & mask) == (*aptr & mask)); - } - /** * Compute SDBM hash of a binary string *