NeighborDiscovery.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
  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. * You can be released from the requirements of the license by purchasing
  21. * a commercial license. Buying such a license is mandatory as soon as you
  22. * develop commercial closed-source software that incorporates or links
  23. * directly against ZeroTier software without disclosing the source code
  24. * of your own application.
  25. */
  26. #include "NeighborDiscovery.hpp"
  27. #include "OSUtils.hpp"
  28. #include "../include/ZeroTierOne.h"
  29. #include <assert.h>
  30. namespace ZeroTier {
  31. uint16_t calc_checksum (uint16_t *addr, int len)
  32. {
  33. int count = len;
  34. uint32_t sum = 0;
  35. uint16_t answer = 0;
  36. // Sum up 2-byte values until none or only one byte left.
  37. while (count > 1) {
  38. sum += *(addr++);
  39. count -= 2;
  40. }
  41. // Add left-over byte, if any.
  42. if (count > 0) {
  43. sum += *(uint8_t *) addr;
  44. }
  45. // Fold 32-bit sum into 16 bits; we lose information by doing this,
  46. // increasing the chances of a collision.
  47. // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
  48. while (sum >> 16) {
  49. sum = (sum & 0xffff) + (sum >> 16);
  50. }
  51. // Checksum is one's compliment of sum.
  52. answer = ~sum;
  53. return (answer);
  54. }
  55. struct _pseudo_header {
  56. uint8_t sourceAddr[16];
  57. uint8_t targetAddr[16];
  58. uint32_t length;
  59. uint8_t zeros[3];
  60. uint8_t next; // 58
  61. };
  62. struct _option {
  63. _option(int optionType)
  64. : type(optionType)
  65. , length(8)
  66. {
  67. memset(mac, 0, sizeof(mac));
  68. }
  69. uint8_t type;
  70. uint8_t length;
  71. uint8_t mac[6];
  72. };
  73. struct _neighbor_solicitation {
  74. _neighbor_solicitation()
  75. : type(135)
  76. , code(0)
  77. , checksum(0)
  78. , option(1)
  79. {
  80. memset(&reserved, 0, sizeof(reserved));
  81. memset(target, 0, sizeof(target));
  82. }
  83. void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) {
  84. _pseudo_header ph;
  85. memset(&ph, 0, sizeof(_pseudo_header));
  86. const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
  87. const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
  88. memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
  89. memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
  90. ph.next = 58;
  91. ph.length = htonl(sizeof(_neighbor_solicitation));
  92. size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation);
  93. uint8_t *tmp = (uint8_t*)malloc(len);
  94. memcpy(tmp, &ph, sizeof(_pseudo_header));
  95. memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation));
  96. checksum = calc_checksum((uint16_t*)tmp, (int)len);
  97. free(tmp);
  98. tmp = NULL;
  99. }
  100. uint8_t type; // 135
  101. uint8_t code; // 0
  102. uint16_t checksum;
  103. uint32_t reserved;
  104. uint8_t target[16];
  105. _option option;
  106. };
  107. struct _neighbor_advertisement {
  108. _neighbor_advertisement()
  109. : type(136)
  110. , code(0)
  111. , checksum(0)
  112. , rso(0x40)
  113. , option(2)
  114. {
  115. memset(padding, 0, sizeof(padding));
  116. memset(target, 0, sizeof(target));
  117. }
  118. void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) {
  119. _pseudo_header ph;
  120. memset(&ph, 0, sizeof(_pseudo_header));
  121. const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
  122. const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
  123. memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
  124. memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
  125. ph.next = 58;
  126. ph.length = htonl(sizeof(_neighbor_advertisement));
  127. size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement);
  128. uint8_t *tmp = (uint8_t*)malloc(len);
  129. memcpy(tmp, &ph, sizeof(_pseudo_header));
  130. memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement));
  131. checksum = calc_checksum((uint16_t*)tmp, (int)len);
  132. free(tmp);
  133. tmp = NULL;
  134. }
  135. uint8_t type; // 136
  136. uint8_t code; // 0
  137. uint16_t checksum;
  138. uint8_t rso;
  139. uint8_t padding[3];
  140. uint8_t target[16];
  141. _option option;
  142. };
  143. NeighborDiscovery::NeighborDiscovery()
  144. : _cache(256)
  145. , _lastCleaned(OSUtils::now())
  146. {}
  147. void NeighborDiscovery::addLocal(const sockaddr_storage &address, const MAC &mac)
  148. {
  149. _NDEntry &e = _cache[InetAddress(address)];
  150. e.lastQuerySent = 0;
  151. e.lastResponseReceived = 0;
  152. e.mac = mac;
  153. e.local = true;
  154. }
  155. void NeighborDiscovery::remove(const sockaddr_storage &address)
  156. {
  157. _cache.erase(InetAddress(address));
  158. }
  159. sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest)
  160. {
  161. assert(sizeof(_neighbor_solicitation) == 28);
  162. assert(sizeof(_neighbor_advertisement) == 32);
  163. const uint64_t now = OSUtils::now();
  164. sockaddr_storage ip = {0};
  165. if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) {
  166. // respond to Neighbor Solicitation request for local address
  167. _neighbor_solicitation solicitation;
  168. memcpy(&solicitation, nd, len);
  169. InetAddress targetAddress(solicitation.target, 16, 0);
  170. _NDEntry *targetEntry = _cache.get(targetAddress);
  171. if (targetEntry && targetEntry->local) {
  172. _neighbor_advertisement adv;
  173. targetEntry->mac.copyTo(adv.option.mac, 6);
  174. memcpy(adv.target, solicitation.target, 16);
  175. adv.calculateChecksum(localIp, targetAddress);
  176. memcpy(response, &adv, sizeof(_neighbor_advertisement));
  177. responseLen = sizeof(_neighbor_advertisement);
  178. responseDest.setTo(solicitation.option.mac, 6);
  179. }
  180. } else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) {
  181. _neighbor_advertisement adv;
  182. memcpy(&adv, nd, len);
  183. InetAddress responseAddress(adv.target, 16, 0);
  184. _NDEntry *queryEntry = _cache.get(responseAddress);
  185. if(queryEntry && !queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) {
  186. queryEntry->lastResponseReceived = now;
  187. queryEntry->mac.setTo(adv.option.mac, 6);
  188. ip = responseAddress;
  189. }
  190. }
  191. if ((now - _lastCleaned) >= ZT_ND_EXPIRE) {
  192. _lastCleaned = now;
  193. Hashtable<InetAddress, _NDEntry>::Iterator i(_cache);
  194. InetAddress *k = NULL;
  195. _NDEntry *v = NULL;
  196. while (i.next(k, v)) {
  197. if(!v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) {
  198. _cache.erase(*k);
  199. }
  200. }
  201. }
  202. return ip;
  203. }
  204. MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest)
  205. {
  206. const uint64_t now = OSUtils::now();
  207. InetAddress localAddress(localIp);
  208. localAddress.setPort(0);
  209. InetAddress targetAddress(targetIp);
  210. targetAddress.setPort(0);
  211. _NDEntry &e = _cache[targetAddress];
  212. if ( (e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) ||
  213. (!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) {
  214. e.lastQuerySent = now;
  215. _neighbor_solicitation ns;
  216. memcpy(ns.target, targetAddress.rawIpData(), 16);
  217. localMac.copyTo(ns.option.mac, 6);
  218. ns.calculateChecksum(localIp, targetIp);
  219. if (e.mac) {
  220. queryDest = e.mac;
  221. } else {
  222. queryDest = (uint64_t)0xffffffffffffULL;
  223. }
  224. } else {
  225. queryLen = 0;
  226. queryDest.zero();
  227. }
  228. return e.mac;
  229. }
  230. }