BSDRoutingTable.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2011-2014 ZeroTier Networks LLC
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #include <stdint.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <sys/param.h>
  32. #include <sys/sysctl.h>
  33. #include <sys/socket.h>
  34. #include <netinet/in.h>
  35. #include <arpa/inet.h>
  36. #include <net/route.h>
  37. #include <net/if_dl.h>
  38. #include <algorithm>
  39. #include <utility>
  40. #include "Constants.hpp"
  41. #include "BSDRoutingTable.hpp"
  42. // All I wanted was the bloody rounting table. I didn't expect the Spanish inquisition.
  43. namespace ZeroTier {
  44. BSDRoutingTable::BSDRoutingTable()
  45. {
  46. }
  47. BSDRoutingTable::~BSDRoutingTable()
  48. {
  49. }
  50. std::vector<RoutingTable::Entry> BSDRoutingTable::get() const
  51. {
  52. std::vector<RoutingTable::Entry> entries;
  53. int mib[6];
  54. size_t needed;
  55. mib[0] = CTL_NET;
  56. mib[1] = PF_ROUTE;
  57. mib[2] = 0;
  58. mib[3] = 0;
  59. mib[4] = NET_RT_DUMP;
  60. mib[5] = 0;
  61. if (!sysctl(mib,6,NULL,&needed,NULL,0)) {
  62. if (needed <= 0)
  63. return entries;
  64. char *buf = (char *)::malloc(needed);
  65. if (buf) {
  66. if (!sysctl(mib,6,buf,&needed,NULL,0)) {
  67. struct rt_msghdr *rtm;
  68. for(char *next=buf,*end=buf+needed;next<end;) {
  69. rtm = (struct rt_msghdr *)next;
  70. char *saptr = (char *)(rtm + 1);
  71. char *saend = next + rtm->rtm_msglen;
  72. 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)) {
  73. RoutingTable::Entry e;
  74. int which = 0;
  75. while (saptr < saend) {
  76. struct sockaddr *sa = (struct sockaddr *)saptr;
  77. unsigned int salen = sa->sa_len;
  78. if (!salen)
  79. break;
  80. // Skip missing fields in rtm_addrs bit field
  81. while ((rtm->rtm_addrs & 1) == 0) {
  82. rtm->rtm_addrs >>= 1;
  83. ++which;
  84. if (which > 6)
  85. break;
  86. }
  87. if (which > 6)
  88. break;
  89. rtm->rtm_addrs >>= 1;
  90. switch(which++) {
  91. case 0:
  92. //printf("RTA_DST\n");
  93. if (sa->sa_family == AF_INET6) {
  94. struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
  95. // Nobody expects the Spanish inquisition!
  96. if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) {
  97. // Our chief weapon is... in-band signaling!
  98. unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff);
  99. sin6->sin6_addr.s6_addr[2] = 0;
  100. sin6->sin6_addr.s6_addr[3] = 0;
  101. if (!sin6->sin6_scope_id)
  102. sin6->sin6_scope_id = interfaceIndex;
  103. }
  104. }
  105. e.destination.set(sa);
  106. break;
  107. case 1:
  108. //printf("RTA_GATEWAY\n");
  109. e.gateway.set(sa);
  110. break;
  111. case 2: {
  112. if (e.destination.isV6()) {
  113. salen = sizeof(struct sockaddr_in6); // Confess!
  114. unsigned int bits = 0;
  115. for(int i=0;i<16;++i) {
  116. unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i];
  117. if (c == 0xff)
  118. bits += 8;
  119. else break;
  120. /* must they be multiples of 8? Most of the BSD source I can find says yes..?
  121. else {
  122. while ((c & 0x80) == 0x80) {
  123. ++bits;
  124. c <<= 1;
  125. }
  126. break;
  127. }
  128. */
  129. }
  130. e.destination.setPort(bits);
  131. } else {
  132. salen = sizeof(struct sockaddr_in); // Confess!
  133. e.destination.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr));
  134. }
  135. //printf("RTA_NETMASK\n");
  136. } break;
  137. case 3:
  138. //printf("RTA_GENMASK\n");
  139. break;
  140. case 4:
  141. //printf("RTA_IFP\n");
  142. break;
  143. case 5:
  144. //printf("RTA_IFA\n");
  145. break;
  146. case 6:
  147. //printf("RTA_AUTHOR\n");
  148. break;
  149. }
  150. saptr += salen;
  151. }
  152. e.metric = (int)rtm->rtm_rmx.rmx_hopcount;
  153. entries.push_back(e);
  154. printf("%s\n",e.toString().c_str());
  155. }
  156. next = saend;
  157. }
  158. }
  159. ::free(buf);
  160. }
  161. }
  162. std::sort(entries.begin(),entries.end());
  163. return entries;
  164. }
  165. bool BSDRoutingTable::set(const RoutingTable::Entry &re)
  166. {
  167. return true;
  168. }
  169. } // namespace ZeroTier
  170. // Enable and build to test routing table interface
  171. ///*
  172. int main(int argc,char **argv)
  173. {
  174. ZeroTier::BSDRoutingTable rt;
  175. std::vector<ZeroTier::RoutingTable::Entry> ents(rt.get());
  176. return 0;
  177. }
  178. //*/