mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +02:00
Gogogogogogogo
This commit is contained in:
parent
b44bd19c53
commit
b6175bd408
12 changed files with 583 additions and 150 deletions
32
go/cmd/zerotier/zerotier.go
Normal file
32
go/cmd/zerotier/zerotier.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func nodeStart() {
|
||||||
|
osSignalChannel := make(chan os.Signal, 2)
|
||||||
|
signal.Notify(osSignalChannel, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGBUS)
|
||||||
|
signal.Ignore(syscall.SIGUSR1, syscall.SIGUSR2)
|
||||||
|
go func() {
|
||||||
|
<-osSignalChannel
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
|
@ -2,4 +2,7 @@ module zerotier
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95
|
require (
|
||||||
|
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||||
|
github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95
|
||||||
|
)
|
||||||
|
|
11
go/go.sum
11
go/go.sum
|
@ -1,4 +1,15 @@
|
||||||
|
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||||
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
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 h1:S4qyfL2sEm5Budr4KVMyEniCy+PbS55651I/a+Kn/NQ=
|
||||||
github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E=
|
github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190529164535-6a60838ec259 h1:so6Hr/LodwSZ5UQDu/7PmQiDeS112WwtLvU3lpSPZTU=
|
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=
|
golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#ifdef __WINDOWS__
|
#ifdef __WINDOWS__
|
||||||
#define SETSOCKOPT_FLAG_TYPE BOOL
|
#define SETSOCKOPT_FLAG_TYPE BOOL
|
||||||
|
@ -79,7 +80,7 @@ struct ZT_GoNodeThread
|
||||||
std::string ip;
|
std::string ip;
|
||||||
int port;
|
int port;
|
||||||
int af;
|
int af;
|
||||||
std::atomic_bool run;
|
std::atomic<bool> run;
|
||||||
std::thread thr;
|
std::thread thr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ struct ZT_GoNode_Impl
|
||||||
volatile int64_t nextBackgroundTaskDeadline;
|
volatile int64_t nextBackgroundTaskDeadline;
|
||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
std::atomic_bool run;
|
std::atomic<bool> run;
|
||||||
|
|
||||||
std::map< ZT_SOCKET,ZT_GoNodeThread > threads;
|
std::map< ZT_SOCKET,ZT_GoNodeThread > threads;
|
||||||
std::mutex threads_l;
|
std::mutex threads_l;
|
||||||
|
|
|
@ -14,24 +14,32 @@
|
||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
secrand "crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
acl "github.com/hectane/go-acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type apiStatus struct {
|
type apiStatus struct {
|
||||||
Address Address
|
Address Address
|
||||||
Clock int64
|
Clock int64
|
||||||
Config *LocalConfig
|
Config LocalConfig
|
||||||
Online bool
|
Online bool
|
||||||
Identity *Identity
|
Identity *Identity
|
||||||
Version string
|
InterfaceAddresses []net.IP
|
||||||
VersionMajor int
|
MappedExternalAddresses []*InetAddress
|
||||||
VersionMinor int
|
Version string
|
||||||
VersionRevision int
|
VersionMajor int
|
||||||
VersionBuild int
|
VersionMinor int
|
||||||
|
VersionRevision int
|
||||||
|
VersionBuild int
|
||||||
}
|
}
|
||||||
|
|
||||||
type apiNetwork struct {
|
type apiNetwork struct {
|
||||||
|
@ -80,36 +88,119 @@ func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiCheckAuth(out http.ResponseWriter, req *http.Request, token string) bool {
|
||||||
|
ah := req.Header.Get("X-ZT1-Auth")
|
||||||
|
if len(ah) > 0 && strings.TrimSpace(ah) == token {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ah = req.Header.Get("Authorization")
|
||||||
|
if len(ah) > 0 && strings.TrimSpace(ah) == ("bearer "+token) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
apiSendObj(out, req, http.StatusUnauthorized, nil)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// createAPIServer creates and starts an HTTP server for a given node
|
// createAPIServer creates and starts an HTTP server for a given node
|
||||||
func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
||||||
|
// Read authorization token, automatically generating one if it's missing
|
||||||
|
var authToken string
|
||||||
|
authTokenFile := path.Join(basePath, "authtoken.secret")
|
||||||
|
authTokenB, err := ioutil.ReadFile(authTokenFile)
|
||||||
|
if err != nil {
|
||||||
|
var atb [20]byte
|
||||||
|
_, err = secrand.Read(atb[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
atb[i] = byte("abcdefghijklmnopqrstuvwxyz0123456789"[atb[i]%36])
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(authTokenFile, atb[:], 0600)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
acl.Chmod(authTokenFile, 0600)
|
||||||
|
authToken = string(atb[:])
|
||||||
|
} else {
|
||||||
|
authToken = strings.TrimSpace(string(authTokenB))
|
||||||
|
}
|
||||||
|
|
||||||
smux := http.NewServeMux()
|
smux := http.NewServeMux()
|
||||||
|
|
||||||
smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
|
return
|
||||||
|
}
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
apiSendObj(out, req, http.StatusOK, nil)
|
apiSendObj(out, req, http.StatusOK, &apiStatus{
|
||||||
|
Address: node.Address(),
|
||||||
|
Clock: TimeMs(),
|
||||||
|
Config: node.LocalConfig(),
|
||||||
|
Online: node.Online(),
|
||||||
|
Identity: node.Identity(),
|
||||||
|
InterfaceAddresses: node.InterfaceAddresses(),
|
||||||
|
MappedExternalAddresses: nil,
|
||||||
|
Version: fmt.Sprintf("%d.%d.%d", CoreVersionMajor, CoreVersionMinor, CoreVersionRevision),
|
||||||
|
VersionMajor: CoreVersionMajor,
|
||||||
|
VersionMinor: CoreVersionMinor,
|
||||||
|
VersionRevision: CoreVersionRevision,
|
||||||
|
VersionBuild: CoreVersionBuild,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
out.Header().Set("Allow", "GET, HEAD")
|
out.Header().Set("Allow", "GET, HEAD")
|
||||||
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
|
return
|
||||||
|
}
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||||
var status apiStatus
|
var c LocalConfig
|
||||||
apiSendObj(out, req, http.StatusOK, &status)
|
if apiReadObj(out, req, &c) == nil {
|
||||||
|
apiSendObj(out, req, http.StatusOK, node.LocalConfig())
|
||||||
|
}
|
||||||
|
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
|
apiSendObj(out, req, http.StatusOK, node.LocalConfig())
|
||||||
} else {
|
} else {
|
||||||
out.Header().Set("Allow", "GET, HEAD")
|
out.Header().Set("Allow", "GET, HEAD, PUT, POST")
|
||||||
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
|
return
|
||||||
|
}
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
|
|
||||||
|
var queriedID Address
|
||||||
|
if len(req.URL.Path) > 6 {
|
||||||
|
var err error
|
||||||
|
queriedID, err = NewAddressFromString(req.URL.Path[6:])
|
||||||
|
if err != nil {
|
||||||
|
apiSendObj(out, req, http.StatusNotFound, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
peers := node.Peers()
|
peers := node.Peers()
|
||||||
apiSendObj(out, req, http.StatusOK, peers)
|
if queriedID != 0 {
|
||||||
|
p2 := make([]*Peer, 0, len(peers))
|
||||||
|
for _, p := range peers {
|
||||||
|
if p.Address == queriedID {
|
||||||
|
p2 = append(p2, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apiSendObj(out, req, http.StatusOK, p2)
|
||||||
|
} else {
|
||||||
|
apiSendObj(out, req, http.StatusOK, peers)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
out.Header().Set("Allow", "GET, HEAD")
|
out.Header().Set("Allow", "GET, HEAD")
|
||||||
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
|
@ -117,17 +208,67 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
||||||
})
|
})
|
||||||
|
|
||||||
smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
|
return
|
||||||
|
}
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
|
||||||
networks := node.Networks()
|
var queriedID NetworkID
|
||||||
apiSendObj(out, req, http.StatusOK, networks)
|
if len(req.URL.Path) > 9 {
|
||||||
|
var err error
|
||||||
|
queriedID, err = NewNetworkIDFromString(req.URL.Path[9:])
|
||||||
|
if err != nil {
|
||||||
|
apiSendObj(out, req, http.StatusNotFound, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||||
|
if queriedID == 0 {
|
||||||
|
apiSendObj(out, req, http.StatusBadRequest, nil)
|
||||||
|
}
|
||||||
|
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
|
if queriedID == 0 { // no queried ID lists all networks
|
||||||
|
networks := node.Networks()
|
||||||
|
apiSendObj(out, req, http.StatusOK, networks)
|
||||||
|
} else {
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
out.Header().Set("Allow", "GET, HEAD")
|
out.Header().Set("Allow", "GET, HEAD, PUT, POST")
|
||||||
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
unixListener, err := net.Listen("unix", path.Join(basePath, "apisocket"))
|
smux.HandleFunc("/root/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiSetStandardHeaders(out)
|
||||||
|
|
||||||
|
var queriedID Address
|
||||||
|
if len(req.URL.Path) > 6 {
|
||||||
|
var err error
|
||||||
|
queriedID, err = NewAddressFromString(req.URL.Path[6:])
|
||||||
|
if err != nil {
|
||||||
|
apiSendObj(out, req, http.StatusNotFound, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||||
|
if queriedID == 0 {
|
||||||
|
apiSendObj(out, req, http.StatusBadRequest, nil)
|
||||||
|
}
|
||||||
|
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
|
roots := node.Roots()
|
||||||
|
apiSendObj(out, req, http.StatusOK, roots)
|
||||||
|
} else {
|
||||||
|
out.Header().Set("Allow", "GET, HEAD, PUT, POST")
|
||||||
|
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
listener, err := createNamedSocketListener(basePath, "apisocket")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -139,7 +280,10 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
||||||
WriteTimeout: 600 * time.Second,
|
WriteTimeout: 600 * time.Second,
|
||||||
}
|
}
|
||||||
httpServer.SetKeepAlivesEnabled(true)
|
httpServer.SetKeepAlivesEnabled(true)
|
||||||
go httpServer.Serve(unixListener)
|
go func() {
|
||||||
|
httpServer.Serve(listener)
|
||||||
|
listener.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
return httpServer, nil
|
return httpServer, nil
|
||||||
}
|
}
|
||||||
|
|
123
go/pkg/zerotier/inetaddress.go
Normal file
123
go/pkg/zerotier/inetaddress.go
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* 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 (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InetAddress implements net.Addr but has a ZeroTier-like string representation
|
||||||
|
type InetAddress struct {
|
||||||
|
IP net.IP
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less returns true if this IP/port is lexicographically less than another
|
||||||
|
func (i *InetAddress) Less(i2 *InetAddress) bool {
|
||||||
|
c := bytes.Compare(i.IP, i2.IP)
|
||||||
|
if c < 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if c == 0 {
|
||||||
|
return i.Port < i2.Port
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInetAddressFromString parses an IP[/port] format address
|
||||||
|
func NewInetAddressFromString(s string) *InetAddress {
|
||||||
|
i := new(InetAddress)
|
||||||
|
ss := strings.Split(s, "/")
|
||||||
|
if len(ss) > 0 {
|
||||||
|
i.IP = net.ParseIP(ss[0])
|
||||||
|
i4 := i.IP.To4()
|
||||||
|
if len(i4) == 4 { // down-convert IPv4-in-6 IPs to native IPv4 as this is what all our code expects
|
||||||
|
i.IP = i4
|
||||||
|
}
|
||||||
|
if len(ss) > 1 {
|
||||||
|
p64, _ := strconv.ParseUint(s, 10, 64)
|
||||||
|
i.Port = int(p64 & 0xffff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInetAddressFromSockaddr parses a sockaddr_in or sockaddr_in6 C structure (may crash if given something other than these!)
|
||||||
|
// This is a convenience wrapper around the CGO functions in node.go.
|
||||||
|
func NewInetAddressFromSockaddr(sa unsafe.Pointer) *InetAddress {
|
||||||
|
i := new(InetAddress)
|
||||||
|
if uintptr(sa) != 0 {
|
||||||
|
ua := sockaddrStorageToUDPAddr2(sa)
|
||||||
|
if ua != nil {
|
||||||
|
i.IP = ua.IP
|
||||||
|
i.Port = ua.Port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network returns "udp" to implement net.Addr
|
||||||
|
func (i *InetAddress) Network() string {
|
||||||
|
return "udp"
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns this address in ZeroTier-canonical IP/port format
|
||||||
|
func (i *InetAddress) String() string {
|
||||||
|
return i.IP.String() + "/" + strconv.FormatInt(int64(i.Port), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Family returns the address family (AFInet etc.) or 0 if none
|
||||||
|
func (i *InetAddress) Family() int {
|
||||||
|
switch len(i.IP) {
|
||||||
|
case 4:
|
||||||
|
return AFInet
|
||||||
|
case 16:
|
||||||
|
return AFInet6
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid returns true if both the IP and port have valid values
|
||||||
|
func (i *InetAddress) Valid() bool {
|
||||||
|
return (len(i.IP) == 4 || len(i.IP) == 16) && (i.Port > 0 && i.Port < 65536)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals this MAC as a string
|
||||||
|
func (i *InetAddress) MarshalJSON() ([]byte, error) {
|
||||||
|
s := i.String()
|
||||||
|
return json.Marshal(&s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals this MAC from a string
|
||||||
|
func (i *InetAddress) UnmarshalJSON(j []byte) error {
|
||||||
|
var s string
|
||||||
|
err := json.Unmarshal(j, &s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*i = *NewInetAddressFromString(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// key returns a short array suitable for use as a map[] key for this IP
|
||||||
|
func (i *InetAddress) key() (k [3]uint64) {
|
||||||
|
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], i.IP)
|
||||||
|
k[2] = uint64(i.Port)
|
||||||
|
return
|
||||||
|
}
|
|
@ -17,42 +17,69 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
rand "math/rand"
|
rand "math/rand"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalConfigPhysicalPathConfiguration contains settings for physical paths
|
// LocalConfigPhysicalPathConfiguration contains settings for physical paths
|
||||||
type LocalConfigPhysicalPathConfiguration struct {
|
type LocalConfigPhysicalPathConfiguration struct {
|
||||||
Blacklist bool
|
// Blacklist flags this path as unusable for ZeroTier traffic
|
||||||
|
Blacklist bool
|
||||||
|
|
||||||
|
// TrustedPathID identifies a path for unencrypted/unauthenticated traffic
|
||||||
TrustedPathID uint64
|
TrustedPathID uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalConfigVirtualAddressConfiguration contains settings for virtual addresses
|
// LocalConfigVirtualAddressConfiguration contains settings for virtual addresses
|
||||||
type LocalConfigVirtualAddressConfiguration struct {
|
type LocalConfigVirtualAddressConfiguration struct {
|
||||||
Try []net.Addr
|
// Try is a list of IPs/ports to try for this peer in addition to anything learned from roots or direct path push
|
||||||
|
Try []*InetAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalConfigSettings contains node settings
|
// LocalConfigSettings contains node settings
|
||||||
type LocalConfigSettings struct {
|
type LocalConfigSettings struct {
|
||||||
PrimaryPort int
|
// PrimaryPort is the main UDP port and must be set (defaults to 9993)
|
||||||
SecondaryPort int
|
PrimaryPort int
|
||||||
TertiaryPort int
|
|
||||||
PortMappingEnabled bool
|
// SecondaryPort is the secondary UDP port, set to 0 to disbale (picked at random by default)
|
||||||
MuiltipathMode int
|
SecondaryPort int
|
||||||
|
|
||||||
|
// TertiaryPort is a third UDP port, set to 0 to disable (picked at random by default)
|
||||||
|
TertiaryPort int
|
||||||
|
|
||||||
|
// PortAutoSearch causes ZeroTier to try other ports automatically if it can't bind to configured ports
|
||||||
|
PortAutoSearch bool
|
||||||
|
|
||||||
|
// PortMappingEnabled enables uPnP and NAT-PMP support
|
||||||
|
PortMappingEnabled bool
|
||||||
|
|
||||||
|
// MultipathMode sets the multipath link aggregation mode
|
||||||
|
MuiltipathMode int
|
||||||
|
|
||||||
|
// InterfacePrefixBlacklist are prefixes of physical network interface names that won't be used by ZeroTier (e.g. "lo" or "utun")
|
||||||
InterfacePrefixBlacklist []string
|
InterfacePrefixBlacklist []string
|
||||||
|
|
||||||
|
// ExplicitAddresses are explicit IP/port addresses to advertise to other nodes, such as externally mapped ports on a router
|
||||||
|
ExplicitAddresses []*InetAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 path configurations by CIDR IP/bits
|
||||||
Physical map[string]*LocalConfigPhysicalPathConfiguration
|
Physical map[string]*LocalConfigPhysicalPathConfiguration
|
||||||
Virtual map[Address]*LocalConfigVirtualAddressConfiguration
|
|
||||||
Network map[NetworkID]*NetworkLocalSettings
|
// Virtual node specific configurations by 10-digit hex ZeroTier address
|
||||||
|
Virtual map[Address]*LocalConfigVirtualAddressConfiguration
|
||||||
|
|
||||||
|
// Network local configurations by 16-digit hex ZeroTier network ID
|
||||||
|
Network map[NetworkID]*NetworkLocalSettings
|
||||||
|
|
||||||
|
// LocalConfigSettings contains other local settings for this node
|
||||||
Settings LocalConfigSettings
|
Settings LocalConfigSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read this local config from a file, initializing to defaults if the file does not exist
|
// Read this local config from a file, initializing to defaults if the file does not exist
|
||||||
func (lc *LocalConfig) Read(p string) error {
|
func (lc *LocalConfig) Read(p string, saveDefaultsIfNotExist bool) error {
|
||||||
if lc.Physical == nil {
|
if lc.Physical == nil {
|
||||||
lc.Physical = make(map[string]*LocalConfigPhysicalPathConfiguration)
|
lc.Physical = make(map[string]*LocalConfigPhysicalPathConfiguration)
|
||||||
lc.Virtual = make(map[Address]*LocalConfigVirtualAddressConfiguration)
|
lc.Virtual = make(map[Address]*LocalConfigVirtualAddressConfiguration)
|
||||||
|
@ -60,6 +87,7 @@ func (lc *LocalConfig) Read(p string) error {
|
||||||
lc.Settings.PrimaryPort = 9993
|
lc.Settings.PrimaryPort = 9993
|
||||||
lc.Settings.SecondaryPort = 16384 + (rand.Int() % 16384)
|
lc.Settings.SecondaryPort = 16384 + (rand.Int() % 16384)
|
||||||
lc.Settings.TertiaryPort = 32768 + (rand.Int() % 16384)
|
lc.Settings.TertiaryPort = 32768 + (rand.Int() % 16384)
|
||||||
|
lc.Settings.PortAutoSearch = true
|
||||||
lc.Settings.PortMappingEnabled = true
|
lc.Settings.PortMappingEnabled = true
|
||||||
lc.Settings.MuiltipathMode = 0
|
lc.Settings.MuiltipathMode = 0
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
|
@ -75,10 +103,18 @@ func (lc *LocalConfig) Read(p string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(p)
|
data, err := ioutil.ReadFile(p)
|
||||||
if err != nil && err != os.ErrNotExist {
|
if err != nil {
|
||||||
return err
|
if err != os.ErrNotExist {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if saveDefaultsIfNotExist {
|
||||||
|
err = lc.Write(p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Unmarshal(data, lc)
|
return json.Unmarshal(data, lc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
|
|
||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
|
// This wraps the C++ Node implementation, C++ EthernetTap implementations,
|
||||||
|
// and generally contains all the other CGO stuff.
|
||||||
|
|
||||||
//#cgo CFLAGS: -O3
|
//#cgo CFLAGS: -O3
|
||||||
//#cgo LDFLAGS: ${SRCDIR}/../../../build/node/libzt_core.a ${SRCDIR}/../../../build/osdep/libzt_osdep.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
|
//#define ZT_CGO 1
|
||||||
|
@ -20,14 +23,17 @@ package zerotier
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
rand "math/rand"
|
rand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -61,8 +67,8 @@ const (
|
||||||
// PlatformDefaultHomePath is the default location of ZeroTier's working path on this system
|
// PlatformDefaultHomePath is the default location of ZeroTier's working path on this system
|
||||||
PlatformDefaultHomePath string = C.GoString(C.ZT_PLATFORM_DEFAULT_HOMEPATH)
|
PlatformDefaultHomePath string = C.GoString(C.ZT_PLATFORM_DEFAULT_HOMEPATH)
|
||||||
|
|
||||||
afInet = C.AF_INET
|
AFInet = C.AF_INET
|
||||||
afInet6 = C.AF_INET6
|
AFInet6 = C.AF_INET6
|
||||||
|
|
||||||
defaultVirtualNetworkMTU = C.ZT_DEFAULT_MTU
|
defaultVirtualNetworkMTU = C.ZT_DEFAULT_MTU
|
||||||
)
|
)
|
||||||
|
@ -75,14 +81,14 @@ var (
|
||||||
func sockaddrStorageToIPNet(ss *C.struct_sockaddr_storage) *net.IPNet {
|
func sockaddrStorageToIPNet(ss *C.struct_sockaddr_storage) *net.IPNet {
|
||||||
var a net.IPNet
|
var a net.IPNet
|
||||||
switch ss.ss_family {
|
switch ss.ss_family {
|
||||||
case afInet:
|
case AFInet:
|
||||||
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
||||||
var ip4 [4]byte
|
var ip4 [4]byte
|
||||||
copy(ip4[:], (*[4]byte)(unsafe.Pointer(&sa4.sin_addr))[:])
|
copy(ip4[:], (*[4]byte)(unsafe.Pointer(&sa4.sin_addr))[:])
|
||||||
a.IP = net.IP(ip4[:])
|
a.IP = net.IP(ip4[:])
|
||||||
a.Mask = net.CIDRMask(int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:])), 32)
|
a.Mask = net.CIDRMask(int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:])), 32)
|
||||||
return &a
|
return &a
|
||||||
case afInet6:
|
case AFInet6:
|
||||||
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
||||||
var ip6 [16]byte
|
var ip6 [16]byte
|
||||||
copy(ip6[:], (*[16]byte)(unsafe.Pointer(&sa6.sin6_addr))[:])
|
copy(ip6[:], (*[16]byte)(unsafe.Pointer(&sa6.sin6_addr))[:])
|
||||||
|
@ -96,14 +102,14 @@ func sockaddrStorageToIPNet(ss *C.struct_sockaddr_storage) *net.IPNet {
|
||||||
func sockaddrStorageToUDPAddr(ss *C.struct_sockaddr_storage) *net.UDPAddr {
|
func sockaddrStorageToUDPAddr(ss *C.struct_sockaddr_storage) *net.UDPAddr {
|
||||||
var a net.UDPAddr
|
var a net.UDPAddr
|
||||||
switch ss.ss_family {
|
switch ss.ss_family {
|
||||||
case afInet:
|
case AFInet:
|
||||||
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
||||||
var ip4 [4]byte
|
var ip4 [4]byte
|
||||||
copy(ip4[:], (*[4]byte)(unsafe.Pointer(&sa4.sin_addr))[:])
|
copy(ip4[:], (*[4]byte)(unsafe.Pointer(&sa4.sin_addr))[:])
|
||||||
a.IP = net.IP(ip4[:])
|
a.IP = net.IP(ip4[:])
|
||||||
a.Port = int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:]))
|
a.Port = int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:]))
|
||||||
return &a
|
return &a
|
||||||
case afInet6:
|
case AFInet6:
|
||||||
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
||||||
var ip6 [16]byte
|
var ip6 [16]byte
|
||||||
copy(ip6[:], (*[16]byte)(unsafe.Pointer(&sa6.sin6_addr))[:])
|
copy(ip6[:], (*[16]byte)(unsafe.Pointer(&sa6.sin6_addr))[:])
|
||||||
|
@ -114,18 +120,22 @@ func sockaddrStorageToUDPAddr(ss *C.struct_sockaddr_storage) *net.UDPAddr {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sockaddrStorageToUDPAddr2(ss unsafe.Pointer) *net.UDPAddr {
|
||||||
|
return sockaddrStorageToUDPAddr((*C.struct_sockaddr_storage)(ss))
|
||||||
|
}
|
||||||
|
|
||||||
func makeSockaddrStorage(ip net.IP, port int, ss *C.struct_sockaddr_storage) bool {
|
func makeSockaddrStorage(ip net.IP, port int, ss *C.struct_sockaddr_storage) bool {
|
||||||
C.memset(unsafe.Pointer(ss), 0, C.sizeof_struct_sockaddr_storage)
|
C.memset(unsafe.Pointer(ss), 0, C.sizeof_struct_sockaddr_storage)
|
||||||
if len(ip) == 4 {
|
if len(ip) == 4 {
|
||||||
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
||||||
sa4.sin_family = afInet
|
sa4.sin_family = AFInet
|
||||||
copy(((*[4]byte)(unsafe.Pointer(&sa4.sin_addr)))[:], ip)
|
copy(((*[4]byte)(unsafe.Pointer(&sa4.sin_addr)))[:], ip)
|
||||||
binary.BigEndian.PutUint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:], uint16(port))
|
binary.BigEndian.PutUint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:], uint16(port))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if len(ip) == 16 {
|
if len(ip) == 16 {
|
||||||
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
||||||
sa6.sin6_family = afInet6
|
sa6.sin6_family = AFInet6
|
||||||
copy(((*[16]byte)(unsafe.Pointer(&sa6.sin6_addr)))[:], ip)
|
copy(((*[16]byte)(unsafe.Pointer(&sa6.sin6_addr)))[:], ip)
|
||||||
binary.BigEndian.PutUint16(((*[2]byte)(unsafe.Pointer(&sa6.sin6_port)))[:], uint16(port))
|
binary.BigEndian.PutUint16(((*[2]byte)(unsafe.Pointer(&sa6.sin6_port)))[:], uint16(port))
|
||||||
return true
|
return true
|
||||||
|
@ -137,26 +147,26 @@ func makeSockaddrStorage(ip net.IP, port int, ss *C.struct_sockaddr_storage) boo
|
||||||
|
|
||||||
// Node is 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 {
|
||||||
basePath string
|
basePath string
|
||||||
localConfig LocalConfig
|
localConfigPath string
|
||||||
networks map[NetworkID]*Network
|
localConfig LocalConfig
|
||||||
networksByMAC map[MAC]*Network // locked by networksLock
|
networks map[NetworkID]*Network
|
||||||
externalAddresses map[string]*net.IPNet
|
networksByMAC map[MAC]*Network // locked by networksLock
|
||||||
localConfigLock sync.RWMutex
|
interfaceAddresses map[string]net.IP // physical external IPs on the machine
|
||||||
networksLock sync.RWMutex
|
localConfigLock sync.RWMutex
|
||||||
externalAddressesLock sync.Mutex
|
networksLock sync.RWMutex
|
||||||
gn *C.ZT_GoNode
|
interfaceAddressesLock sync.Mutex
|
||||||
zn *C.ZT_Node
|
gn *C.ZT_GoNode
|
||||||
id *Identity
|
zn *C.ZT_Node
|
||||||
online uint32
|
id *Identity
|
||||||
running uint32
|
apiServer *http.Server
|
||||||
runLock sync.Mutex
|
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(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
|
||||||
|
@ -164,9 +174,14 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
|
|
||||||
n := new(Node)
|
n := new(Node)
|
||||||
n.basePath = basePath
|
n.basePath = basePath
|
||||||
|
n.localConfigPath = path.Join(basePath, "local.conf")
|
||||||
|
err := n.localConfig.Read(n.localConfigPath, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
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.externalAddresses = make(map[string]*net.IPNet)
|
n.interfaceAddresses = make(map[string]net.IP)
|
||||||
|
|
||||||
cpath := C.CString(basePath)
|
cpath := C.CString(basePath)
|
||||||
n.gn = C.ZT_GoNode_new(cpath)
|
n.gn = C.ZT_GoNode_new(cpath)
|
||||||
|
@ -184,6 +199,12 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.apiServer, err = createAPIServer(basePath, n)
|
||||||
|
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
|
||||||
|
@ -202,7 +223,7 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
if (now - lastScannedInterfaces) >= 30000 {
|
if (now - lastScannedInterfaces) >= 30000 {
|
||||||
lastScannedInterfaces = now
|
lastScannedInterfaces = now
|
||||||
|
|
||||||
externalAddresses := make(map[string]*net.IPNet)
|
interfaceAddresses := make(map[string]net.IP)
|
||||||
ifs, _ := net.Interfaces()
|
ifs, _ := net.Interfaces()
|
||||||
if len(ifs) > 0 {
|
if len(ifs) > 0 {
|
||||||
n.networksLock.RLock()
|
n.networksLock.RLock()
|
||||||
|
@ -214,7 +235,7 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
for _, a := range addrs {
|
for _, a := range addrs {
|
||||||
ipn, _ := a.(*net.IPNet)
|
ipn, _ := a.(*net.IPNet)
|
||||||
if ipn != nil {
|
if ipn != nil {
|
||||||
externalAddresses[ipn.String()] = ipn
|
interfaceAddresses[ipn.IP.String()] = ipn.IP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,10 +245,10 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
n.localConfigLock.RLock()
|
n.localConfigLock.RLock()
|
||||||
n.externalAddressesLock.Lock()
|
n.interfaceAddressesLock.Lock()
|
||||||
for astr, ipn := range externalAddresses {
|
for astr, ipn := range interfaceAddresses {
|
||||||
if _, alreadyKnown := n.externalAddresses[astr]; !alreadyKnown {
|
if _, alreadyKnown := n.interfaceAddresses[astr]; !alreadyKnown {
|
||||||
ipCstr := C.CString(ipn.IP.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 {
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
@ -240,9 +261,9 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
C.free(unsafe.Pointer(ipCstr))
|
C.free(unsafe.Pointer(ipCstr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for astr, ipn := range n.externalAddresses {
|
for astr, ipn := range n.interfaceAddresses {
|
||||||
if _, stillPresent := externalAddresses[astr]; !stillPresent {
|
if _, stillPresent := interfaceAddresses[astr]; !stillPresent {
|
||||||
ipCstr := C.CString(ipn.IP.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 {
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
@ -255,8 +276,8 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
C.free(unsafe.Pointer(ipCstr))
|
C.free(unsafe.Pointer(ipCstr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.externalAddresses = externalAddresses
|
n.interfaceAddresses = interfaceAddresses
|
||||||
n.externalAddressesLock.Unlock()
|
n.interfaceAddressesLock.Unlock()
|
||||||
n.localConfigLock.RUnlock()
|
n.localConfigLock.RUnlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,6 +290,7 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
// Close closes this Node and frees its underlying C++ Node structures
|
// Close closes this Node and frees its underlying C++ Node structures
|
||||||
func (n *Node) Close() {
|
func (n *Node) Close() {
|
||||||
if atomic.SwapUint32(&n.running, 0) != 0 {
|
if atomic.SwapUint32(&n.running, 0) != 0 {
|
||||||
|
n.apiServer.Close()
|
||||||
C.ZT_GoNode_delete(n.gn)
|
C.ZT_GoNode_delete(n.gn)
|
||||||
nodesByUserPtrLock.Lock()
|
nodesByUserPtrLock.Lock()
|
||||||
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n.gn)))
|
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n.gn)))
|
||||||
|
@ -284,6 +306,21 @@ func (n *Node) Address() Address { return n.id.address }
|
||||||
// Identity returns this node's identity (including secret portion)
|
// Identity returns this node's identity (including secret portion)
|
||||||
func (n *Node) Identity() *Identity { return n.id }
|
func (n *Node) Identity() *Identity { return n.id }
|
||||||
|
|
||||||
|
// Online returns true if this node can reach something
|
||||||
|
func (n *Node) Online() bool { return atomic.LoadUint32(&n.online) != 0 }
|
||||||
|
|
||||||
|
// InterfaceAddresses are external IPs belonging to physical interfaces on this machine
|
||||||
|
func (n *Node) InterfaceAddresses() []net.IP {
|
||||||
|
var ea []net.IP
|
||||||
|
n.interfaceAddressesLock.Lock()
|
||||||
|
for _, a := range n.interfaceAddresses {
|
||||||
|
ea = append(ea, a)
|
||||||
|
}
|
||||||
|
n.interfaceAddressesLock.Unlock()
|
||||||
|
sort.Slice(ea, func(a, b int) bool { return bytes.Compare(ea[a], ea[b]) < 0 })
|
||||||
|
return ea
|
||||||
|
}
|
||||||
|
|
||||||
// LocalConfig gets this node's local configuration
|
// LocalConfig gets this node's local configuration
|
||||||
func (n *Node) LocalConfig() LocalConfig {
|
func (n *Node) LocalConfig() LocalConfig {
|
||||||
n.localConfigLock.RLock()
|
n.localConfigLock.RLock()
|
||||||
|
@ -396,11 +433,11 @@ func (n *Node) Roots() []*Root {
|
||||||
root := (*C.ZT_Root)(unsafe.Pointer(uintptr(unsafe.Pointer(rl)) + C.sizeof_ZT_RootList))
|
root := (*C.ZT_Root)(unsafe.Pointer(uintptr(unsafe.Pointer(rl)) + C.sizeof_ZT_RootList))
|
||||||
id, err := NewIdentityFromString(C.GoString(root.identity))
|
id, err := NewIdentityFromString(C.GoString(root.identity))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var addrs []net.Addr
|
var addrs []InetAddress
|
||||||
for j := uintptr(0); j < uintptr(root.addressCount); j++ {
|
for j := uintptr(0); j < uintptr(root.addressCount); j++ {
|
||||||
a := sockaddrStorageToUDPAddr((*C.struct_sockaddr_storage)(unsafe.Pointer(uintptr(unsafe.Pointer(root.addresses)) + (j * C.sizeof_struct_sockaddr_storage))))
|
a := NewInetAddressFromSockaddr(unsafe.Pointer(uintptr(unsafe.Pointer(root.addresses)) + (j * C.sizeof_struct_sockaddr_storage)))
|
||||||
if a != nil {
|
if a != nil && a.Valid() {
|
||||||
addrs = append(addrs, a)
|
addrs = append(addrs, *a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
roots = append(roots, &Root{
|
roots = append(roots, &Root{
|
||||||
|
@ -488,10 +525,8 @@ func (n *Node) pathLookup(ztAddress Address) (net.IP, int) {
|
||||||
defer n.localConfigLock.RUnlock()
|
defer n.localConfigLock.RUnlock()
|
||||||
virt := n.localConfig.Virtual[ztAddress]
|
virt := n.localConfig.Virtual[ztAddress]
|
||||||
if virt != nil && len(virt.Try) > 0 {
|
if virt != nil && len(virt.Try) > 0 {
|
||||||
udpA, _ := virt.Try[rand.Int()%len(virt.Try)].(*net.UDPAddr)
|
idx := rand.Int() % len(virt.Try)
|
||||||
if udpA != nil {
|
return virt.Try[idx].IP, virt.Try[idx].Port
|
||||||
return udpA.IP, udpA.Port
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
@ -521,28 +556,24 @@ func (n *Node) makeStateObjectPath(objType int, id [2]uint64) (string, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) stateObjectPut(objType int, id [2]uint64, data []byte) {
|
func (n *Node) stateObjectPut(objType int, id [2]uint64, data []byte) {
|
||||||
go func() {
|
fp, secret := n.makeStateObjectPath(objType, id)
|
||||||
fp, secret := n.makeStateObjectPath(objType, id)
|
if len(fp) > 0 {
|
||||||
if len(fp) > 0 {
|
fileMode := os.FileMode(0644)
|
||||||
fileMode := os.FileMode(0644)
|
if secret {
|
||||||
if secret {
|
fileMode = os.FileMode(0600)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
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) {
|
func (n *Node) stateObjectDelete(objType int, id [2]uint64) {
|
||||||
go func() {
|
fp, _ := n.makeStateObjectPath(objType, id)
|
||||||
fp, _ := n.makeStateObjectPath(objType, id)
|
if len(fp) > 0 {
|
||||||
if len(fp) > 0 {
|
os.Remove(fp)
|
||||||
os.Remove(fp)
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) stateObjectGet(objType int, id [2]uint64) ([]byte, bool) {
|
func (n *Node) stateObjectGet(objType int, id [2]uint64) ([]byte, bool) {
|
||||||
|
@ -592,12 +623,12 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFam
|
||||||
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 {
|
||||||
*((*C.int)(familyP)) = C.int(afInet)
|
*((*C.int)(familyP)) = C.int(AFInet)
|
||||||
copy((*[4]byte)(ipP)[:], ip4)
|
copy((*[4]byte)(ipP)[:], ip4)
|
||||||
*((*C.int)(portP)) = C.int(port)
|
*((*C.int)(portP)) = C.int(port)
|
||||||
return 1
|
return 1
|
||||||
} else if len(ip) == 16 {
|
} else if len(ip) == 16 {
|
||||||
*((*C.int)(familyP)) = C.int(afInet6)
|
*((*C.int)(familyP)) = C.int(AFInet6)
|
||||||
copy((*[16]byte)(ipP)[:], ip)
|
copy((*[16]byte)(ipP)[:], ip)
|
||||||
*((*C.int)(portP)) = C.int(port)
|
*((*C.int)(portP)) = C.int(port)
|
||||||
return 1
|
return 1
|
||||||
|
@ -609,17 +640,19 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFam
|
||||||
|
|
||||||
//export goStateObjectPutFunc
|
//export goStateObjectPutFunc
|
||||||
func goStateObjectPutFunc(gn unsafe.Pointer, objType C.int, id, data unsafe.Pointer, len C.int) {
|
func goStateObjectPutFunc(gn unsafe.Pointer, objType C.int, id, data unsafe.Pointer, len C.int) {
|
||||||
nodesByUserPtrLock.RLock()
|
go func() {
|
||||||
node := nodesByUserPtr[uintptr(gn)]
|
nodesByUserPtrLock.RLock()
|
||||||
nodesByUserPtrLock.RUnlock()
|
node := nodesByUserPtr[uintptr(gn)]
|
||||||
if node == nil {
|
nodesByUserPtrLock.RUnlock()
|
||||||
return
|
if node == nil {
|
||||||
}
|
return
|
||||||
if len < 0 {
|
}
|
||||||
node.stateObjectDelete(int(objType), *((*[2]uint64)(id)))
|
if len < 0 {
|
||||||
} else {
|
node.stateObjectDelete(int(objType), *((*[2]uint64)(id)))
|
||||||
node.stateObjectPut(int(objType), *((*[2]uint64)(id)), C.GoBytes(data, len))
|
} else {
|
||||||
}
|
node.stateObjectPut(int(objType), *((*[2]uint64)(id)), C.GoBytes(data, len))
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
//export goStateObjectGetFunc
|
//export goStateObjectGetFunc
|
||||||
|
@ -642,17 +675,17 @@ func goStateObjectGetFunc(gn unsafe.Pointer, objType C.int, id, data unsafe.Poin
|
||||||
|
|
||||||
//export goDNSResolverFunc
|
//export goDNSResolverFunc
|
||||||
func goDNSResolverFunc(gn unsafe.Pointer, dnsRecordTypes unsafe.Pointer, numDNSRecordTypes C.int, name unsafe.Pointer, requestID C.uintptr_t) {
|
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() {
|
go func() {
|
||||||
|
nodesByUserPtrLock.RLock()
|
||||||
|
node := nodesByUserPtr[uintptr(gn)]
|
||||||
|
nodesByUserPtrLock.RUnlock()
|
||||||
|
if node == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
recordTypes := C.GoBytes(dnsRecordTypes, numDNSRecordTypes)
|
||||||
|
recordName := C.GoString((*C.char)(name))
|
||||||
|
|
||||||
recordNameCStrCopy := C.CString(recordName)
|
recordNameCStrCopy := C.CString(recordName)
|
||||||
for _, rt := range recordTypes {
|
for _, rt := range recordTypes {
|
||||||
switch rt {
|
switch rt {
|
||||||
|
@ -794,12 +827,12 @@ func (t *nativeTap) AddIP(ip *net.IPNet) error {
|
||||||
if bits > 128 || bits < 0 {
|
if bits > 128 || bits < 0 {
|
||||||
return ErrInvalidParameter
|
return ErrInvalidParameter
|
||||||
}
|
}
|
||||||
C.ZT_GoTap_addIp(t.tap, C.int(afInet6), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
C.ZT_GoTap_addIp(t.tap, C.int(AFInet6), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
||||||
} else if len(ip.IP) == 4 {
|
} else if len(ip.IP) == 4 {
|
||||||
if bits > 32 || bits < 0 {
|
if bits > 32 || bits < 0 {
|
||||||
return ErrInvalidParameter
|
return ErrInvalidParameter
|
||||||
}
|
}
|
||||||
C.ZT_GoTap_addIp(t.tap, C.int(afInet), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
C.ZT_GoTap_addIp(t.tap, C.int(AFInet), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
||||||
}
|
}
|
||||||
return ErrInvalidParameter
|
return ErrInvalidParameter
|
||||||
}
|
}
|
||||||
|
@ -811,14 +844,14 @@ func (t *nativeTap) RemoveIP(ip *net.IPNet) error {
|
||||||
if bits > 128 || bits < 0 {
|
if bits > 128 || bits < 0 {
|
||||||
return ErrInvalidParameter
|
return ErrInvalidParameter
|
||||||
}
|
}
|
||||||
C.ZT_GoTap_removeIp(t.tap, C.int(afInet6), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
C.ZT_GoTap_removeIp(t.tap, C.int(AFInet6), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(ip.IP) == 4 {
|
if len(ip.IP) == 4 {
|
||||||
if bits > 32 || bits < 0 {
|
if bits > 32 || bits < 0 {
|
||||||
return ErrInvalidParameter
|
return ErrInvalidParameter
|
||||||
}
|
}
|
||||||
C.ZT_GoTap_removeIp(t.tap, C.int(afInet), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
C.ZT_GoTap_removeIp(t.tap, C.int(AFInet), unsafe.Pointer(&ip.IP[0]), C.int(bits))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ErrInvalidParameter
|
return ErrInvalidParameter
|
||||||
|
@ -839,7 +872,7 @@ func (t *nativeTap) IPs() (ips []net.IPNet, err error) {
|
||||||
af := int(ipbuf[ipptr])
|
af := int(ipbuf[ipptr])
|
||||||
ipptr++
|
ipptr++
|
||||||
switch af {
|
switch af {
|
||||||
case afInet:
|
case AFInet:
|
||||||
var ip [4]byte
|
var ip [4]byte
|
||||||
for j := 0; j < 4; j++ {
|
for j := 0; j < 4; j++ {
|
||||||
ip[j] = ipbuf[ipptr]
|
ip[j] = ipbuf[ipptr]
|
||||||
|
@ -848,7 +881,7 @@ func (t *nativeTap) IPs() (ips []net.IPNet, err error) {
|
||||||
bits := ipbuf[ipptr]
|
bits := ipbuf[ipptr]
|
||||||
ipptr++
|
ipptr++
|
||||||
ips = append(ips, net.IPNet{IP: net.IP(ip[:]), Mask: net.CIDRMask(int(bits), 32)})
|
ips = append(ips, net.IPNet{IP: net.IP(ip[:]), Mask: net.CIDRMask(int(bits), 32)})
|
||||||
case afInet6:
|
case AFInet6:
|
||||||
var ip [16]byte
|
var ip [16]byte
|
||||||
for j := 0; j < 16; j++ {
|
for j := 0; j < 16; j++ {
|
||||||
ip[j] = ipbuf[ipptr]
|
ip[j] = ipbuf[ipptr]
|
||||||
|
@ -888,16 +921,16 @@ func (t *nativeTap) AddRoute(r *Route) error {
|
||||||
if len(r.Target.IP) == 4 {
|
if len(r.Target.IP) == 4 {
|
||||||
mask, _ := r.Target.Mask.Size()
|
mask, _ := r.Target.Mask.Size()
|
||||||
if len(r.Via) == 4 {
|
if len(r.Via) == 4 {
|
||||||
rc = int(C.ZT_GoTap_addRoute(t.tap, afInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), afInet, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_addRoute(t.tap, AFInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), AFInet, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
||||||
} else {
|
} else {
|
||||||
rc = int(C.ZT_GoTap_addRoute(t.tap, afInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_addRoute(t.tap, AFInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
||||||
}
|
}
|
||||||
} else if len(r.Target.IP) == 16 {
|
} else if len(r.Target.IP) == 16 {
|
||||||
mask, _ := r.Target.Mask.Size()
|
mask, _ := r.Target.Mask.Size()
|
||||||
if len(r.Via) == 4 {
|
if len(r.Via) == 4 {
|
||||||
rc = int(C.ZT_GoTap_addRoute(t.tap, afInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), afInet6, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_addRoute(t.tap, AFInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), AFInet6, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
||||||
} else {
|
} else {
|
||||||
rc = int(C.ZT_GoTap_addRoute(t.tap, afInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_addRoute(t.tap, AFInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -914,16 +947,16 @@ func (t *nativeTap) RemoveRoute(r *Route) error {
|
||||||
if len(r.Target.IP) == 4 {
|
if len(r.Target.IP) == 4 {
|
||||||
mask, _ := r.Target.Mask.Size()
|
mask, _ := r.Target.Mask.Size()
|
||||||
if len(r.Via) == 4 {
|
if len(r.Via) == 4 {
|
||||||
rc = int(C.ZT_GoTap_removeRoute(t.tap, afInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), afInet, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_removeRoute(t.tap, AFInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), AFInet, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
||||||
} else {
|
} else {
|
||||||
rc = int(C.ZT_GoTap_removeRoute(t.tap, afInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_removeRoute(t.tap, AFInet, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
||||||
}
|
}
|
||||||
} else if len(r.Target.IP) == 16 {
|
} else if len(r.Target.IP) == 16 {
|
||||||
mask, _ := r.Target.Mask.Size()
|
mask, _ := r.Target.Mask.Size()
|
||||||
if len(r.Via) == 4 {
|
if len(r.Via) == 4 {
|
||||||
rc = int(C.ZT_GoTap_removeRoute(t.tap, afInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), afInet6, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_removeRoute(t.tap, AFInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), AFInet6, unsafe.Pointer(&r.Via[0]), C.uint(r.Metric)))
|
||||||
} else {
|
} else {
|
||||||
rc = int(C.ZT_GoTap_removeRoute(t.tap, afInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
rc = int(C.ZT_GoTap_removeRoute(t.tap, AFInet6, unsafe.Pointer(&r.Target.IP[0]), C.int(mask), 0, nil, C.uint(r.Metric)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -933,12 +966,6 @@ func (t *nativeTap) RemoveRoute(r *Route) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncRoutes synchronizes managed routes
|
|
||||||
func (t *nativeTap) SyncRoutes() error {
|
|
||||||
C.ZT_GoTap_syncRoutes(t.tap)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func handleTapMulticastGroupChange(gn unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t, added bool) {
|
func handleTapMulticastGroupChange(gn unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t, added bool) {
|
||||||
|
|
28
go/pkg/zerotier/osdep-posix.go
Normal file
28
go/pkg/zerotier/osdep-posix.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createNamedSocketListener(basePath, name string) (net.Listener, error) {
|
||||||
|
apiSockPath := path.Join(basePath, name)
|
||||||
|
os.Remove(apiSockPath)
|
||||||
|
return net.Listen("unix", apiSockPath)
|
||||||
|
}
|
28
go/pkg/zerotier/osdep-windows.go
Normal file
28
go/pkg/zerotier/osdep-windows.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
winio "github.com/Microsoft/go-winio"
|
||||||
|
)
|
||||||
|
|
||||||
|
const windowsAPISocketPathPrefix = "\\\\.\\pipe\\zerotier_"
|
||||||
|
|
||||||
|
func createNamedSocketListener(basePath, name string) (net.Listener, error) {
|
||||||
|
winio.ListenPipe(windowsAPISocketPathPrefix+name, nil)
|
||||||
|
}
|
|
@ -13,13 +13,14 @@
|
||||||
|
|
||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
import "net"
|
|
||||||
|
|
||||||
// Root describes a root server used to find and establish communication with other nodes.
|
// Root describes a root server used to find and establish communication with other nodes.
|
||||||
type Root struct {
|
type Root struct {
|
||||||
DNSName string
|
DNSName string
|
||||||
Identity *Identity
|
Identity *Identity
|
||||||
Addresses []net.Addr
|
Addresses []InetAddress
|
||||||
Preferred bool
|
Preferred bool
|
||||||
Online bool
|
Online bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Static returns true if this is a static root
|
||||||
|
func (r *Root) Static() bool { return len(r.DNSName) == 0 }
|
||||||
|
|
|
@ -28,5 +28,4 @@ type Tap interface {
|
||||||
AddMulticastGroupChangeHandler(func(bool, *MulticastGroup))
|
AddMulticastGroupChangeHandler(func(bool, *MulticastGroup))
|
||||||
AddRoute(r *Route) error
|
AddRoute(r *Route) error
|
||||||
RemoveRoute(r *Route) error
|
RemoveRoute(r *Route) error
|
||||||
SyncRoutes() error
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue