From d3151567331716341210fe957df69fd2a705dc8b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 16 Jul 2014 15:13:53 -0700 Subject: [PATCH] BSD routing table implementation work. --- make-mac.mk | 2 + node/BSDRoutingTable.cpp | 201 +++++++++++++++++++++++++++++++++++++++ node/BSDRoutingTable.hpp | 51 ++++++++++ node/RoutingTable.hpp | 2 +- 4 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 node/BSDRoutingTable.cpp create mode 100644 node/BSDRoutingTable.hpp diff --git a/make-mac.mk b/make-mac.mk index 550cad435..db7ebfb68 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -42,6 +42,8 @@ CXXFLAGS=$(CFLAGS) -fno-rtti include objects.mk +OBJS+=node/BSDRoutingTable.o + all: one one: $(OBJS) diff --git a/node/BSDRoutingTable.cpp b/node/BSDRoutingTable.cpp new file mode 100644 index 000000000..d886b60fc --- /dev/null +++ b/node/BSDRoutingTable.cpp @@ -0,0 +1,201 @@ +/* + * ZeroTier One - Global Peer to Peer Ethernet + * Copyright (C) 2011-2014 ZeroTier Networks LLC + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "Constants.hpp" +#include "BSDRoutingTable.hpp" + +// All I wanted was the bloody rounting table. I didn't expect the Spanish inquisition. + +namespace ZeroTier { + +BSDRoutingTable::BSDRoutingTable() +{ +} + +BSDRoutingTable::~BSDRoutingTable() +{ +} + +std::vector BSDRoutingTable::get() 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)) { + RoutingTable::Entry e; + + 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! + 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"); + e.gateway.set(sa); + 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; + + entries.push_back(e); + printf("%s\n",e.toString().c_str()); + } + + next = saend; + } + } + + ::free(buf); + } + } + + std::sort(entries.begin(),entries.end()); + return entries; +} + +bool BSDRoutingTable::set(const RoutingTable::Entry &re) +{ + return true; +} + +} // namespace ZeroTier + +// Enable and build to test routing table interface +///* +int main(int argc,char **argv) +{ + ZeroTier::BSDRoutingTable rt; + std::vector ents(rt.get()); + return 0; +} +//*/ diff --git a/node/BSDRoutingTable.hpp b/node/BSDRoutingTable.hpp new file mode 100644 index 000000000..8947bddef --- /dev/null +++ b/node/BSDRoutingTable.hpp @@ -0,0 +1,51 @@ +/* + * ZeroTier One - Global Peer to Peer Ethernet + * Copyright (C) 2011-2014 ZeroTier Networks LLC + * + * 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 "RoutingTable.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 RoutingTable +{ +public: + BSDRoutingTable(); + virtual ~BSDRoutingTable(); + virtual std::vector get() const; + virtual bool set(const RoutingTable::Entry &re); +}; + +} // namespace ZeroTier + +#endif diff --git a/node/RoutingTable.hpp b/node/RoutingTable.hpp index 8f6a4642d..8894018da 100644 --- a/node/RoutingTable.hpp +++ b/node/RoutingTable.hpp @@ -48,7 +48,7 @@ public: Entry() { device[0] = (char)0; } InetAddress destination; - InetAddress gateway; // port/netmaskBits field not used, should be 0 + InetAddress gateway; // port/netmaskBits field not used, should be 0 -- null if direct-to-device route char device[128]; int metric;