main.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. package main
  2. import (
  3. "errors"
  4. "log"
  5. "os"
  6. "os/exec"
  7. "strconv"
  8. "github.com/gravitl/netmaker/netclient/command"
  9. "github.com/gravitl/netmaker/netclient/config"
  10. "github.com/urfave/cli/v2"
  11. )
  12. func main() {
  13. app := cli.NewApp()
  14. app.Name = "Netclient CLI"
  15. app.Usage = "Netmaker's netclient agent and CLI. Used to perform interactions with Netmaker server and set local WireGuard config."
  16. app.Version = "v0.5.11"
  17. cliFlags := []cli.Flag{
  18. &cli.StringFlag{
  19. Name: "network",
  20. Aliases: []string{"n"},
  21. EnvVars: []string{"NETCLIENT_NETWORK"},
  22. Value: "all",
  23. Usage: "Network to perform specified action against.",
  24. },
  25. &cli.StringFlag{
  26. Name: "password",
  27. Aliases: []string{"p"},
  28. EnvVars: []string{"NETCLIENT_PASSWORD"},
  29. Value: "badpassword",
  30. Usage: "Password for authenticating with netmaker.",
  31. },
  32. &cli.StringFlag{
  33. Name: "endpoint",
  34. Aliases: []string{"e"},
  35. EnvVars: []string{"NETCLIENT_ENDPOINT"},
  36. Value: "",
  37. Usage: "Reachable (usually public) address for WireGuard (not the private WG address).",
  38. },
  39. &cli.StringFlag{
  40. Name: "macaddress",
  41. Aliases: []string{"m"},
  42. EnvVars: []string{"NETCLIENT_MACADDRESS"},
  43. Value: "",
  44. Usage: "Mac Address for this machine. Used as a unique identifier within Netmaker network.",
  45. },
  46. &cli.StringFlag{
  47. Name: "publickey",
  48. Aliases: []string{"pubkey"},
  49. EnvVars: []string{"NETCLIENT_PUBLICKEY"},
  50. Value: "",
  51. Usage: "Public Key for WireGuard Interface.",
  52. },
  53. &cli.StringFlag{
  54. Name: "privatekey",
  55. Aliases: []string{"privkey"},
  56. EnvVars: []string{"NETCLIENT_PRIVATEKEY"},
  57. Value: "",
  58. Usage: "Private Key for WireGuard Interface.",
  59. },
  60. &cli.StringFlag{
  61. Name: "port",
  62. EnvVars: []string{"NETCLIENT_PORT"},
  63. Value: "",
  64. Usage: "Port for WireGuard Interface.",
  65. },
  66. &cli.IntFlag{
  67. Name: "keepalive",
  68. EnvVars: []string{"NETCLIENT_KEEPALIVE"},
  69. Value: 0,
  70. Usage: "Default PersistentKeepAlive for Peers in WireGuard Interface.",
  71. },
  72. &cli.StringFlag{
  73. Name: "operatingsystem",
  74. Aliases: []string{"os"},
  75. EnvVars: []string{"NETCLIENT_OS"},
  76. Value: "",
  77. Usage: "Identifiable name for machine within Netmaker network.",
  78. },
  79. &cli.StringFlag{
  80. Name: "name",
  81. EnvVars: []string{"NETCLIENT_NAME"},
  82. Value: "",
  83. Usage: "Identifiable name for machine within Netmaker network.",
  84. },
  85. &cli.StringFlag{
  86. Name: "localaddress",
  87. EnvVars: []string{"NETCLIENT_LOCALADDRESS"},
  88. Value: "",
  89. Usage: "Local address for machine. Can be used in place of Endpoint for machines on the same LAN.",
  90. },
  91. &cli.StringFlag{
  92. Name: "address",
  93. Aliases: []string{"a"},
  94. EnvVars: []string{"NETCLIENT_ADDRESS"},
  95. Value: "",
  96. Usage: "WireGuard address for machine within Netmaker network.",
  97. },
  98. &cli.StringFlag{
  99. Name: "addressIPv6",
  100. Aliases: []string{"a6"},
  101. EnvVars: []string{"NETCLIENT_ADDRESSIPV6"},
  102. Value: "",
  103. Usage: "WireGuard address for machine within Netmaker network.",
  104. },
  105. &cli.StringFlag{
  106. Name: "interface",
  107. Aliases: []string{"i"},
  108. EnvVars: []string{"NETCLIENT_INTERFACE"},
  109. Value: "",
  110. Usage: "WireGuard local network interface name.",
  111. },
  112. &cli.StringFlag{
  113. Name: "apiserver",
  114. EnvVars: []string{"NETCLIENT_API_SERVER"},
  115. Value: "",
  116. Usage: "Address + GRPC Port (e.g. 1.2.3.4:50051) of Netmaker server.",
  117. },
  118. &cli.StringFlag{
  119. Name: "grpcserver",
  120. EnvVars: []string{"NETCLIENT_GRPC_SERVER"},
  121. Value: "",
  122. Usage: "Address + API Port (e.g. 1.2.3.4:8081) of Netmaker server.",
  123. },
  124. &cli.StringFlag{
  125. Name: "key",
  126. Aliases: []string{"k"},
  127. EnvVars: []string{"NETCLIENT_ACCESSKEY"},
  128. Value: "",
  129. Usage: "Access Key for signing up machine with Netmaker server during initial 'add'.",
  130. },
  131. &cli.StringFlag{
  132. Name: "token",
  133. Aliases: []string{"t"},
  134. EnvVars: []string{"NETCLIENT_ACCESSTOKEN"},
  135. Value: "",
  136. Usage: "Access Token for signing up machine with Netmaker server during initial 'add'.",
  137. },
  138. &cli.StringFlag{
  139. Name: "localrange",
  140. EnvVars: []string{"NETCLIENT_LOCALRANGE"},
  141. Value: "",
  142. Usage: "Local Range if network is local, for instance 192.168.1.0/24.",
  143. },
  144. &cli.StringFlag{
  145. Name: "dns",
  146. EnvVars: []string{"NETCLIENT_DNS"},
  147. Value: "on",
  148. Usage: "Sets private dns if 'on'. Ignores if 'off'. Will retrieve from network if unset.",
  149. },
  150. &cli.StringFlag{
  151. Name: "islocal",
  152. EnvVars: []string{"NETCLIENT_IS_LOCAL"},
  153. Value: "",
  154. Usage: "Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
  155. },
  156. &cli.StringFlag{
  157. Name: "isdualstack",
  158. EnvVars: []string{"NETCLIENT_IS_DUALSTACK"},
  159. Value: "",
  160. Usage: "Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
  161. },
  162. &cli.StringFlag{
  163. Name: "udpholepunch",
  164. EnvVars: []string{"NETCLIENT_UDP_HOLEPUNCH"},
  165. Value: "",
  166. Usage: "Turns on udp holepunching if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
  167. },
  168. &cli.StringFlag{
  169. Name: "ipforwarding",
  170. EnvVars: []string{"NETCLIENT_IPFORWARDING"},
  171. Value: "on",
  172. Usage: "Sets ip forwarding on if 'on'. Ignores if 'off'. On by default.",
  173. },
  174. &cli.StringFlag{
  175. Name: "postup",
  176. EnvVars: []string{"NETCLIENT_POSTUP"},
  177. Value: "",
  178. Usage: "Sets PostUp command for WireGuard.",
  179. },
  180. &cli.StringFlag{
  181. Name: "postdown",
  182. EnvVars: []string{"NETCLIENT_POSTDOWN"},
  183. Value: "",
  184. Usage: "Sets PostDown command for WireGuard.",
  185. },
  186. &cli.StringFlag{
  187. Name: "daemon",
  188. EnvVars: []string{"NETCLIENT_DAEMON"},
  189. Value: "on",
  190. Usage: "Installs daemon if 'on'. Ignores if 'off'. On by default.",
  191. },
  192. &cli.StringFlag{
  193. Name: "roaming",
  194. EnvVars: []string{"NETCLIENT_ROAMING"},
  195. Value: "on",
  196. Usage: "Checks for IP changes if 'on'. Ignores if 'off'. On by default.",
  197. },
  198. }
  199. app.Commands = []*cli.Command{
  200. {
  201. Name: "register",
  202. Usage: "Register with Netmaker Server for secure GRPC communications.",
  203. Flags: cliFlags,
  204. Action: func(c *cli.Context) error {
  205. cfg, err := config.GetCLIConfigRegister(c)
  206. if err != nil {
  207. return err
  208. }
  209. if cfg.GRPCWireGuard == "off" {
  210. log.Println("Server is not using WireGuard to secure GRPC. Skipping.")
  211. return err
  212. }
  213. if cfg.Client.ServerPrivateAddress == "" {
  214. err = errors.New("No server address provided.")
  215. return err
  216. }
  217. err = command.Register(cfg)
  218. return err
  219. },
  220. },
  221. {
  222. Name: "join",
  223. Usage: "Join a Netmaker network.",
  224. Flags: cliFlags,
  225. Action: func(c *cli.Context) error {
  226. cfg, err := config.GetCLIConfig(c)
  227. if err != nil {
  228. return err
  229. }
  230. if cfg.Network == "all" {
  231. err = errors.New("No network provided.")
  232. return err
  233. }
  234. if cfg.Server.GRPCAddress == "" {
  235. err = errors.New("No server address provided.")
  236. return err
  237. }
  238. err = command.Join(cfg)
  239. return err
  240. },
  241. },
  242. {
  243. Name: "leave",
  244. Usage: "Leave a Netmaker network.",
  245. Flags: cliFlags,
  246. // the action, or code that will be executed when
  247. // we execute our `ns` command
  248. Action: func(c *cli.Context) error {
  249. cfg, err := config.GetCLIConfig(c)
  250. if err != nil {
  251. return err
  252. }
  253. err = command.Leave(cfg)
  254. return err
  255. },
  256. },
  257. {
  258. Name: "checkin",
  259. Usage: "Checks for local changes and then checks into the specified Netmaker network to ask about remote changes.",
  260. Flags: cliFlags,
  261. // the action, or code that will be executed when
  262. // we execute our `ns` command
  263. Action: func(c *cli.Context) error {
  264. cfg, err := config.GetCLIConfig(c)
  265. if err != nil {
  266. return err
  267. }
  268. err = command.CheckIn(cfg)
  269. return err
  270. },
  271. },
  272. {
  273. Name: "push",
  274. Usage: "Push configuration changes to server.",
  275. Flags: cliFlags,
  276. // the action, or code that will be executed when
  277. // we execute our `ns` command
  278. Action: func(c *cli.Context) error {
  279. cfg, err := config.GetCLIConfig(c)
  280. if err != nil {
  281. return err
  282. }
  283. err = command.Push(cfg)
  284. return err
  285. },
  286. },
  287. {
  288. Name: "pull",
  289. Usage: "Pull latest configuration and peers from server.",
  290. Flags: cliFlags,
  291. // the action, or code that will be executed when
  292. // we execute our `ns` command
  293. Action: func(c *cli.Context) error {
  294. cfg, err := config.GetCLIConfig(c)
  295. if err != nil {
  296. return err
  297. }
  298. err = command.Pull(cfg)
  299. return err
  300. },
  301. },
  302. {
  303. Name: "list",
  304. Usage: "Get list of networks.",
  305. Flags: cliFlags,
  306. // the action, or code that will be executed when
  307. // we execute our `ns` command
  308. Action: func(c *cli.Context) error {
  309. cfg, err := config.GetCLIConfig(c)
  310. if err != nil {
  311. return err
  312. }
  313. err = command.List(cfg)
  314. return err
  315. },
  316. },
  317. {
  318. Name: "uninstall",
  319. Usage: "Uninstall the netclient system service.",
  320. Flags: cliFlags,
  321. // the action, or code that will be executed when
  322. // we execute our `ns` command
  323. Action: func(c *cli.Context) error {
  324. cfg, err := config.ReadGlobalConfig()
  325. if err != nil {
  326. return err
  327. }
  328. var gconf config.GlobalConfig
  329. gconf = *cfg
  330. err = command.Uninstall(gconf)
  331. return err
  332. },
  333. },
  334. {
  335. Name: "unregister",
  336. Usage: "Unregister the netclient from secure server GRPC.",
  337. Flags: cliFlags,
  338. // the action, or code that will be executed when
  339. // we execute our `ns` command
  340. Action: func(c *cli.Context) error {
  341. cfg, err := config.ReadGlobalConfig()
  342. if err != nil {
  343. return err
  344. }
  345. var gconf config.GlobalConfig
  346. gconf = *cfg
  347. err = command.Unregister(gconf)
  348. return err
  349. },
  350. },
  351. }
  352. // start our application
  353. getID := exec.Command("id", "-u")
  354. out, err := getID.Output()
  355. if err != nil {
  356. log.Fatal(err)
  357. }
  358. id, err := strconv.Atoi(string(out[:len(out)-1]))
  359. if err != nil {
  360. log.Fatal(err)
  361. }
  362. if id != 0 {
  363. log.Fatal("This program must be run with elevated privileges (sudo). This program installs a SystemD service and configures WireGuard and networking rules. Please re-run with sudo/root.")
  364. }
  365. _, err = exec.LookPath("wg")
  366. if err != nil {
  367. log.Println(err)
  368. log.Fatal("WireGuard not installed. Please install WireGuard (wireguard-tools) and try again.")
  369. }
  370. err = app.Run(os.Args)
  371. if err != nil {
  372. log.Fatal(err)
  373. }
  374. }