MulticastGroup.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2012-2013 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. #ifndef ZT_MULTICASTGROUP_HPP
  28. #define ZT_MULTICASTGROUP_HPP
  29. #include <stdint.h>
  30. #include <string>
  31. #include "MAC.hpp"
  32. #include "InetAddress.hpp"
  33. namespace ZeroTier {
  34. /**
  35. * A multicast group composed of a multicast MAC and a 32-bit ADI field
  36. *
  37. * ADI stands for additional distinguishing information. ADI is primarily for
  38. * adding additional information to broadcast (ff:ff:ff:ff:ff:ff) memberships,
  39. * since straight-up broadcast won't scale. Right now it's zero except for
  40. * IPv4 ARP, where it holds the IPv4 address itself to make ARP into a
  41. * selective multicast query that can scale.
  42. *
  43. * In the future we might add some kind of plugin architecture that can add
  44. * ADI for things like mDNS (multicast DNS) to improve the selectivity of
  45. * those protocols.
  46. *
  47. * MulticastGroup behaves as an immutable value object.
  48. */
  49. class MulticastGroup
  50. {
  51. public:
  52. MulticastGroup()
  53. throw() :
  54. _mac(),
  55. _adi(0)
  56. {
  57. }
  58. MulticastGroup(const MAC &m,uint32_t a)
  59. throw() :
  60. _mac(m),
  61. _adi(a)
  62. {
  63. }
  64. MulticastGroup(const char *s)
  65. {
  66. fromString(s);
  67. }
  68. MulticastGroup(const std::string &s)
  69. {
  70. fromString(s.c_str());
  71. }
  72. /**
  73. * Derive the multicast group used for address resolution (ARP/NDP) for an IP
  74. *
  75. * @param ip IP address (port field is ignored)
  76. * @return Multicat group for ARP/NDP
  77. */
  78. static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
  79. throw()
  80. {
  81. if (ip.isV4()) {
  82. // IPv4 wants braodcast MACs, so we shove the V4 address itself into
  83. // the Multicast Group ADI field. Making V4 ARP work is basically why
  84. // ADI was added, as well as handling other things that want mindless
  85. // Ethernet broadcast to all.
  86. return MulticastGroup(MAC((unsigned char)0xff),Utils::ntoh(*((const uint32_t *)ip.rawIpData())));
  87. } else if (ip.isV6()) {
  88. // IPv6 is better designed in this respect. We can compute the IPv6
  89. // multicast address directly from the IP address, and it gives us
  90. // 24 bits of uniqueness. Collisions aren't likely to be common enough
  91. // to care about.
  92. const unsigned char *a = (const unsigned char *)ip.rawIpData();
  93. MAC m;
  94. m.data[0] = 0x33;
  95. m.data[1] = 0x33;
  96. m.data[2] = 0xff;
  97. m.data[3] = a[13];
  98. m.data[4] = a[14];
  99. m.data[5] = a[15];
  100. return MulticastGroup(m,0);
  101. }
  102. return MulticastGroup();
  103. }
  104. /**
  105. * @return Human readable string representing this group (MAC/ADI in hex)
  106. */
  107. inline std::string toString() const
  108. {
  109. char buf[64];
  110. Utils::snprintf(buf,sizeof(buf),"%.2x%.2x%.2x%.2x%.2x%.2x/%lx",(unsigned int)_mac.data[0],(unsigned int)_mac.data[1],(unsigned int)_mac.data[2],(unsigned int)_mac.data[3],(unsigned int)_mac.data[4],(unsigned int)_mac.data[5],(unsigned long)_adi);
  111. return std::string(buf);
  112. }
  113. /**
  114. * Parse a human-readable multicast group
  115. *
  116. * @param s Multicast group in hex MAC/ADI format
  117. */
  118. inline void fromString(const char *s)
  119. {
  120. char hex[17];
  121. unsigned int hexlen = 0;
  122. while ((*s)&&(*s != '/')&&(hexlen < sizeof(hex) - 1))
  123. hex[hexlen++] = *s;
  124. hex[hexlen] = (char)0;
  125. _mac.fromString(hex);
  126. if (*s == '/')
  127. _adi = (uint32_t)Utils::hexStrToULong(++s);
  128. else _adi = 0;
  129. }
  130. /**
  131. * @return Multicast address
  132. */
  133. inline const MAC &mac() const throw() { return _mac; }
  134. /**
  135. * @return Additional distinguishing information
  136. */
  137. inline uint32_t adi() const throw() { return _adi; }
  138. inline bool operator==(const MulticastGroup &g) const throw() { return ((_mac == g._mac)&&(_adi == g._adi)); }
  139. inline bool operator!=(const MulticastGroup &g) const throw() { return ((_mac != g._mac)||(_adi != g._adi)); }
  140. inline bool operator<(const MulticastGroup &g) const throw()
  141. {
  142. if (_mac < g._mac)
  143. return true;
  144. else if (_mac == g._mac)
  145. return (_adi < g._adi);
  146. return false;
  147. }
  148. inline bool operator>(const MulticastGroup &g) const throw() { return (g < *this); }
  149. inline bool operator<=(const MulticastGroup &g) const throw() { return !(g < *this); }
  150. inline bool operator>=(const MulticastGroup &g) const throw() { return !(*this < g); }
  151. private:
  152. MAC _mac;
  153. uint32_t _adi;
  154. };
  155. } // namespace ZeroTier
  156. #endif