Go code!
This commit is contained in:
parent
e0ddbc2f28
commit
b34aa10bf8
15 changed files with 668 additions and 300 deletions
25
go/pkg/zerotier/errors.go
Normal file
25
go/pkg/zerotier/errors.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
// Err is a basic string error type for ZeroTier
|
||||
type Err string
|
||||
|
||||
func (e Err) Error() string { return (string)(e) }
|
||||
|
||||
// Simple ZeroTier Errors
|
||||
const (
|
||||
ErrInvalidMACAddress Err = "invalid MAC address"
|
||||
ErrInvalidParameter Err = "invalid parameter"
|
||||
)
|
63
go/pkg/zerotier/mac.go
Normal file
63
go/pkg/zerotier/mac.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MAC represents an Ethernet hardware address
|
||||
type MAC uint64
|
||||
|
||||
// NewMACFromString decodes a MAC address in canonical colon-separated hex format
|
||||
func NewMACFromString(s string) (MAC, error) {
|
||||
ss := strings.Split(s, ":")
|
||||
if len(ss) != 6 {
|
||||
return MAC(0), ErrInvalidMACAddress
|
||||
}
|
||||
var m uint64
|
||||
for i := 0; i < 6; i++ {
|
||||
m <<= 8
|
||||
c, _ := strconv.ParseUint(ss[i], 16, 64)
|
||||
if c > 0xff {
|
||||
return MAC(0), ErrInvalidMACAddress
|
||||
}
|
||||
m |= (c & 0xff)
|
||||
}
|
||||
return MAC(m), nil
|
||||
}
|
||||
|
||||
// String returns this MAC address in canonical human-readable form
|
||||
func (m MAC) String() string {
|
||||
return fmt.Sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (m>>40)&0xff, (m>>32)&0xff, (m>>24)&0xff, (m>>16)&0xff, (m>>8)&0xff, m&0xff)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals this MAC as a string
|
||||
func (m MAC) MarshalJSON() ([]byte, error) {
|
||||
return []byte(m.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this MAC from a string
|
||||
func (m *MAC) UnmarshalJSON(j []byte) error {
|
||||
var s string
|
||||
err := json.Unmarshal(j, &s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m, err = NewMACFromString(s)
|
||||
return err
|
||||
}
|
19
go/pkg/zerotier/misc.go
Normal file
19
go/pkg/zerotier/misc.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import "time"
|
||||
|
||||
// TimeMs returns the time in milliseconds since epoch.
|
||||
func TimeMs() int64 { return int64(time.Now().UnixNano()) / int64(1000000) }
|
20
go/pkg/zerotier/multicastgroup.go
Normal file
20
go/pkg/zerotier/multicastgroup.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
// MulticastGroup represents a normal Ethernet multicast or broadcast address plus 32 additional ZeroTier-specific bits
|
||||
type MulticastGroup struct {
|
||||
MAC MAC
|
||||
ADI uint32
|
||||
}
|
74
go/pkg/zerotier/network.go
Normal file
74
go/pkg/zerotier/network.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NetworkConfig represents the network's current state
|
||||
type NetworkConfig struct {
|
||||
// ID is this network's 64-bit globally unique identifier
|
||||
ID uint64
|
||||
|
||||
// MAC is the Ethernet MAC address of this device on this network
|
||||
MAC MAC
|
||||
|
||||
// Name is a short human-readable name set by the controller
|
||||
Name string
|
||||
|
||||
// Status is a status code indicating this network's authorization status
|
||||
Status int
|
||||
|
||||
// LastUpdated is the time this network's configuration was last updated from the controller
|
||||
LastUpdated time.Time
|
||||
|
||||
// Type is this network's type
|
||||
Type int
|
||||
|
||||
// MTU is the Ethernet MTU for this network
|
||||
MTU int
|
||||
|
||||
// CanBridge is true if this network is allowed to bridge in other devices with different Ethernet addresses
|
||||
CanBridge bool
|
||||
|
||||
// AllowsBroadcast is true if the broadcast (ff:ff:ff:ff:ff:ff) address works (excluding IPv4 ARP which is handled via a special path)
|
||||
AllowsBroadcast bool
|
||||
|
||||
// IPs are static IPs assigned by the network controller to this device
|
||||
IPs []net.IPNet
|
||||
|
||||
// Routes are static routes assigned by the network controller to this device
|
||||
Routes []Route
|
||||
|
||||
// MulticastSubscriptions are this device's current multicast subscriptions
|
||||
MulticastSubscriptions []MulticastGroup
|
||||
|
||||
// PortType is a human-readable description of this port's implementation type or name
|
||||
PortType string
|
||||
|
||||
// PortDeviceName is the OS-specific device name (e.g. tun0 or feth1856) for this network's virtual port
|
||||
PortDeviceName string
|
||||
|
||||
// PortErrorCode is an OS-specific error code returned by the virtual NIC driver
|
||||
PortErrorCode int
|
||||
}
|
||||
|
||||
// Network is a currently joined network
|
||||
type Network struct {
|
||||
config atomic.Value
|
||||
tap atomic.Value
|
||||
}
|
180
go/pkg/zerotier/node-callbacks.go
Normal file
180
go/pkg/zerotier/node-callbacks.go
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
//#cgo CFLAGS: -O3
|
||||
//#define ZT_CGO 1
|
||||
//#include <stdint.h>
|
||||
//#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
//#include "../../native/GoGlue.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
afInet = C.AF_INET
|
||||
afInet6 = C.AF_INET6
|
||||
|
||||
networkStatusRequestingConfiguration = C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION
|
||||
networkStatusOK = C.ZT_NETWORK_STATUS_OK
|
||||
networkStatusAccessDenied = C.ZT_NETWORK_STATUS_ACCESS_DENIED
|
||||
networkStatusNotFound = C.ZT_NETWORK_STATUS_NOT_FOUND
|
||||
networkStatusPortError = C.ZT_NETWORK_STATUS_PORT_ERROR
|
||||
networkStatusClientTooOld = C.ZT_NETWORK_STATUS_CLIENT_TOO_OLD
|
||||
)
|
||||
|
||||
var (
|
||||
nodesByUserPtr map[uintptr]*Node
|
||||
nodesByUserPtrLock sync.RWMutex
|
||||
)
|
||||
|
||||
//export goPathCheckFunc
|
||||
func goPathCheckFunc(gn unsafe.Pointer, ztAddress C.uint64_t, af C.int, ip unsafe.Pointer, port C.int) C.int {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node != nil && node.pathCheck(uint64(ztAddress), int(af), nil, int(port)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//export goPathLookupFunc
|
||||
func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFamily int, familyP, ipP, portP unsafe.Pointer) C.int {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
ip, port := node.pathLookup(uint64(ztAddress))
|
||||
ip4 := ip.To4()
|
||||
if len(ip4) == 4 {
|
||||
*((*C.int)(familyP)) = afInet
|
||||
copy((*[4]byte)(ipP)[:], ip4)
|
||||
*((*C.int)(portP)) = C.int(port)
|
||||
} else if len(ip) == 16 {
|
||||
*((*C.int)(familyP)) = afInet6
|
||||
copy((*[16]byte)(ipP)[:], ip)
|
||||
*((*C.int)(portP)) = C.int(port)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//export goStateObjectPutFunc
|
||||
func goStateObjectPutFunc(gn unsafe.Pointer, objType C.int, id, data unsafe.Pointer, len C.int) {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
if len < 0 {
|
||||
node.stateObjectDelete(int(objType), *((*[2]uint64)(id)))
|
||||
} else {
|
||||
node.stateObjectPut(int(objType), *((*[2]uint64)(id)), C.GoBytes(data, len))
|
||||
}
|
||||
}
|
||||
|
||||
//export goStateObjectGetFunc
|
||||
func goStateObjectGetFunc(gn unsafe.Pointer, objType C.int, id, data unsafe.Pointer, bufSize C.uint) C.int {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return -1
|
||||
}
|
||||
tmp, found := node.stateObjectGet(int(objType), *((*[2]uint64)(id)))
|
||||
if found && len(tmp) < int(bufSize) {
|
||||
if len(tmp) > 0 {
|
||||
C.memcpy(data, unsafe.Pointer(&(tmp[0])), C.ulong(len(tmp)))
|
||||
}
|
||||
return C.int(len(tmp))
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
//export goDNSResolverFunc
|
||||
func goDNSResolverFunc(gn unsafe.Pointer, dnsRecordTypes unsafe.Pointer, numDNSRecordTypes C.int, name unsafe.Pointer, requestID C.uintptr_t) {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
|
||||
recordTypes := C.GoBytes(dnsRecordTypes, numDNSRecordTypes)
|
||||
recordName := C.GoString((*C.char)(name))
|
||||
|
||||
go func() {
|
||||
recordNameCStrCopy := C.CString(recordName)
|
||||
for _, rt := range recordTypes {
|
||||
switch rt {
|
||||
case C.ZT_DNS_RECORD_TXT:
|
||||
recs, _ := net.LookupTXT(recordName)
|
||||
for _, rec := range recs {
|
||||
if len(rec) > 0 {
|
||||
rnCS := C.CString(rec)
|
||||
C.ZT_Node_processDNSResult(unsafe.Pointer(node.zn), nil, requestID, recordNameCStrCopy, C.ZT_DNS_RECORD_TXT, unsafe.Pointer(rnCS), C.uint(len(rec)), 0)
|
||||
C.free(unsafe.Pointer(rnCS))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
C.ZT_Node_processDNSResult(unsafe.Pointer(node.zn), nil, requestID, recordNameCStrCopy, C.ZT_DNS_RECORD__END_OF_RESULTS, nil, 0, 0)
|
||||
C.free(unsafe.Pointer(recordNameCStrCopy))
|
||||
}()
|
||||
}
|
||||
|
||||
//export goVirtualNetworkConfigFunc
|
||||
func goVirtualNetworkConfigFunc(gn, tapP unsafe.Pointer, nwid C.uint64_t, op C.int, conf unsafe.Pointer) C.int {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return 255
|
||||
}
|
||||
return C.int(node.handleNetworkConfigUpdate(int(op), (*C.ZT_VirtualNetworkConfig)(conf)))
|
||||
}
|
||||
|
||||
//export goZtEvent
|
||||
func goZtEvent(gn unsafe.Pointer, eventType C.int, data unsafe.Pointer) {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
switch eventType {
|
||||
case C.ZT_EVENT_OFFLINE:
|
||||
atomic.StoreUint32(&node.online, 0)
|
||||
case C.ZT_EVENT_ONLINE:
|
||||
atomic.StoreUint32(&node.online, 1)
|
||||
case C.ZT_EVENT_TRACE:
|
||||
node.handleTrace(C.GoString((*C.char)(data)))
|
||||
case C.ZT_EVENT_USER_MESSAGE:
|
||||
um := (*C.ZT_UserMessage)(data)
|
||||
node.handleUserMessage(uint64(um.origin), uint64(um.typeId), C.GoBytes(um.data, C.int(um.length)))
|
||||
case C.ZT_EVENT_REMOTE_TRACE:
|
||||
rt := (*C.ZT_RemoteTrace)(data)
|
||||
node.handleRemoteTrace(uint64(rt.origin), C.GoBytes(unsafe.Pointer(rt.data), C.int(rt.len)))
|
||||
}
|
||||
}
|
128
go/pkg/zerotier/node.go
Normal file
128
go/pkg/zerotier/node.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
//#cgo CFLAGS: -O3
|
||||
//#cgo LDFLAGS: ${SRCDIR}/../../../build/node/libzt_core.a ${SRCDIR}/../../../build/go/native/libzt_go_native.a -lc++
|
||||
//#define ZT_CGO 1
|
||||
//#include <stdint.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"
|
||||
import (
|
||||
"net"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
// Tap is an instance of an EthernetTap object
|
||||
type Tap struct {
|
||||
tap *C.ZT_GoTap
|
||||
networkStatus uint32
|
||||
}
|
||||
|
||||
// Node is an instance of a ZeroTier node
|
||||
type Node struct {
|
||||
gn *C.ZT_GoNode
|
||||
zn *C.ZT_Node
|
||||
|
||||
taps map[uint64]*Tap
|
||||
tapsLock sync.RWMutex
|
||||
|
||||
online uint32
|
||||
running uint32
|
||||
}
|
||||
|
||||
// NewNode creates and initializes a new instance of the ZeroTier node service
|
||||
func NewNode() *Node {
|
||||
n := new(Node)
|
||||
|
||||
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.running = 1
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// Close closes this Node and frees its underlying C++ Node structures
|
||||
func (n *Node) Close() {
|
||||
if atomic.SwapUint32(&n.running, 0) != 0 {
|
||||
C.ZT_GoNode_delete(n.gn)
|
||||
nodesByUserPtrLock.Lock()
|
||||
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n.gn)))
|
||||
nodesByUserPtrLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) pathCheck(ztAddress uint64, af int, ip net.IP, port int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (n *Node) pathLookup(ztAddress uint64) (net.IP, int) {
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
func (n *Node) stateObjectPut(objType int, id [2]uint64, data []byte) {
|
||||
}
|
||||
|
||||
func (n *Node) stateObjectDelete(objType int, id [2]uint64) {
|
||||
}
|
||||
|
||||
func (n *Node) stateObjectGet(objType int, id [2]uint64) ([]byte, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (n *Node) handleTrace(traceMessage string) {
|
||||
}
|
||||
|
||||
func (n *Node) handleUserMessage(originAddress, messageTypeID uint64, data []byte) {
|
||||
}
|
||||
|
||||
func (n *Node) handleRemoteTrace(originAddress uint64, dictData []byte) {
|
||||
}
|
||||
|
||||
func (n *Node) handleNetworkConfigUpdate(op int, config *C.ZT_VirtualNetworkConfig) int {
|
||||
return 0
|
||||
}
|
28
go/pkg/zerotier/route.go
Normal file
28
go/pkg/zerotier/route.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import "net"
|
||||
|
||||
// Route represents a route in a host's routing table
|
||||
type Route struct {
|
||||
// Target for this route
|
||||
Target net.IPNet
|
||||
|
||||
// Via is how to reach this target (null/empty if the target IP range is local to this virtual LAN)
|
||||
Via net.IP
|
||||
|
||||
// Metric is an interface metric that can affect route priority (behavior can be OS-specific)
|
||||
Metric int
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue