zerotier.go 17 KB

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