mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
.
This commit is contained in:
parent
e5bd230fb0
commit
8a9669f130
6 changed files with 307 additions and 79 deletions
76
go/cmd/zerotier/cli/help.go
Normal file
76
go/cmd/zerotier/cli/help.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* 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 cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"zerotier/pkg/zerotier"
|
||||||
|
)
|
||||||
|
|
||||||
|
var copyrightText = fmt.Sprintf(`ZeroTier Network Virtualization Service Version %d.%d.%d
|
||||||
|
(c)2019 ZeroTier, Inc.
|
||||||
|
Licensed under the ZeroTier BSL (see LICENSE.txt)`, zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
||||||
|
|
||||||
|
// Help dumps help to stdout
|
||||||
|
func Help() {
|
||||||
|
fmt.Println(copyrightText + `
|
||||||
|
|
||||||
|
Usage: zerotier [-options] <command> [-options] [command args]
|
||||||
|
|
||||||
|
Global Options
|
||||||
|
-j Output raw JSON where applicable
|
||||||
|
-p <path> Use alternate base path
|
||||||
|
-t <authtoken.secret path> Use secret auth token from this file
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
help Show this help
|
||||||
|
version Print version
|
||||||
|
service Start in system service mode
|
||||||
|
status Show ZeroTier service status and config
|
||||||
|
peers Show VL1 peers
|
||||||
|
roots Show VL1 root servers
|
||||||
|
addroot <type> [options] Add a VL1 root
|
||||||
|
static <identity> <ip/port> [...] Add a root with a set identity and IPs
|
||||||
|
dynamic <name> [default locator] Add a dynamic root fetched by name
|
||||||
|
removeroot <type> [options] Remove a VL1 root
|
||||||
|
static <identity> Remove a root with a set identity
|
||||||
|
dynamic <name> Remove a dynamic root fetched by name
|
||||||
|
networks Show joined VL2 virtual networks
|
||||||
|
join <network ID> Join a virtual network
|
||||||
|
leave <network ID> Leave a virtual network
|
||||||
|
show <network ID> Show verbose network info
|
||||||
|
set <network ID> <option> <value> Set a network local config option
|
||||||
|
manageips <boolean> Is IP management allowed?
|
||||||
|
manageroutes <boolean> Is route management allowed?
|
||||||
|
globalips <boolean> Can IPs in global IP space be managed?
|
||||||
|
globalroutes <boolean> Can global IP space routes be set?
|
||||||
|
defaultroute <boolean> Can default route be overridden?
|
||||||
|
set <local config option> <value> Set a local configuration option
|
||||||
|
phy <IP/bits> blacklist <boolean> Set or clear blacklist for CIDR
|
||||||
|
phy <IP/bits> trust <path ID/0> Set or clear trusted path ID for CIDR
|
||||||
|
virt <address> try <IP/port> [...] Set explicit IPs for reaching a peer
|
||||||
|
port <port> Set primary local port for VL1 P2P
|
||||||
|
secondaryport <port/0> Set or disable secondary VL1 P2P port
|
||||||
|
tertiaryport <port/0> Set or disable tertiary VL1 P2P port
|
||||||
|
portsearch <boolean> Set or disable port search on startup
|
||||||
|
portmapping <boolean> Set or disable use of uPnP and NAT-PMP
|
||||||
|
explicitaddresses <IP/port> [...] Set explicit external IPs to advertise
|
||||||
|
|
||||||
|
Most commands require a secret token to permit control of a running ZeroTier
|
||||||
|
service. The CLI will automatically try to read this token from the
|
||||||
|
authtoken.secret file in the service's working directory and then from a
|
||||||
|
file called .zerotierauth in the user's home directory. The -t option can be
|
||||||
|
used to explicitly specify a location.
|
||||||
|
`)
|
||||||
|
}
|
|
@ -13,17 +13,33 @@
|
||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
/*
|
import (
|
||||||
func nodeStart() {
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"zerotier/pkg/zerotier"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service is "zerotier service ..."
|
||||||
|
func Service(basePath, authToken string, args []string) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
Help()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := zerotier.NewNode(basePath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("FATAL: error initializing node: " + err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
osSignalChannel := make(chan os.Signal, 2)
|
osSignalChannel := make(chan os.Signal, 2)
|
||||||
signal.Notify(osSignalChannel, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGBUS)
|
signal.Notify(osSignalChannel, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGBUS)
|
||||||
signal.Ignore(syscall.SIGUSR1, syscall.SIGUSR2)
|
signal.Ignore(syscall.SIGUSR1, syscall.SIGUSR2)
|
||||||
go func() {
|
go func() {
|
||||||
<-osSignalChannel
|
<-osSignalChannel
|
||||||
|
node.Close()
|
||||||
|
os.Exit(0)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Service is "zerotier service ..."
|
|
||||||
func Service(basePath, authToken string, args []string) {
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,62 +25,6 @@ import (
|
||||||
"zerotier/pkg/zerotier"
|
"zerotier/pkg/zerotier"
|
||||||
)
|
)
|
||||||
|
|
||||||
var copyrightText = fmt.Sprintf(`ZeroTier Network Virtualization Service Version %d.%d.%d
|
|
||||||
(c)2019 ZeroTier, Inc.
|
|
||||||
Licensed under the ZeroTier BSL (see LICENSE.txt)`, zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
|
||||||
|
|
||||||
func printHelp() {
|
|
||||||
fmt.Println(copyrightText + `
|
|
||||||
|
|
||||||
Usage: zerotier [-options] <command> [-options] [command args]
|
|
||||||
|
|
||||||
Global Options
|
|
||||||
-j Output raw JSON where applicable
|
|
||||||
-p <path> Connect to service running at this path
|
|
||||||
-t <authtoken.secret path> Use secret auth token from this file
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
help Show this help
|
|
||||||
version Print version
|
|
||||||
service [path] Start in system service mode
|
|
||||||
status Show ZeroTier service status and config
|
|
||||||
peers Show VL1 peers
|
|
||||||
roots Show VL1 root servers
|
|
||||||
addroot <type> [options] Add a VL1 root
|
|
||||||
static <identity> <ip/port> [...] Add a root with a set identity and IPs
|
|
||||||
dynamic <name> [default locator] Add a dynamic root fetched by name
|
|
||||||
removeroot <type> [options] Remove a VL1 root
|
|
||||||
static <identity> Remove a root with a set identity
|
|
||||||
dynamic <name> Remove a dynamic root fetched by name
|
|
||||||
networks Show joined VL2 virtual networks
|
|
||||||
join <network ID> Join a virtual network
|
|
||||||
leave <network ID> Leave a virtual network
|
|
||||||
show <network ID> Show verbose network info
|
|
||||||
set <network ID> <option> <value> Set a network local config option
|
|
||||||
manageips <boolean> Is IP management allowed?
|
|
||||||
manageroutes <boolean> Is route management allowed?
|
|
||||||
globalips <boolean> Can IPs in global IP space be managed?
|
|
||||||
globalroutes <boolean> Can global IP space routes be set?
|
|
||||||
defaultroute <boolean> Can default route be overridden?
|
|
||||||
set <local config option> <value> Set a local configuration option
|
|
||||||
phy <IP/bits> blacklist <boolean> Set or clear blacklist for CIDR
|
|
||||||
phy <IP/bits> trust <path ID/0> Set or clear trusted path ID for CIDR
|
|
||||||
virt <address> try <IP/port> [...] Set explicit IPs for reaching a peer
|
|
||||||
port <port> Set primary local port for VL1 P2P
|
|
||||||
secondaryport <port/0> Set or disable secondary VL1 P2P port
|
|
||||||
tertiaryport <port/0> Set or disable tertiary VL1 P2P port
|
|
||||||
portsearch <boolean> Set or disable port search on startup
|
|
||||||
portmapping <boolean> Set or disable use of uPnP and NAT-PMP
|
|
||||||
explicitaddresses <IP/port> [...] Set explicit external IPs to advertise
|
|
||||||
|
|
||||||
Most commands require a secret token to permit control of a running ZeroTier
|
|
||||||
service. The CLI will automatically try to read this token from the
|
|
||||||
authtoken.secret file in the service's working directory and then from a
|
|
||||||
file called .zerotierauth in the user's home directory. The -t option can be
|
|
||||||
used to explicitly specify a location.
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readAuthToken(basePath string) string {
|
func readAuthToken(basePath string) string {
|
||||||
data, _ := ioutil.ReadFile(path.Join(basePath, "authtoken.secret"))
|
data, _ := ioutil.ReadFile(path.Join(basePath, "authtoken.secret"))
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
|
@ -118,13 +62,13 @@ func main() {
|
||||||
tflag := globalOpts.String("t", "", "")
|
tflag := globalOpts.String("t", "", "")
|
||||||
err := globalOpts.Parse(os.Args[1:])
|
err := globalOpts.Parse(os.Args[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printHelp()
|
cli.Help()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
args := globalOpts.Args()
|
args := globalOpts.Args()
|
||||||
if len(args) < 1 || *hflag {
|
if len(args) < 1 || *hflag {
|
||||||
printHelp()
|
cli.Help()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -151,7 +95,7 @@ func main() {
|
||||||
|
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "help":
|
case "help":
|
||||||
printHelp()
|
cli.Help()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
case "version":
|
case "version":
|
||||||
fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
||||||
|
@ -180,6 +124,6 @@ func main() {
|
||||||
cli.Set(basePath, authToken, cmdArgs)
|
cli.Set(basePath, authToken, cmdArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
printHelp()
|
cli.Help()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,9 @@ type LocalConfigSettings struct {
|
||||||
// PortMapping enables uPnP and NAT-PMP support
|
// PortMapping enables uPnP and NAT-PMP support
|
||||||
PortMapping bool
|
PortMapping bool
|
||||||
|
|
||||||
|
// LogSizeMax is the maximum size of the log in kilobytes or 0 for no limit and -1 to disable logging
|
||||||
|
LogSizeMax int
|
||||||
|
|
||||||
// MultipathMode sets the multipath link aggregation mode
|
// MultipathMode sets the multipath link aggregation mode
|
||||||
MuiltipathMode int
|
MuiltipathMode int
|
||||||
|
|
||||||
|
@ -89,6 +92,7 @@ func (lc *LocalConfig) Read(p string, saveDefaultsIfNotExist bool) error {
|
||||||
lc.Settings.TertiaryPort = 32768 + (rand.Int() % 16384)
|
lc.Settings.TertiaryPort = 32768 + (rand.Int() % 16384)
|
||||||
lc.Settings.PortSearch = true
|
lc.Settings.PortSearch = true
|
||||||
lc.Settings.PortMapping = true
|
lc.Settings.PortMapping = true
|
||||||
|
lc.Settings.LogSizeMax = 128
|
||||||
lc.Settings.MuiltipathMode = 0
|
lc.Settings.MuiltipathMode = 0
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "darwin":
|
case "darwin":
|
||||||
|
|
|
@ -28,12 +28,14 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
rand "math/rand"
|
rand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -42,6 +44,8 @@ import (
|
||||||
acl "github.com/hectane/go-acl"
|
acl "github.com/hectane/go-acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var nullLogger = log.New(ioutil.Discard, "", 0)
|
||||||
|
|
||||||
// Network status states
|
// Network status states
|
||||||
const (
|
const (
|
||||||
NetworkStatusRequestConfiguration int = C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION
|
NetworkStatusRequestConfiguration int = C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION
|
||||||
|
@ -159,6 +163,8 @@ type Node struct {
|
||||||
localConfigLock sync.RWMutex
|
localConfigLock sync.RWMutex
|
||||||
networksLock sync.RWMutex
|
networksLock sync.RWMutex
|
||||||
interfaceAddressesLock sync.Mutex
|
interfaceAddressesLock sync.Mutex
|
||||||
|
logW *sizeLimitWriter
|
||||||
|
log *log.Logger
|
||||||
gn *C.ZT_GoNode
|
gn *C.ZT_GoNode
|
||||||
zn *C.ZT_Node
|
zn *C.ZT_Node
|
||||||
id *Identity
|
id *Identity
|
||||||
|
@ -170,23 +176,36 @@ type Node struct {
|
||||||
|
|
||||||
// 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(basePath string) (*Node, error) {
|
func NewNode(basePath string) (*Node, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
os.MkdirAll(basePath, 0755)
|
os.MkdirAll(basePath, 0755)
|
||||||
if _, err := os.Stat(basePath); err != nil {
|
if _, err := os.Stat(basePath); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n := new(Node)
|
n := new(Node)
|
||||||
|
|
||||||
n.networks = make(map[NetworkID]*Network)
|
n.networks = make(map[NetworkID]*Network)
|
||||||
n.networksByMAC = make(map[MAC]*Network)
|
n.networksByMAC = make(map[MAC]*Network)
|
||||||
n.interfaceAddresses = make(map[string]net.IP)
|
n.interfaceAddresses = make(map[string]net.IP)
|
||||||
|
|
||||||
n.basePath = basePath
|
n.basePath = basePath
|
||||||
n.localConfigPath = path.Join(basePath, "local.conf")
|
n.localConfigPath = path.Join(basePath, "local.conf")
|
||||||
err := n.localConfig.Read(n.localConfigPath, true)
|
err = n.localConfig.Read(n.localConfigPath, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.localConfig.Settings.LogSizeMax >= 0 {
|
||||||
|
n.logW, err = sizeLimitWriterOpen(path.Join(basePath, "service.log"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
n.log = log.New(n.logW, "", log.LstdFlags)
|
||||||
|
} else {
|
||||||
|
n.log = nullLogger
|
||||||
|
}
|
||||||
|
|
||||||
if n.localConfig.Settings.PortSearch {
|
if n.localConfig.Settings.PortSearch {
|
||||||
portsChanged := false
|
portsChanged := false
|
||||||
|
|
||||||
|
@ -196,6 +215,7 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
if checkPort(n.localConfig.Settings.PrimaryPort) {
|
if checkPort(n.localConfig.Settings.PrimaryPort) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
n.log.Printf("primary port %d unavailable, trying next port (port search enabled)", n.localConfig.Settings.PrimaryPort)
|
||||||
n.localConfig.Settings.PrimaryPort++
|
n.localConfig.Settings.PrimaryPort++
|
||||||
n.localConfig.Settings.PrimaryPort &= 0xffff
|
n.localConfig.Settings.PrimaryPort &= 0xffff
|
||||||
portsChanged = true
|
portsChanged = true
|
||||||
|
@ -211,6 +231,7 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
if checkPort(n.localConfig.Settings.SecondaryPort) {
|
if checkPort(n.localConfig.Settings.SecondaryPort) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
n.log.Printf("secondary port %d unavailable, trying next port (port search enabled)", n.localConfig.Settings.SecondaryPort)
|
||||||
n.localConfig.Settings.SecondaryPort++
|
n.localConfig.Settings.SecondaryPort++
|
||||||
n.localConfig.Settings.SecondaryPort &= 0xffff
|
n.localConfig.Settings.SecondaryPort &= 0xffff
|
||||||
portsChanged = true
|
portsChanged = true
|
||||||
|
@ -227,6 +248,7 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
if checkPort(n.localConfig.Settings.TertiaryPort) {
|
if checkPort(n.localConfig.Settings.TertiaryPort) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
n.log.Printf("tertiary port %d unavailable, trying next port (port search enabled)", n.localConfig.Settings.TertiaryPort)
|
||||||
n.localConfig.Settings.TertiaryPort++
|
n.localConfig.Settings.TertiaryPort++
|
||||||
n.localConfig.Settings.TertiaryPort &= 0xffff
|
n.localConfig.Settings.TertiaryPort &= 0xffff
|
||||||
portsChanged = true
|
portsChanged = true
|
||||||
|
@ -247,20 +269,24 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
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 {
|
||||||
|
n.log.Println("FATAL: node initialization failed")
|
||||||
return nil, ErrNodeInitFailed
|
return nil, ErrNodeInitFailed
|
||||||
}
|
}
|
||||||
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
|
var ns C.ZT_NodeStatus
|
||||||
C.ZT_Node_status(unsafe.Pointer(n.zn), &ns)
|
C.ZT_Node_status(unsafe.Pointer(n.zn), &ns)
|
||||||
n.id, err = NewIdentityFromString(C.GoString(ns.secretIdentity))
|
idstr := C.GoString(ns.secretIdentity)
|
||||||
|
n.id, err = NewIdentityFromString(idstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
n.log.Printf("FATAL: node's identity does not seem valid (%s)", idstr)
|
||||||
C.ZT_GoNode_delete(n.gn)
|
C.ZT_GoNode_delete(n.gn)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n.apiServer, err = createAPIServer(basePath, n)
|
n.apiServer, err = createAPIServer(basePath, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
n.log.Printf("FATAL: unable to start API server: %s", err.Error())
|
||||||
C.ZT_GoNode_delete(n.gn)
|
C.ZT_GoNode_delete(n.gn)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -275,13 +301,13 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
|
|
||||||
n.runLock.Lock()
|
n.runLock.Lock()
|
||||||
go func() {
|
go func() {
|
||||||
lastScannedInterfaces := int64(0)
|
lastMaintenanceRun := int64(0)
|
||||||
for atomic.LoadUint32(&n.running) != 0 {
|
for atomic.LoadUint32(&n.running) != 0 {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
now := TimeMs()
|
now := TimeMs()
|
||||||
if (now - lastScannedInterfaces) >= 30000 {
|
if (now - lastMaintenanceRun) >= 30000 {
|
||||||
lastScannedInterfaces = now
|
lastMaintenanceRun = now
|
||||||
|
|
||||||
interfaceAddresses := make(map[string]net.IP)
|
interfaceAddresses := make(map[string]net.IP)
|
||||||
ifs, _ := net.Interfaces()
|
ifs, _ := net.Interfaces()
|
||||||
|
@ -305,17 +331,21 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
n.localConfigLock.RLock()
|
n.localConfigLock.RLock()
|
||||||
|
|
||||||
n.interfaceAddressesLock.Lock()
|
n.interfaceAddressesLock.Lock()
|
||||||
for astr, ipn := range interfaceAddresses {
|
for astr, ipn := range interfaceAddresses {
|
||||||
if _, alreadyKnown := n.interfaceAddresses[astr]; !alreadyKnown {
|
if _, alreadyKnown := n.interfaceAddresses[astr]; !alreadyKnown {
|
||||||
ipCstr := C.CString(ipn.String())
|
ipCstr := C.CString(ipn.String())
|
||||||
if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
|
if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
|
||||||
|
n.log.Printf("UDP binding to port %d on interface %s", n.localConfig.Settings.PrimaryPort, astr)
|
||||||
C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.PrimaryPort))
|
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 {
|
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
|
||||||
|
n.log.Printf("UDP binding to port %d on interface %s", n.localConfig.Settings.SecondaryPort, astr)
|
||||||
C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.SecondaryPort))
|
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 {
|
if n.localConfig.Settings.TertiaryPort > 0 && n.localConfig.Settings.TertiaryPort < 65536 {
|
||||||
|
n.log.Printf("UDP binding to port %d on interface %s", n.localConfig.Settings.TertiaryPort, astr)
|
||||||
C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
|
C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
|
||||||
}
|
}
|
||||||
C.free(unsafe.Pointer(ipCstr))
|
C.free(unsafe.Pointer(ipCstr))
|
||||||
|
@ -325,12 +355,15 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
if _, stillPresent := interfaceAddresses[astr]; !stillPresent {
|
if _, stillPresent := interfaceAddresses[astr]; !stillPresent {
|
||||||
ipCstr := C.CString(ipn.String())
|
ipCstr := C.CString(ipn.String())
|
||||||
if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
|
if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
|
||||||
|
n.log.Printf("UDP closing socket bound to port %d on interface %s", n.localConfig.Settings.PrimaryPort, astr)
|
||||||
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.PrimaryPort))
|
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 {
|
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
|
||||||
|
n.log.Printf("UDP closing socket bound to port %d on interface %s", n.localConfig.Settings.SecondaryPort, astr)
|
||||||
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.SecondaryPort))
|
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 {
|
if n.localConfig.Settings.TertiaryPort > 0 && n.localConfig.Settings.TertiaryPort < 65536 {
|
||||||
|
n.log.Printf("UDP closing socket bound to port %d on interface %s", n.localConfig.Settings.TertiaryPort, astr)
|
||||||
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
|
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
|
||||||
}
|
}
|
||||||
C.free(unsafe.Pointer(ipCstr))
|
C.free(unsafe.Pointer(ipCstr))
|
||||||
|
@ -338,6 +371,11 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
}
|
}
|
||||||
n.interfaceAddresses = interfaceAddresses
|
n.interfaceAddresses = interfaceAddresses
|
||||||
n.interfaceAddressesLock.Unlock()
|
n.interfaceAddressesLock.Unlock()
|
||||||
|
|
||||||
|
if n.localConfig.Settings.LogSizeMax > 0 && n.logW != nil {
|
||||||
|
n.logW.trim(n.localConfig.Settings.LogSizeMax*1024, 0.5, true)
|
||||||
|
}
|
||||||
|
|
||||||
n.localConfigLock.RUnlock()
|
n.localConfigLock.RUnlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,25 +426,64 @@ func (n *Node) LocalConfig() LocalConfig {
|
||||||
return n.localConfig
|
return n.localConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLocalConfig updates this node's local configuration
|
||||||
|
func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error) {
|
||||||
|
n.networksLock.RLock()
|
||||||
|
n.localConfigLock.Lock()
|
||||||
|
defer n.localConfigLock.Unlock()
|
||||||
|
defer n.networksLock.RUnlock()
|
||||||
|
|
||||||
|
for nid, nc := range lc.Network {
|
||||||
|
nw := n.networks[nid]
|
||||||
|
if nw != nil {
|
||||||
|
nw.SetLocalSettings(nc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.localConfig.Settings.PrimaryPort != lc.Settings.PrimaryPort || n.localConfig.Settings.SecondaryPort != lc.Settings.SecondaryPort || n.localConfig.Settings.TertiaryPort != lc.Settings.TertiaryPort {
|
||||||
|
restartRequired = true
|
||||||
|
}
|
||||||
|
if lc.Settings.LogSizeMax < 0 {
|
||||||
|
n.log = nullLogger
|
||||||
|
n.logW.Close()
|
||||||
|
n.logW = nil
|
||||||
|
} else if n.logW != nil {
|
||||||
|
n.logW, err = sizeLimitWriterOpen(path.Join(n.basePath, "service.log"))
|
||||||
|
if err == nil {
|
||||||
|
n.log = log.New(n.logW, "", log.LstdFlags)
|
||||||
|
} else {
|
||||||
|
n.log = nullLogger
|
||||||
|
n.logW = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n.localConfig = *lc
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 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[NetworkID(nwid)]; have {
|
if nw, have := n.networks[NetworkID(nwid)]; have {
|
||||||
|
n.log.Printf("join network %.16x ignored: already a member", nwid)
|
||||||
return nw, nil
|
return nw, nil
|
||||||
}
|
}
|
||||||
n.networksLock.RUnlock()
|
n.networksLock.RUnlock()
|
||||||
|
|
||||||
if tap != nil {
|
if tap != nil {
|
||||||
return nil, errors.New("non-native taps not implemented yet")
|
panic("non-native taps not yet implemented")
|
||||||
}
|
}
|
||||||
ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid))
|
ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid))
|
||||||
if ntap == nil {
|
if ntap == nil {
|
||||||
|
n.log.Printf("join network %.16x failed: tap device failed to initialize (check drivers / kernel modules)")
|
||||||
return nil, ErrTapInitFailed
|
return nil, ErrTapInitFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
nw, err := newNetwork(n, NetworkID(nwid), &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1})
|
nw, err := newNetwork(n, NetworkID(nwid), &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
n.log.Printf("join network %.16x failed: network failed to initialize: %s", nwid, err.Error())
|
||||||
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -419,6 +496,7 @@ func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
|
||||||
|
|
||||||
// Leave leaves a network
|
// Leave leaves a network
|
||||||
func (n *Node) Leave(nwid uint64) error {
|
func (n *Node) Leave(nwid uint64) error {
|
||||||
|
n.log.Printf("leaving network %.16x", nwid)
|
||||||
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, NetworkID(nwid))
|
delete(n.networks, NetworkID(nwid))
|
||||||
|
@ -439,15 +517,17 @@ func (n *Node) Networks() []*Network {
|
||||||
|
|
||||||
// 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 []InetAddress) {
|
||||||
var saddrs []C.struct_sockaddr_storage
|
var saddrs []C.struct_sockaddr_storage
|
||||||
|
var straddrs strings.Builder
|
||||||
for _, a := range addrs {
|
for _, a := range addrs {
|
||||||
aa, _ := a.(*net.UDPAddr)
|
ss := new(C.struct_sockaddr_storage)
|
||||||
if aa != nil {
|
if makeSockaddrStorage(a.IP, a.Port, ss) {
|
||||||
ss := new(C.struct_sockaddr_storage)
|
saddrs = append(saddrs, *ss)
|
||||||
if makeSockaddrStorage(aa.IP, aa.Port, ss) {
|
if straddrs.Len() > 0 {
|
||||||
saddrs = append(saddrs, *ss)
|
straddrs.WriteString(",")
|
||||||
}
|
}
|
||||||
|
straddrs.WriteString(a.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(saddrs) > 0 {
|
if len(saddrs) > 0 {
|
||||||
|
|
108
go/pkg/zerotier/sizelimitwriter.go
Normal file
108
go/pkg/zerotier/sizelimitwriter.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* 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 (
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sizeLimitWriter struct {
|
||||||
|
f *os.File
|
||||||
|
l sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func sizeLimitWriterOpen(p string) (*sizeLimitWriter, error) {
|
||||||
|
f, err := os.OpenFile(p, os.O_CREATE|os.O_RDWR, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f.Seek(0, os.SEEK_END)
|
||||||
|
return &sizeLimitWriter{f: f}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implements io.Writer
|
||||||
|
func (w *sizeLimitWriter) Write(b []byte) (int, error) {
|
||||||
|
w.l.Lock()
|
||||||
|
defer w.l.Unlock()
|
||||||
|
return w.f.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the underlying file
|
||||||
|
func (w *sizeLimitWriter) Close() error {
|
||||||
|
w.l.Lock()
|
||||||
|
defer w.l.Unlock()
|
||||||
|
return w.f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *sizeLimitWriter) trim(maxSize int, trimFactor float64, trimAtCR bool) error {
|
||||||
|
w.l.Lock()
|
||||||
|
defer w.l.Unlock()
|
||||||
|
|
||||||
|
flen, err := w.f.Seek(0, os.SEEK_END)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if flen > int64(maxSize) {
|
||||||
|
var buf [131072]byte
|
||||||
|
trimAt := int64(float64(flen) * trimFactor)
|
||||||
|
if trimAt >= flen { // sanity check
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if trimAtCR {
|
||||||
|
lookForCR:
|
||||||
|
for {
|
||||||
|
nr, err := w.f.ReadAt(buf[0:1024], trimAt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := 0; i < nr; i++ {
|
||||||
|
trimAt++
|
||||||
|
if buf[i] == byte('\n') {
|
||||||
|
break lookForCR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if trimAt >= flen {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
copyTo := int64(0)
|
||||||
|
for trimAt < flen {
|
||||||
|
nr, _ := w.f.ReadAt(buf[:], trimAt)
|
||||||
|
if nr > 0 {
|
||||||
|
wr, _ := w.f.WriteAt(buf[0:nr], copyTo)
|
||||||
|
if wr > 0 {
|
||||||
|
copyTo += int64(wr)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.f.Truncate(copyTo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = w.f.Seek(0, os.SEEK_END)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue