Adam Ierymenko 5 years ago
parent
commit
6ce4663a31
6 changed files with 176 additions and 43 deletions
  1. 2 0
      go/go.mod
  2. 4 0
      go/go.sum
  3. 5 0
      go/native/GoGlue.cpp
  4. 16 10
      go/pkg/zerotier/node-callbacks.go
  5. 111 33
      go/pkg/zerotier/node.go
  6. 38 0
      go/pkg/zerotier/version.go

+ 2 - 0
go/go.mod

@@ -1,3 +1,5 @@
 module zerotier
 
 go 1.13
+
+require github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95

+ 4 - 0
go/go.sum

@@ -0,0 +1,4 @@
+github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 h1:S4qyfL2sEm5Budr4KVMyEniCy+PbS55651I/a+Kn/NQ=
+github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E=
+golang.org/x/sys v0.0.0-20190529164535-6a60838ec259 h1:so6Hr/LodwSZ5UQDu/7PmQiDeS112WwtLvU3lpSPZTU=
+golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

+ 5 - 0
go/native/GoGlue.cpp

@@ -391,6 +391,11 @@ extern "C" void ZT_GoNode_delete(ZT_GoNode *gn)
 	delete gn;
 }
 
+extern "C" ZT_Node *ZT_GoNode_getNode(ZT_GoNode *gn)
+{
+	return gn->node;
+}
+
 // Sets flags and socket options common to both IPv4 and IPv6 UDP sockets
 static void setCommonUdpSocketSettings(ZT_SOCKET udpSock,const char *dev)
 {

+ 16 - 10
go/pkg/zerotier/node-callbacks.go

@@ -68,15 +68,19 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFam
 	}
 
 	ip, port := node.pathLookup(uint64(ztAddress))
-	ip4 := ip.To4()
-	if len(ip4) == 4 {
-		*((*C.int)(familyP)) = C.int(afInet)
-		copy((*[4]byte)(ipP)[:], ip4)
-		*((*C.int)(portP)) = C.int(port)
-	} else if len(ip) == 16 {
-		*((*C.int)(familyP)) = C.int(afInet6)
-		copy((*[16]byte)(ipP)[:], ip)
-		*((*C.int)(portP)) = C.int(port)
+	if len(ip) > 0 && port > 0 && port <= 65535 {
+		ip4 := ip.To4()
+		if len(ip4) == 4 {
+			*((*C.int)(familyP)) = C.int(afInet)
+			copy((*[4]byte)(ipP)[:], ip4)
+			*((*C.int)(portP)) = C.int(port)
+			return 1
+		} else if len(ip) == 16 {
+			*((*C.int)(familyP)) = C.int(afInet6)
+			copy((*[16]byte)(ipP)[:], ip)
+			*((*C.int)(portP)) = C.int(port)
+			return 1
+		}
 	}
 	return 0
 }
@@ -154,7 +158,7 @@ func goVirtualNetworkConfigFunc(gn, tapP unsafe.Pointer, nwid C.uint64_t, op C.i
 	if node == nil {
 		return 255
 	}
-	return C.int(node.handleNetworkConfigUpdate(int(op), (*C.ZT_VirtualNetworkConfig)(conf)))
+	return C.int(node.handleNetworkConfigUpdate(uint64(nwid), int(op), (*C.ZT_VirtualNetworkConfig)(conf)))
 }
 
 //export goZtEvent
@@ -181,6 +185,8 @@ func goZtEvent(gn unsafe.Pointer, eventType C.int, data unsafe.Pointer) {
 	}
 }
 
+// These are really part of nativeTap
+
 func handleTapMulticastGroupChange(gn unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t, added bool) {
 	nodesByUserPtrLock.RLock()
 	node := nodesByUserPtr[uintptr(gn)]

+ 111 - 33
go/pkg/zerotier/node.go

@@ -14,74 +14,77 @@
 package zerotier
 
 import (
+	"errors"
+	"fmt"
+	"io/ioutil"
 	"net"
-	"runtime"
+	"os"
+	"path"
 	"sync"
 	"sync/atomic"
+	"time"
 	"unsafe"
+
+	acl "github.com/hectane/go-acl"
 )
 
 //#cgo CFLAGS: -O3
-//#cgo LDFLAGS: ${SRCDIR}/../../../build/node/libzt_core.a ${SRCDIR}/../../../build/go/native/libzt_go_native.a -lc++ -lpthread
+//#cgo LDFLAGS: ${SRCDIR}/../../../build/node/libzt_core.a ${SRCDIR}/../../../build/osdep/libzt_osdep.a ${SRCDIR}/../../../build/go/native/libzt_go_native.a -lc++ -lpthread
 //#define ZT_CGO 1
 //#include <stdint.h>
+//#include <stdlib.h>
+//#include <string.h>
 //#include "../../native/GoGlue.h"
-//#if __has_include("../../../version.h")
-//#include "../../../version.h"
-//#else
-//#define ZEROTIER_ONE_VERSION_MAJOR 255
-//#define ZEROTIER_ONE_VERSION_MINOR 255
-//#define ZEROTIER_ONE_VERSION_REVISION 255
-//#define ZEROTIER_ONE_VERSION_BUILD 255
-//#endif
 import "C"
 
+// Network status states
 const (
-	// CoreVersionMajor is the major version of the ZeroTier core
-	CoreVersionMajor int = C.ZEROTIER_ONE_VERSION_MAJOR
-
-	// CoreVersionMinor is the minor version of the ZeroTier core
-	CoreVersionMinor int = C.ZEROTIER_ONE_VERSION_MINOR
-
-	// CoreVersionRevision is the revision of the ZeroTier core
-	CoreVersionRevision int = C.ZEROTIER_ONE_VERSION_REVISION
-
-	// CoreVersionBuild is the build version of the ZeroTier core
-	CoreVersionBuild int = C.ZEROTIER_ONE_VERSION_BUILD
+	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
+	NetworkStatusPortError            int = C.ZT_NETWORK_STATUS_PORT_ERROR
+	NetworkStatusClientTooOld         int = C.ZT_NETWORK_STATUS_CLIENT_TOO_OLD
 )
 
 //////////////////////////////////////////////////////////////////////////////
 
 // Node is an instance of a ZeroTier node
 type Node struct {
-	gn *C.ZT_GoNode
-	zn *C.ZT_Node
-
+	path         string
 	networks     map[uint64]*Network
 	networksLock sync.RWMutex
 
+	gn *C.ZT_GoNode
+	zn *C.ZT_Node
+
 	online  uint32
 	running uint32
 }
 
 // NewNode creates and initializes a new instance of the ZeroTier node service
-func NewNode() *Node {
+func NewNode(path string) (*Node, error) {
 	n := new(Node)
+	n.path = path
 	n.networks = make(map[uint64]*Network)
 
+	cpath := C.CString(path)
+	n.gn = C.ZT_GoNode_new(cpath)
+	C.free(unsafe.Pointer(cpath))
+	if n.gn == nil {
+		return nil, errors.New("unable to create new Node instance")
+	}
+	n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn))
+
 	gnRawAddr := uintptr(unsafe.Pointer(n.gn))
 	nodesByUserPtrLock.Lock()
 	nodesByUserPtr[gnRawAddr] = n
 	nodesByUserPtrLock.Unlock()
-	runtime.SetFinalizer(n, func(obj interface{}) { // make sure this always happens
-		nodesByUserPtrLock.Lock()
-		delete(nodesByUserPtr, gnRawAddr)
-		nodesByUserPtrLock.Unlock()
-	})
 
+	n.online = 0
 	n.running = 1
 
-	return n
+	return n, nil
 }
 
 // Close closes this Node and frees its underlying C++ Node structures
@@ -97,7 +100,35 @@ func (n *Node) Close() {
 // Join joins a network
 // If tap is nil, the default system tap for this OS/platform is used (if available).
 func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
-	return nil, nil
+	n.networksLock.RLock()
+	if nw, have := n.networks[nwid]; have {
+		return nw, nil
+	}
+	n.networksLock.RUnlock()
+
+	if tap != nil {
+		return nil, errors.New("not implemented yet")
+	}
+	ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid))
+	if ntap == nil {
+		return nil, errors.New("unable to initialize native tap (check device driver or permissions)")
+	}
+
+	nw := &Network{
+		id: NetworkID(nwid),
+		config: NetworkConfig{
+			ID:          NetworkID(nwid),
+			Status:      NetworkStatusRequestConfiguration,
+			LastUpdated: time.Now(),
+			Enabled:     true,
+		},
+		tap: &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1},
+	}
+	n.networksLock.Lock()
+	n.networks[nwid] = nw
+	n.networksLock.Unlock()
+
+	return nw, nil
 }
 
 // Leave leaves a network
