zerotier.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2025-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. package main
  14. import (
  15. "flag"
  16. "fmt"
  17. "io/ioutil"
  18. "os"
  19. "path"
  20. "runtime"
  21. "runtime/debug"
  22. "strings"
  23. "time"
  24. "zerotier/cmd/zerotier/cli"
  25. "zerotier/pkg/zerotier"
  26. )
  27. // authToken returns a function that reads the authorization token if needed.
  28. // If the authorization token can't be read, the function terminates the program with a fatal error.
  29. func authToken(basePath, tflag, tTflag string) func () string {
  30. savedAuthToken := new(string)
  31. return func() string {
  32. authToken := *savedAuthToken
  33. if len(authToken) > 0 {
  34. return authToken
  35. }
  36. if len(tflag) > 0 {
  37. at, err := ioutil.ReadFile(tflag)
  38. if err != nil || len(at) == 0 {
  39. fmt.Println("FATAL: unable to read local service API authorization token from " + tflag)
  40. os.Exit(1)
  41. return ""
  42. }
  43. authToken = string(at)
  44. } else if len(tTflag) > 0 {
  45. authToken = tTflag
  46. } else {
  47. var authTokenPaths []string
  48. authTokenPaths = append(authTokenPaths, path.Join(basePath, "authtoken.secret"))
  49. userHome, _ := os.UserHomeDir()
  50. if len(userHome) > 0 {
  51. if runtime.GOOS == "darwin" {
  52. authTokenPaths = append(authTokenPaths, path.Join(userHome, "Library", "Application Support", "ZeroTier", "authtoken.secret"))
  53. authTokenPaths = append(authTokenPaths, path.Join(userHome, "Library", "Application Support", "ZeroTier", "One", "authtoken.secret"))
  54. }
  55. authTokenPaths = append(authTokenPaths, path.Join(userHome, ".zerotierauth"))
  56. authTokenPaths = append(authTokenPaths, path.Join(userHome, ".zeroTierOneAuthToken"))
  57. }
  58. for _, p := range authTokenPaths {
  59. tmp, _ := ioutil.ReadFile(p)
  60. if len(tmp) > 0 {
  61. authToken = string(tmp)
  62. break
  63. }
  64. }
  65. if len(authToken) == 0 {
  66. fmt.Println("FATAL: unable to read local service API authorization token from any of:")
  67. for _, p := range authTokenPaths {
  68. fmt.Println(" " + p)
  69. }
  70. os.Exit(1)
  71. return ""
  72. }
  73. }
  74. authToken = strings.TrimSpace(authToken)
  75. if len(authToken) == 0 {
  76. fmt.Println("FATAL: unable to read API authorization token from command line or any filesystem location.")
  77. os.Exit(1)
  78. return ""
  79. }
  80. *savedAuthToken = authToken
  81. return authToken
  82. }
  83. }
  84. func main() {
  85. // Reduce Go's thread and memory footprint. This would slow things down if the Go code
  86. // were doing a lot, but it's not. It just manages the core and is not directly involved
  87. // in pushing a lot of packets around. If that ever changes this should be adjusted.
  88. runtime.GOMAXPROCS(1)
  89. debug.SetGCPercent(10)
  90. globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
  91. hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities
  92. jflag := globalOpts.Bool("j", false, "")
  93. pflag := globalOpts.String("p", "", "")
  94. tflag := globalOpts.String("t", "", "")
  95. tTflag := globalOpts.String("T", "", "")
  96. err := globalOpts.Parse(os.Args[1:])
  97. if err != nil {
  98. cli.Help()
  99. os.Exit(1)
  100. return
  101. }
  102. args := globalOpts.Args()
  103. if len(args) < 1 || *hflag {
  104. cli.Help()
  105. os.Exit(0)
  106. return
  107. }
  108. var cmdArgs []string
  109. if len(args) > 1 {
  110. cmdArgs = args[1:]
  111. }
  112. basePath := zerotier.PlatformDefaultHomePath
  113. if len(*pflag) > 0 {
  114. basePath = *pflag
  115. }
  116. exitCode := 0
  117. switch args[0] {
  118. default:
  119. cli.Help()
  120. exitCode = 1
  121. case "help":
  122. cli.Help()
  123. case "version":
  124. fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
  125. case "now":
  126. if len(args) > 2 {
  127. cli.Help()
  128. exitCode = 1
  129. } else if len(args) == 2 {
  130. d, err := time.ParseDuration(args[1])
  131. if err == nil {
  132. fmt.Printf("%d\n", zerotier.TimeMs() + d.Milliseconds())
  133. } else {
  134. fmt.Printf("FATAL: invalid duration \"%s\": %s\n", args[1], err.Error())
  135. exitCode = 1
  136. }
  137. } else {
  138. fmt.Printf("%d\n", zerotier.TimeMs())
  139. }
  140. case "service":
  141. exitCode = cli.Service(basePath, cmdArgs)
  142. case "status", "info":
  143. exitCode = cli.Status(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs, *jflag)
  144. case "join":
  145. exitCode = cli.Join(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs)
  146. case "leave":
  147. exitCode = cli.Leave(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs)
  148. case "networks", "listnetworks":
  149. exitCode = cli.Network(basePath, authToken(basePath, *tflag, *tTflag), []string{"list"}, *jflag)
  150. case "network":
  151. exitCode = cli.Network(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs, *jflag)
  152. case "peers", "listpeers":
  153. exitCode = cli.Peer(basePath, authToken(basePath, *tflag, *tTflag), []string{"list"}, *jflag)
  154. case "peer":
  155. exitCode = cli.Peer(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs, *jflag)
  156. case "controller":
  157. exitCode = cli.Controller(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs, *jflag)
  158. case "set":
  159. exitCode = cli.Set(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs)
  160. case "identity":
  161. exitCode = cli.Identity(cmdArgs)
  162. case "locator":
  163. exitCode = cli.Locator(cmdArgs)
  164. case "certs", "listcerts", "lscerts": // same as "cert show" with no specific serial to show
  165. exitCode = cli.Cert(basePath, authToken(basePath, *tflag, *tTflag), []string{"show"}, *jflag)
  166. case "cert":
  167. exitCode = cli.Cert(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs, *jflag)
  168. }
  169. os.Exit(exitCode)
  170. }