zerotier.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. package ganserv
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "os"
  10. "strconv"
  11. "strings"
  12. )
  13. /*
  14. zerotier.go
  15. This hold the functions that required to communicate with
  16. a zerotier instance
  17. See more on
  18. https://docs.zerotier.com/self-hosting/network-controllers/
  19. */
  20. type NodeInfo struct {
  21. Address string `json:"address"`
  22. Clock int64 `json:"clock"`
  23. Config struct {
  24. Settings struct {
  25. AllowTCPFallbackRelay bool `json:"allowTcpFallbackRelay,omitempty"`
  26. ForceTCPRelay bool `json:"forceTcpRelay,omitempty"`
  27. HomeDir string `json:"homeDir,omitempty"`
  28. ListeningOn []string `json:"listeningOn,omitempty"`
  29. PortMappingEnabled bool `json:"portMappingEnabled,omitempty"`
  30. PrimaryPort int `json:"primaryPort,omitempty"`
  31. SecondaryPort int `json:"secondaryPort,omitempty"`
  32. SoftwareUpdate string `json:"softwareUpdate,omitempty"`
  33. SoftwareUpdateChannel string `json:"softwareUpdateChannel,omitempty"`
  34. SurfaceAddresses []string `json:"surfaceAddresses,omitempty"`
  35. TertiaryPort int `json:"tertiaryPort,omitempty"`
  36. } `json:"settings"`
  37. } `json:"config"`
  38. Online bool `json:"online"`
  39. PlanetWorldID int `json:"planetWorldId"`
  40. PlanetWorldTimestamp int64 `json:"planetWorldTimestamp"`
  41. PublicIdentity string `json:"publicIdentity"`
  42. TCPFallbackActive bool `json:"tcpFallbackActive"`
  43. Version string `json:"version"`
  44. VersionBuild int `json:"versionBuild"`
  45. VersionMajor int `json:"versionMajor"`
  46. VersionMinor int `json:"versionMinor"`
  47. VersionRev int `json:"versionRev"`
  48. }
  49. type ErrResp struct {
  50. Message string `json:"message"`
  51. }
  52. type NetworkInfo struct {
  53. AuthTokens []interface{} `json:"authTokens"`
  54. AuthorizationEndpoint string `json:"authorizationEndpoint"`
  55. Capabilities []interface{} `json:"capabilities"`
  56. ClientID string `json:"clientId"`
  57. CreationTime int64 `json:"creationTime"`
  58. DNS []interface{} `json:"dns"`
  59. EnableBroadcast bool `json:"enableBroadcast"`
  60. ID string `json:"id"`
  61. IPAssignmentPools []interface{} `json:"ipAssignmentPools"`
  62. Mtu int `json:"mtu"`
  63. MulticastLimit int `json:"multicastLimit"`
  64. Name string `json:"name"`
  65. Nwid string `json:"nwid"`
  66. Objtype string `json:"objtype"`
  67. Private bool `json:"private"`
  68. RemoteTraceLevel int `json:"remoteTraceLevel"`
  69. RemoteTraceTarget interface{} `json:"remoteTraceTarget"`
  70. Revision int `json:"revision"`
  71. Routes []interface{} `json:"routes"`
  72. Rules []struct {
  73. Not bool `json:"not"`
  74. Or bool `json:"or"`
  75. Type string `json:"type"`
  76. } `json:"rules"`
  77. RulesSource string `json:"rulesSource"`
  78. SsoEnabled bool `json:"ssoEnabled"`
  79. Tags []interface{} `json:"tags"`
  80. V4AssignMode struct {
  81. Zt bool `json:"zt"`
  82. } `json:"v4AssignMode"`
  83. V6AssignMode struct {
  84. SixPlane bool `json:"6plane"`
  85. Rfc4193 bool `json:"rfc4193"`
  86. Zt bool `json:"zt"`
  87. } `json:"v6AssignMode"`
  88. }
  89. type MemberInfo struct {
  90. ActiveBridge bool `json:"activeBridge"`
  91. Address string `json:"address"`
  92. AuthenticationExpiryTime int `json:"authenticationExpiryTime"`
  93. Authorized bool `json:"authorized"`
  94. Capabilities []interface{} `json:"capabilities"`
  95. CreationTime int64 `json:"creationTime"`
  96. ID string `json:"id"`
  97. Identity string `json:"identity"`
  98. IPAssignments []string `json:"ipAssignments"`
  99. LastAuthorizedCredential interface{} `json:"lastAuthorizedCredential"`
  100. LastAuthorizedCredentialType string `json:"lastAuthorizedCredentialType"`
  101. LastAuthorizedTime int `json:"lastAuthorizedTime"`
  102. LastDeauthorizedTime int `json:"lastDeauthorizedTime"`
  103. NoAutoAssignIps bool `json:"noAutoAssignIps"`
  104. Nwid string `json:"nwid"`
  105. Objtype string `json:"objtype"`
  106. RemoteTraceLevel int `json:"remoteTraceLevel"`
  107. RemoteTraceTarget interface{} `json:"remoteTraceTarget"`
  108. Revision int `json:"revision"`
  109. SsoExempt bool `json:"ssoExempt"`
  110. Tags []interface{} `json:"tags"`
  111. VMajor int `json:"vMajor"`
  112. VMinor int `json:"vMinor"`
  113. VProto int `json:"vProto"`
  114. VRev int `json:"vRev"`
  115. }
  116. // Get the zerotier node info from local service
  117. func getControllerInfo(token string, apiPort int) (*NodeInfo, error) {
  118. url := "http://localhost:" + strconv.Itoa(apiPort) + "/status"
  119. req, err := http.NewRequest("GET", url, nil)
  120. if err != nil {
  121. return nil, err
  122. }
  123. req.Header.Set("X-ZT1-AUTH", token)
  124. client := &http.Client{}
  125. resp, err := client.Do(req)
  126. if err != nil {
  127. return nil, err
  128. }
  129. //Read from zerotier service instance
  130. defer resp.Body.Close()
  131. payload, err := io.ReadAll(resp.Body)
  132. if err != nil {
  133. return nil, err
  134. }
  135. //Parse the payload into struct
  136. thisInstanceInfo := NodeInfo{}
  137. err = json.Unmarshal(payload, &thisInstanceInfo)
  138. if err != nil {
  139. return nil, err
  140. }
  141. return &thisInstanceInfo, nil
  142. }
  143. /*
  144. Network Functions
  145. */
  146. //Create a zerotier network
  147. func (m *NetworkManager) createNetwork() (*NetworkInfo, error) {
  148. url := fmt.Sprintf("http://localhost:"+strconv.Itoa(m.apiPort)+"/controller/network/%s______", m.ControllerID)
  149. data := []byte(`{}`)
  150. req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
  151. if err != nil {
  152. return nil, err
  153. }
  154. req.Header.Set("X-ZT1-AUTH", m.authToken)
  155. client := &http.Client{}
  156. resp, err := client.Do(req)
  157. if err != nil {
  158. return nil, err
  159. }
  160. defer resp.Body.Close()
  161. payload, err := io.ReadAll(resp.Body)
  162. if err != nil {
  163. return nil, err
  164. }
  165. networkInfo := NetworkInfo{}
  166. err = json.Unmarshal(payload, &networkInfo)
  167. if err != nil {
  168. return nil, err
  169. }
  170. return &networkInfo, nil
  171. }
  172. // List network details
  173. func (m *NetworkManager) getNetworkInfoById(networkId string) (*NetworkInfo, error) {
  174. req, err := http.NewRequest("GET", os.ExpandEnv("http://localhost:"+strconv.Itoa(m.apiPort)+"/controller/network/"+networkId+"/"), nil)
  175. if err != nil {
  176. return nil, err
  177. }
  178. req.Header.Set("X-Zt1-Auth", m.authToken)
  179. resp, err := http.DefaultClient.Do(req)
  180. if err != nil {
  181. return nil, err
  182. }
  183. defer resp.Body.Close()
  184. if resp.StatusCode != 200 {
  185. return nil, errors.New("network error. Status code: " + strconv.Itoa(resp.StatusCode))
  186. }
  187. thisNetworkInfo := NetworkInfo{}
  188. payload, err := io.ReadAll(resp.Body)
  189. if err != nil {
  190. return nil, err
  191. }
  192. err = json.Unmarshal(payload, &thisNetworkInfo)
  193. if err != nil {
  194. return nil, err
  195. }
  196. return &thisNetworkInfo, nil
  197. }
  198. func (m *NetworkManager) setNetworkInfoByID(networkId string, newNetworkInfo *NetworkInfo) error {
  199. payloadBytes, err := json.Marshal(newNetworkInfo)
  200. if err != nil {
  201. return err
  202. }
  203. payloadBuffer := bytes.NewBuffer(payloadBytes)
  204. // Create the HTTP request
  205. url := "http://localhost:" + strconv.Itoa(m.apiPort) + "/controller/network/" + networkId + "/"
  206. req, err := http.NewRequest("POST", url, payloadBuffer)
  207. if err != nil {
  208. return err
  209. }
  210. req.Header.Set("X-Zt1-Auth", m.authToken)
  211. req.Header.Set("Content-Type", "application/json")
  212. // Send the HTTP request
  213. resp, err := http.DefaultClient.Do(req)
  214. if err != nil {
  215. return err
  216. }
  217. defer resp.Body.Close()
  218. // Print the response status code
  219. if resp.StatusCode != 200 {
  220. return errors.New("network error. status code: " + strconv.Itoa(resp.StatusCode))
  221. }
  222. return nil
  223. }
  224. // List network IDs
  225. func (m *NetworkManager) listNetworkIds() ([]string, error) {
  226. req, err := http.NewRequest("GET", "http://localhost:"+strconv.Itoa(m.apiPort)+"/controller/network/", nil)
  227. if err != nil {
  228. return []string{}, err
  229. }
  230. req.Header.Set("X-Zt1-Auth", m.authToken)
  231. resp, err := http.DefaultClient.Do(req)
  232. if err != nil {
  233. return []string{}, err
  234. }
  235. defer resp.Body.Close()
  236. if resp.StatusCode != 200 {
  237. return []string{}, errors.New("network error")
  238. }
  239. networkIds := []string{}
  240. payload, err := io.ReadAll(resp.Body)
  241. if err != nil {
  242. return []string{}, err
  243. }
  244. err = json.Unmarshal(payload, &networkIds)
  245. if err != nil {
  246. return []string{}, err
  247. }
  248. return networkIds, nil
  249. }
  250. // wrapper for checking if a network id exists
  251. func (m *NetworkManager) networkExists(networkId string) bool {
  252. networkIds, err := m.listNetworkIds()
  253. if err != nil {
  254. return false
  255. }
  256. for _, thisid := range networkIds {
  257. if thisid == networkId {
  258. return true
  259. }
  260. }
  261. return false
  262. }
  263. // delete a network
  264. func (m *NetworkManager) deleteNetwork(networkID string) error {
  265. url := "http://localhost:" + strconv.Itoa(m.apiPort) + "/controller/network/" + networkID + "/"
  266. client := &http.Client{}
  267. // Create a new DELETE request
  268. req, err := http.NewRequest("DELETE", url, nil)
  269. if err != nil {
  270. return err
  271. }
  272. // Add the required authorization header
  273. req.Header.Set("X-Zt1-Auth", m.authToken)
  274. // Send the request and get the response
  275. resp, err := client.Do(req)
  276. if err != nil {
  277. return err
  278. }
  279. // Close the response body when we're done
  280. defer resp.Body.Close()
  281. s, err := io.ReadAll(resp.Body)
  282. fmt.Println(string(s), err, resp.StatusCode)
  283. // Print the response status code
  284. if resp.StatusCode != 200 {
  285. return errors.New("network error. status code: " + strconv.Itoa(resp.StatusCode))
  286. }
  287. return nil
  288. }
  289. // Configure network
  290. // Example: configureNetwork(netid, "192.168.192.1", "192.168.192.254", "192.168.192.0/24")
  291. func (m *NetworkManager) configureNetwork(networkID string, ipRangeStart string, ipRangeEnd string, routeTarget string) error {
  292. url := "http://localhost:" + strconv.Itoa(m.apiPort) + "/controller/network/" + networkID + "/"
  293. data := map[string]interface{}{
  294. "ipAssignmentPools": []map[string]string{
  295. {
  296. "ipRangeStart": ipRangeStart,
  297. "ipRangeEnd": ipRangeEnd,
  298. },
  299. },
  300. "routes": []map[string]interface{}{
  301. {
  302. "target": routeTarget,
  303. "via": nil,
  304. },
  305. },
  306. "v4AssignMode": "zt",
  307. "private": true,
  308. }
  309. payload, err := json.Marshal(data)
  310. if err != nil {
  311. return err
  312. }
  313. req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
  314. if err != nil {
  315. return err
  316. }
  317. req.Header.Set("Content-Type", "application/json")
  318. req.Header.Set("X-ZT1-AUTH", m.authToken)
  319. client := &http.Client{}
  320. resp, err := client.Do(req)
  321. if err != nil {
  322. return err
  323. }
  324. defer resp.Body.Close()
  325. // Print the response status code
  326. if resp.StatusCode != 200 {
  327. return errors.New("network error. status code: " + strconv.Itoa(resp.StatusCode))
  328. }
  329. return nil
  330. }
  331. func (m *NetworkManager) setAssignedIps(networkID string, memid string, newIps []string) error {
  332. url := "http://localhost:" + strconv.Itoa(m.apiPort) + "/controller/network/" + networkID + "/member/" + memid
  333. data := map[string]interface{}{
  334. "ipAssignments": newIps,
  335. }
  336. payload, err := json.Marshal(data)
  337. if err != nil {
  338. return err
  339. }
  340. req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
  341. if err != nil {
  342. return err
  343. }
  344. req.Header.Set("Content-Type", "application/json")
  345. req.Header.Set("X-ZT1-AUTH", m.authToken)
  346. client := &http.Client{}
  347. resp, err := client.Do(req)
  348. if err != nil {
  349. return err
  350. }
  351. defer resp.Body.Close()
  352. // Print the response status code
  353. if resp.StatusCode != 200 {
  354. return errors.New("network error. status code: " + strconv.Itoa(resp.StatusCode))
  355. }
  356. return nil
  357. }
  358. func (m *NetworkManager) setNetworkNameAndDescription(netid string, name string, desc string) error {
  359. // Convert string to rune slice
  360. r := []rune(name)
  361. // Loop over runes and remove non-ASCII characters
  362. for i, v := range r {
  363. if v > 127 {
  364. r[i] = ' '
  365. }
  366. }
  367. // Convert back to string and trim whitespace
  368. name = strings.TrimSpace(string(r))
  369. url := "http://localhost:" + strconv.Itoa(m.apiPort) + "/controller/network/" + netid + "/"
  370. data := map[string]interface{}{
  371. "name": name,
  372. }
  373. payload, err := json.Marshal(data)
  374. if err != nil {
  375. return err
  376. }
  377. req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
  378. if err != nil {
  379. return err
  380. }
  381. req.Header.Set("Content-Type", "application/json")
  382. req.Header.Set("X-ZT1-AUTH", m.authToken)
  383. client := &http.Client{}
  384. resp, err := client.Do(req)
  385. if err != nil {
  386. return err
  387. }
  388. defer resp.Body.Close()
  389. // Print the response status code
  390. if resp.StatusCode != 200 {
  391. return errors.New("network error. status code: " + strconv.Itoa(resp.StatusCode))
  392. }
  393. meta := m.GetNetworkMetaData(netid)
  394. if meta != nil {
  395. meta.Desc = desc
  396. m.WriteNetworkMetaData(netid, meta)
  397. }
  398. return nil
  399. }
  400. func (m *NetworkManager) getNetworkNameAndDescription(netid string) (string, string, error) {
  401. //Get name from network info
  402. netinfo, err := m.getNetworkInfoById(netid)
  403. if err != nil {
  404. return "", "", err
  405. }
  406. name := netinfo.Name
  407. //Get description from meta
  408. desc := ""
  409. networkMeta := m.GetNetworkMetaData(netid)
  410. if networkMeta != nil {
  411. desc = networkMeta.Desc
  412. }
  413. return name, desc, nil
  414. }
  415. /*
  416. Member functions
  417. */
  418. func (m *NetworkManager) getNetworkMembers(networkId string) ([]string, error) {
  419. url := "http://localhost:" + strconv.Itoa(m.apiPort) + "/controller/network/" + networkId + "/member"
  420. reqBody := bytes.NewBuffer([]byte{})
  421. req, err := http.NewRequest("GET", url, reqBody)
  422. if err != nil {
  423. return nil, err
  424. }
  425. req.Header.Set("X-ZT1-AUTH", m.authToken)
  426. client := &http.Client{}
  427. resp, err := client.Do(req)
  428. if err != nil {
  429. return nil, err
  430. }
  431. defer resp.Body.Close()
  432. if resp.StatusCode != http.StatusOK {
  433. return nil, errors.New("failed to get network members")
  434. }
  435. memberList := map[string]int{}
  436. payload, err := io.ReadAll(resp.Body)
  437. if err != nil {
  438. return nil, err
  439. }
  440. err = json.Unmarshal(payload, &memberList)
  441. if err != nil {
  442. return nil, err
  443. }
  444. members := make([]string, 0, len(memberList))
  445. for k := range memberList {
  446. members = append(members, k)
  447. }
  448. return members, nil
  449. }
  450. func (m *NetworkManager) memberExistsInNetwork(netid string, memid string) bool {
  451. //Get a list of member
  452. memberids, err := m.getNetworkMembers(netid)
  453. if err != nil {
  454. return false
  455. }
  456. for _, thisMemberId := range memberids {
  457. if thisMemberId == memid {
  458. return true
  459. }
  460. }
  461. return false
  462. }
  463. // Get a network memeber info by netid and memberid
  464. func (m *NetworkManager) getNetworkMemberInfo(netid string, memberid string) (*MemberInfo, error) {
  465. req, err := http.NewRequest("GET", "http://localhost:"+strconv.Itoa(m.apiPort)+"/controller/network/"+netid+"/member/"+memberid, nil)
  466. if err != nil {
  467. return nil, err
  468. }
  469. req.Header.Set("X-Zt1-Auth", m.authToken)
  470. resp, err := http.DefaultClient.Do(req)
  471. if err != nil {
  472. return nil, err
  473. }
  474. defer resp.Body.Close()
  475. thisMemeberInfo := &MemberInfo{}
  476. payload, err := io.ReadAll(resp.Body)
  477. if err != nil {
  478. return nil, err
  479. }
  480. err = json.Unmarshal(payload, &thisMemeberInfo)
  481. if err != nil {
  482. return nil, err
  483. }
  484. return thisMemeberInfo, nil
  485. }
  486. // Set the authorization state of a member
  487. func (m *NetworkManager) AuthorizeMember(netid string, memberid string, setAuthorized bool) error {
  488. url := "http://localhost:" + strconv.Itoa(m.apiPort) + "/controller/network/" + netid + "/member/" + memberid
  489. payload := []byte(`{"authorized": true}`)
  490. if !setAuthorized {
  491. payload = []byte(`{"authorized": false}`)
  492. }
  493. req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
  494. if err != nil {
  495. return err
  496. }
  497. req.Header.Set("X-ZT1-AUTH", m.authToken)
  498. client := &http.Client{}
  499. resp, err := client.Do(req)
  500. if err != nil {
  501. return err
  502. }
  503. defer resp.Body.Close()
  504. if resp.StatusCode != 200 {
  505. return errors.New("network error. Status code: " + strconv.Itoa(resp.StatusCode))
  506. }
  507. return nil
  508. }
  509. // Delete a member from the network
  510. func (m *NetworkManager) deleteMember(netid string, memid string) error {
  511. req, err := http.NewRequest("DELETE", "http://localhost:"+strconv.Itoa(m.apiPort)+"/controller/network/"+netid+"/member/"+memid, nil)
  512. if err != nil {
  513. return err
  514. }
  515. req.Header.Set("X-Zt1-Auth", os.ExpandEnv(m.authToken))
  516. resp, err := http.DefaultClient.Do(req)
  517. if err != nil {
  518. return err
  519. }
  520. defer resp.Body.Close()
  521. if resp.StatusCode != 200 {
  522. return errors.New("network error. Status code: " + strconv.Itoa(resp.StatusCode))
  523. }
  524. return nil
  525. }
  526. // Make the host to join a given network
  527. func (m *NetworkManager) joinNetwork(netid string) error {
  528. req, err := http.NewRequest("POST", "http://localhost:"+strconv.Itoa(m.apiPort)+"/network/"+netid, nil)
  529. if err != nil {
  530. return err
  531. }
  532. req.Header.Set("X-Zt1-Auth", os.ExpandEnv(m.authToken))
  533. resp, err := http.DefaultClient.Do(req)
  534. if err != nil {
  535. return err
  536. }
  537. defer resp.Body.Close()
  538. if resp.StatusCode != 200 {
  539. return errors.New("network error. Status code: " + strconv.Itoa(resp.StatusCode))
  540. }
  541. return nil
  542. }
  543. // Make the host to leave a given network
  544. func (m *NetworkManager) leaveNetwork(netid string) error {
  545. req, err := http.NewRequest("DELETE", "http://localhost:"+strconv.Itoa(m.apiPort)+"/network/"+netid, nil)
  546. if err != nil {
  547. return err
  548. }
  549. req.Header.Set("X-Zt1-Auth", os.ExpandEnv(m.authToken))
  550. resp, err := http.DefaultClient.Do(req)
  551. if err != nil {
  552. return err
  553. }
  554. defer resp.Body.Close()
  555. if resp.StatusCode != 200 {
  556. return errors.New("network error. Status code: " + strconv.Itoa(resp.StatusCode))
  557. }
  558. return nil
  559. }