wgcentos.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package wg
  2. import (
  3. "bytes"
  4. _ "embed"
  5. "fmt"
  6. "log"
  7. "os/exec"
  8. "text/template"
  9. )
  10. const (
  11. ExitSetupSuccess = 0
  12. ExitSetupFailed = 1
  13. )
  14. const (
  15. ENV_WG_TUN_FD = "WG_TUN_FD"
  16. ENV_WG_UAPI_FD = "WG_UAPI_FD"
  17. ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
  18. )
  19. //go:embed wireguard.conf.templ
  20. var confTmpl string
  21. type WireguardTemplateSeed struct {
  22. VpnClientPrivateKey string
  23. VpnClientAddress string
  24. Peers []WireguardTemplatePeer
  25. }
  26. type WireguardTemplatePeer struct {
  27. Pubkey string
  28. Address string
  29. Port int
  30. }
  31. /*
  32. Render out a client configuration file, utilizing the data provided from Semaphore and the daemon keyring
  33. :param tmpl: a template.Template that will be populated with the VPN data
  34. :param wgData: a WireGuardTemplateSeed struct that contains all the info needed to populate a wireguard config file
  35. */
  36. func RenderClientConfiguration(wgData WireguardTemplateSeed) ([]byte, error) {
  37. buff := bytes.NewBuffer([]byte{})
  38. tmpl, err := template.New("wireguard.conf.templ").Parse(confTmpl)
  39. if err != nil {
  40. log.Fatal(err)
  41. }
  42. err = tmpl.Execute(buff, wgData)
  43. if err != nil {
  44. return buff.Bytes(), &TemplatingError{TemplateData: wgData, Msg: err.Error()}
  45. }
  46. return buff.Bytes(), nil
  47. }
  48. /*
  49. Start a wireguard interface
  50. */
  51. func ChangeWgInterfaceState(intfName string, state string) ([]byte, error) {
  52. wgCmd := exec.Command("wg-quick", state, intfName)
  53. return wgCmd.Output()
  54. /*
  55. var foreground bool
  56. if !foreground {
  57. foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1"
  58. }
  59. // get log level (default: info)
  60. logLevel := func() int {
  61. switch os.Getenv("LOG_LEVEL") {
  62. case "verbose", "debug":
  63. return device.LogLevelVerbose
  64. case "error":
  65. return device.LogLevelError
  66. case "silent":
  67. return device.LogLevelSilent
  68. }
  69. return device.LogLevelError
  70. }()
  71. // open TUN device (or use supplied fd)
  72. tdev, err := func() (tun.Device, error) {
  73. tunFdStr := os.Getenv(ENV_WG_TUN_FD)
  74. if tunFdStr == "" {
  75. return tun.CreateTUN(intfName, device.DefaultMTU)
  76. }
  77. // construct tun device from supplied fd
  78. fd, err := strconv.ParseUint(tunFdStr, 10, 32)
  79. if err != nil {
  80. return nil, err
  81. }
  82. err = unix.SetNonblock(int(fd), true)
  83. if err != nil {
  84. return nil, err
  85. }
  86. file := os.NewFile(uintptr(fd), "")
  87. return tun.CreateTUNFromFile(file, device.DefaultMTU)
  88. }()
  89. if err == nil {
  90. realInterfaceName, err2 := tdev.Name()
  91. if err2 == nil {
  92. intfName = realInterfaceName
  93. }
  94. }
  95. logger := device.NewLogger(
  96. logLevel,
  97. fmt.Sprintf("(%s) ", intfName),
  98. )
  99. if err != nil {
  100. logger.Errorf("Failed to create TUN device: %v", err)
  101. os.Exit(ExitSetupFailed)
  102. }
  103. // open UAPI file (or use supplied fd)
  104. fileUAPI, err := func() (*os.File, error) {
  105. uapiFdStr := os.Getenv(ENV_WG_UAPI_FD)
  106. if uapiFdStr == "" {
  107. return ipc.UAPIOpen(intfName)
  108. }
  109. // use supplied fd
  110. fd, err := strconv.ParseUint(uapiFdStr, 10, 32)
  111. if err != nil {
  112. return nil, err
  113. }
  114. return os.NewFile(uintptr(fd), ""), nil
  115. }()
  116. if err != nil {
  117. logger.Errorf("UAPI listen error: %v", err)
  118. os.Exit(ExitSetupFailed)
  119. return
  120. }
  121. // daemonize the process
  122. if !foreground {
  123. env := os.Environ()
  124. env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD))
  125. env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD))
  126. env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND))
  127. files := [3]*os.File{}
  128. if os.Getenv("LOG_LEVEL") != "" && logLevel != device.LogLevelSilent {
  129. files[0], _ = os.Open(os.DevNull)
  130. files[1] = os.Stdout
  131. files[2] = os.Stderr
  132. } else {
  133. files[0], _ = os.Open(os.DevNull)
  134. files[1], _ = os.Open(os.DevNull)
  135. files[2], _ = os.Open(os.DevNull)
  136. }
  137. attr := &os.ProcAttr{
  138. Files: []*os.File{
  139. files[0], // stdin
  140. files[1], // stdout
  141. files[2], // stderr
  142. tdev.File(),
  143. fileUAPI,
  144. },
  145. Dir: ".",
  146. Env: env,
  147. }
  148. path, err := os.Executable()
  149. if err != nil {
  150. logger.Errorf("Failed to determine executable: %v", err)
  151. os.Exit(ExitSetupFailed)
  152. }
  153. process, err := os.StartProcess(
  154. path,
  155. os.Args,
  156. attr,
  157. )
  158. if err != nil {
  159. logger.Errorf("Failed to daemonize: %v", err)
  160. os.Exit(ExitSetupFailed)
  161. }
  162. process.Release()
  163. return
  164. }
  165. device := device.NewDevice(tdev, conn.NewDefaultBind(), logger)
  166. logger.Verbosef("Device started")
  167. errs := make(chan error)
  168. term := make(chan os.Signal, 1)
  169. uapi, err := ipc.UAPIListen(intfName, fileUAPI)
  170. if err != nil {
  171. logger.Errorf("Failed to listen on uapi socket: %v", err)
  172. os.Exit(ExitSetupFailed)
  173. }
  174. go func() {
  175. for {
  176. conn, err := uapi.Accept()
  177. if err != nil {
  178. errs <- err
  179. return
  180. }
  181. go device.IpcHandle(conn)
  182. }
  183. }()
  184. logger.Verbosef("UAPI listener started")
  185. // wait for program to terminate
  186. signal.Notify(term, unix.SIGTERM)
  187. signal.Notify(term, os.Interrupt)
  188. select {
  189. case <-term:
  190. case <-errs:
  191. case <-device.Wait():
  192. }
  193. // clean up
  194. uapi.Close()
  195. device.Close()
  196. logger.Verbosef("Shutting down")
  197. */
  198. }
  199. type TemplatingError struct {
  200. TemplateData WireguardTemplateSeed
  201. Msg string
  202. }
  203. func (t *TemplatingError) Error() string {
  204. return fmt.Sprintf("There was an error executing the template file: %s, Seed data: %+v\n", t.Msg, t.TemplateData)
  205. }