mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-21 22:46:54 +02:00
A bunch more go plumbing.
This commit is contained in:
parent
1b2a4f00f2
commit
9babfcb9b6
7 changed files with 128 additions and 56 deletions
|
@ -193,13 +193,13 @@ func readLocator(s string) *zerotier.Locator {
|
|||
func networkStatusStr(status int) string {
|
||||
switch status {
|
||||
case zerotier.NetworkStatusNotFound:
|
||||
return "NOTFOUND"
|
||||
return "not-found"
|
||||
case zerotier.NetworkStatusAccessDenied:
|
||||
return "ACCESSDENIED"
|
||||
case zerotier.NetworkStatusRequestConfiguration:
|
||||
return "UPDATING"
|
||||
return "access-denied"
|
||||
case zerotier.NetworkStatusRequestingConfiguration:
|
||||
return "updating"
|
||||
case zerotier.NetworkStatusOK:
|
||||
return "OK"
|
||||
return "ok"
|
||||
}
|
||||
return "???"
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ func NewAddressFromBytes(b []byte) (Address, error) {
|
|||
return Address((uint64(b[0]) << 32) | (uint64(b[1]) << 24) | (uint64(b[2]) << 16) | (uint64(b[3]) << 8) | uint64(b[4])), nil
|
||||
}
|
||||
|
||||
// Copy this address to a byte array, which must be 5 bytes in length or this will panic.
|
||||
// CopyTo writes this address to five bytes.
|
||||
// If b cannot store five bytes this will panic.
|
||||
func (a Address) CopyTo(b []byte) {
|
||||
_ = b[4]
|
||||
b[0] = byte(a >> 32)
|
||||
|
@ -52,7 +53,7 @@ func (a Address) CopyTo(b []byte) {
|
|||
// IsReserved returns true if this address is reserved and therefore is not valid for a real node.
|
||||
func (a Address) IsReserved() bool { return a == 0 || (a>>32) == 0xff }
|
||||
|
||||
// String returns this address's 10-digit hex identifier
|
||||
// String returns this address's 10-digit hex identifier.
|
||||
func (a Address) String() string {
|
||||
return fmt.Sprintf("%.10x", uint64(a))
|
||||
}
|
||||
|
|
|
@ -473,7 +473,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||
}
|
||||
var nw APINetwork
|
||||
if apiReadObj(out, req, &nw) == nil {
|
||||
n := node.GetNetwork(nw.ID)
|
||||
n := node.Network(nw.ID)
|
||||
if n == nil {
|
||||
if nw.ControllerFingerprint != nil && nw.ControllerFingerprint.Address != nw.ID.Controller() {
|
||||
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"fingerprint's address does not match what should be the controller's address"})
|
||||
|
|
|
@ -24,11 +24,20 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// FingerprintHashSize is the length of a fingerprint hash in bytes.
|
||||
const FingerprintHashSize = 48
|
||||
|
||||
// Fingerprint bundles an address with an optional SHA384 full hash of the identity's key(s).
|
||||
type Fingerprint struct {
|
||||
Address Address
|
||||
Hash []byte
|
||||
}
|
||||
|
||||
// NewFingerprintFromString decodes a string-format fingerprint.
|
||||
// A fingerprint has the format address-hash, where address is a 10-digit
|
||||
// ZeroTier address and a hash is a base32-encoded SHA384 hash. Fingerprints
|
||||
// can be missing the hash in which case they are represented the same as
|
||||
// an Address and the hash field will be nil.
|
||||
func NewFingerprintFromString(fps string) (*Fingerprint, error) {
|
||||
if len(fps) < AddressStringLength {
|
||||
return nil, ErrInvalidZeroTierAddress
|
||||
|
@ -66,22 +75,28 @@ func newFingerprintFromCFingerprint(cfp *C.ZT_Fingerprint) *Fingerprint {
|
|||
return &fp
|
||||
}
|
||||
|
||||
// String returns an address or a full address-hash depenting on whether a hash is present.
|
||||
func (fp *Fingerprint) String() string {
|
||||
if len(fp.Hash) == 48 {
|
||||
if len(fp.Hash) == FingerprintHashSize {
|
||||
return fmt.Sprintf("%.10x-%s", uint64(fp.Address), Base32StdLowerCase.EncodeToString(fp.Hash))
|
||||
}
|
||||
return fp.Address.String()
|
||||
}
|
||||
|
||||
// Equals test for full equality with another fingerprint (including hash).
|
||||
func (fp *Fingerprint) Equals(fp2 *Fingerprint) bool {
|
||||
return fp.Address == fp2.Address && bytes.Equal(fp.Hash[:], fp2.Hash[:])
|
||||
}
|
||||
|
||||
func (fp *Fingerprint) cFingerprint() *C.ZT_Fingerprint {
|
||||
var apifp C.ZT_Fingerprint
|
||||
apifp.address = C.uint64_t(fp.Address)
|
||||
copy((*[48]byte)(unsafe.Pointer(&apifp.hash[0]))[:], fp.Hash[:])
|
||||
return &apifp
|
||||
// BestSpecificityEquals compares either just the addresses or also the hashes if both are present.
|
||||
func (fp *Fingerprint) BestSpecificityEquals(fp2 *Fingerprint) bool {
|
||||
if fp2 == nil || fp.Address != fp2.Address {
|
||||
return false
|
||||
}
|
||||
if len(fp.Hash) == FingerprintHashSize && len(fp2.Hash) == FingerprintHashSize {
|
||||
return bytes.Equal(fp.Hash, fp2.Hash)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (fp *Fingerprint) MarshalJSON() ([]byte, error) {
|
||||
|
@ -99,3 +114,10 @@ func (fp *Fingerprint) UnmarshalJSON(j []byte) error {
|
|||
fp.Hash = fp2.Hash
|
||||
return err
|
||||
}
|
||||
|
||||
func (fp *Fingerprint) cFingerprint() *C.ZT_Fingerprint {
|
||||
var apifp C.ZT_Fingerprint
|
||||
apifp.address = C.uint64_t(fp.Address)
|
||||
copy((*[48]byte)(unsafe.Pointer(&apifp.hash[0]))[:], fp.Hash[:])
|
||||
return &apifp
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ func (id *Identity) initCIdentityPtr() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// NewIdentity generates a new identity of the selected type
|
||||
// NewIdentity generates a new identity of the selected type.
|
||||
func NewIdentity(identityType int) (*Identity, error) {
|
||||
switch identityType {
|
||||
case C.ZT_IDENTITY_TYPE_C25519:
|
||||
|
@ -160,7 +160,7 @@ func NewIdentityFromString(s string) (*Identity, error) {
|
|||
return id, nil
|
||||
}
|
||||
|
||||
// Address returns this identity's address
|
||||
// Address returns this identity's address.
|
||||
func (id *Identity) Address() Address { return id.address }
|
||||
|
||||
// HasPrivate returns true if this identity has its own private portion.
|
||||
|
@ -172,7 +172,8 @@ func (id *Identity) Fingerprint() *Fingerprint {
|
|||
return newFingerprintFromCFingerprint(C.ZT_Identity_fingerprint(id.cid))
|
||||
}
|
||||
|
||||
// PrivateKeyString returns the full identity.secret if the private key is set, or an empty string if no private key is set.
|
||||
// PrivateKeyString returns the full identity.secret if the private key is set,
|
||||
// or an empty string if no private key is set.
|
||||
func (id *Identity) PrivateKeyString() string {
|
||||
switch id.idtype {
|
||||
case IdentityTypeC25519:
|
||||
|
@ -253,12 +254,10 @@ func (id *Identity) Equals(id2 *Identity) bool {
|
|||
return id.address == id2.address && id.idtype == id2.idtype && bytes.Equal(id.publicKey, id2.publicKey) && bytes.Equal(id.privateKey, id2.privateKey)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals this Identity in its string format (private key is never included)
|
||||
func (id *Identity) MarshalJSON() ([]byte, error) {
|
||||
return []byte("\"" + id.String() + "\""), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this Identity from a string
|
||||
func (id *Identity) UnmarshalJSON(j []byte) error {
|
||||
var s string
|
||||
err := json.Unmarshal(j, &s)
|
||||
|
|
|
@ -155,7 +155,7 @@ func newNetwork(node *Node, id NetworkID, t Tap) (*Network, error) {
|
|||
config: NetworkConfig{
|
||||
ID: id,
|
||||
MAC: m,
|
||||
Status: NetworkStatusRequestConfiguration,
|
||||
Status: NetworkStatusRequestingConfiguration,
|
||||
Type: NetworkTypePrivate,
|
||||
MTU: int(defaultVirtualNetworkMTU),
|
||||
},
|
||||
|
|
|
@ -47,12 +47,14 @@ var nullLogger = log.New(ioutil.Discard, "", 0)
|
|||
|
||||
const (
|
||||
NetworkIDStringLength = 16
|
||||
NEtworkIDLength = 8
|
||||
AddressStringLength = 10
|
||||
AddressLength = 5
|
||||
|
||||
NetworkStatusRequestConfiguration int = C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION
|
||||
NetworkStatusOK int = C.ZT_NETWORK_STATUS_OK
|
||||
NetworkStatusAccessDenied int = C.ZT_NETWORK_STATUS_ACCESS_DENIED
|
||||
NetworkStatusNotFound int = C.ZT_NETWORK_STATUS_NOT_FOUND
|
||||
NetworkStatusRequestingConfiguration int = C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION
|
||||
NetworkStatusOK int = C.ZT_NETWORK_STATUS_OK
|
||||
NetworkStatusAccessDenied int = C.ZT_NETWORK_STATUS_ACCESS_DENIED
|
||||
NetworkStatusNotFound int = C.ZT_NETWORK_STATUS_NOT_FOUND
|
||||
|
||||
NetworkTypePrivate int = C.ZT_NETWORK_TYPE_PRIVATE
|
||||
NetworkTypePublic int = C.ZT_NETWORK_TYPE_PUBLIC
|
||||
|
@ -62,7 +64,8 @@ const (
|
|||
|
||||
defaultVirtualNetworkMTU = C.ZT_DEFAULT_MTU
|
||||
|
||||
// maxCNodeRefs is the maximum number of Node instances that can be created in this process (increasing is fine)
|
||||
// maxCNodeRefs is the maximum number of Node instances that can be created in this process.
|
||||
// This is perfectly fine to increase.
|
||||
maxCNodeRefs = 8
|
||||
)
|
||||
|
||||
|
@ -73,7 +76,10 @@ var (
|
|||
CoreVersionRevision int
|
||||
CoreVersionBuild int
|
||||
|
||||
cNodeRefs [maxCNodeRefs]*Node
|
||||
// cNodeRefs maps an index to a *Node
|
||||
cNodeRefs [maxCNodeRefs]*Node
|
||||
|
||||
// cNodeRefsUsed maps an index to whether or not the corresponding cNodeRefs[] entry is used.
|
||||
cNodeRefUsed [maxCNodeRefs]uint32
|
||||
)
|
||||
|
||||
|
@ -92,7 +98,9 @@ type Node struct {
|
|||
// Time this node was created
|
||||
startupTime int64
|
||||
|
||||
// an arbitrary uintptr given to the core as its pointer back to Go's Node instance
|
||||
// an arbitrary uintptr given to the core as its pointer back to Go's Node instance.
|
||||
// This is an index in the cNodeRefs array, which is synchronized by way of a set of
|
||||
// used/free booleans accessed atomically.
|
||||
cPtr uintptr
|
||||
|
||||
// networks contains networks we have joined, and networksByMAC by their local MAC address
|
||||
|
@ -100,13 +108,14 @@ type Node struct {
|
|||
networksByMAC map[MAC]*Network // locked by networksLock
|
||||
networksLock sync.RWMutex
|
||||
|
||||
// interfaceAddresses are physical IPs assigned to the local machine (detected, not configured)
|
||||
// interfaceAddresses are physical IPs assigned to the local machine.
|
||||
// These are the detected IPs, not those configured explicitly. They include
|
||||
// both private and global IPs.
|
||||
interfaceAddresses map[string]net.IP
|
||||
interfaceAddressesLock sync.Mutex
|
||||
|
||||
// online and running are atomic flags set to control and monitor background tasks
|
||||
online uint32
|
||||
running uint32
|
||||
online uint32
|
||||
|
||||
basePath string
|
||||
peersPath string
|
||||
|
@ -115,20 +124,20 @@ type Node struct {
|
|||
infoLogPath string
|
||||
errorLogPath string
|
||||
|
||||
// localConfig is the current state of local.conf
|
||||
// localConfig is the current state of local.conf.
|
||||
localConfig *LocalConfig
|
||||
previousLocalConfig *LocalConfig
|
||||
localConfigLock sync.RWMutex
|
||||
|
||||
// logs for information, errors, and trace output
|
||||
infoLogW *sizeLimitWriter
|
||||
errLogW *sizeLimitWriter
|
||||
traceLogW io.Writer
|
||||
infoLog *log.Logger
|
||||
errLog *log.Logger
|
||||
traceLog *log.Logger
|
||||
|
||||
// gn is the GoNode instance
|
||||
infoLog *log.Logger
|
||||
errLog *log.Logger
|
||||
traceLog *log.Logger
|
||||
|
||||
// gn is the GoNode instance, see go/native/GoNode.hpp
|
||||
gn *C.ZT_GoNode
|
||||
|
||||
// zn is the underlying ZT_Node (ZeroTier::Node) instance
|
||||
|
@ -137,11 +146,12 @@ type Node struct {
|
|||
// id is the identity of this node (includes private key)
|
||||
id *Identity
|
||||
|
||||
// HTTP server instances: one for a named socket (Unix domain or Windows named pipe) and one on a local TCP socket
|
||||
namedSocketApiServer *http.Server
|
||||
tcpApiServer *http.Server
|
||||
namedSocketAPIServer *http.Server
|
||||
tcpAPIServer *http.Server
|
||||
|
||||
// runWaitGroup is used to wait for all node goroutines on shutdown
|
||||
// runWaitGroup is used to wait for all node goroutines on shutdown.
|
||||
// Any new goroutine is tracked via this wait group so node shutdown can
|
||||
// itself wait until all goroutines have exited.
|
||||
runWaitGroup sync.WaitGroup
|
||||
}
|
||||
|
||||
|
@ -163,8 +173,11 @@ func NewNode(basePath string) (n *Node, err error) {
|
|||
}
|
||||
}
|
||||
if cPtr < 0 {
|
||||
return nil, errors.New("too many nodes in this instance")
|
||||
return nil, ErrInternal
|
||||
}
|
||||
|
||||
// Check and delete node reference pointer if it's non-negative. This helps
|
||||
// with error handling cleanup. At the end we set cPtr to -1 to disable.
|
||||
defer func() {
|
||||
if cPtr >= 0 {
|
||||
atomic.StoreUint32(&cNodeRefUsed[cPtr], 0)
|
||||
|
@ -175,7 +188,7 @@ func NewNode(basePath string) (n *Node, err error) {
|
|||
n.networks = make(map[NetworkID]*Network)
|
||||
n.networksByMAC = make(map[MAC]*Network)
|
||||
n.interfaceAddresses = make(map[string]net.IP)
|
||||
n.online = 0
|
||||
|
||||
n.running = 1
|
||||
|
||||
_ = os.MkdirAll(basePath, 0755)
|
||||
|
@ -265,7 +278,7 @@ func NewNode(basePath string) (n *Node, err error) {
|
|||
_ = n.localConfig.Write(n.localConfigPath)
|
||||
}
|
||||
|
||||
n.namedSocketApiServer, n.tcpApiServer, err = createAPIServer(basePath, n)
|
||||
n.namedSocketAPIServer, n.tcpAPIServer, err = createAPIServer(basePath, n)
|
||||
if err != nil {
|
||||
n.infoLog.Printf("FATAL: unable to start API server: %s", err.Error())
|
||||
return nil, err
|
||||
|
@ -293,12 +306,13 @@ func NewNode(basePath string) (n *Node, err error) {
|
|||
defer n.runWaitGroup.Done()
|
||||
lastMaintenanceRun := int64(0)
|
||||
for atomic.LoadUint32(&n.running) != 0 {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
nowS := time.Now().Unix()
|
||||
if (nowS - lastMaintenanceRun) >= 30 {
|
||||
lastMaintenanceRun = nowS
|
||||
n.runMaintenance()
|
||||
}
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -311,11 +325,11 @@ func NewNode(basePath string) (n *Node, err error) {
|
|||
// Close closes this Node and frees its underlying C++ Node structures
|
||||
func (n *Node) Close() {
|
||||
if atomic.SwapUint32(&n.running, 0) != 0 {
|
||||
if n.namedSocketApiServer != nil {
|
||||
_ = n.namedSocketApiServer.Close()
|
||||
if n.namedSocketAPIServer != nil {
|
||||
_ = n.namedSocketAPIServer.Close()
|
||||
}
|
||||
if n.tcpApiServer != nil {
|
||||
_ = n.tcpApiServer.Close()
|
||||
if n.tcpAPIServer != nil {
|
||||
_ = n.tcpAPIServer.Close()
|
||||
}
|
||||
|
||||
C.ZT_GoNode_delete(n.gn)
|
||||
|
@ -369,9 +383,7 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error)
|
|||
}
|
||||
}
|
||||
|
||||
if n.localConfig.Settings.PrimaryPort != lc.Settings.PrimaryPort ||
|
||||
n.localConfig.Settings.SecondaryPort != lc.Settings.SecondaryPort ||
|
||||
n.localConfig.Settings.LogSizeMax != lc.Settings.LogSizeMax {
|
||||
if n.localConfig.Settings.PrimaryPort != lc.Settings.PrimaryPort || n.localConfig.Settings.SecondaryPort != lc.Settings.SecondaryPort || n.localConfig.Settings.LogSizeMax != lc.Settings.LogSizeMax {
|
||||
restartRequired = true
|
||||
}
|
||||
|
||||
|
@ -437,17 +449,29 @@ func (n *Node) Leave(nwid NetworkID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (n *Node) AddRoot(id *Identity, loc *Locator) (*Peer, error) {
|
||||
// TODO
|
||||
return nil, nil
|
||||
// AddRoot designates a peer as root, adding it if missing.
|
||||
func (n *Node) AddRoot(id *Identity) (*Peer, error) {
|
||||
if !id.initCIdentityPtr() {
|
||||
return nil, ErrInvalidKey
|
||||
}
|
||||
rc := C.ZT_Node_addRoot(n.zn, nil, id.cid)
|
||||
if rc != 0 {
|
||||
return nil, ErrInvalidParameter
|
||||
}
|
||||
p := n.Peer(id.Fingerprint())
|
||||
if p == nil {
|
||||
return nil, ErrInvalidParameter
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// RemoveRoot un-designates a peer as root.
|
||||
func (n *Node) RemoveRoot(address Address) {
|
||||
C.ZT_Node_removeRoot(n.zn, nil, C.uint64_t(address))
|
||||
}
|
||||
|
||||
// GetNetwork looks up a network by ID or returns nil if not joined
|
||||
func (n *Node) GetNetwork(nwid NetworkID) *Network {
|
||||
// Network looks up a network by ID or returns nil if not joined
|
||||
func (n *Node) Network(nwid NetworkID) *Network {
|
||||
n.networksLock.RLock()
|
||||
nw := n.networks[nwid]
|
||||
n.networksLock.RUnlock()
|
||||
|
@ -484,6 +508,32 @@ func (n *Node) Peers() []*Peer {
|
|||
return peers
|
||||
}
|
||||
|
||||
// Peer looks up a single peer by address or full fingerprint.
|
||||
// The fpOrAddress parameter may be either. If it is neither nil is returned.
|
||||
// A nil pointer is returned if nothing is found.
|
||||
func (n *Node) Peer(fpOrAddress interface{}) *Peer {
|
||||
fp, _ := fpOrAddress.(*Fingerprint)
|
||||
if fp == nil {
|
||||
a, _ := fpOrAddress.(*Address)
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
fp = &Fingerprint{Address: *a}
|
||||
}
|
||||
pl := C.ZT_Node_peers(n.zn)
|
||||
if pl != nil {
|
||||
for i := uintptr(0); i < uintptr(pl.peerCount); i++ {
|
||||
p, _ := newPeerFromCPeer((*C.ZT_Peer)(unsafe.Pointer(uintptr(unsafe.Pointer(pl.peers)) + (i * C.sizeof_ZT_Peer))))
|
||||
if p != nil && p.Identity.Fingerprint().BestSpecificityEquals(fp) {
|
||||
C.ZT_freeQueryResult(unsafe.Pointer(pl))
|
||||
return p
|
||||
}
|
||||
}
|
||||
C.ZT_freeQueryResult(unsafe.Pointer(pl))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddPeer adds a peer by explicit identity.
|
||||
func (n *Node) AddPeer(id *Identity) error {
|
||||
if id == nil {
|
||||
|
|
Loading…
Add table
Reference in a new issue