join.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package functions
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "log"
  9. "math/rand"
  10. "net"
  11. "time"
  12. nodepb "github.com/gravitl/netmaker/grpc"
  13. "github.com/gravitl/netmaker/models"
  14. "github.com/gravitl/netmaker/netclient/auth"
  15. "github.com/gravitl/netmaker/netclient/config"
  16. "github.com/gravitl/netmaker/netclient/local"
  17. "github.com/gravitl/netmaker/netclient/server"
  18. "github.com/gravitl/netmaker/netclient/wireguard"
  19. "golang.zx2c4.com/wireguard/wgctrl"
  20. "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
  21. "google.golang.org/grpc"
  22. "google.golang.org/grpc/credentials"
  23. //homedir "github.com/mitchellh/go-homedir"
  24. )
  25. func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
  26. hasnet := local.HasNetwork(cfg.Network)
  27. if hasnet {
  28. err := errors.New("ALREADY_INSTALLED. Netclient appears to already be installed for " + cfg.Network + ". To re-install, please remove by executing 'sudo netclient leave -n " + cfg.Network + "'. Then re-run the install command.")
  29. return err
  30. }
  31. log.Println("attempting to join " + cfg.Network + " at " + cfg.Server.GRPCAddress)
  32. err := config.Write(&cfg, cfg.Network)
  33. if err != nil {
  34. return err
  35. }
  36. wgclient, err := wgctrl.New()
  37. if err != nil {
  38. return err
  39. }
  40. defer wgclient.Close()
  41. if cfg.Node.Network == "" {
  42. return errors.New("no network provided")
  43. }
  44. if cfg.Node.LocalRange != "" {
  45. if cfg.Node.LocalAddress == "" {
  46. log.Println("local vpn, getting local address from range: " + cfg.Node.LocalRange)
  47. ifaces, err := net.Interfaces()
  48. if err != nil {
  49. return err
  50. }
  51. _, localrange, err := net.ParseCIDR(cfg.Node.LocalRange)
  52. if err != nil {
  53. return err
  54. }
  55. var local string
  56. found := false
  57. for _, i := range ifaces {
  58. if i.Flags&net.FlagUp == 0 {
  59. continue // interface down
  60. }
  61. if i.Flags&net.FlagLoopback != 0 {
  62. continue // loopback interface
  63. }
  64. addrs, err := i.Addrs()
  65. if err != nil {
  66. return err
  67. }
  68. for _, addr := range addrs {
  69. var ip net.IP
  70. switch v := addr.(type) {
  71. case *net.IPNet:
  72. if !found {
  73. ip = v.IP
  74. local = ip.String()
  75. if cfg.Node.IsLocal == "yes" {
  76. found = localrange.Contains(ip)
  77. } else {
  78. found = true
  79. }
  80. }
  81. case *net.IPAddr:
  82. if !found {
  83. ip = v.IP
  84. local = ip.String()
  85. if cfg.Node.IsLocal == "yes" {
  86. found = localrange.Contains(ip)
  87. } else {
  88. found = true
  89. }
  90. }
  91. }
  92. }
  93. }
  94. cfg.Node.LocalAddress = local
  95. }
  96. }
  97. if cfg.Node.Password == "" {
  98. cfg.Node.Password = GenPass()
  99. }
  100. auth.StoreSecret(cfg.Node.Password, cfg.Node.Network)
  101. if cfg.Node.Endpoint == "" {
  102. if cfg.Node.IsLocal == "yes" && cfg.Node.LocalAddress != "" {
  103. cfg.Node.Endpoint = cfg.Node.LocalAddress
  104. } else {
  105. cfg.Node.Endpoint, err = getPublicIP()
  106. if err != nil {
  107. fmt.Println("Error setting cfg.Node.Endpoint.")
  108. return err
  109. }
  110. }
  111. } else {
  112. cfg.Node.Endpoint = cfg.Node.Endpoint
  113. }
  114. if privateKey == "" {
  115. wgPrivatekey, err := wgtypes.GeneratePrivateKey()
  116. if err != nil {
  117. log.Fatal(err)
  118. }
  119. privateKey = wgPrivatekey.String()
  120. cfg.Node.PublicKey = wgPrivatekey.PublicKey().String()
  121. }
  122. if cfg.Node.MacAddress == "" {
  123. macs, err := getMacAddr()
  124. if err != nil {
  125. return err
  126. } else if len(macs) == 0 {
  127. log.Fatal()
  128. } else {
  129. cfg.Node.MacAddress = macs[0]
  130. }
  131. }
  132. if cfg.Node.ListenPort == 0 {
  133. cfg.Node.ListenPort, err = GetFreePort(51821)
  134. if err != nil {
  135. fmt.Printf("Error retrieving port: %v", err)
  136. }
  137. }
  138. var wcclient nodepb.NodeServiceClient
  139. var requestOpts grpc.DialOption
  140. requestOpts = grpc.WithInsecure()
  141. if cfg.Server.GRPCSSL == "on" {
  142. h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
  143. requestOpts = grpc.WithTransportCredentials(h2creds)
  144. }
  145. conn, err := grpc.Dial(cfg.Server.GRPCAddress, requestOpts)
  146. if err != nil {
  147. log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
  148. }
  149. wcclient = nodepb.NewNodeServiceClient(conn)
  150. postnode := &models.Node{
  151. Password: cfg.Node.Password,
  152. MacAddress: cfg.Node.MacAddress,
  153. AccessKey: cfg.Server.AccessKey,
  154. Network: cfg.Network,
  155. ListenPort: cfg.Node.ListenPort,
  156. PostUp: cfg.Node.PostUp,
  157. PostDown: cfg.Node.PostDown,
  158. PersistentKeepalive: cfg.Node.PersistentKeepalive,
  159. LocalAddress: cfg.Node.LocalAddress,
  160. Interface: cfg.Node.Interface,
  161. PublicKey: cfg.Node.PublicKey,
  162. Name: cfg.Node.Name,
  163. Endpoint: cfg.Node.Endpoint,
  164. SaveConfig: cfg.Node.SaveConfig,
  165. UDPHolePunch: cfg.Node.UDPHolePunch,
  166. }
  167. if err = config.ModConfig(postnode); err != nil {
  168. return err
  169. }
  170. data, err := json.Marshal(&postnode)
  171. if err != nil {
  172. return err
  173. }
  174. res, err := wcclient.CreateNode(
  175. context.TODO(),
  176. &nodepb.Object{
  177. Data: string(data),
  178. Type: nodepb.NODE_TYPE,
  179. },
  180. )
  181. if err != nil {
  182. return err
  183. }
  184. log.Println("node created on remote server...updating configs")
  185. nodeData := res.Data
  186. var node models.Node
  187. if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
  188. return err
  189. }
  190. if node.DNSOn == "yes" {
  191. cfg.Node.DNSOn = "yes"
  192. }
  193. if !(cfg.Node.IsLocal == "yes") && node.IsLocal == "yes" && node.LocalRange != "" {
  194. node.LocalAddress, err = getLocalIP(node.LocalRange)
  195. if err != nil {
  196. return err
  197. }
  198. node.Endpoint = node.LocalAddress
  199. }
  200. err = config.ModConfig(&node)
  201. if err != nil {
  202. return err
  203. }
  204. if node.IsPending == "yes" {
  205. fmt.Println("Node is marked as PENDING.")
  206. fmt.Println("Awaiting approval from Admin before configuring WireGuard.")
  207. if cfg.Daemon != "off" {
  208. err = local.ConfigureSystemD(cfg.Network)
  209. return err
  210. }
  211. }
  212. log.Println("retrieving remote peers")
  213. peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
  214. if err != nil {
  215. log.Println("failed to retrieve peers")
  216. return err
  217. }
  218. err = wireguard.StorePrivKey(privateKey, cfg.Network)
  219. if err != nil {
  220. return err
  221. }
  222. log.Println("starting wireguard")
  223. err = wireguard.InitWireguard(&node, privateKey, peers, hasGateway, gateways)
  224. if err != nil {
  225. return err
  226. }
  227. if cfg.Daemon != "off" {
  228. err = local.ConfigureSystemD(cfg.Network)
  229. }
  230. if err != nil {
  231. return err
  232. }
  233. return err
  234. }
  235. //generate an access key value
  236. func GenPass() string {
  237. var seededRand *rand.Rand = rand.New(
  238. rand.NewSource(time.Now().UnixNano()))
  239. length := 16
  240. charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  241. b := make([]byte, length)
  242. for i := range b {
  243. b[i] = charset[seededRand.Intn(len(charset))]
  244. }
  245. return string(b)
  246. }