mac.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /*
  2. * Copyright (C)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2025-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. package zerotier
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "strconv"
  18. "strings"
  19. )
  20. // MAC represents an Ethernet hardware address
  21. type MAC uint64
  22. // NewMACFromString decodes a MAC address in canonical colon-separated hex format
  23. func NewMACFromString(s string) (MAC, error) {
  24. ss := strings.Split(s, ":")
  25. if len(ss) != 6 {
  26. return MAC(0), ErrInvalidMACAddress
  27. }
  28. var m uint64
  29. for i := 0; i < 6; i++ {
  30. m <<= 8
  31. c, _ := strconv.ParseUint(ss[i], 16, 64)
  32. if c > 0xff {
  33. return MAC(0), ErrInvalidMACAddress
  34. }
  35. m |= c & 0xff
  36. }
  37. return MAC(m), nil
  38. }
  39. // NewMACFromBytes decodes a MAC from a 6-byte array
  40. func NewMACFromBytes(b []byte) (MAC, error) {
  41. if len(b) < 6 {
  42. return MAC(0), ErrInvalidMACAddress
  43. }
  44. var m uint64
  45. for i := 0; i < 6; i++ {
  46. m <<= 8
  47. m |= uint64(b[i])
  48. }
  49. return MAC(m), nil
  50. }
  51. // NewMACForNetworkMember computes the static MAC for a given address and network ID
  52. func NewMACForNetworkMember(addr Address, nwid NetworkID) MAC {
  53. // This is the same algorithm as found in MAC::fromAddress() in MAC.hpp
  54. firstOctetForNetwork := byte((byte(nwid) & 0xfe) | 0x02)
  55. if firstOctetForNetwork == 0x52 {
  56. firstOctetForNetwork = 0x32
  57. }
  58. m := uint64(firstOctetForNetwork) << 40
  59. m |= uint64(addr)
  60. m ^= ((uint64(nwid) >> 8) & 0xff) << 32
  61. m ^= ((uint64(nwid) >> 16) & 0xff) << 24
  62. m ^= ((uint64(nwid) >> 24) & 0xff) << 16
  63. m ^= ((uint64(nwid) >> 32) & 0xff) << 8
  64. m ^= (uint64(nwid) >> 40) & 0xff
  65. return MAC(m)
  66. }
  67. // String returns this MAC address in canonical human-readable form
  68. func (m MAC) String() string {
  69. return fmt.Sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (uint64(m)>>40)&0xff, (uint64(m)>>32)&0xff, (uint64(m)>>24)&0xff, (uint64(m)>>16)&0xff, (uint64(m)>>8)&0xff, uint64(m)&0xff)
  70. }
  71. // MarshalJSON marshals this MAC as a string
  72. func (m MAC) MarshalJSON() ([]byte, error) {
  73. return []byte("\"" + m.String() + "\""), nil
  74. }
  75. // UnmarshalJSON unmarshals this MAC from a string
  76. func (m *MAC) UnmarshalJSON(j []byte) error {
  77. var s string
  78. err := json.Unmarshal(j, &s)
  79. if err != nil {
  80. return err
  81. }
  82. *m, err = NewMACFromString(s)
  83. return err
  84. }