api.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. * Copyright (c)2019 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: 2023-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 zerotier
  14. import (
  15. "bytes"
  16. secrand "crypto/rand"
  17. "encoding/json"
  18. "fmt"
  19. "io/ioutil"
  20. "net"
  21. "net/http"
  22. "path"
  23. "strings"
  24. "time"
  25. acl "github.com/hectane/go-acl"
  26. )
  27. // APISocketName is the default socket name for accessing the API
  28. const APISocketName = "apisocket"
  29. // APIGet makes a query to the API via a Unix domain or windows pipe socket
  30. func APIGet(basePath, socketName, authToken, queryPath string, obj interface{}) (int, error) {
  31. client, err := createNamedSocketHTTPClient(basePath, socketName)
  32. if err != nil {
  33. return http.StatusTeapot, err
  34. }
  35. req, err := http.NewRequest("GET", "http://socket"+queryPath, nil)
  36. if err != nil {
  37. return http.StatusTeapot, err
  38. }
  39. req.Header.Add("Authorization", "bearer "+authToken)
  40. resp, err := client.Do(req)
  41. if err != nil {
  42. return http.StatusTeapot, err
  43. }
  44. err = json.NewDecoder(resp.Body).Decode(obj)
  45. return resp.StatusCode, err
  46. }
  47. // APIPost posts a JSON object to the API via a Unix domain or windows pipe socket and reads a response
  48. func APIPost(basePath, socketName, authToken, queryPath string, post, result interface{}) (int, error) {
  49. client, err := createNamedSocketHTTPClient(basePath, socketName)
  50. if err != nil {
  51. return http.StatusTeapot, err
  52. }
  53. var data []byte
  54. if post != nil {
  55. data, err = json.Marshal(post)
  56. if err != nil {
  57. return http.StatusTeapot, err
  58. }
  59. } else {
  60. data = []byte("null")
  61. }
  62. req, err := http.NewRequest("POST", "http://socket"+queryPath, bytes.NewReader(data))
  63. if err != nil {
  64. return http.StatusTeapot, err
  65. }
  66. req.Header.Add("Authorization", "bearer "+authToken)
  67. resp, err := client.Do(req)
  68. if err != nil {
  69. return http.StatusTeapot, err
  70. }
  71. err = json.NewDecoder(resp.Body).Decode(result)
  72. return resp.StatusCode, err
  73. }
  74. // APIStatus is the object returned by API status inquiries
  75. type APIStatus struct {
  76. Address Address
  77. Clock int64
  78. Config LocalConfig
  79. Online bool
  80. Identity *Identity
  81. InterfaceAddresses []net.IP
  82. MappedExternalAddresses []*InetAddress
  83. Version string
  84. VersionMajor int
  85. VersionMinor int
  86. VersionRevision int
  87. VersionBuild int
  88. }
  89. // APINetwork is the object returned by API network inquiries
  90. type APINetwork struct {
  91. ID NetworkID
  92. Config *NetworkConfig
  93. Settings *NetworkLocalSettings
  94. MulticastSubscriptions []*MulticastGroup
  95. TapDeviceType string
  96. TapDeviceName string
  97. TapDeviceEnabled bool
  98. }
  99. func apiNetworkFromNetwork(n *Network) *APINetwork {
  100. var nn APINetwork
  101. nn.ID = n.ID()
  102. c := n.Config()
  103. nn.Config = &c
  104. ls := n.LocalSettings()
  105. nn.Settings = &ls
  106. nn.MulticastSubscriptions = n.MulticastSubscriptions()
  107. nn.TapDeviceType = n.Tap().Type()
  108. nn.TapDeviceName = n.Tap().DeviceName()
  109. nn.TapDeviceEnabled = n.Tap().Enabled()
  110. return &nn
  111. }
  112. func apiSetStandardHeaders(out http.ResponseWriter) {
  113. now := time.Now().UTC()
  114. h := out.Header()
  115. h.Set("Cache-Control", "no-cache, no-store, must-revalidate")
  116. h.Set("Expires", "0")
  117. h.Set("Pragma", "no-cache")
  118. h.Set("Date", now.Format(time.RFC1123))
  119. }
  120. func apiSendObj(out http.ResponseWriter, req *http.Request, httpStatusCode int, obj interface{}) error {
  121. h := out.Header()
  122. h.Set("Content-Type", "application/json")
  123. if req.Method == http.MethodHead {
  124. out.WriteHeader(httpStatusCode)
  125. return nil
  126. }
  127. var j []byte
  128. var err error
  129. if obj != nil {
  130. j, err = json.Marshal(obj)
  131. if err != nil {
  132. return err
  133. }
  134. }
  135. out.WriteHeader(httpStatusCode)
  136. _, err = out.Write(j)
  137. return err
  138. }
  139. func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (err error) {
  140. err = json.NewDecoder(req.Body).Decode(&dest)
  141. if err != nil {
  142. apiSendObj(out, req, http.StatusBadRequest, nil)
  143. }
  144. return
  145. }
  146. func apiCheckAuth(out http.ResponseWriter, req *http.Request, token string) bool {
  147. ah := req.Header.Get("Authorization")
  148. if len(ah) > 0 && strings.TrimSpace(ah) == ("bearer "+token) {
  149. return true
  150. }
  151. ah = req.Header.Get("X-ZT1-Auth")
  152. if len(ah) > 0 && strings.TrimSpace(ah) == token {
  153. return true
  154. }
  155. apiSendObj(out, req, http.StatusUnauthorized, nil)
  156. return false
  157. }
  158. // createAPIServer creates and starts an HTTP server for a given node
  159. func createAPIServer(basePath string, node *Node) (*http.Server, error) {
  160. // Read authorization token, automatically generating one if it's missing
  161. var authToken string
  162. authTokenFile := path.Join(basePath, "authtoken.secret")
  163. authTokenB, err := ioutil.ReadFile(authTokenFile)
  164. if err != nil {
  165. var atb [20]byte
  166. _, err = secrand.Read(atb[:])
  167. if err != nil {
  168. return nil, err
  169. }
  170. for i := 0; i < 20; i++ {
  171. atb[i] = byte("abcdefghijklmnopqrstuvwxyz0123456789"[atb[i]%36])
  172. }
  173. err = ioutil.WriteFile(authTokenFile, atb[:], 0600)
  174. if err != nil {
  175. return nil, err
  176. }
  177. acl.Chmod(authTokenFile, 0600)
  178. authToken = string(atb[:])
  179. } else {
  180. authToken = strings.TrimSpace(string(authTokenB))
  181. }
  182. smux := http.NewServeMux()
  183. smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
  184. if !apiCheckAuth(out, req, authToken) {
  185. return
  186. }
  187. apiSetStandardHeaders(out)
  188. if req.Method == http.MethodGet || req.Method == http.MethodHead {
  189. apiSendObj(out, req, http.StatusOK, &APIStatus{
  190. Address: node.Address(),
  191. Clock: TimeMs(),
  192. Config: node.LocalConfig(),
  193. Online: node.Online(),
  194. Identity: node.Identity(),
  195. InterfaceAddresses: node.InterfaceAddresses(),
  196. MappedExternalAddresses: nil,
  197. Version: fmt.Sprintf("%d.%d.%d", CoreVersionMajor, CoreVersionMinor, CoreVersionRevision),
  198. VersionMajor: CoreVersionMajor,
  199. VersionMinor: CoreVersionMinor,
  200. VersionRevision: CoreVersionRevision,
  201. VersionBuild: CoreVersionBuild,
  202. })
  203. } else {
  204. out.Header().Set("Allow", "GET, HEAD")
  205. apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
  206. }
  207. })
  208. smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
  209. if !apiCheckAuth(out, req, authToken) {
  210. return
  211. }
  212. apiSetStandardHeaders(out)
  213. if req.Method == http.MethodPost || req.Method == http.MethodPut {
  214. var c LocalConfig
  215. if apiReadObj(out, req, &c) == nil {
  216. node.SetLocalConfig(&c)
  217. apiSendObj(out, req, http.StatusOK, node.LocalConfig())
  218. }
  219. } else if req.Method == http.MethodGet || req.Method == http.MethodHead {
  220. apiSendObj(out, req, http.StatusOK, node.LocalConfig())
  221. } else {
  222. out.Header().Set("Allow", "GET, HEAD, PUT, POST")
  223. apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
  224. }
  225. })
  226. smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
  227. if !apiCheckAuth(out, req, authToken) {
  228. return
  229. }
  230. apiSetStandardHeaders(out)
  231. var queriedID Address
  232. if len(req.URL.Path) > 6 {
  233. var err error
  234. queriedID, err = NewAddressFromString(req.URL.Path[6:])
  235. if err != nil {
  236. apiSendObj(out, req, http.StatusNotFound, nil)
  237. return
  238. }
  239. }
  240. if req.Method == http.MethodGet || req.Method == http.MethodHead {
  241. peers := node.Peers()
  242. if queriedID != 0 {
  243. p2 := make([]*Peer, 0, len(peers))
  244. for _, p := range peers {
  245. if p.Address == queriedID {
  246. p2 = append(p2, p)
  247. }
  248. }
  249. apiSendObj(out, req, http.StatusOK, p2)
  250. } else {
  251. apiSendObj(out, req, http.StatusOK, peers)
  252. }
  253. } else {
  254. out.Header().Set("Allow", "GET, HEAD")
  255. apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
  256. }
  257. })
  258. smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
  259. if !apiCheckAuth(out, req, authToken) {
  260. return
  261. }
  262. apiSetStandardHeaders(out)
  263. var queriedID NetworkID
  264. if len(req.URL.Path) > 9 {
  265. var err error
  266. queriedID, err = NewNetworkIDFromString(req.URL.Path[9:])
  267. if err != nil {
  268. apiSendObj(out, req, http.StatusNotFound, nil)
  269. return
  270. }
  271. }
  272. if req.Method == http.MethodPost || req.Method == http.MethodPut {
  273. if queriedID == 0 {
  274. apiSendObj(out, req, http.StatusBadRequest, nil)
  275. } else {
  276. var nw APINetwork
  277. if apiReadObj(out, req, &nw) == nil {
  278. n := node.GetNetwork(nw.ID)
  279. if n == nil {
  280. n, err := node.Join(nw.ID, nw.Settings, nil)
  281. if err != nil {
  282. apiSendObj(out, req, http.StatusBadRequest, nil)
  283. } else {
  284. apiSendObj(out, req, http.StatusOK, apiNetworkFromNetwork(n))
  285. }
  286. } else {
  287. if nw.Settings != nil {
  288. n.SetLocalSettings(nw.Settings)
  289. }
  290. apiSendObj(out, req, http.StatusOK, apiNetworkFromNetwork(n))
  291. }
  292. }
  293. }
  294. } else if req.Method == http.MethodGet || req.Method == http.MethodHead {
  295. networks := node.Networks()
  296. if queriedID == 0 { // no queried ID lists all networks
  297. nws := make([]*APINetwork, 0, len(networks))
  298. for _, nw := range networks {
  299. nws = append(nws, apiNetworkFromNetwork(nw))
  300. }
  301. apiSendObj(out, req, http.StatusOK, nws)
  302. } else {
  303. for _, nw := range networks {
  304. if nw.ID() == queriedID {
  305. apiSendObj(out, req, http.StatusOK, apiNetworkFromNetwork(nw))
  306. break
  307. }
  308. }
  309. }
  310. } else {
  311. out.Header().Set("Allow", "GET, HEAD, PUT, POST")
  312. apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
  313. }
  314. })
  315. smux.HandleFunc("/root/", func(out http.ResponseWriter, req *http.Request) {
  316. if !apiCheckAuth(out, req, authToken) {
  317. return
  318. }
  319. apiSetStandardHeaders(out)
  320. var queriedID Address
  321. if len(req.URL.Path) > 6 {
  322. var err error
  323. queriedID, err = NewAddressFromString(req.URL.Path[6:])
  324. if err != nil {
  325. apiSendObj(out, req, http.StatusNotFound, nil)
  326. return
  327. }
  328. }
  329. if req.Method == http.MethodPost || req.Method == http.MethodPut {
  330. if queriedID == 0 {
  331. apiSendObj(out, req, http.StatusBadRequest, nil)
  332. } else {
  333. var r Root
  334. if apiReadObj(out, req, &r) == nil {
  335. }
  336. }
  337. } else if req.Method == http.MethodGet || req.Method == http.MethodHead {
  338. roots := node.Roots()
  339. apiSendObj(out, req, http.StatusOK, roots)
  340. } else {
  341. out.Header().Set("Allow", "GET, HEAD, PUT, POST")
  342. apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
  343. }
  344. })
  345. listener, err := createNamedSocketListener(basePath, APISocketName)
  346. if err != nil {
  347. return nil, err
  348. }
  349. httpServer := &http.Server{
  350. MaxHeaderBytes: 4096,
  351. Handler: smux,
  352. IdleTimeout: 10 * time.Second,
  353. ReadTimeout: 10 * time.Second,
  354. WriteTimeout: 600 * time.Second,
  355. }
  356. httpServer.SetKeepAlivesEnabled(true)
  357. go func() {
  358. httpServer.Serve(listener)
  359. listener.Close()
  360. }()
  361. return httpServer, nil
  362. }