Gogogogogogogo
This commit is contained in:
parent
b44bd19c53
commit
b6175bd408
12 changed files with 583 additions and 150 deletions
|
@ -14,24 +14,32 @@
|
|||
package zerotier
|
||||
|
||||
import (
|
||||
secrand "crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
acl "github.com/hectane/go-acl"
|
||||
)
|
||||
|
||||
type apiStatus struct {
|
||||
Address Address
|
||||
Clock int64
|
||||
Config *LocalConfig
|
||||
Online bool
|
||||
Identity *Identity
|
||||
Version string
|
||||
VersionMajor int
|
||||
VersionMinor int
|
||||
VersionRevision int
|
||||
VersionBuild int
|
||||
Address Address
|
||||
Clock int64
|
||||
Config LocalConfig
|
||||
Online bool
|
||||
Identity *Identity
|
||||
InterfaceAddresses []net.IP
|
||||
MappedExternalAddresses []*InetAddress
|
||||
Version string
|
||||
VersionMajor int
|
||||
VersionMinor int
|
||||
VersionRevision int
|
||||
VersionBuild int
|
||||
}
|
||||
|
||||
type apiNetwork struct {
|
||||
|
@ -80,36 +88,119 @@ func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (e
|
|||
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
|
||||
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.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)
|
||||
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 {
|
||||
out.Header().Set("Allow", "GET, HEAD")
|
||||
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)
|
||||
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||
var status apiStatus
|
||||
apiSendObj(out, req, http.StatusOK, &status)
|
||||
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||
var c LocalConfig
|
||||
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 {
|
||||
out.Header().Set("Allow", "GET, HEAD")
|
||||
out.Header().Set("Allow", "GET, HEAD, PUT, POST")
|
||||
apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
|
||||
}
|
||||
})
|
||||
|
||||
smux.HandleFunc("/peer/", 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.MethodGet || req.Method == http.MethodHead {
|
||||
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 {
|
||||
out.Header().Set("Allow", "GET, HEAD")
|
||||
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) {
|
||||
if !apiCheckAuth(out, req, authToken) {
|
||||
return
|
||||
}
|
||||
apiSetStandardHeaders(out)
|
||||
if req.Method == http.MethodGet || req.Method == http.MethodHead {
|
||||
networks := node.Networks()
|
||||
apiSendObj(out, req, http.StatusOK, networks)
|
||||
|
||||
var queriedID NetworkID
|
||||
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 {
|
||||
out.Header().Set("Allow", "GET, HEAD")
|
||||
out.Header().Set("Allow", "GET, HEAD, PUT, POST")
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -139,7 +280,10 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
|||
WriteTimeout: 600 * time.Second,
|
||||
}
|
||||
httpServer.SetKeepAlivesEnabled(true)
|
||||
go httpServer.Serve(unixListener)
|
||||
go func() {
|
||||
httpServer.Serve(listener)
|
||||
listener.Close()
|
||||
}()
|
||||
|
||||
return httpServer, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue