Mirror of Go implementation of WireGuard.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.go 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // +build !windows
  2. /* SPDX-License-Identifier: MIT
  3. *
  4. * Copyright (C) 2017-2020 WireGuard LLC. All Rights Reserved.
  5. */
  6. package main
  7. import (
  8. "fmt"
  9. "os"
  10. "os/signal"
  11. "runtime"
  12. "strconv"
  13. "syscall"
  14. "golang.zx2c4.com/wireguard/device"
  15. "golang.zx2c4.com/wireguard/ipc"
  16. "golang.zx2c4.com/wireguard/tun"
  17. )
  18. const (
  19. ExitSetupSuccess = 0
  20. ExitSetupFailed = 1
  21. )
  22. const (
  23. ENV_WG_TUN_FD = "WG_TUN_FD"
  24. ENV_WG_UAPI_FD = "WG_UAPI_FD"
  25. ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
  26. )
  27. func printUsage() {
  28. fmt.Printf("usage:\n")
  29. fmt.Printf("%s [-f/--foreground] INTERFACE-NAME\n", os.Args[0])
  30. }
  31. func warning() {
  32. if runtime.GOOS != "linux" || os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1" {
  33. return
  34. }
  35. fmt.Fprintln(os.Stderr, "┌───────────────────────────────────────────────────┐")
  36. fmt.Fprintln(os.Stderr, "│ │")
  37. fmt.Fprintln(os.Stderr, "│ Running this software on Linux is unnecessary, │")
  38. fmt.Fprintln(os.Stderr, "│ because the Linux kernel has built-in first │")
  39. fmt.Fprintln(os.Stderr, "│ class support for WireGuard, which will be │")
  40. fmt.Fprintln(os.Stderr, "│ faster, slicker, and better integrated. For │")
  41. fmt.Fprintln(os.Stderr, "│ information on installing the kernel module, │")
  42. fmt.Fprintln(os.Stderr, "│ please visit: <https://wireguard.com/install>. │")
  43. fmt.Fprintln(os.Stderr, "│ │")
  44. fmt.Fprintln(os.Stderr, "└───────────────────────────────────────────────────┘")
  45. }
  46. func main() {
  47. if len(os.Args) == 2 && os.Args[1] == "--version" {
  48. fmt.Printf("wireguard-go v%s\n\nUserspace WireGuard daemon for %s-%s.\nInformation available at https://www.wireguard.com.\nCopyright (C) Jason A. Donenfeld <Jason@zx2c4.com>.\n", device.WireGuardGoVersion, runtime.GOOS, runtime.GOARCH)
  49. return
  50. }
  51. warning()
  52. var foreground bool
  53. var interfaceName string
  54. if len(os.Args) < 2 || len(os.Args) > 3 {
  55. printUsage()
  56. return
  57. }
  58. switch os.Args[1] {
  59. case "-f", "--foreground":
  60. foreground = true
  61. if len(os.Args) != 3 {
  62. printUsage()
  63. return
  64. }
  65. interfaceName = os.Args[2]
  66. default:
  67. foreground = false
  68. if len(os.Args) != 2 {
  69. printUsage()
  70. return
  71. }
  72. interfaceName = os.Args[1]
  73. }
  74. if !foreground {
  75. foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1"
  76. }
  77. // get log level (default: info)
  78. logLevel := func() int {
  79. switch os.Getenv("LOG_LEVEL") {
  80. case "debug":
  81. return device.LogLevelDebug
  82. case "info":
  83. return device.LogLevelInfo
  84. case "error":
  85. return device.LogLevelError
  86. case "silent":
  87. return device.LogLevelSilent
  88. }
  89. return device.LogLevelInfo
  90. }()
  91. // open TUN device (or use supplied fd)
  92. tun, err := func() (tun.Device, error) {
  93. tunFdStr := os.Getenv(ENV_WG_TUN_FD)
  94. if tunFdStr == "" {
  95. return tun.CreateTUN(interfaceName, device.DefaultMTU)
  96. }
  97. // construct tun device from supplied fd
  98. fd, err := strconv.ParseUint(tunFdStr, 10, 32)
  99. if err != nil {
  100. return nil, err
  101. }
  102. err = syscall.SetNonblock(int(fd), true)
  103. if err != nil {
  104. return nil, err
  105. }
  106. file := os.NewFile(uintptr(fd), "")
  107. return tun.CreateTUNFromFile(file, device.DefaultMTU)
  108. }()
  109. if err == nil {
  110. realInterfaceName, err2 := tun.Name()
  111. if err2 == nil {
  112. interfaceName = realInterfaceName
  113. }
  114. }
  115. logger := device.NewLogger(
  116. logLevel,
  117. fmt.Sprintf("(%s) ", interfaceName),
  118. )
  119. logger.Info.Println("Starting wireguard-go version", device.WireGuardGoVersion)
  120. logger.Debug.Println("Debug log enabled")
  121. if err != nil {
  122. logger.Error.Println("Failed to create TUN device:", err)
  123. os.Exit(ExitSetupFailed)
  124. }
  125. // open UAPI file (or use supplied fd)
  126. fileUAPI, err := func() (*os.File, error) {
  127. uapiFdStr := os.Getenv(ENV_WG_UAPI_FD)
  128. if uapiFdStr == "" {
  129. return ipc.UAPIOpen(interfaceName)
  130. }
  131. // use supplied fd
  132. fd, err := strconv.ParseUint(uapiFdStr, 10, 32)
  133. if err != nil {
  134. return nil, err
  135. }
  136. return os.NewFile(uintptr(fd), ""), nil
  137. }()
  138. if err != nil {
  139. logger.Error.Println("UAPI listen error:", err)
  140. os.Exit(ExitSetupFailed)
  141. return
  142. }
  143. // daemonize the process
  144. if !foreground {
  145. env := os.Environ()
  146. env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD))
  147. env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD))
  148. env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND))
  149. files := [3]*os.File{}
  150. if os.Getenv("LOG_LEVEL") != "" && logLevel != device.LogLevelSilent {
  151. files[0], _ = os.Open(os.DevNull)
  152. files[1] = os.Stdout
  153. files[2] = os.Stderr
  154. } else {
  155. files[0], _ = os.Open(os.DevNull)
  156. files[1], _ = os.Open(os.DevNull)
  157. files[2], _ = os.Open(os.DevNull)
  158. }
  159. attr := &os.ProcAttr{
  160. Files: []*os.File{
  161. files[0], // stdin
  162. files[1], // stdout
  163. files[2], // stderr
  164. tun.File(),
  165. fileUAPI,
  166. },
  167. Dir: ".",
  168. Env: env,
  169. }
  170. path, err := os.Executable()
  171. if err != nil {
  172. logger.Error.Println("Failed to determine executable:", err)
  173. os.Exit(ExitSetupFailed)
  174. }
  175. process, err := os.StartProcess(
  176. path,
  177. os.Args,
  178. attr,
  179. )
  180. if err != nil {
  181. logger.Error.Println("Failed to daemonize:", err)
  182. os.Exit(ExitSetupFailed)
  183. }
  184. process.Release()
  185. return
  186. }
  187. device := device.NewDevice(tun, logger)
  188. logger.Info.Println("Device started")
  189. errs := make(chan error)
  190. term := make(chan os.Signal, 1)
  191. uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
  192. if err != nil {
  193. logger.Error.Println("Failed to listen on uapi socket:", err)
  194. os.Exit(ExitSetupFailed)
  195. }
  196. go func() {
  197. for {
  198. conn, err := uapi.Accept()
  199. if err != nil {
  200. errs <- err
  201. return
  202. }
  203. go device.IpcHandle(conn)
  204. }
  205. }()
  206. logger.Info.Println("UAPI listener started")
  207. // wait for program to terminate
  208. signal.Notify(term, syscall.SIGTERM)
  209. signal.Notify(term, os.Interrupt)
  210. select {
  211. case <-term:
  212. case <-errs:
  213. case <-device.Wait():
  214. }
  215. // clean up
  216. uapi.Close()
  217. device.Close()
  218. logger.Info.Println("Shutting down")
  219. }