mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-02-08 20:30:10 +00:00
Regularize JSON stuff
This commit is contained in:
parent
b9911d0db7
commit
c3e0f262d1
@ -48,7 +48,7 @@ func Network(basePath, authToken string, args []string, jsonOutput bool) {
|
|||||||
fmt.Printf("%s: %s\n", nwids, network.Config.Name)
|
fmt.Printf("%s: %s\n", nwids, network.Config.Name)
|
||||||
fmt.Printf("\tstatus:\t%s\n", networkStatusStr(network.Config.Status))
|
fmt.Printf("\tstatus:\t%s\n", networkStatusStr(network.Config.Status))
|
||||||
enabled := "no"
|
enabled := "no"
|
||||||
if network.TapDeviceEnabled {
|
if network.PortEnabled {
|
||||||
enabled = "yes"
|
enabled = "yes"
|
||||||
}
|
}
|
||||||
bridge := "no"
|
bridge := "no"
|
||||||
@ -59,7 +59,7 @@ func Network(basePath, authToken string, args []string, jsonOutput bool) {
|
|||||||
if network.Config.BroadcastEnabled {
|
if network.Config.BroadcastEnabled {
|
||||||
broadcast = "on"
|
broadcast = "on"
|
||||||
}
|
}
|
||||||
fmt.Printf("\tport:\t%s dev %s type %s mtu %d enabled %s bridge %s broadcast %s\n", network.Config.MAC.String(), network.TapDeviceName, network.TapDeviceType, network.Config.MTU, enabled, bridge, broadcast)
|
fmt.Printf("\tport:\t%s dev %s type %s mtu %d enabled %s bridge %s broadcast %s\n", network.Config.MAC.String(), network.PortName, network.PortType, network.Config.MTU, enabled, bridge, broadcast)
|
||||||
fmt.Printf("\tmanaged addresses:\t")
|
fmt.Printf("\tmanaged addresses:\t")
|
||||||
for i, a := range network.Config.AssignedAddresses {
|
for i, a := range network.Config.AssignedAddresses {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
@ -34,7 +34,7 @@ func Networks(basePath, authToken string, args []string, jsonOutput bool) {
|
|||||||
if nw.Config.Type == zerotier.NetworkTypePublic {
|
if nw.Config.Type == zerotier.NetworkTypePublic {
|
||||||
t = "PUBLIC"
|
t = "PUBLIC"
|
||||||
}
|
}
|
||||||
fmt.Printf("%.16x %-24s %-17s %-16s %-7s %-16s ", uint64(nw.ID), nw.Config.Name, nw.Config.MAC.String(), networkStatusStr(nw.Config.Status), t, nw.TapDeviceName)
|
fmt.Printf("%.16x %-24s %-17s %-16s %-7s %-16s ", uint64(nw.ID), nw.Config.Name, nw.Config.MAC.String(), networkStatusStr(nw.Config.Status), t, nw.PortName)
|
||||||
for i, ip := range nw.Config.AssignedAddresses {
|
for i, ip := range nw.Config.AssignedAddresses {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Print(',')
|
fmt.Print(',')
|
||||||
|
@ -49,7 +49,7 @@ func (a Address) String() string {
|
|||||||
|
|
||||||
// MarshalJSON marshals this Address as a string
|
// MarshalJSON marshals this Address as a string
|
||||||
func (a Address) MarshalJSON() ([]byte, error) {
|
func (a Address) MarshalJSON() ([]byte, error) {
|
||||||
return []byte("\"" + a.String() + "\""), nil
|
return []byte(fmt.Sprintf("\"%.10x\"", uint64(a))), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals this Address from a string
|
// UnmarshalJSON unmarshals this Address from a string
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -31,6 +32,8 @@ import (
|
|||||||
// APISocketName is the default socket name for accessing the API
|
// APISocketName is the default socket name for accessing the API
|
||||||
const APISocketName = "apisocket"
|
const APISocketName = "apisocket"
|
||||||
|
|
||||||
|
var startTime = TimeMs()
|
||||||
|
|
||||||
// APIGet makes a query to the API via a Unix domain or windows pipe socket
|
// APIGet makes a query to the API via a Unix domain or windows pipe socket
|
||||||
func APIGet(basePath, socketName, authToken, queryPath string, obj interface{}) (int, error) {
|
func APIGet(basePath, socketName, authToken, queryPath string, obj interface{}) (int, error) {
|
||||||
client, err := createNamedSocketHTTPClient(basePath, socketName)
|
client, err := createNamedSocketHTTPClient(basePath, socketName)
|
||||||
@ -106,31 +109,38 @@ func APIDelete(basePath, socketName, authToken, queryPath string, result interfa
|
|||||||
|
|
||||||
// APIStatus is the object returned by API status inquiries
|
// APIStatus is the object returned by API status inquiries
|
||||||
type APIStatus struct {
|
type APIStatus struct {
|
||||||
Address Address
|
Address Address `json:"address"`
|
||||||
Clock int64
|
Clock int64 `json:"clock"`
|
||||||
Config LocalConfig
|
StartupTime int64 `json:"startupTime"`
|
||||||
Online bool
|
Config LocalConfig `json:"config"`
|
||||||
PeerCount int
|
Online bool `json:"online"`
|
||||||
PathCount int
|
PeerCount int `json:"peerCount"`
|
||||||
Identity *Identity
|
PathCount int `json:"pathCount"`
|
||||||
InterfaceAddresses []net.IP `json:",omitempty"`
|
Identity *Identity `json:"identity"`
|
||||||
MappedExternalAddresses []*InetAddress `json:",omitempty"`
|
InterfaceAddresses []net.IP `json:"interfaceAddresses,omitempty"`
|
||||||
Version string
|
MappedExternalAddresses []*InetAddress `json:"mappedExternalAddresses,omitempty"`
|
||||||
VersionMajor int
|
Version string `json:"version"`
|
||||||
VersionMinor int
|
VersionMajor int `json:"versionMajor"`
|
||||||
VersionRevision int
|
VersionMinor int `json:"versionMinor"`
|
||||||
VersionBuild int
|
VersionRevision int `json:"versionRevision"`
|
||||||
|
VersionBuild int `json:"versionBuild"`
|
||||||
|
OS string `json:"os"`
|
||||||
|
Architecture string `json:"architecture"`
|
||||||
|
Concurrency int `json:"cpus"`
|
||||||
|
Runtime string `json:"runtimeVersion"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// APINetwork is the object returned by API network inquiries
|
// APINetwork is the object returned by API network inquiries
|
||||||
type APINetwork struct {
|
type APINetwork struct {
|
||||||
ID NetworkID
|
ID NetworkID `json:"id"`
|
||||||
Config NetworkConfig
|
Config NetworkConfig `json:"config"`
|
||||||
Settings *NetworkLocalSettings `json:",omitempty"`
|
Settings *NetworkLocalSettings `json:"settings,omitempty"`
|
||||||
MulticastSubscriptions []*MulticastGroup `json:",omitempty"`
|
MulticastSubscriptions []*MulticastGroup `json:"multicastSubscriptions,omitempty"`
|
||||||
TapDeviceType string
|
PortType string `json:"portType"`
|
||||||
TapDeviceName string
|
PortName string `json:"portName"`
|
||||||
TapDeviceEnabled bool
|
PortEnabled bool `json:"portEnabled"`
|
||||||
|
PortErrorCode int `json:"portErrorCode"`
|
||||||
|
PortError string `json:"portError"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiNetworkFromNetwork(n *Network) *APINetwork {
|
func apiNetworkFromNetwork(n *Network) *APINetwork {
|
||||||
@ -140,19 +150,21 @@ func apiNetworkFromNetwork(n *Network) *APINetwork {
|
|||||||
ls := n.LocalSettings()
|
ls := n.LocalSettings()
|
||||||
nn.Settings = &ls
|
nn.Settings = &ls
|
||||||
nn.MulticastSubscriptions = n.MulticastSubscriptions()
|
nn.MulticastSubscriptions = n.MulticastSubscriptions()
|
||||||
nn.TapDeviceType = n.Tap().Type()
|
nn.PortType = n.Tap().Type()
|
||||||
nn.TapDeviceName = n.Tap().DeviceName()
|
nn.PortName = n.Tap().DeviceName()
|
||||||
nn.TapDeviceEnabled = n.Tap().Enabled()
|
nn.PortEnabled = n.Tap().Enabled()
|
||||||
|
ec, errStr := n.Tap().Error()
|
||||||
|
nn.PortErrorCode = ec
|
||||||
|
nn.PortError = errStr
|
||||||
return &nn
|
return &nn
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiSetStandardHeaders(out http.ResponseWriter) {
|
func apiSetStandardHeaders(out http.ResponseWriter) {
|
||||||
now := time.Now().UTC()
|
|
||||||
h := out.Header()
|
h := out.Header()
|
||||||
h.Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
h.Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
h.Set("Expires", "0")
|
h.Set("Expires", "0")
|
||||||
h.Set("Pragma", "no-cache")
|
h.Set("Pragma", "no-cache")
|
||||||
h.Set("Date", now.Format(time.RFC1123))
|
h.Set("Date", time.Now().UTC().Format(time.RFC1123))
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiSendObj(out http.ResponseWriter, req *http.Request, httpStatusCode int, obj interface{}) error {
|
func apiSendObj(out http.ResponseWriter, req *http.Request, httpStatusCode int, obj interface{}) error {
|
||||||
@ -178,7 +190,7 @@ func apiSendObj(out http.ResponseWriter, req *http.Request, httpStatusCode int,
|
|||||||
func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (err error) {
|
func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (err error) {
|
||||||
err = json.NewDecoder(req.Body).Decode(&dest)
|
err = json.NewDecoder(req.Body).Decode(&dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusBadRequest, nil)
|
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"invalid JSON: " + err.Error()})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -192,7 +204,7 @@ func apiCheckAuth(out http.ResponseWriter, req *http.Request, token string) bool
|
|||||||
if len(ah) > 0 && strings.TrimSpace(ah) == token {
|
if len(ah) > 0 && strings.TrimSpace(ah) == token {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
_ = apiSendObj(out, req, http.StatusUnauthorized, nil)
|
_ = apiSendObj(out, req, http.StatusUnauthorized, &APIErr{"authorization token not found or incorrect (checked X-ZT1-Auth and Authorization headers)"})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +235,8 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
|
|
||||||
smux := http.NewServeMux()
|
smux := http.NewServeMux()
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
e := recover()
|
e := recover()
|
||||||
@ -234,8 +248,8 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
if !apiCheckAuth(out, req, authToken) {
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
|
|
||||||
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
pathCount := 0
|
pathCount := 0
|
||||||
peers := node.Peers()
|
peers := node.Peers()
|
||||||
@ -245,6 +259,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
_ = apiSendObj(out, req, http.StatusOK, &APIStatus{
|
_ = apiSendObj(out, req, http.StatusOK, &APIStatus{
|
||||||
Address: node.Address(),
|
Address: node.Address(),
|
||||||
Clock: TimeMs(),
|
Clock: TimeMs(),
|
||||||
|
StartupTime: startTime,
|
||||||
Config: node.LocalConfig(),
|
Config: node.LocalConfig(),
|
||||||
Online: node.Online(),
|
Online: node.Online(),
|
||||||
PeerCount: len(peers),
|
PeerCount: len(peers),
|
||||||
@ -257,34 +272,41 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
VersionMinor: CoreVersionMinor,
|
VersionMinor: CoreVersionMinor,
|
||||||
VersionRevision: CoreVersionRevision,
|
VersionRevision: CoreVersionRevision,
|
||||||
VersionBuild: CoreVersionBuild,
|
VersionBuild: CoreVersionBuild,
|
||||||
|
OS: runtime.GOOS,
|
||||||
|
Architecture: runtime.GOARCH,
|
||||||
|
Concurrency: runtime.NumCPU(),
|
||||||
|
Runtime: runtime.Version(),
|
||||||
})
|
})
|
||||||
} 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, &APIErr{"/status is read-only"})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusInternalServerError, nil)
|
_ = apiSendObj(out, req, http.StatusInternalServerError, &APIErr{"caught unexpected error in request handler"})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if !apiCheckAuth(out, req, authToken) {
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
|
|
||||||
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||||
var c LocalConfig
|
var c LocalConfig
|
||||||
if apiReadObj(out, req, &c) == nil {
|
if apiReadObj(out, req, &c) == nil {
|
||||||
_, err := node.SetLocalConfig(&c)
|
_, err := node.SetLocalConfig(&c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusBadRequest, nil)
|
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"error applying local config: " + err.Error()})
|
||||||
} else {
|
} else {
|
||||||
_ = apiSendObj(out, req, http.StatusOK, node.LocalConfig())
|
lc := node.LocalConfig()
|
||||||
|
_ = apiSendObj(out, req, http.StatusOK, &lc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
@ -295,18 +317,19 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusInternalServerError, nil)
|
_ = apiSendObj(out, req, http.StatusInternalServerError, &APIErr{"caught unexpected error in request handler"})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if !apiCheckAuth(out, req, authToken) {
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
|
|
||||||
var queriedID Address
|
var queriedID Address
|
||||||
@ -314,7 +337,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
var err error
|
var err error
|
||||||
queriedID, err = NewAddressFromString(req.URL.Path[6:])
|
queriedID, err = NewAddressFromString(req.URL.Path[6:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,28 +351,29 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||||
} else {
|
} else {
|
||||||
_ = apiSendObj(out, req, http.StatusOK, peers)
|
_ = 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, &APIErr{"peers are read only"})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusInternalServerError, nil)
|
_ = apiSendObj(out, req, http.StatusInternalServerError, &APIErr{"caught unexpected error in request handler"})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if !apiCheckAuth(out, req, authToken) {
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
|
|
||||||
var queriedID NetworkID
|
var queriedID NetworkID
|
||||||
@ -374,7 +398,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"network not found"})
|
||||||
}
|
}
|
||||||
} else if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
} else if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||||
if queriedID == 0 {
|
if queriedID == 0 {
|
||||||
@ -386,7 +410,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
if n == nil {
|
if n == nil {
|
||||||
n, err := node.Join(nw.ID, nw.Settings, nil)
|
n, err := node.Join(nw.ID, nw.Settings, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusBadRequest, nil)
|
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"only individual networks can be added or modified with POST/PUT"})
|
||||||
} else {
|
} else {
|
||||||
_ = apiSendObj(out, req, http.StatusOK, apiNetworkFromNetwork(n))
|
_ = apiSendObj(out, req, http.StatusOK, apiNetworkFromNetwork(n))
|
||||||
}
|
}
|
||||||
@ -413,26 +437,27 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"network not found"})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")
|
out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")
|
||||||
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, &APIErr{"unsupported method " + req.Method})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
smux.HandleFunc("/root/", func(out http.ResponseWriter, req *http.Request) {
|
smux.HandleFunc("/root/", func(out http.ResponseWriter, req *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusInternalServerError, nil)
|
_ = apiSendObj(out, req, http.StatusInternalServerError, &APIErr{"caught unexpected error in request handler"})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if !apiCheckAuth(out, req, authToken) {
|
if !apiCheckAuth(out, req, authToken) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiSetStandardHeaders(out)
|
apiSetStandardHeaders(out)
|
||||||
|
|
||||||
var queriedName string
|
var queriedName string
|
||||||
@ -453,15 +478,19 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
}
|
}
|
||||||
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
||||||
} else if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
} else if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||||
|
if len(queriedName) == 0 {
|
||||||
|
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"only individual roots can be added or modified with POST/PUT"})
|
||||||
|
return
|
||||||
|
}
|
||||||
var r Root
|
var r Root
|
||||||
if apiReadObj(out, req, &r) == nil {
|
if apiReadObj(out, req, &r) == nil {
|
||||||
if r.Name != queriedName {
|
if r.Name != queriedName {
|
||||||
_ = apiSendObj(out, req, http.StatusBadRequest, nil)
|
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"root name does not match name in path"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := node.SetRoot(r.Name, r.Locator)
|
err := node.SetRoot(r.Name, r.Locator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = apiSendObj(out, req, http.StatusBadRequest, nil)
|
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"set/update root failed: " + err.Error()})
|
||||||
} else {
|
} else {
|
||||||
roots := node.Roots()
|
roots := node.Roots()
|
||||||
for _, r := range roots {
|
for _, r := range roots {
|
||||||
@ -470,7 +499,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"set/update root failed: root set but not subsequently found in list"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||||
@ -481,13 +510,15 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = apiSendObj(out, req, http.StatusNotFound, nil)
|
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"root not found"})
|
||||||
} else {
|
} else {
|
||||||
out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")
|
out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")
|
||||||
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, &APIErr{"unsupported method: " + req.Method})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
listener, err := createNamedSocketListener(basePath, APISocketName)
|
listener, err := createNamedSocketListener(basePath, APISocketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -32,3 +32,10 @@ const (
|
|||||||
ErrInvalidSignature Err = "invalid signature"
|
ErrInvalidSignature Err = "invalid signature"
|
||||||
ErrSecretKeyRequired Err = "secret key required"
|
ErrSecretKeyRequired Err = "secret key required"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// APIErr is returned by the JSON API when a call fails
|
||||||
|
type APIErr struct {
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *APIErr) Error() string { return e.Reason }
|
||||||
|
@ -39,49 +39,49 @@ type LocalConfigVirtualAddressConfiguration struct {
|
|||||||
// LocalConfigSettings contains node settings
|
// LocalConfigSettings contains node settings
|
||||||
type LocalConfigSettings struct {
|
type LocalConfigSettings struct {
|
||||||
// PrimaryPort is the main UDP port and must be set (defaults to 9993)
|
// PrimaryPort is the main UDP port and must be set (defaults to 9993)
|
||||||
PrimaryPort int
|
PrimaryPort int `json:"primaryPort"`
|
||||||
|
|
||||||
// SecondaryPort is the secondary UDP port, set to 0 to disbale (picked at random by default)
|
// SecondaryPort is the secondary UDP port, set to 0 to disbale (picked at random by default)
|
||||||
SecondaryPort int
|
SecondaryPort int `json:"secondaryPort"`
|
||||||
|
|
||||||
// TertiaryPort is a third UDP port, set to 0 to disable (picked at random by default)
|
// TertiaryPort is a third UDP port, set to 0 to disable (picked at random by default)
|
||||||
TertiaryPort int
|
TertiaryPort int `json:"tertiaryPort"`
|
||||||
|
|
||||||
// PortSearch causes ZeroTier to try other ports automatically if it can't bind to configured ports
|
// PortSearch causes ZeroTier to try other ports automatically if it can't bind to configured ports
|
||||||
PortSearch bool
|
PortSearch bool `json:"portSearch"`
|
||||||
|
|
||||||
// PortMapping enables uPnP and NAT-PMP support
|
// PortMapping enables uPnP and NAT-PMP support
|
||||||
PortMapping bool
|
PortMapping bool `json:"portMapping"`
|
||||||
|
|
||||||
// LogSizeMax is the maximum size of the log in kilobytes or 0 for no limit and -1 to disable logging
|
// LogSizeMax is the maximum size of the log in kilobytes or 0 for no limit and -1 to disable logging
|
||||||
LogSizeMax int
|
LogSizeMax int `json:"logSizeMax"`
|
||||||
|
|
||||||
// MultipathMode sets the multipath link aggregation mode
|
// MultipathMode sets the multipath link aggregation mode
|
||||||
MuiltipathMode int
|
MuiltipathMode int `json:"multipathMode"`
|
||||||
|
|
||||||
// IP/port to bind for TCP access to control API (disabled if null)
|
// IP/port to bind for TCP access to control API (disabled if null)
|
||||||
APITCPBindAddress *InetAddress `json:",omitempty"`
|
APITCPBindAddress *InetAddress `json:"apiTCPBindAddress,omitempty"`
|
||||||
|
|
||||||
// InterfacePrefixBlacklist are prefixes of physical network interface names that won't be used by ZeroTier (e.g. "lo" or "utun")
|
// InterfacePrefixBlacklist are prefixes of physical network interface names that won't be used by ZeroTier (e.g. "lo" or "utun")
|
||||||
InterfacePrefixBlacklist []string `json:",omitempty"`
|
InterfacePrefixBlacklist []string `json:"interfacePrefixBlacklist,omitempty"`
|
||||||
|
|
||||||
// ExplicitAddresses are explicit IP/port addresses to advertise to other nodes, such as externally mapped ports on a router
|
// ExplicitAddresses are explicit IP/port addresses to advertise to other nodes, such as externally mapped ports on a router
|
||||||
ExplicitAddresses []*InetAddress `json:",omitempty"`
|
ExplicitAddresses []*InetAddress `json:"explicitAddresses,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 path configurations by CIDR IP/bits
|
||||||
Physical map[string]*LocalConfigPhysicalPathConfiguration `json:",omitempty"`
|
Physical map[string]*LocalConfigPhysicalPathConfiguration `json:"physical,omitempty"`
|
||||||
|
|
||||||
// Virtual node specific configurations by 10-digit hex ZeroTier address
|
// Virtual node specific configurations by 10-digit hex ZeroTier address
|
||||||
Virtual map[Address]*LocalConfigVirtualAddressConfiguration `json:",omitempty"`
|
Virtual map[Address]*LocalConfigVirtualAddressConfiguration `json:"virtual,omitempty"`
|
||||||
|
|
||||||
// Network local configurations by 16-digit hex ZeroTier network ID
|
// Network local configurations by 16-digit hex ZeroTier network ID
|
||||||
Network map[NetworkID]*NetworkLocalSettings `json:",omitempty"`
|
Network map[NetworkID]*NetworkLocalSettings `json:"network,omitempty"`
|
||||||
|
|
||||||
// LocalConfigSettings contains other local settings for this node
|
// LocalConfigSettings contains other local settings for this node
|
||||||
Settings LocalConfigSettings `json:",omitempty"`
|
Settings LocalConfigSettings `json:"settings,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -24,8 +24,8 @@ import (
|
|||||||
|
|
||||||
// LocatorDNSSigningKey is the public (as a secure DNS name) and private keys for entering locators into DNS
|
// LocatorDNSSigningKey is the public (as a secure DNS name) and private keys for entering locators into DNS
|
||||||
type LocatorDNSSigningKey struct {
|
type LocatorDNSSigningKey struct {
|
||||||
SecureDNSName string
|
SecureDNSName string `json:"secureDNSName"`
|
||||||
PrivateKey []byte
|
PrivateKey []byte `json:"privateKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocatorDNSSigningKey creates a new signing key and secure DNS name for storing locators in DNS
|
// NewLocatorDNSSigningKey creates a new signing key and secure DNS name for storing locators in DNS
|
||||||
@ -47,16 +47,16 @@ func NewLocatorDNSSigningKey() (*LocatorDNSSigningKey, error) {
|
|||||||
// and the others are always reconstructed from it.
|
// and the others are always reconstructed from it.
|
||||||
type Locator struct {
|
type Locator struct {
|
||||||
// Identity is the full identity of the node being located
|
// Identity is the full identity of the node being located
|
||||||
Identity *Identity
|
Identity *Identity `json:"identity"`
|
||||||
|
|
||||||
// Physical is a list of static physical network addresses for this node
|
// Physical is a list of static physical network addresses for this node
|
||||||
Physical []*InetAddress
|
Physical []*InetAddress `json:"physical,omitempty"`
|
||||||
|
|
||||||
// Virtual is a list of ZeroTier nodes that can relay to this node
|
// Virtual is a list of ZeroTier nodes that can relay to this node
|
||||||
Virtual []*Identity
|
Virtual []*Identity `json:"virtual,omitempty"`
|
||||||
|
|
||||||
// Bytes is the raw serialized Locator
|
// Bytes is the raw serialized Locator
|
||||||
Bytes []byte
|
Bytes []byte `json:"bytes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocator creates a new locator with the given identity and addresses and the current time as timestamp.
|
// NewLocator creates a new locator with the given identity and addresses and the current time as timestamp.
|
||||||
@ -172,7 +172,7 @@ func (l *Locator) MakeTXTRecords(key *LocatorDNSSigningKey) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type locatorForUnmarshal struct {
|
type locatorForUnmarshal struct {
|
||||||
Bytes []byte
|
Bytes []byte `json:"bytes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals this Locator from a byte array in JSON.
|
// UnmarshalJSON unmarshals this Locator from a byte array in JSON.
|
||||||
|
@ -17,8 +17,8 @@ import "fmt"
|
|||||||
|
|
||||||
// MulticastGroup represents a normal Ethernet multicast or broadcast address plus 32 additional ZeroTier-specific bits
|
// MulticastGroup represents a normal Ethernet multicast or broadcast address plus 32 additional ZeroTier-specific bits
|
||||||
type MulticastGroup struct {
|
type MulticastGroup struct {
|
||||||
MAC MAC
|
MAC MAC `json:"mac"`
|
||||||
ADI uint32
|
ADI uint32 `json:"adi"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns MAC#ADI
|
// String returns MAC#ADI
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
*/
|
*/
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
|
// This wraps EthernetTap from osdep/
|
||||||
|
|
||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
//#cgo CFLAGS: -O3
|
//#cgo CFLAGS: -O3
|
||||||
@ -159,17 +161,21 @@ func (t *nativeTap) AddMulticastGroupChangeHandler(handler func(bool, *Multicast
|
|||||||
func (t *nativeTap) AddRoute(r *Route) error {
|
func (t *nativeTap) AddRoute(r *Route) error {
|
||||||
rc := 0
|
rc := 0
|
||||||
if r != nil {
|
if r != nil {
|
||||||
|
var via []byte
|
||||||
|
if r.Via != nil {
|
||||||
|
via = *r.Via
|
||||||
|
}
|
||||||
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(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(&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(via) == 16 {
|
||||||
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(&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)))
|
||||||
}
|
}
|
||||||
@ -185,17 +191,21 @@ func (t *nativeTap) AddRoute(r *Route) error {
|
|||||||
func (t *nativeTap) RemoveRoute(r *Route) error {
|
func (t *nativeTap) RemoveRoute(r *Route) error {
|
||||||
rc := 0
|
rc := 0
|
||||||
if r != nil {
|
if r != nil {
|
||||||
|
var via []byte
|
||||||
|
if r.Via != nil {
|
||||||
|
via = *r.Via
|
||||||
|
}
|
||||||
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(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(&(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(via) == 16 {
|
||||||
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(&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)))
|
||||||
}
|
}
|
||||||
|
@ -17,18 +17,18 @@ import "net"
|
|||||||
|
|
||||||
// Path is a path to another peer on the network
|
// Path is a path to another peer on the network
|
||||||
type Path struct {
|
type Path struct {
|
||||||
IP net.IP
|
IP net.IP `json:"ip"`
|
||||||
Port int
|
Port int `json:"port"`
|
||||||
LastSend int64
|
LastSend int64 `json:"lastSend"`
|
||||||
LastReceive int64
|
LastReceive int64 `json:"lastReceive"`
|
||||||
TrustedPathID uint64
|
TrustedPathID uint64 `json:"trustedPathID"`
|
||||||
Latency float32
|
Latency float32 `json:"latency"`
|
||||||
PacketDelayVariance float32
|
PacketDelayVariance float32 `json:"packetDelayVariance"`
|
||||||
ThroughputDisturbCoeff float32
|
ThroughputDisturbCoeff float32 `json:"throughputDisturbCoeff"`
|
||||||
PacketErrorRatio float32
|
PacketErrorRatio float32 `json:"packetErrorRatio"`
|
||||||
PacketLossRatio float32
|
PacketLossRatio float32 `json:"packetLossRatio"`
|
||||||
Stability float32
|
Stability float32 `json:"stability"`
|
||||||
Throughput uint64
|
Throughput uint64 `json:"throughput"`
|
||||||
MaxThroughput uint64
|
MaxThroughput uint64 `json:"maxThroughput"`
|
||||||
Allocation float32
|
Allocation float32 `json:"allocation"`
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@ package zerotier
|
|||||||
|
|
||||||
// Peer is another ZeroTier node
|
// Peer is another ZeroTier node
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
Address Address
|
Address Address `json:"address"`
|
||||||
Version [3]int
|
Version [3]int `json:"version"`
|
||||||
Latency int
|
Latency int `json:"latency"`
|
||||||
Role int
|
Role int `json:"role"`
|
||||||
Paths []Path
|
Paths []Path `json:"paths,omitempty"`
|
||||||
Clock int64
|
Clock int64 `json:"clock"`
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,6 @@ package zerotier
|
|||||||
|
|
||||||
// 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 {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Locator *Locator
|
Locator *Locator `json:"locator,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,16 @@ import (
|
|||||||
// Route represents a route in a host's routing table
|
// Route represents a route in a host's routing table
|
||||||
type Route struct {
|
type Route struct {
|
||||||
// Target for this route
|
// Target for this route
|
||||||
Target net.IPNet
|
Target net.IPNet `json:"target"`
|
||||||
|
|
||||||
// Via is how to reach this target (null/empty if the target IP range is local to this virtual LAN)
|
// Via is how to reach this target (null/empty if the target IP range is local to this virtual LAN)
|
||||||
Via *net.IP
|
Via *net.IP `json:"via,omitempty"`
|
||||||
|
|
||||||
// Route flags (currently unused, always 0)
|
// Route flags (currently unused, always 0)
|
||||||
Flags uint16
|
Flags uint16 `json:"flags"`
|
||||||
|
|
||||||
// Metric is an interface metric that can affect route priority (behavior can be OS-specific)
|
// Metric is an interface metric that can affect route priority (behavior can be OS-specific)
|
||||||
Metric uint16
|
Metric uint16 `json:"metric"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of this route
|
// String returns a string representation of this route
|
||||||
@ -46,7 +46,9 @@ func (r *Route) key() (k [6]uint64) {
|
|||||||
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], r.Target.IP)
|
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], r.Target.IP)
|
||||||
ones, bits := r.Target.Mask.Size()
|
ones, bits := r.Target.Mask.Size()
|
||||||
k[2] = (uint64(ones) << 32) | uint64(bits)
|
k[2] = (uint64(ones) << 32) | uint64(bits)
|
||||||
copy(((*[16]byte)(unsafe.Pointer(&k[3])))[:], r.Via)
|
if r.Via != nil {
|
||||||
|
copy(((*[16]byte)(unsafe.Pointer(&k[3])))[:], *r.Via)
|
||||||
|
}
|
||||||
k[5] = (uint64(r.Flags) << 32) | uint64(r.Metric)
|
k[5] = (uint64(r.Flags) << 32) | uint64(r.Metric)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user