@@ -115,13 +146,60 @@ func (n *Node) pathLookup(ztAddress uint64) (net.IP, int) {
 	return nil, 0
 }
 
+func (n *Node) makeStateObjectPath(objType int, id [2]uint64) (string, bool) {
+	var fp string
+	secret := false
+	switch objType {
+	case C.ZT_STATE_OBJECT_IDENTITY_PUBLIC:
+		fp = path.Join(n.path, "identity.public")
+	case C.ZT_STATE_OBJECT_IDENTITY_SECRET:
+		fp = path.Join(n.path, "identity.secret")
+		secret = true
+	case C.ZT_STATE_OBJECT_PEER:
+		fp = path.Join(n.path, "peers.d")
+		os.Mkdir(fp, 0755)
+		fp = path.Join(fp, fmt.Sprintf("%.10x.peer", id[0]))
+		secret = true
+	case C.ZT_STATE_OBJECT_NETWORK_CONFIG:
+		fp = path.Join(n.path, "networks.d")
+		os.Mkdir(fp, 0755)
+		fp = path.Join(fp, fmt.Sprintf("%.16x.conf", id[0]))
+	case C.ZT_STATE_OBJECT_ROOT_LIST:
+		fp = path.Join(n.path, "roots")
+	}
+	return fp, secret
+}
+
 func (n *Node) stateObjectPut(objType int, id [2]uint64, data []byte) {
+	fp, secret := n.makeStateObjectPath(objType, id)
+	if len(fp) > 0 {
+		fileMode := os.FileMode(0644)
+		if secret {
+			fileMode = os.FileMode(0600)
+		}
+		ioutil.WriteFile(fp, data, fileMode)
+		if secret {
+			acl.Chmod(fp, 0600) // this emulates Unix chmod on Windows and uses os.Chmod on Unix-type systems
+		}
+	}
 }
 
 func (n *Node) stateObjectDelete(objType int, id [2]uint64) {
+	fp, _ := n.makeStateObjectPath(objType, id)
+	if len(fp) > 0 {
+		os.Remove(fp)
+	}
 }
 
 func (n *Node) stateObjectGet(objType int, id [2]uint64) ([]byte, bool) {
+	fp, _ := n.makeStateObjectPath(objType, id)
+	if len(fp) > 0 {
+		fd, err := ioutil.ReadFile(fp)
+		if err != nil {
+			return nil, false
+		}
+		return fd, true
+	}
 	return nil, false
 }
 
@@ -134,6 +212,6 @@ func (n *Node) handleUserMessage(originAddress, messageTypeID uint64, data []byt
 func (n *Node) handleRemoteTrace(originAddress uint64, dictData []byte) {
 }
 
-func (n *Node) handleNetworkConfigUpdate(op int, config *C.ZT_VirtualNetworkConfig) int {
+func (n *Node) handleNetworkConfigUpdate(nwid uint64, op int, config *C.ZT_VirtualNetworkConfig) int {
 	return 0
 }

+ 38 - 0
go/pkg/zerotier/version.go

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c)2019 ZeroTier, Inc.
+ *
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
+ *
+ * Change Date: 2023-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+package zerotier
+
+//#if __has_include("../../../version.h")
+//#include "../../../version.h"
+//#else
+//#define ZEROTIER_ONE_VERSION_MAJOR 255
+//#define ZEROTIER_ONE_VERSION_MINOR 255
+//#define ZEROTIER_ONE_VERSION_REVISION 255
+//#define ZEROTIER_ONE_VERSION_BUILD 255
+//#endif
+import "C"
+
+const (
+	// CoreVersionMajor is the major version of the ZeroTier core
+	CoreVersionMajor int = C.ZEROTIER_ONE_VERSION_MAJOR
+
+	// CoreVersionMinor is the minor version of the ZeroTier core
+	CoreVersionMinor int = C.ZEROTIER_ONE_VERSION_MINOR
+
+	// CoreVersionRevision is the revision of the ZeroTier core
+	CoreVersionRevision int = C.ZEROTIER_ONE_VERSION_REVISION
+
+	// CoreVersionBuild is the build version of the ZeroTier core
+	CoreVersionBuild int = C.ZEROTIER_ONE_VERSION_BUILD
+)