ZeroTierOne/go/attic/endpoint.go
2020-01-20 16:03:19 -08:00

145 lines
3.4 KiB
Go

package attic
import (
"encoding/binary"
"errors"
)
// Endpoint types are the same as the enum values in Endpoint.hpp in the core.
const (
EndpointTypeNil = 0
EndpointTypeInetAddr = 1
EndpointTypeDnsName = 2
EndpointTypeZeroTier = 3
EndpointTypeUrl = 4
EndpointTypeEthernet = 5
EndpointTypeUnrecognized = 255
)
// Endpoint wraps a variety of different ways of describing a node's physical network location.
type Endpoint struct {
// Type is this endpoint's type
Type int
// Location is the X, Y, Z coordinate of this endpoint or 0,0,0 if unspecified.
Location [3]int
value, value2 interface{}
}
var (
ErrInvalidEndpoint = errors.New("invalid marshaled endpoint object")
)
func (ep *Endpoint) unmarshalZT(b []byte) (int, error) {
if len(b) < 7 {
return 0, ErrInvalidEndpoint
}
ep.Type = int(b[0])
ep.Location[0] = int(binary.BigEndian.Uint16(b[1:3]))
ep.Location[1] = int(binary.BigEndian.Uint16(b[3:5]))
ep.Location[2] = int(binary.BigEndian.Uint16(b[5:7]))
ep.value = nil
ep.value2 = nil
switch ep.Type {
case EndpointTypeNil:
return 7, nil
case EndpointTypeInetAddr:
ina := new(InetAddress)
inlen, err := ina.unmarshalZT(b[7:])
if err != nil {
return 0, err
}
ep.value = ina
return 7 + inlen, nil
case EndpointTypeDnsName:
stringEnd := 0
for i := 7; i < len(b); i++ {
if b[i] == 0 {
stringEnd = i + 1
break
}
}
if stringEnd == 0 || (stringEnd+2) > len(b) {
return 0, ErrInvalidEndpoint
}
ep.value = string(b[7:stringEnd])
port := binary.BigEndian.Uint16(b[stringEnd : stringEnd+2])
ep.value2 = &port
return stringEnd + 2, nil
case EndpointTypeZeroTier:
if len(b) < 60 {
return 0, ErrInvalidEndpoint
}
a, err := NewAddressFromBytes(b[7:12])
if err != nil {
return 0, err
}
ep.value = a
ep.value2 = append(make([]byte, 0, 48), b[12:60]...)
return 60, nil
case EndpointTypeUrl:
stringEnd := 0
for i := 7; i < len(b); i++ {
if b[i] == 0 {
stringEnd = i + 1
break
}
}
if stringEnd == 0 {
return 0, ErrInvalidEndpoint
}
ep.value = string(b[7:stringEnd])
return stringEnd, nil
case EndpointTypeEthernet:
if len(b) < 13 {
return 0, ErrInvalidEndpoint
}
m, err := NewMACFromBytes(b[7:13])
if err != nil {
return 0, err
}
ep.value = m
return 13, nil
default:
if len(b) < 8 {
return 0, ErrInvalidEndpoint
}
ep.Type = EndpointTypeUnrecognized
return 8 + int(b[1]), nil
}
}
// InetAddress gets the address associated with this endpoint or nil if it is not of this type.
func (ep *Endpoint) InetAddress() *InetAddress {
v, _ := ep.value.(*InetAddress)
return v
}
// Address gets the address associated with this endpoint or nil if it is not of this type.
func (ep *Endpoint) Address() *Address {
v, _ := ep.value.(*Address)
return v
}
// DNSName gets the DNS name and port associated with this endpoint or an empty string and -1 if it is not of this type.
func (ep *Endpoint) DNSName() (string, int) {
if ep.Type == EndpointTypeDnsName {
return ep.value.(string), int(*(ep.value2.(*uint16)))
}
return "", -1
}
// InetAddress gets the URL assocaited with this endpoint or an empty string if it is not of this type.
func (ep *Endpoint) URL() string {
if ep.Type == EndpointTypeUrl {
return ep.value.(string)
}
return ""
}
// Ethernet gets the address associated with this endpoint or nil if it is not of this type.
func (ep *Endpoint) Ethernet() *MAC {
v, _ := ep.value.(*MAC)
return v
}