locator.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (c)2019 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: 2023-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. //#cgo CFLAGS: -O3
  15. //#include "../../native/GoGlue.h"
  16. import "C"
  17. import (
  18. "encoding/json"
  19. "unsafe"
  20. )
  21. // LocatorDNSSigningKey is the public (as a secure DNS name) and private keys for entering locators into DNS
  22. type LocatorDNSSigningKey struct {
  23. SecureDNSName string `json:"secureDNSName"`
  24. PrivateKey []byte `json:"privateKey"`
  25. }
  26. // NewLocatorDNSSigningKey creates a new signing key and secure DNS name for storing locators in DNS
  27. func NewLocatorDNSSigningKey() (*LocatorDNSSigningKey, error) {
  28. var nameBuf [256]C.char
  29. var keyBuf [64]byte
  30. keySize := int(C.ZT_GoLocator_makeSecureDNSName(&nameBuf[0], 256, (*C.uint8_t)(unsafe.Pointer(&keyBuf[0])), 128))
  31. if keySize <= 0 {
  32. return nil, ErrInternal
  33. }
  34. var sk LocatorDNSSigningKey
  35. sk.SecureDNSName = C.GoString(&nameBuf[0])
  36. sk.PrivateKey = keyBuf[0:keySize]
  37. return &sk, nil
  38. }
  39. // Locator is a binary serialized record containing information about where a ZeroTier node is located on the network.
  40. // Note that for JSON objects only Bytes needs to be specified. When JSON is deserialized only this field is used
  41. // and the others are always reconstructed from it.
  42. type Locator struct {
  43. // Identity is the full identity of the node being located
  44. Identity *Identity `json:"identity"`
  45. // Physical is a list of static physical network addresses for this node
  46. Physical []*InetAddress `json:"physical,omitempty"`
  47. // Virtual is a list of ZeroTier nodes that can relay to this node
  48. Virtual []*Identity `json:"virtual,omitempty"`
  49. // Bytes is the raw serialized Locator
  50. Bytes []byte `json:"bytes,omitempty"`
  51. }
  52. // NewLocator creates a new locator with the given identity and addresses and the current time as timestamp.
  53. // The identity must include its secret key so that it can sign the final locator.
  54. func NewLocator(id *Identity, virtualAddresses []*Identity, physicalAddresses []*InetAddress) (*Locator, error) {
  55. if !id.HasPrivate() {
  56. return nil, ErrSecretKeyRequired
  57. }
  58. idstr := id.PrivateKeyString()
  59. phy := make([]C.struct_sockaddr_storage, len(physicalAddresses))
  60. virt := make([]*C.char, len(virtualAddresses))
  61. idCstr := C.CString(idstr)
  62. defer func() {
  63. C.free(unsafe.Pointer(idCstr))
  64. for _, v := range virt {
  65. if uintptr(unsafe.Pointer(v)) != 0 {
  66. C.free(unsafe.Pointer(v))
  67. }
  68. }
  69. }()
  70. for i := 0; i < len(physicalAddresses); i++ {
  71. if !makeSockaddrStorage(physicalAddresses[i].IP, physicalAddresses[i].Port, &phy[i]) {
  72. return nil, ErrInvalidParameter
  73. }
  74. }
  75. for i := 0; i < len(virtualAddresses); i++ {
  76. idstr := virtualAddresses[i].String()
  77. virt[i] = C.CString(idstr)
  78. }
  79. var buf [65536]byte
  80. var pPhy *C.struct_sockaddr_storage
  81. var pVirt **C.char
  82. if len(phy) > 0 {
  83. pPhy = &phy[0]
  84. }
  85. if len(virt) > 0 {
  86. pVirt = &virt[0]
  87. }
  88. locSize := C.ZT_GoLocator_makeLocator((*C.uint8_t)(unsafe.Pointer(&buf[0])), 65536, C.int64_t(TimeMs()), idCstr, pPhy, C.uint(len(phy)), pVirt, C.uint(len(virt)))
  89. if locSize <= 0 {
  90. return nil, ErrInvalidParameter
  91. }
  92. r := make([]byte, int(locSize))
  93. copy(r[:], buf[0:int(locSize)])
  94. return &Locator{
  95. Identity: id,
  96. Physical: physicalAddresses,
  97. Virtual: virtualAddresses,
  98. Bytes: r,
  99. }, nil
  100. }
  101. // NewLocatorFromBytes decodes a locator from its serialized byte array form
  102. func NewLocatorFromBytes(b []byte) (*Locator, error) {
  103. if len(b) == 0 {
  104. return nil, ErrInvalidParameter
  105. }
  106. var info C.struct_ZT_GoLocator_Info
  107. res := C.ZT_GoLocator_decodeLocator((*C.uint8_t)(unsafe.Pointer(&b[0])), C.uint(len(b)), &info)
  108. if res == -2 {
  109. return nil, ErrInvalidSignature
  110. } else if res <= 0 {
  111. return nil, ErrInvalidParameter
  112. }
  113. var loc Locator
  114. var err error
  115. loc.Identity, err = NewIdentityFromString(C.GoString(&info.id[0]))
  116. if err != nil {
  117. return nil, err
  118. }
  119. for i := 0; i < int(info.phyCount); i++ {
  120. ua := sockaddrStorageToUDPAddr(&info.phy[i])
  121. if ua != nil {
  122. loc.Physical = append(loc.Physical, &InetAddress{IP: ua.IP, Port: ua.Port})
  123. }
  124. }
  125. for i := 0; i < int(info.virtCount); i++ {
  126. id, err := NewIdentityFromString(C.GoString(&info.virt[i][0]))
  127. if err == nil {
  128. loc.Virtual = append(loc.Virtual, id)
  129. }
  130. }
  131. loc.Bytes = b
  132. return &loc, nil
  133. }
  134. // MakeTXTRecords creates secure DNS TXT records for this locator
  135. func (l *Locator) MakeTXTRecords(key *LocatorDNSSigningKey) ([]string, error) {
  136. if key == nil || len(l.Bytes) == 0 || len(key.PrivateKey) == 0 {
  137. return nil, ErrInvalidParameter
  138. }
  139. var results [256][256]C.char
  140. cName := C.CString(key.SecureDNSName)
  141. defer C.free(unsafe.Pointer(cName))
  142. count := int(C.ZT_GoLocator_makeSignedTxtRecords((*C.uint8_t)(&l.Bytes[0]), C.uint(len(l.Bytes)), cName, (*C.uint8_t)(&key.PrivateKey[0]), C.uint(len(key.PrivateKey)), &results[0]))
  143. if count > 0 {
  144. var t []string
  145. for i := 0; i < int(count); i++ {
  146. t = append(t, C.GoString(&results[i][0]))
  147. }
  148. return t, nil
  149. }
  150. return nil, ErrInternal
  151. }
  152. type locatorForUnmarshal struct {
  153. Bytes []byte `json:"bytes,omitempty"`
  154. }
  155. // UnmarshalJSON unmarshals this Locator from a byte array in JSON.
  156. func (l *Locator) UnmarshalJSON(j []byte) error {
  157. var bytes locatorForUnmarshal
  158. err := json.Unmarshal(j, &bytes)
  159. if err != nil {
  160. return err
  161. }
  162. tmp, err := NewLocatorFromBytes(bytes.Bytes)
  163. if err != nil {
  164. return err
  165. }
  166. *l = *tmp
  167. return nil
  168. }