mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-03-10 22:44:21 +00:00
.
This commit is contained in:
parent
e3d47e588a
commit
e5bd230fb0
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// AddRoot CLI command
|
// AddRoot CLI command
|
||||||
func AddRoot(args []string) {
|
func AddRoot(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Join CLI command
|
// Join CLI command
|
||||||
func Join(args []string) {
|
func Join(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Leave CLI command
|
// Leave CLI command
|
||||||
func Leave(args []string) {
|
func Leave(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Networks CLI command
|
// Networks CLI command
|
||||||
func Networks(args []string) {
|
func Networks(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Peers CLI command
|
// Peers CLI command
|
||||||
func Peers(args []string) {
|
func Peers(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// RemoveRoot CLI command
|
// RemoveRoot CLI command
|
||||||
func RemoveRoot(args []string) {
|
func RemoveRoot(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Roots CLI command
|
// Roots CLI command
|
||||||
func Roots(args []string) {
|
func Roots(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,17 @@
|
|||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Service is "zerotier service ..."
|
/*
|
||||||
func Service(args []string) {
|
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
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Service is "zerotier service ..."
|
||||||
|
func Service(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Set CLI command
|
// Set CLI command
|
||||||
func Set(args []string) {
|
func Set(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// Show CLI command
|
// Show CLI command
|
||||||
func Show(args []string) {
|
func Show(basePath, authToken string, args []string) {
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,37 @@
|
|||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"zerotier/pkg/zerotier"
|
||||||
|
)
|
||||||
|
|
||||||
// Status shows service status info
|
// Status shows service status info
|
||||||
func Status(args []string) {
|
func Status(basePath, authToken string, args []string, jsonOutput bool) {
|
||||||
|
var status zerotier.APIStatus
|
||||||
|
statusCode, err := zerotier.APIGet(basePath, zerotier.APISocketName, authToken, "/status", &status)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("FATAL: API response code %d: %s\n", statusCode, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if statusCode != http.StatusOK {
|
||||||
|
if statusCode == http.StatusUnauthorized {
|
||||||
|
fmt.Printf("FATAL: API response code %d: unauthorized (authorization token incorrect)\n", statusCode)
|
||||||
|
}
|
||||||
|
fmt.Printf("FATAL: API response code %d\n", statusCode)
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if jsonOutput {
|
||||||
|
j, _ := json.MarshalIndent(&status, "", " ")
|
||||||
|
fmt.Println(string(j))
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
@ -16,15 +16,18 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"zerotier/cmd/zerotier/cli"
|
"zerotier/cmd/zerotier/cli"
|
||||||
"zerotier/pkg/zerotier"
|
"zerotier/pkg/zerotier"
|
||||||
)
|
)
|
||||||
|
|
||||||
var copyrightText = fmt.Sprintf(`ZeroTier Network Virtualization Service Version %d.%d.%d
|
var copyrightText = fmt.Sprintf(`ZeroTier Network Virtualization Service Version %d.%d.%d
|
||||||
(c)2019 ZeroTier, Inc.
|
(c)2019 ZeroTier, Inc.
|
||||||
Licensed under the ZeroTier BSL (see LICENSE.txt)`,
|
Licensed under the ZeroTier BSL (see LICENSE.txt)`, zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
||||||
zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
|
||||||
|
|
||||||
func printHelp() {
|
func printHelp() {
|
||||||
fmt.Println(copyrightText + `
|
fmt.Println(copyrightText + `
|
||||||
@ -78,20 +81,41 @@ used to explicitly specify a location.
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func readAuthToken(basePath string) string {
|
||||||
func nodeStart() {
|
data, _ := ioutil.ReadFile(path.Join(basePath, "authtoken.secret"))
|
||||||
osSignalChannel := make(chan os.Signal, 2)
|
if len(data) > 0 {
|
||||||
signal.Notify(osSignalChannel, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGBUS)
|
return string(data)
|
||||||
signal.Ignore(syscall.SIGUSR1, syscall.SIGUSR2)
|
}
|
||||||
go func() {
|
userHome, _ := os.UserHomeDir()
|
||||||
<-osSignalChannel
|
if len(userHome) > 0 {
|
||||||
}()
|
if runtime.GOOS == "darwin" {
|
||||||
|
data, _ = ioutil.ReadFile(userHome + "/Library/Application Support/ZeroTier/authtoken.secret")
|
||||||
|
if len(data) > 0 {
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
data, _ = ioutil.ReadFile(userHome + "/Library/Application Support/ZeroTier/One/authtoken.secret")
|
||||||
|
if len(data) > 0 {
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data, _ = ioutil.ReadFile(path.Join(userHome, ".zerotierauth"))
|
||||||
|
if len(data) > 0 {
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
data, _ = ioutil.ReadFile(path.Join(userHome, ".zeroTierOneAuthToken"))
|
||||||
|
if len(data) > 0 {
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
|
globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
|
||||||
hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities
|
hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities
|
||||||
|
jflag := globalOpts.Bool("j", false, "")
|
||||||
|
pflag := globalOpts.String("p", "", "")
|
||||||
|
tflag := globalOpts.String("t", "", "")
|
||||||
err := globalOpts.Parse(os.Args[1:])
|
err := globalOpts.Parse(os.Args[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printHelp()
|
printHelp()
|
||||||
@ -109,6 +133,22 @@ func main() {
|
|||||||
cmdArgs = args[1:]
|
cmdArgs = args[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
basePath := zerotier.PlatformDefaultHomePath
|
||||||
|
if len(*pflag) > 0 {
|
||||||
|
basePath = *pflag
|
||||||
|
}
|
||||||
|
var authToken string
|
||||||
|
if len(*tflag) > 0 {
|
||||||
|
authToken = *tflag
|
||||||
|
} else {
|
||||||
|
authToken = readAuthToken(basePath)
|
||||||
|
}
|
||||||
|
if len(authToken) == 0 {
|
||||||
|
fmt.Println("FATAL: unable to read API authorization token from service path or user home ('sudo' may be needed)")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
authToken = strings.TrimSpace(authToken)
|
||||||
|
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "help":
|
case "help":
|
||||||
printHelp()
|
printHelp()
|
||||||
@ -117,27 +157,27 @@ func main() {
|
|||||||
fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
case "service":
|
case "service":
|
||||||
cli.Service(cmdArgs)
|
cli.Service(basePath, authToken, cmdArgs)
|
||||||
case "status":
|
case "status":
|
||||||
cli.Status(cmdArgs)
|
cli.Status(basePath, authToken, cmdArgs, *jflag)
|
||||||
case "peers":
|
case "peers":
|
||||||
cli.Peers(cmdArgs)
|
cli.Peers(basePath, authToken, cmdArgs)
|
||||||
case "roots":
|
case "roots":
|
||||||
cli.Roots(cmdArgs)
|
cli.Roots(basePath, authToken, cmdArgs)
|
||||||
case "addroot":
|
case "addroot":
|
||||||
cli.AddRoot(cmdArgs)
|
cli.AddRoot(basePath, authToken, cmdArgs)
|
||||||
case "removeroot":
|
case "removeroot":
|
||||||
cli.RemoveRoot(cmdArgs)
|
cli.RemoveRoot(basePath, authToken, cmdArgs)
|
||||||
case "networks":
|
case "networks":
|
||||||
cli.Networks(cmdArgs)
|
cli.Networks(basePath, authToken, cmdArgs)
|
||||||
case "join":
|
case "join":
|
||||||
cli.Join(cmdArgs)
|
cli.Join(basePath, authToken, cmdArgs)
|
||||||
case "leave":
|
case "leave":
|
||||||
cli.Leave(cmdArgs)
|
cli.Leave(basePath, authToken, cmdArgs)
|
||||||
case "show":
|
case "show":
|
||||||
cli.Show(cmdArgs)
|
cli.Show(basePath, authToken, cmdArgs)
|
||||||
case "set":
|
case "set":
|
||||||
cli.Set(cmdArgs)
|
cli.Set(basePath, authToken, cmdArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
printHelp()
|
printHelp()
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
secrand "crypto/rand"
|
secrand "crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -27,7 +28,58 @@ import (
|
|||||||
acl "github.com/hectane/go-acl"
|
acl "github.com/hectane/go-acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type apiStatus struct {
|
// APISocketName is the default socket name for accessing the API
|
||||||
|
const APISocketName = "apisocket"
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
client, err := createNamedSocketHTTPClient(basePath, socketName)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusTeapot, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("GET", "http://socket"+queryPath, nil)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusTeapot, err
|
||||||
|
}
|
||||||
|
req.Header.Add("Authorization", "bearer "+authToken)
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusTeapot, err
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(obj)
|
||||||
|
return resp.StatusCode, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIPost posts a JSON object to the API via a Unix domain or windows pipe socket and reads a response
|
||||||
|
func APIPost(basePath, socketName, authToken, queryPath string, post, result interface{}) (int, error) {
|
||||||
|
client, err := createNamedSocketHTTPClient(basePath, socketName)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusTeapot, err
|
||||||
|
}
|
||||||
|
var data []byte
|
||||||
|
if post != nil {
|
||||||
|
data, err = json.Marshal(post)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusTeapot, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = []byte("null")
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", "http://socket"+queryPath, bytes.NewReader(data))
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusTeapot, err
|
||||||
|
}
|
||||||
|
req.Header.Add("Authorization", "bearer "+authToken)
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusTeapot, err
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(result)
|
||||||
|
return resp.StatusCode, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIStatus is the object returned by API status inquiries
|
||||||
|
type APIStatus struct {
|
||||||
Address Address
|
Address Address
|
||||||
Clock int64
|
Clock int64
|
||||||
Config LocalConfig
|
Config LocalConfig
|
||||||
@ -42,7 +94,8 @@ type apiStatus struct {
|
|||||||
VersionBuild int
|
VersionBuild int
|
||||||
}
|
}
|
||||||
|
|
||||||
type apiNetwork struct {
|
// APINetwork is the object returned by API network inquiries
|
||||||
|
type APINetwork struct {
|
||||||
Config *NetworkConfig
|
Config *NetworkConfig
|
||||||
Settings *NetworkLocalSettings
|
Settings *NetworkLocalSettings
|
||||||
MulticastSubscriptions []*MulticastGroup
|
MulticastSubscriptions []*MulticastGroup
|
||||||
@ -89,12 +142,12 @@ func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func apiCheckAuth(out http.ResponseWriter, req *http.Request, token string) bool {
|
func apiCheckAuth(out http.ResponseWriter, req *http.Request, token string) bool {
|
||||||
ah := req.Header.Get("X-ZT1-Auth")
|
ah := req.Header.Get("Authorization")
|
||||||
if len(ah) > 0 && strings.TrimSpace(ah) == token {
|
if len(ah) > 0 && strings.TrimSpace(ah) == ("bearer "+token) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
ah = req.Header.Get("Authorization")
|
ah = req.Header.Get("X-ZT1-Auth")
|
||||||
if len(ah) > 0 && strings.TrimSpace(ah) == ("bearer "+token) {
|
if len(ah) > 0 && strings.TrimSpace(ah) == token {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
apiSendObj(out, req, http.StatusUnauthorized, nil)
|
apiSendObj(out, req, http.StatusUnauthorized, nil)
|
||||||
@ -134,7 +187,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
|||||||
}
|
}
|
||||||
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, &apiStatus{
|
apiSendObj(out, req, http.StatusOK, &APIStatus{
|
||||||
Address: node.Address(),
|
Address: node.Address(),
|
||||||
Clock: TimeMs(),
|
Clock: TimeMs(),
|
||||||
Config: node.LocalConfig(),
|
Config: node.LocalConfig(),
|
||||||
@ -268,7 +321,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
listener, err := createNamedSocketListener(basePath, "apisocket")
|
listener, err := createNamedSocketListener(basePath, APISocketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ZeroTierLogoChar is the unicode character that is ZeroTier's logo
|
||||||
|
const ZeroTierLogoChar = "⏁"
|
||||||
|
|
||||||
var base32StdLowerCase = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567").WithPadding(base32.NoPadding)
|
var base32StdLowerCase = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567").WithPadding(base32.NoPadding)
|
||||||
|
|
||||||
// TimeMs returns the time in milliseconds since epoch.
|
// TimeMs returns the time in milliseconds since epoch.
|
||||||
|
@ -16,9 +16,12 @@
|
|||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createNamedSocketListener(basePath, name string) (net.Listener, error) {
|
func createNamedSocketListener(basePath, name string) (net.Listener, error) {
|
||||||
@ -26,3 +29,17 @@ func createNamedSocketListener(basePath, name string) (net.Listener, error) {
|
|||||||
os.Remove(apiSockPath)
|
os.Remove(apiSockPath)
|
||||||
return net.Listen("unix", apiSockPath)
|
return net.Listen("unix", apiSockPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createNamedSocketHTTPClient(basePath, name string) (*http.Client, error) {
|
||||||
|
apiSockPath := path.Join(basePath, name)
|
||||||
|
return &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
Transport: &http.Transport{
|
||||||
|
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||||
|
return net.Dial("unix", apiSockPath)
|
||||||
|
},
|
||||||
|
DisableKeepAlives: true,
|
||||||
|
DisableCompression: true,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user