mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
.
This commit is contained in:
parent
70d5da1e2a
commit
536bc59abb
5 changed files with 390 additions and 55 deletions
145
go/pkg/zerotier/api.go
Normal file
145
go/pkg/zerotier/api.go
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type apiStatus struct {
|
||||||
|
Address Address
|
||||||
|
Clock int64
|
||||||
|
Config *LocalConfig
|
||||||
|
Online bool
|
||||||
|
Identity *Identity
|
||||||
|
Version string
|
||||||
|
VersionMajor int
|
||||||
|
VersionMinor int
|
||||||
|
VersionRevision int
|
||||||
|
VersionBuild int
|
||||||
|
}
|
||||||
|
|
||||||
|
type apiNetwork struct {
|
||||||
|
Config *NetworkConfig
|
||||||
|
Settings *NetworkLocalSettings
|
||||||
|
MulticastSubscriptions []*MulticastGroup
|
||||||
|
TapDeviceType string
|
||||||
|
TapDeviceName string
|
||||||
|
TapDeviceEnabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiSetStandardHeaders(out http.ResponseWriter) {
|
||||||
|
now := time.Now().UTC()
|
||||||
|
h := out.Header()
|
||||||
|
h.Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
h.Set("Expires", "0")
|
||||||
|
h.Set("Pragma", "no-cache")
|
||||||
|
h.Set("Date", now.Format(time.RFC1123))
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiSendObj(out http.ResponseWriter, req *http.Request, httpStatusCode int, obj interface{}) error {
|
||||||
|
h := out.Header()
|
||||||
|
h.Set("Content-Type", "application/json")
|
||||||
|
if req.Method == http.MethodHead {
|
||||||
|
out.WriteHeader(httpStatusCode)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var j []byte
|
||||||
|
var err error
|
||||||
|
if obj != nil {
|
||||||
|
j, err = json.Marshal(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteHeader(httpStatusCode)
|
||||||
|
_, err = out.Write(j)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (err error) {
|
||||||
|
err = json.NewDecoder(req.Body).Decode(&dest)
|
||||||
|
if err != nil {
|
||||||
|
apiSendObj(out, req, http.StatusBadRequest, nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// createAPIServer creates and starts an HTTP server for a given node
|
||||||
|
func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
||||||
|
smux := http.NewServeMux()
|
||||||
|
|
||||||
|
smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
apiSetStandardHeaders(out)
|
||||||
|
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
|
apiSendObj(out, req, http.StatusOK, nil)
|
||||||
|
} else {
|
||||||
|
out.Header().Set("Allow", "GET, HEAD")
|
||||||
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
apiSetStandardHeaders(out)
|
||||||
|
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
|
var status apiStatus
|
||||||
|
apiSendObj(out, req, http.StatusOK, &status)
|
||||||
|
} else {
|
||||||
|
out.Header().Set("Allow", "GET, HEAD")
|
||||||
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
apiSetStandardHeaders(out)
|
||||||
|
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
|
peers := node.Peers()
|
||||||
|
apiSendObj(out, req, http.StatusOK, peers)
|
||||||
|
} else {
|
||||||
|
out.Header().Set("Allow", "GET, HEAD")
|
||||||
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
apiSetStandardHeaders(out)
|
||||||
|
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
|
networks := node.Networks()
|
||||||
|
apiSendObj(out, req, http.StatusOK, networks)
|
||||||
|
} else {
|
||||||
|
out.Header().Set("Allow", "GET, HEAD")
|
||||||
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
unixListener, err := net.Listen("unix", path.Join(basePath, "apisocket"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
httpServer := &http.Server{
|
||||||
|
MaxHeaderBytes: 4096,
|
||||||
|
Handler: smux,
|
||||||
|
IdleTimeout: 10 * time.Second,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 600 * time.Second,
|
||||||
|
}
|
||||||
|
httpServer.SetKeepAlivesEnabled(true)
|
||||||
|
go httpServer.Serve(unixListener)
|
||||||
|
|
||||||
|
return httpServer, nil
|
||||||
|
}
|
|
@ -14,7 +14,11 @@
|
||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
rand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,33 +45,48 @@ type LocalConfigSettings struct {
|
||||||
|
|
||||||
// LocalConfig is the local.conf file and stores local settings for the node.
|
// LocalConfig is the local.conf file and stores local settings for the node.
|
||||||
type LocalConfig struct {
|
type LocalConfig struct {
|
||||||
Physical map[string]LocalConfigPhysicalPathConfiguration
|
Physical map[string]*LocalConfigPhysicalPathConfiguration
|
||||||
Virtual map[Address]LocalConfigVirtualAddressConfiguration
|
Virtual map[Address]*LocalConfigVirtualAddressConfiguration
|
||||||
|
Network map[NetworkID]*NetworkLocalSettings
|
||||||
Settings LocalConfigSettings
|
Settings LocalConfigSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocalConfig creates a new local.conf file with defaults
|
// Read this local config from a file, initializing to defaults if the file does not exist
|
||||||
func NewLocalConfig() *LocalConfig {
|
func (lc *LocalConfig) Read(p string) error {
|
||||||
lc := &LocalConfig{
|
if lc.Physical == nil {
|
||||||
Physical: make(map[string]LocalConfigPhysicalPathConfiguration),
|
lc.Physical = make(map[string]*LocalConfigPhysicalPathConfiguration)
|
||||||
Virtual: make(map[Address]LocalConfigVirtualAddressConfiguration),
|
lc.Virtual = make(map[Address]*LocalConfigVirtualAddressConfiguration)
|
||||||
Settings: LocalConfigSettings{
|
lc.Network = make(map[NetworkID]*NetworkLocalSettings)
|
||||||
PrimaryPort: 9993,
|
lc.Settings.PrimaryPort = 9993
|
||||||
SecondaryPort: 0,
|
lc.Settings.SecondaryPort = 16384 + (rand.Int() % 16384)
|
||||||
TertiaryPort: 0,
|
lc.Settings.TertiaryPort = 32768 + (rand.Int() % 16384)
|
||||||
PortMappingEnabled: true,
|
lc.Settings.PortMappingEnabled = true
|
||||||
MuiltipathMode: 0,
|
lc.Settings.MuiltipathMode = 0
|
||||||
},
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
lc.Settings.InterfacePrefixBlacklist = []string{"utun", "tun", "tap", "feth", "lo", "zt"}
|
||||||
|
case "linux":
|
||||||
|
lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "lo", "zt"}
|
||||||
|
case "freebsd", "openbsd", "netbsd", "illumos", "solaris", "dragonfly":
|
||||||
|
lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "zt"}
|
||||||
|
case "android":
|
||||||
|
lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap"}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch runtime.GOOS {
|
|
||||||
case "darwin":
|
data, err := ioutil.ReadFile(p)
|
||||||
lc.Settings.InterfacePrefixBlacklist = []string{"utun", "tun", "tap", "feth", "lo", "zt"}
|
if err != nil && err != os.ErrNotExist {
|
||||||
case "linux":
|
return err
|
||||||
lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "lo", "zt"}
|
|
||||||
case "freebsd", "openbsd", "netbsd", "illumos", "solaris", "dragonfly":
|
|
||||||
lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "zt"}
|
|
||||||
case "android":
|
|
||||||
lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap"}
|
|
||||||
}
|
}
|
||||||
return lc
|
|
||||||
|
return json.Unmarshal(data, lc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write this local config to a file
|
||||||
|
func (lc *LocalConfig) Write(p string) error {
|
||||||
|
data, err := json.MarshalIndent(lc, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ioutil.WriteFile(p, data, 0644)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,36 @@ func NewMACFromString(s string) (MAC, error) {
|
||||||
return MAC(m), nil
|
return MAC(m), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewMACFromBytes decodes a MAC from a 6-byte array
|
||||||
|
func NewMACFromBytes(b []byte) (MAC, error) {
|
||||||
|
if len(b) < 6 {
|
||||||
|
return MAC(0), ErrInvalidMACAddress
|
||||||
|
}
|
||||||
|
var m uint64
|
||||||
|
for i := 0; i < 6; i++ {
|
||||||
|
m <<= 8
|
||||||
|
m |= uint64(b[i])
|
||||||
|
}
|
||||||
|
return MAC(m), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMACForNetworkMember computes the static MAC for a given address and network ID
|
||||||
|
func NewMACForNetworkMember(addr Address, nwid NetworkID) MAC {
|
||||||
|
// This is the same algorithm as found in MAC::fromAddress() in MAC.hpp
|
||||||
|
firstOctetForNetwork := byte((byte(nwid) & 0xfe) | 0x02)
|
||||||
|
if firstOctetForNetwork == 0x52 {
|
||||||
|
firstOctetForNetwork = 0x32
|
||||||
|
}
|
||||||
|
m := uint64(firstOctetForNetwork) << 40
|
||||||
|
m |= uint64(addr)
|
||||||
|
m ^= ((uint64(nwid) >> 8) & 0xff) << 32
|
||||||
|
m ^= ((uint64(nwid) >> 16) & 0xff) << 24
|
||||||
|
m ^= ((uint64(nwid) >> 24) & 0xff) << 16
|
||||||
|
m ^= ((uint64(nwid) >> 32) & 0xff) << 8
|
||||||
|
m ^= (uint64(nwid) >> 40) & 0xff
|
||||||
|
return MAC(m)
|
||||||
|
}
|
||||||
|
|
||||||
// String returns this MAC address in canonical human-readable form
|
// String returns this MAC address in canonical human-readable form
|
||||||
func (m MAC) String() string {
|
func (m MAC) String() string {
|
||||||
return fmt.Sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (uint64(m)>>40)&0xff, (uint64(m)>>32)&0xff, (uint64(m)>>24)&0xff, (uint64(m)>>16)&0xff, (uint64(m)>>8)&0xff, uint64(m)&0xff)
|
return fmt.Sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (uint64(m)>>40)&0xff, (uint64(m)>>32)&0xff, (uint64(m)>>24)&0xff, (uint64(m)>>16)&0xff, (uint64(m)>>8)&0xff, uint64(m)&0xff)
|
||||||
|
|
|
@ -130,6 +130,7 @@ type NetworkLocalSettings struct {
|
||||||
type Network struct {
|
type Network struct {
|
||||||
node *Node
|
node *Node
|
||||||
id NetworkID
|
id NetworkID
|
||||||
|
mac MAC
|
||||||
tap Tap
|
tap Tap
|
||||||
config NetworkConfig
|
config NetworkConfig
|
||||||
settings NetworkLocalSettings // locked by configLock
|
settings NetworkLocalSettings // locked by configLock
|
||||||
|
@ -143,6 +144,7 @@ func newNetwork(node *Node, id NetworkID, t Tap) (*Network, error) {
|
||||||
n := &Network{
|
n := &Network{
|
||||||
node: node,
|
node: node,
|
||||||
id: id,
|
id: id,
|
||||||
|
mac: NewMACForNetworkMember(node.Identity().address, id),
|
||||||
tap: t,
|
tap: t,
|
||||||
config: NetworkConfig{
|
config: NetworkConfig{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -172,6 +174,12 @@ func newNetwork(node *Node, id NetworkID, t Tap) (*Network, error) {
|
||||||
// ID gets this network's unique ID
|
// ID gets this network's unique ID
|
||||||
func (n *Network) ID() NetworkID { return n.id }
|
func (n *Network) ID() NetworkID { return n.id }
|
||||||
|
|
||||||
|
// MAC returns the assigned MAC address of this network
|
||||||
|
func (n *Network) MAC() MAC { return n.mac }
|
||||||
|
|
||||||
|
// Tap gets this network's tap device
|
||||||
|
func (n *Network) Tap() Tap { return n.tap }
|
||||||
|
|
||||||
// Config returns a copy of this network's current configuration
|
// Config returns a copy of this network's current configuration
|
||||||
func (n *Network) Config() NetworkConfig {
|
func (n *Network) Config() NetworkConfig {
|
||||||
n.configLock.RLock()
|
n.configLock.RLock()
|
||||||
|
@ -179,9 +187,6 @@ func (n *Network) Config() NetworkConfig {
|
||||||
return n.config
|
return n.config
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tap gets this network's tap device
|
|
||||||
func (n *Network) Tap() Tap { return n.tap }
|
|
||||||
|
|
||||||
// SetLocalSettings modifies this network's local settings
|
// SetLocalSettings modifies this network's local settings
|
||||||
func (n *Network) SetLocalSettings(ls *NetworkLocalSettings) { n.updateConfig(nil, ls) }
|
func (n *Network) SetLocalSettings(ls *NetworkLocalSettings) { n.updateConfig(nil, ls) }
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,13 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
rand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
acl "github.com/hectane/go-acl"
|
acl "github.com/hectane/go-acl"
|
||||||
|
@ -131,31 +133,40 @@ func makeSockaddrStorage(ip net.IP, port int, ss *C.struct_sockaddr_storage) boo
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Node represents an instance of the ZeroTier core node and related C++ I/O code
|
// Node is an instance of the ZeroTier core node and related C++ I/O code
|
||||||
type Node struct {
|
type Node struct {
|
||||||
path string
|
basePath string
|
||||||
networks map[uint64]*Network
|
localConfig LocalConfig
|
||||||
networksLock sync.RWMutex
|
networks map[NetworkID]*Network
|
||||||
|
networksByMAC map[MAC]*Network // locked by networksLock
|
||||||
gn *C.ZT_GoNode
|
externalAddresses map[string]*net.IPNet
|
||||||
zn *C.ZT_Node
|
localConfigLock sync.RWMutex
|
||||||
|
networksLock sync.RWMutex
|
||||||
online uint32
|
externalAddressesLock sync.Mutex
|
||||||
running uint32
|
gn *C.ZT_GoNode
|
||||||
|
zn *C.ZT_Node
|
||||||
|
id *Identity
|
||||||
|
online uint32
|
||||||
|
running uint32
|
||||||
|
runLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNode creates and initializes a new instance of the ZeroTier node service
|
// NewNode creates and initializes a new instance of the ZeroTier node service
|
||||||
func NewNode(path string) (*Node, error) {
|
func NewNode(basePath string) (*Node, error) {
|
||||||
os.MkdirAll(path, 0755)
|
var err error
|
||||||
if _, err := os.Stat(path); err != nil {
|
|
||||||
|
os.MkdirAll(basePath, 0755)
|
||||||
|
if _, err := os.Stat(basePath); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n := new(Node)
|
n := new(Node)
|
||||||
n.path = path
|
n.basePath = basePath
|
||||||
n.networks = make(map[uint64]*Network)
|
n.networks = make(map[NetworkID]*Network)
|
||||||
|
n.networksByMAC = make(map[MAC]*Network)
|
||||||
|
n.externalAddresses = make(map[string]*net.IPNet)
|
||||||
|
|
||||||
cpath := C.CString(path)
|
cpath := C.CString(basePath)
|
||||||
n.gn = C.ZT_GoNode_new(cpath)
|
n.gn = C.ZT_GoNode_new(cpath)
|
||||||
C.free(unsafe.Pointer(cpath))
|
C.free(unsafe.Pointer(cpath))
|
||||||
if n.gn == nil {
|
if n.gn == nil {
|
||||||
|
@ -163,6 +174,14 @@ func NewNode(path string) (*Node, error) {
|
||||||
}
|
}
|
||||||
n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn))
|
n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn))
|
||||||
|
|
||||||
|
var ns C.ZT_NodeStatus
|
||||||
|
C.ZT_Node_status(unsafe.Pointer(n.zn), &ns)
|
||||||
|
n.id, err = NewIdentityFromString(C.GoString(ns.secretIdentity))
|
||||||
|
if err != nil {
|
||||||
|
C.ZT_GoNode_delete(n.gn)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
gnRawAddr := uintptr(unsafe.Pointer(n.gn))
|
gnRawAddr := uintptr(unsafe.Pointer(n.gn))
|
||||||
nodesByUserPtrLock.Lock()
|
nodesByUserPtrLock.Lock()
|
||||||
nodesByUserPtr[gnRawAddr] = n
|
nodesByUserPtr[gnRawAddr] = n
|
||||||
|
@ -171,6 +190,77 @@ func NewNode(path string) (*Node, error) {
|
||||||
n.online = 0
|
n.online = 0
|
||||||
n.running = 1
|
n.running = 1
|
||||||
|
|
||||||
|
n.runLock.Lock()
|
||||||
|
go func() {
|
||||||
|
lastScannedInterfaces := int64(0)
|
||||||
|
for atomic.LoadUint32(&n.running) != 0 {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
now := TimeMs()
|
||||||
|
if (now - lastScannedInterfaces) >= 30000 {
|
||||||
|
lastScannedInterfaces = now
|
||||||
|
|
||||||
|
externalAddresses := make(map[string]*net.IPNet)
|
||||||
|
ifs, _ := net.Interfaces()
|
||||||
|
if len(ifs) > 0 {
|
||||||
|
n.networksLock.RLock()
|
||||||
|
for _, i := range ifs {
|
||||||
|
m, _ := NewMACFromBytes(i.HardwareAddr)
|
||||||
|
if _, isZeroTier := n.networksByMAC[m]; !isZeroTier {
|
||||||
|
addrs, _ := i.Addrs()
|
||||||
|
if len(addrs) > 0 {
|
||||||
|
for _, a := range addrs {
|
||||||
|
ipn, _ := a.(*net.IPNet)
|
||||||
|
if ipn != nil {
|
||||||
|
externalAddresses[ipn.String()] = ipn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.networksLock.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
n.localConfigLock.RLock()
|
||||||
|
n.externalAddressesLock.Lock()
|
||||||
|
for astr, ipn := range externalAddresses {
|
||||||
|
if _, alreadyKnown := n.externalAddresses[astr]; !alreadyKnown {
|
||||||
|
ipCstr := C.CString(ipn.IP.String())
|
||||||
|
if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
|
||||||
|
C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.PrimaryPort))
|
||||||
|
}
|
||||||
|
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
|
||||||
|
C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.SecondaryPort))
|
||||||
|
}
|
||||||
|
if n.localConfig.Settings.TertiaryPort > 0 && n.localConfig.Settings.TertiaryPort < 65536 {
|
||||||
|
C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
|
||||||
|
}
|
||||||
|
C.free(unsafe.Pointer(ipCstr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for astr, ipn := range n.externalAddresses {
|
||||||
|
if _, stillPresent := externalAddresses[astr]; !stillPresent {
|
||||||
|
ipCstr := C.CString(ipn.IP.String())
|
||||||
|
if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
|
||||||
|
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.PrimaryPort))
|
||||||
|
}
|
||||||
|
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
|
||||||
|
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.SecondaryPort))
|
||||||
|
}
|
||||||
|
if n.localConfig.Settings.TertiaryPort > 0 && n.localConfig.Settings.TertiaryPort < 65536 {
|
||||||
|
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
|
||||||
|
}
|
||||||
|
C.free(unsafe.Pointer(ipCstr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.externalAddresses = externalAddresses
|
||||||
|
n.externalAddressesLock.Unlock()
|
||||||
|
n.localConfigLock.RUnlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.runLock.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,14 +271,29 @@ func (n *Node) Close() {
|
||||||
nodesByUserPtrLock.Lock()
|
nodesByUserPtrLock.Lock()
|
||||||
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n.gn)))
|
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n.gn)))
|
||||||
nodesByUserPtrLock.Unlock()
|
nodesByUserPtrLock.Unlock()
|
||||||
|
n.runLock.Lock() // wait for gorountine to die
|
||||||
|
n.runLock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Address returns this node's address
|
||||||
|
func (n *Node) Address() Address { return n.id.address }
|
||||||
|
|
||||||
|
// Identity returns this node's identity (including secret portion)
|
||||||
|
func (n *Node) Identity() *Identity { return n.id }
|
||||||
|
|
||||||
|
// LocalConfig gets this node's local configuration
|
||||||
|
func (n *Node) LocalConfig() LocalConfig {
|
||||||
|
n.localConfigLock.RLock()
|
||||||
|
defer n.localConfigLock.RUnlock()
|
||||||
|
return n.localConfig
|
||||||
|
}
|
||||||
|
|
||||||
// Join joins a network
|
// Join joins a network
|
||||||
// If tap is nil, the default system tap for this OS/platform is used (if available).
|
// 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) {
|
func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
|
||||||
n.networksLock.RLock()
|
n.networksLock.RLock()
|
||||||
if nw, have := n.networks[nwid]; have {
|
if nw, have := n.networks[NetworkID(nwid)]; have {
|
||||||
return nw, nil
|
return nw, nil
|
||||||
}
|
}
|
||||||
n.networksLock.RUnlock()
|
n.networksLock.RUnlock()
|
||||||
|
@ -207,7 +312,7 @@ func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
n.networksLock.Lock()
|
n.networksLock.Lock()
|
||||||
n.networks[nwid] = nw
|
n.networks[NetworkID(nwid)] = nw
|
||||||
n.networksLock.Unlock()
|
n.networksLock.Unlock()
|
||||||
|
|
||||||
return nw, nil
|
return nw, nil
|
||||||
|
@ -217,11 +322,22 @@ func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
|
||||||
func (n *Node) Leave(nwid uint64) error {
|
func (n *Node) Leave(nwid uint64) error {
|
||||||
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
||||||
n.networksLock.Lock()
|
n.networksLock.Lock()
|
||||||
delete(n.networks, nwid)
|
delete(n.networks, NetworkID(nwid))
|
||||||
n.networksLock.Unlock()
|
n.networksLock.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Networks returns a list of networks that this node has joined
|
||||||
|
func (n *Node) Networks() []*Network {
|
||||||
|
var nws []*Network
|
||||||
|
n.networksLock.RLock()
|
||||||
|
for _, nw := range n.networks {
|
||||||
|
nws = append(nws, nw)
|
||||||
|
}
|
||||||
|
n.networksLock.RUnlock()
|
||||||
|
return nws
|
||||||
|
}
|
||||||
|
|
||||||
// AddStaticRoot adds a statically defined root server to this node.
|
// AddStaticRoot adds a statically defined root server to this node.
|
||||||
// If a static root with the given identity already exists this will update its IP and port information.
|
// If a static root with the given identity already exists this will update its IP and port information.
|
||||||
func (n *Node) AddStaticRoot(id *Identity, addrs []net.Addr) {
|
func (n *Node) AddStaticRoot(id *Identity, addrs []net.Addr) {
|
||||||
|
@ -351,11 +467,30 @@ func (n *Node) multicastUnsubscribe(nwid uint64, mg *MulticastGroup) {
|
||||||
C.ZT_Node_multicastUnsubscribe(unsafe.Pointer(n.zn), C.uint64_t(nwid), C.uint64_t(mg.MAC), C.ulong(mg.ADI))
|
C.ZT_Node_multicastUnsubscribe(unsafe.Pointer(n.zn), C.uint64_t(nwid), C.uint64_t(mg.MAC), C.ulong(mg.ADI))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) pathCheck(ztAddress uint64, af int, ip net.IP, port int) bool {
|
func (n *Node) pathCheck(ztAddress Address, af int, ip net.IP, port int) bool {
|
||||||
|
n.localConfigLock.RLock()
|
||||||
|
defer n.localConfigLock.RUnlock()
|
||||||
|
for cidr, phy := range n.localConfig.Physical {
|
||||||
|
if phy.Blacklist {
|
||||||
|
_, ipn, _ := net.ParseCIDR(cidr)
|
||||||
|
if ipn != nil && ipn.Contains(ip) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) pathLookup(ztAddress uint64) (net.IP, int) {
|
func (n *Node) pathLookup(ztAddress Address) (net.IP, int) {
|
||||||
|
n.localConfigLock.RLock()
|
||||||
|
defer n.localConfigLock.RUnlock()
|
||||||
|
virt := n.localConfig.Virtual[ztAddress]
|
||||||
|
if virt != nil && len(virt.Try) > 0 {
|
||||||
|
udpA, _ := virt.Try[rand.Int()%len(virt.Try)].(*net.UDPAddr)
|
||||||
|
if udpA != nil {
|
||||||
|
return udpA.IP, udpA.Port
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,21 +499,21 @@ func (n *Node) makeStateObjectPath(objType int, id [2]uint64) (string, bool) {
|
||||||
secret := false
|
secret := false
|
||||||
switch objType {
|
switch objType {
|
||||||
case C.ZT_STATE_OBJECT_IDENTITY_PUBLIC:
|
case C.ZT_STATE_OBJECT_IDENTITY_PUBLIC:
|
||||||
fp = path.Join(n.path, "identity.public")
|
fp = path.Join(n.basePath, "identity.public")
|
||||||
case C.ZT_STATE_OBJECT_IDENTITY_SECRET:
|
case C.ZT_STATE_OBJECT_IDENTITY_SECRET:
|
||||||
fp = path.Join(n.path, "identity.secret")
|
fp = path.Join(n.basePath, "identity.secret")
|
||||||
secret = true
|
secret = true
|
||||||
case C.ZT_STATE_OBJECT_PEER:
|
case C.ZT_STATE_OBJECT_PEER:
|
||||||
fp = path.Join(n.path, "peers.d")
|
fp = path.Join(n.basePath, "peers.d")
|
||||||
os.Mkdir(fp, 0700)
|
os.Mkdir(fp, 0700)
|
||||||
fp = path.Join(fp, fmt.Sprintf("%.10x.peer", id[0]))
|
fp = path.Join(fp, fmt.Sprintf("%.10x.peer", id[0]))
|
||||||
secret = true
|
secret = true
|
||||||
case C.ZT_STATE_OBJECT_NETWORK_CONFIG:
|
case C.ZT_STATE_OBJECT_NETWORK_CONFIG:
|
||||||
fp = path.Join(n.path, "networks.d")
|
fp = path.Join(n.basePath, "networks.d")
|
||||||
os.Mkdir(fp, 0755)
|
os.Mkdir(fp, 0755)
|
||||||
fp = path.Join(fp, fmt.Sprintf("%.16x.conf", id[0]))
|
fp = path.Join(fp, fmt.Sprintf("%.16x.conf", id[0]))
|
||||||
case C.ZT_STATE_OBJECT_ROOT_LIST:
|
case C.ZT_STATE_OBJECT_ROOT_LIST:
|
||||||
fp = path.Join(n.path, "roots")
|
fp = path.Join(n.basePath, "roots")
|
||||||
}
|
}
|
||||||
return fp, secret
|
return fp, secret
|
||||||
}
|
}
|
||||||
|
@ -436,7 +571,7 @@ func goPathCheckFunc(gn unsafe.Pointer, ztAddress C.uint64_t, af C.int, ip unsaf
|
||||||
nodesByUserPtrLock.RLock()
|
nodesByUserPtrLock.RLock()
|
||||||
node := nodesByUserPtr[uintptr(gn)]
|
node := nodesByUserPtr[uintptr(gn)]
|
||||||
nodesByUserPtrLock.RUnlock()
|
nodesByUserPtrLock.RUnlock()
|
||||||
if node != nil && node.pathCheck(uint64(ztAddress), int(af), nil, int(port)) {
|
if node != nil && node.pathCheck(Address(ztAddress), int(af), nil, int(port)) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
@ -451,7 +586,7 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFam
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, port := node.pathLookup(uint64(ztAddress))
|
ip, port := node.pathLookup(Address(ztAddress))
|
||||||
if len(ip) > 0 && port > 0 && port <= 65535 {
|
if len(ip) > 0 && port > 0 && port <= 65535 {
|
||||||
ip4 := ip.To4()
|
ip4 := ip.To4()
|
||||||
if len(ip4) == 4 {
|
if len(ip4) == 4 {
|
||||||
|
@ -466,6 +601,7 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFam
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue