BSD routing table works... that hurt much worse than it should have.

This commit is contained in:
Adam Ierymenko 2014-07-17 13:08:37 -07:00
parent d315156733
commit 51766e6549
7 changed files with 94 additions and 34 deletions

View File

@ -28,6 +28,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/sysctl.h>
@ -35,7 +36,9 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <algorithm>
#include <utility>
@ -55,7 +58,7 @@ BSDRoutingTable::~BSDRoutingTable()
{
}
std::vector<RoutingTable::Entry> BSDRoutingTable::get() const
std::vector<RoutingTable::Entry> BSDRoutingTable::get(bool includeLinkLocal,bool includeLoopback) const
{
std::vector<RoutingTable::Entry> entries;
int mib[6];
@ -82,6 +85,7 @@ std::vector<RoutingTable::Entry> 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<RoutingTable::Entry> 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<RoutingTable::Entry> BSDRoutingTable::get() const
}
//printf("RTA_NETMASK\n");
} break;
/*
case 3:
//printf("RTA_GENMASK\n");
break;
@ -160,6 +173,7 @@ std::vector<RoutingTable::Entry> BSDRoutingTable::get() const
case 6:
//printf("RTA_AUTHOR\n");
break;
*/
}
saptr += salen;
@ -167,8 +181,8 @@ std::vector<RoutingTable::Entry> 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<RoutingTable::Entry> BSDRoutingTable::get() const
}
}
for(std::vector<ZeroTier::RoutingTable::Entry>::iterator e1(entries.begin());e1!=entries.end();++e1) {
if ((!e1->device[0])&&(e1->deviceIndex >= 0))
if_indextoname(e1->deviceIndex,e1->device);
}
for(std::vector<ZeroTier::RoutingTable::Entry>::iterator e1(entries.begin());e1!=entries.end();++e1) {
if ((!e1->device[0])&&(e1->gateway)) {
int bestMetric = 9999999;
for(std::vector<ZeroTier::RoutingTable::Entry>::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<ZeroTier::RoutingTable::Entry> ents(rt.get());
for(std::vector<ZeroTier::RoutingTable::Entry>::iterator e(ents.begin());e!=ents.end();++e)
printf("%s\n",e->toString().c_str());
return 0;
}
//*/

View File

@ -42,7 +42,7 @@ class BSDRoutingTable : public RoutingTable
public:
BSDRoutingTable();
virtual ~BSDRoutingTable();
virtual std::vector<RoutingTable::Entry> get() const;
virtual std::vector<RoutingTable::Entry> get(bool includeLinkLocal = false,bool includeLoopback = false) const;
virtual bool set(const RoutingTable::Entry &re);
};

View File

@ -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()
{

View File

@ -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
*/

View File

@ -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() : "<link>"),device,metric);
return std::string(tmp);
}

View File

@ -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<Entry> get() const = 0;
virtual std::vector<Entry> get(bool includeLinkLocal = false,bool includeLoopback = false) const = 0;
/**
* Add or update a routing table entry

View File

@ -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
*