diff --git a/go/go.mod b/go/go.mod index bad0f7cf4..8c49ab486 100644 --- a/go/go.mod +++ b/go/go.mod @@ -1,3 +1,5 @@ module zerotier go 1.13 + +require github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 diff --git a/go/go.sum b/go/go.sum index e69de29bb..ad7bf1bb3 100644 --- a/go/go.sum +++ b/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= diff --git a/go/native/GoGlue.cpp b/go/native/GoGlue.cpp index bd7509237..741141856 100644 --- a/go/native/GoGlue.cpp +++ b/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) { diff --git a/go/pkg/zerotier/node-callbacks.go b/go/pkg/zerotier/node-callbacks.go index fd9593df1..ad6e49081 100644 --- a/go/pkg/zerotier/node-callbacks.go +++ b/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)] diff --git a/go/pkg/zerotier/node.go b/go/pkg/zerotier/node.go index d31c77728..5cbd79fde 100644 --- a/go/pkg/zerotier/node.go +++ b/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 +//#include +//#include //#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 } diff --git a/go/pkg/zerotier/version.go b/go/pkg/zerotier/version.go new file mode 100644 index 000000000..52f0932e7 --- /dev/null +++ b/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 +)