MulticastGroup.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2015 ZeroTier, Inc.
  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. return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
  94. }
  95. return MulticastGroup();
  96. }
  97. /**
  98. * @return Human readable string representing this group (MAC/ADI in hex)
  99. */
  100. inline std::string toString() const
  101. {
  102. char buf[64];
  103. Utils::snprintf(buf,sizeof(buf),"%.2x%.2x%.2x%.2x%.2x%.2x/%.4x",(unsigned int)_mac[0],(unsigned int)_mac[1],(unsigned int)_mac[2],(unsigned int)_mac[3],(unsigned int)_mac[4],(unsigned int)_mac[5],(unsigned int)_adi);
  104. return std::string(buf);
  105. }
  106. /**
  107. * Parse a human-readable multicast group
  108. *
  109. * @param s Multicast group in hex MAC/ADI format
  110. */
  111. inline void fromString(const char *s)
  112. {
  113. char hex[17];
  114. unsigned int hexlen = 0;
  115. while ((*s)&&(*s != '/')&&(hexlen < (sizeof(hex) - 1)))
  116. hex[hexlen++] = *s;
  117. hex[hexlen] = (char)0;
  118. _mac.fromString(hex);
  119. _adi = (*s == '/') ? (uint32_t)Utils::hexStrToULong(s + 1) : (uint32_t)0;
  120. }
  121. /**
  122. * @return Multicast address
  123. */
  124. inline const MAC &mac() const throw() { return _mac; }
  125. /**
  126. * @return Additional distinguishing information
  127. */
  128. inline uint32_t adi() const throw() { return _adi; }
  129. inline bool operator==(const MulticastGroup &g) const throw() { return ((_mac == g._mac)&&(_adi == g._adi)); }
  130. inline bool operator!=(const MulticastGroup &g) const throw() { return ((_mac != g._mac)||(_adi != g._adi)); }
  131. inline bool operator<(const MulticastGroup &g) const throw()
  132. {
  133. if (_mac < g._mac)
  134. return true;
  135. else if (_mac == g._mac)
  136. return (_adi < g._adi);
  137. return false;
  138. }
  139. inline bool operator>(const MulticastGroup &g) const throw() { return (g < *this); }
  140. inline bool operator<=(const MulticastGroup &g) const throw() { return !(g < *this); }
  141. inline bool operator>=(const MulticastGroup &g) const throw() { return !(*this < g); }
  142. private:
  143. MAC _mac;
  144. uint32_t _adi;
  145. };
  146. } // namespace ZeroTier
  147. #endif